A DeepSeek Harness (DSH) Web UI plugin that tells you, audibly and visibly, when the model has stopped and needs you:
- raises a system notification (Windows/OS toast with the system sound and
a popup message) whenever any session finishes a turn while you are not
looking at that exact session — a question is asked (
ask_user_question), a plan is finished (exit_plan_mode), a turn/session completes, or a turn ends in error — and - shows a pending-notification count as a number badge on the app icon
(1 notification →
1, two →2, …).
Windows 系统通知(弹窗 + 系统提示音)见 README.zh.md。
中文说明见 README.zh.md。
The trigger is per session, not per window: whenever any session's turn finishes and you are not actively looking at that specific session, dsh-notify raises an alert. That covers background tasks/sessions completing while you chat in the foreground one, and the current session completing while the app is in the background. The one case that is skipped is a turn finishing in the exact session you are looking at while the window has focus.
For each completed turn that needs your attention:
- raises a system popup notification via the Web Notifications API
(
new Notification(...)) — on Windows this is a toast with the system notification sound and a popup message. Each toast shows:- title = the conversation (session) name, e.g.
Test1; - body = the prompt that was sent (
提示词:…), then the status (已完成/正在等待你的回答/计划已提交审阅/本轮出错), plus(当前共 N 个待处理提醒)when several are pending. A one-time permission prompt appears on your first interaction with the app. If notifications are unavailable or denied, it falls back to a synthesized Web Audio chime (no asset, works offline, CSP-friendly).
- title = the conversation (session) name, e.g.
- increments the badge count and displays it on the app icon. One pending
notification shows
1, a second shows2, and so on. Returning to the window (focus / visibilitychange) clears the badge.
The badge is delivered through three layers, in order of capability:
- OS dock / taskbar badge via the App Badging API
(
navigator.setAppBadge(n)) — this is the real “number on the app icon” when DSH runs inside Electron with badging enabled, or as an installed PWA. - Tab title badge — the count is prefixed to
document.title(e.g.(2) DeepSeek Harness); always works in any browser tab. - Favicon badge — a red dot with the number is drawn onto the tab icon.
Only the currently selected session is watched. Event detection uses the running bit and the latest assistant message’s tool calls from the session’s conversation snapshot — no DOM poking, no host RPC.
- DeepSeek Harness ≥
0.1.0-rc.6(Web UI profile) - For the popup + sound: grant the site/browser notification permission (a one-time prompt appears on your first click/key press). Notifications unavailable or denied → auto-fallback to a synthesized Web Audio chime (which needs a prior user gesture on the page due to the autoplay policy).
The package ships prebuilt (lib/ is committed), so no build step is needed.
Hand this repository URL to your DSH agent (it reads AGENTS.md and installs
it), or:
dsh plugin --profile web add github:<owner>/dsh-notify- Clone/unpack to a stable path
$P(e.g.~/dsh-notify). - Make the package resolvable from the profile’s module fallback (the linked
name must equal
dsh-notify):# POSIX mkdir -p "$DSH_HOME/profiles/node_modules" ln -s "$P" "$DSH_HOME/profiles/node_modules/dsh-notify" # Windows (no admin needed): junction New-Item -ItemType Junction -Path "$env:USERPROFILE\.dsh\profiles\node_modules\dsh-notify" -Target "$P"
- In
$DSH_HOME/profiles/web/package.json:- add
"dsh-notify": "link:$P"todependencies; - append
"dsh-notify"todsh.profile.bundles.
- add
- Restart DSH (plugin-set changes take effect on restart), then refresh the Web UI.
Plain-JS knobs at the top of lib/client.js (no rebuild or restart beyond the
plugin reload):
| Flag | Default | Meaning |
|---|---|---|
USE_SYSTEM_NOTIFICATION |
true |
raise a Windows/OS popup toast (with system sound) as the primary alert |
USE_BEEP_FALLBACK |
true |
fall back to the synthesized chime when notifications are unavailable/denied |
MIN_BEEP_GAP_MS |
800 |
minimum gap between alerts to avoid rapid duplicates |
The client bundle is hand-written plain JS (lib/client.js) and runs through
DSH’s client-modules loader as a window.__ModuleLoader__.load({ id, factory })
CJS factory — exactly the pattern used by the other hand-written DSH plugins.
Run node --check lib/client.js to syntax-check.
- The OS dock/taskbar badge only appears when the browser context supports the App Badging API (Electron with badging enabled, or an installed PWA); all environments still get the tab-title + favicon badge, which always work.
- The system popup needs notification permission; the badge/title/favicon always update regardless.
- All host-listed sessions are watched for background completions. The failing
rich classification (question/plan) and the prompt are read from a session's
conversation snapshot when its window/binding is available; otherwise they
fall back to the session name +
已完成and no prompt.