pitetow/dsh-notify-on-complete

Desktop notifications for DeepSeek Harness (dsh) — run completion, questions, approvals. Zero-dependency Cordis plugin. | DeepSeek Harness(dsh)桌面通知插件:运行结束 / 提问 / 审批时提醒,零依赖 Cordis 插件。

Bundle 已验证 MIT TypeScript 未知
Bundle 已验证

已收录

4

Notify

Bundle 已验证

版本未知
语言TypeScript
许可证MIT
在 GitHub 查看

预览

功能介绍

系统桌面通知:运行结束、模型提问与审批请求即时提醒,三平台提示音,零运行时依赖。

适合

  • 会让 DSH 在后台运行、需要任务结束提醒的用户。
  • 模型提问或审批请求可能长时间无人处理的交互式 Web 工作流。
  • 希望无需额外运行时包即可获得原生通知与可选系统提示音的跨平台桌面用户。

不适合

  • 没有桌面通知服务的无头或 CI 环境。
  • 需要为每个子代理发送通知的用户;该插件会主动过滤子代理会话。
  • 无头审批策略下,`approval/asked` 可能立即被拒绝而非真正等待人工处理的场景。

README

dsh-notify-on-complete — Desktop Notifications for DeepSeek Harness · DeepSeek Harness 桌面通知插件

dsh-notify-on-complete — 运行结束通知与系统提示音

Send desktop notifications from DeepSeek Harness (dsh): get a system notification when a run finishes, and an immediate one when the model asks you a question (ask_user_question) or waits for approval (sandbox escalation / tool permission). The body reflects the result (completed / error / aborted / max-tokens).

DeepSeek Harness(dsh)桌面通知插件:运行结束时向系统发送桌面通知;会话进行中模型提问(ask_user_question)或等待审批(沙箱提权 / 工具权限)时也会即时提醒你回来处理。正文按结果区分(成功 / 失败 / 中止 / 达到 token 上限)。

Author: Luozy · License: MIT · 中文文档:README.zh.md

  • Zero runtime dependencies: no dsh internal packages, no ctx.shell. Notifications are fired via child_process.spawn as a detached child process — non-blocking and unaffected by the harness exit path.
  • Cross-platform: the notifier command is picked from process.platform (macOS osascript / Linux notify-send → kdialog / Windows PowerShell). Unsupported platforms are skipped at load with a warning, never throwing per-event.
  • System sound: macOS system sound (sound name "Glass"), Windows .NET SystemSounds, Linux canberra-gtk-play (falls back to paplay); disable with sound: false.
  • In-session blocking notifications: fires immediately when the model calls ask_user_question, or when a sandbox escalation / tool permission waits for approval — so you know to come back. Controlled by onBlocked / onQuestion / onApproval.
  • Top-level runs only: subagent sessions are filtered out (header.origin === 'subagent'), so a single CLI run produces a single notification.

功能特性(中文)

  • 零运行时依赖:不依赖 dsh 内部包,通知用 child_process.spawn 以 detached 子进程发出,不阻塞、不受 harness 退出影响。
  • 跨平台:macOS osascript / Linux notify-send → kdialog / Windows PowerShell 自动选择;不支持的平台加载时跳过并警告。
  • 系统提示音:macOS sound name "Glass" / Windows SystemSounds / Linux canberra-gtk-play(回退 paplay);可用 sound: false 关闭。
  • 会话中阻塞即时通知:模型提问或等待审批时立即提醒你回来;可用 onBlocked / onQuestion / onApproval 精细控制。
  • 只通知顶层运行:过滤子代理(header.origin === 'subagent'),一次 CLI 运行只弹一条。

完整中文文档见 README.zh.md。

How it works

