dsh-helper
🌏 English · 中文
A DSH plugin that pops native Windows notifications when an agent session finishes, fails, or needs your confirmation — with an optional completion chime — so you can walk away from long runs and still know the moment something needs you.
✨ Features
- 🔔 Task notifications — a native Windows toast when the agent goes idle (task complete), hits an error, is about to ask you a question, or a tool needs permission approval.
- 🔊 Completion chime — plays a sound when a session finishes. Ships with a built-in synthesized two-note chime; volume is adjustable (0–100) and you can point it at any local audio file (wav / mp3 / wma).
- ⚙️ Settings panel — a Task Notifications (dsh-helper) section in DSH Settings with four notification toggles plus the sound controls.
- 🧪 Three test buttons — preview each real notification type (complete / multi-choice confirm / permission approval) with one click.
- 🪶 Zero native dependencies — notifications go through PowerShell WinRT Toast, so there is nothing to compile.
- 🔁 Hot reload — configuration is written back to the profile's
cordis.patch.yml and picked up by DSH's patch watcher, no restart needed.
🚀 Installation
Prerequisites: DSH 0.1.2-rc.1+ with the web profile already initialized (run dsh web at least once), Node.js ≥ 20, pnpm ≥ 10.
Option 1 — npm registry (recommended)
dsh plugin --profile web add dsh-helper@latest
The package ships prebuilt artifacts (lib/ is published) and contains no install scripts, so pnpm never asks you to authorize a build.
Option 2 — from the git repo
dsh plugin --profile web add github:sunligh91/dsh-helper
A git install pulls source and has pnpm run prepare; pnpm ≥10 refuses until you explicitly allow it. Copy the exact package key pnpm prints into that profile's pnpm-workspace.yaml:
allowBuilds:
dsh-helper: true
That authorization means "allow this package's code to run on your machine at install time". If you only want prebuilt code, use Option 1.
Option 3 — from source
git clone https://github.com/sunligh91/dsh-helper.git
cd dsh-helper
# link it into your web profile
cd ~/.dsh/profiles/web
pnpm add file:/absolute/path/to/dsh-helper
Then add "dsh-helper" to the dsh.profile.bundles array in ~/.dsh/profiles/web/package.json, and hard-refresh your browser (Ctrl/Cmd + Shift + R).
⚙️ Configuration
Go to Settings → Task Notifications (dsh-helper).
| Key | Default | Description |
|---|
notifyOnComplete | true | Notify when a session finishes (deduped to once per 60 s per session). |
notifyOnError | true | Notify when a session hits an error. |
notifyOnConfirm | true | Notify when the agent is about to ask you a question (multi-choice). |
notifyOnPermission | true | Notify when a tool triggers a permission approval dialog. |
soundOnComplete | true | Play the completion chime after the completion toast. |
soundVolume | 70 | Chime volume, 0–100. |
soundFile | "" | Path to a local audio file (wav / mp3 / wma). Empty = the bundled chime; if the custom file is missing it falls back to the bundled chime, then to Windows built-in notify sounds. |
Defaults ship in cordis.patch.yml; your overrides are written to ~/.dsh/profiles/web/cordis.patch.yml.
🔌 How it works
| DSH event | Behaviour |
|---|
agent/status (idle) | Completion toast + chime |
agent/request-error | Error toast (passthrough — this plugin never blocks or retries) |
tools/pre-execute (ask_user_question) | Confirmation toast (multi-choice question) |
session/event → approval/asked | Permission toast (tool approval) |
Approval notifications listen on the session audit event approval/asked rather than the approval/request waterfall. Cordis waterfall semantics are "not calling next() vetoes the rest of the chain", so any earlier listener that returns a result directly (e.g. an auto-approval gate) would permanently starve later listeners. approval/asked is a log-only audit event written before the decision, so it cannot be pre-empted.
The settings HTTP route (/_dsh/dsh-helper/settings) is bound to localhost only — anything other than 127.0.0.1 / ::1 gets a 403.
🔄 Need auto-retry too? This plugin intentionally does notifications only. Pair it with a retry plugin such as dsh-task-reliability, which returns { kind: 'retry' } on the same event.
🛠️ Development
git clone https://github.com/sunligh91/dsh-helper.git
cd dsh-helper
| File | Role |
|---|
lib/index.js | Host half — cordis plugin: event hooks + settings route |
lib/client.js | Client half — registered via window.__ModuleLoader__, no build step |
cordis.patch.yml | Default configuration inserted into the profile |
Both halves are plain ES modules / UMD — there is no bundler, so edit and reload.
⚠️ Known limitations
- Notifications target Windows (PowerShell WinRT Toast). On macOS/Linux the plugin still loads, but toasts and sounds are silent no-ops.
- Sound playback uses WPF MediaPlayer via PowerShell. If that's unavailable it falls back to
System.Media.SoundPlayer, which only plays wav and ignores the volume setting.
- If Windows Focus Assist / Do Not Disturb is on, toasts may be suppressed.
- Delivery identity (handled automatically since 0.5.0): Windows requires a desktop app to have a Start-Menu shortcut carrying
System.AppUserModel.ID, otherwise toasts are intermittently and silently dropped (especially while a foreground window exists) — the symptom users report as "I only get notifications while the app is focused". The plugin idempotently creates that shortcut on startup (%APPDATA%\Microsoft\Windows\Start Menu\Programs\dsh-helper.lnk) — no manual step, no admin rights.
- If a cleanup tool removes the shortcut, it is recreated on the next DSH start.
📄 License
MIT © sunligh91
📝 Changelog
- 0.5.0 — Fixed "no notifications unless the app is focused": Windows requires a desktop app's Start-Menu shortcut to carry
System.AppUserModel.ID, otherwise toasts are intermittently dropped silently. The plugin now idempotently creates that shortcut at startup (runtime-created, so the package ships no install scripts and npm installation needs no build authorization). Also: approval notifications now listen on session/event → approval/asked instead of the approval/request waterfall, so an auto-approval gate can no longer starve them.
- 0.4.4 — Removed the global throttle introduced in 0.4.3 (it swallowed completion notifications from concurrent main sessions). Only the sub-agent filter remains.
- 0.4.3 — Fixed notification flooding: completion notifications no longer fire for sub-agents (dsh runs several sub-agents in parallel and each one finishing posted a "task complete" toast, flooding the notification center — main session ids carry a
session- prefix while sub-agent ids are bare UUIDs, used for filtering); added a global 60s throttle so multiple main sessions finishing together still post at most one toast.
- 0.4.2 — The toast header now shows a real app name: the AUMID switched from the borrowed File Explorer GUID to
dsh-helper, with its DisplayName idempotently written to HKCU\Software\Classes\AppUserModelId\dsh-helper before every send — the header changes from a hex GUID to dsh-helper.
- 0.4.1 — Fixed notifications falling back to a popup dialog:
GetTemplateContent was mistakenly called on the ToastNotifier instance (the method belongs to the static ToastNotificationManager class), so the WinRT toast never actually succeeded and every notification took the WScript dialog fallback. Now calls the correct target — real toasts verified.
- 0.4.0 — Added a "needs permission" notification (hooks the
approval/request event for tool approval dialogs); the settings panel now has three test buttons: complete / multi-choice confirm / permission.
- 0.3.2 — Fixed confirmation toasts not appearing. Windows silently drops WinRT toasts sent under an unregistered custom app id, so notifications are now sent under File Explorer's always-registered AUMID. Added a
WScript.Shell popup fallback for environments where WinRT is unavailable.
- 0.3.1 — Added temporary diagnostic logging (to be removed once the confirm-notification issue is verified resolved).