dsh-record
most-silence/dsh-record
Adds a composer microphone button that records audio as MP3 (default), WAV, or WebM and attaches it to the current prompt as a conversation file attachment. The format is chosen on the plugin's own detail page under Settings > Plugins; recordings are passed to the host through the conversation draft-attachment channel and are not written to disk by the plugin.
Установка
dsh plugin --profile web add github:most-silence/dsh-recordREADME
dsh-record
A DeepSeek Harness (dsh) plugin that puts a microphone button in the composer: click to record, click again to stop, and the recording is attached to your current prompt as a conversation file attachment. The output format — MP3 (default), WAV, or WebM — is chosen on the plugin's settings page.
Features
- Composer microphone button — registered at the
conversation.input.rightslot, before the submit action. No floating widgets; coexists with other composer controls. - Format chosen on the settings page — the plugin declares a Loader
Configwith a singleformatfield (mp3/wav/webm, defaultmp3). Pick it in Settings → Plugins → dsh-record; the browser half reads the saved choice overGET /dsh-record/configat startup (falling back tomp3if the route is unreachable). - Language-aware tooltip — hovering the mic shows 录音 on a Chinese interface and Record on an English one. The button registers
zh/endictionaries with the host locale service, so the tooltip, aria-label and status notices follow the interface language and update when you switch it. - Real-time recording — browser
MediaRecorder, webm/opus preferred with capability-based fallback. An elapsed timer and a live file-name preview (rec-YYYYMMDD-HHMMSS-<n>s.mp3) show while recording. - Three output formats (transcoded in the browser after you press stop):
- MP3 — decoded from the native container and encoded via lamejs (128 kbps CBR). No server-side dependency.
- WAV — lossless 16-bit PCM, decoded and re-wrapped.
- WebM — the browser's native Opus container, no transcoding; smallest file, fastest attach.
- Prompt attachment — the file is registered through the host draft-attachment channel (
conversation.createDrafts+inputActions.addAttachments) and shows as a composer file card with upload progress, riding the normal upload queue with your prompt. - Graceful fallback — if MP3/WAV transcoding fails (e.g.
OfflineAudioContextunavailable), the raw WebM is attached instead, so a recording is never lost. - Cancel discipline — Escape, the ✕ button, or leaving the tab discards the recording; recordings under 0.5 s are dropped; a stop during an in-flight submit releases the draft cleanly.
The plugin records, optionally transcodes, and attaches the file to your prompt. It also writes recordings to the configured directory when a save folder is set. It performs no speech recognition — pair it with a speech-to-text plugin such as dsh-stt.
Install
From the marketplace (recommended)
Install it from the plugin marketplace. The listing points at the prebuilt tarball attached to the latest release, so nothing is compiled on your machine and no build toolchain is needed.
From source
The
lib/build output is not committed to this repository (it is gitignored). A fresh clone therefore has nomainentry, anddsh plugin add file:<clone>fails with a missinglib/index.js. Build before installing:
git clone https://github.com/most-silence/dsh-record
cd dsh-record
npm install
npm run build # required: produces lib/index.js + lib/client.js
dsh plugin --profile <your-profile> add file:$PWD
Prefer to skip the build? Download dsh-record.tgz from the latest release and install that instead — it already contains lib/:
dsh plugin --profile <your-profile> add file:dsh-record.tgz
Restart the dsh host after installing, then refresh the web page.
Configuration
Settings → Plugins → dsh-record (open the plugin's own detail page) exposes:
| Field | Values | Meaning |
|---|---|---|
format | mp3 (default) · wav · webm | Output container. MP3 and WAV are transcoded in the browser when you stop; WebM is attached as captured. Takes effect on the next page load. |
dirMode | workspace (default) · custom | Where recordings are written: the current workspace root, or a fixed folder. |
customDir | absolute path | The folder used when dirMode is custom. Recordings are written here through a same-origin-guarded host route (file name sanitized, .. traversal rejected, 64 MB cap). |
Changing format or the directory takes effect on the next page load, since the browser half reads the configuration once at startup.
Architecture
browser half (lib/client.js) host half (lib/index.js)
├─ mic button @ conversation.input.right ├─ Config schema (volatile)
├─ settings card @ plugins.bundle.config │ { format, dirMode, customDir }
├─ zh/en dictionaries → locale service ├─ GET /dsh-record/config → serves config
├─ MediaRecorder → webm/opus └─ POST /dsh-record/save → writes the file
├─ decode → lamejs (mp3) / PCM wrap (wav)
└─ attach via createDrafts + addAttachments
Three hardening rules keep the plugin from ever blocking profile startup — all learned from real crashes:
@breezystack/lamejsis bundled inline. The DSH module table is frozen and does not contain lamejs, so leaving it as a build-time external makesrequire("@breezystack/lamejs")miss the table and abort the whole web boot.tsdownforces it inline (noExternal).- The host
Configschema usesz.union([...]), neverz.enum([...]), and schemastery staysexternal. The host's schemastery version has noenummethod, and a schema built from a bundled private copy is incompatible with the host validator — either one throws during import and fails thedsh-recordrow asrequired, taking down the profile. - The schema is marked
.volatile(). The host's settings projection only surfaces volatile fields; a plain schema renders no form at all, which is why an earlier configuration page appeared empty.
Development
npm install
npm run build # tsdown: lib/index.js (ESM) + lib/client.js (CJS, ModuleLoader-wrapped)
npm test # 21 node:test cases: factory (9) + encoders (5) + settings (7)
Tests run with Node 24 (native TypeScript type stripping); no browser needed.
Known limitations
- The attachment channel relies on host client contracts verified on dsh 0.2.1-rc.2 (
conversation.input.rightslot,createDrafts/addAttachments). Upstream changes may degrade to an inline error notice. - MP3/WAV transcoding runs after you press stop (not during capture), so very long recordings add a brief encode pause.
- Recording requires a microphone-permission grant; the page must be served over HTTPS or localhost.
- The output format and directory live in the host profile config, not the browser — they are read once per page load, so a change applies after a refresh.
- The custom directory is typed by hand; an in-app folder-picker button is planned for the next minor version.
License
Похожие плагины
dsh-web-ui (dsh-tool-describe-image)
zhu1090093659/dsh-web-ui
modlens
liustack/modlens
ipollowork
devin-axis/ipollowork
dsh-vision-router
ysr666/dsh-vision-router