The plugin listens to two events to decide when “a run has ended”:

  1. session/event → turn/end: records the latest reason.kind of a root session (origin !== 'subagent'). A run can span many turns (goal rounds, follow-ups, steering), each with its own turn/end; the plugin only remembers the last one.
  2. agent/status → 'idle': the harness’s own “run ended” signal (the web UI’s running indicator and agent.whenIdle() both derive from it). When the root agent returns to idle, the whole activity has converged, so the plugin sends the recorded final result once and clears it.

So one notification per complete run, not per turn: a multi-round goal run fires once at the end, with the final result; intermediate “task completed” moments never fire early. Body format: result — session title (session: sessionId), e.g. 任务已完成 — 修复登录bug (session: 3f9a…); if the title hasn’t been generated yet it degrades to result (session: sessionId). The title comes from the last session/title event in the session log — an async projection, so very early notifications (e.g. a question right at session start) may not have one yet. Notification commands run with detached: true + unref(), so a normal exit or crash never affects delivery.

reason.kind Notification body
completed 任务已完成 (Task completed)
error 任务失败 (Task failed)
aborted 任务已中止 (Task aborted)
max-tokens 任务达到 token 上限 (Task hit the token limit)
other (unknown) 任务结束 (Task ended)

Requirements

  • Node.js ^22 (same as DeepSeek Harness)
  • An installed dsh CLI (any version — the plugin registers via Cordis events and does not depend on a specific CLI version)
  • Peer dependency @deepseek-ai/cordis@^4.0.1 (provided by the dsh CLI itself; pnpm resolves it automatically on install)

Installation (one-liner, GitHub source distribution, no npm)

Prerequisite: DSH installed (dsh web runs), Node.js ^22 + pnpm.

macOS / Linux / Windows (Git Bash or WSL):

curl -fsSL https://raw.githubusercontent.com/pitetow/dsh-notify-on-complete/main/scripts/install.sh | bash

Other profiles (default web):

curl -fsSL https://raw.githubusercontent.com/pitetow/dsh-notify-on-complete/main/scripts/install.sh | bash -s -- --profile headless

The script does 4 things (all idempotent, safe to re-run):

  1. Downloads the source to ~/.dsh/plugins/dsh-notify-on-complete/ (skips if it exists — never overwrites; add --force to overwrite/update, which asks for confirmation first, or --yes to skip it);
  2. Runs pnpm install && pnpm build;
  3. Runs dsh plugin --profile <name> add link:<dir>: the CLI reads the package’s dsh.bundle.patch declaration (cordis.patch.yml) and auto-registers it into the profile’s bundle stack, so it mounts on the next start — no manual config file edits;
  4. Idempotently removes any leftover manual mount lines to avoid double-mounting (two notifications per run).

curl | bash runs remote code — the script is open source (scripts/install.sh); download and review it first if you like.

Verify
dsh --profile web --dump-config | grep -n notify-on-complete

Seeing - id: notify-on-complete followed by name: dsh-notify-on-complete means the plugin is in the composed tree. Run a real task and watch for a desktop notification to confirm.

Restart to take effect:

  • CLI one-shot runs: the next dsh --profile headless "task" just works, no extra step.
  • Web GUI: restart the web process (stop the current dsh web, then start it again). If HMR is enabled, saving files also picks it up automatically.
Update
curl -fsSL https://raw.githubusercontent.com/pitetow/dsh-notify-on-complete/main/scripts/install.sh | bash -s -- --force

--force deletes and re-downloads the source (local edits in that directory are lost) and asks for confirmation first; add --yes to skip it: bash -s -- --force --yes

Or manually: cd ~/.dsh/plugins/dsh-notify-on-complete && git pull && pnpm install && pnpm run build, then re-run dsh plugin --profile web add link:..

Uninstall
dsh plugin --profile web remove dsh-notify-on-complete
rm -rf ~/.dsh/plugins/dsh-notify-on-complete

Then restart dsh.

常见问题常见问题

在启用了 DSH 的终端中执行已验证命令 dsh plugin --profile default add github:pitetow/dsh-notify-on-complete。命令会解析公开 package 元数据,并保持插件与本页展示的目录身份一致。