knownothing114/dsh-notify

knownothing114/dsh-notify

当 dsh 需要你注意时发出桌面通知——权限确认、提问、计划审批、回合完成、目标、出错、工作流——并提供设置页「通知」选项卡,改动即时生效。

通知与集成

dsh-notify

English | 简体中文 | 日本語

dsh(DeepSeek Harness)插件:当 dsh 需要你注意时,在桌面发出消息提醒。

dsh 本身在“需要用户介入”时没有任何提示:权限确认弹起、ask_user_question 提问、计划审批、 回合完成、目标完成/受阻、出错、工作流结束时,如果你正盯着别的窗口或浏览器标签页在后台, 很容易错过。这个插件监听 dsh 主机事件总线,在这些时刻立刻弹出一条原生桌面通知—— 系统通知(macOS / Linux)、弹窗(Windows)、终端响铃,或你自己的自定义命令。

插件是纯观察者:所有监听器都是被动的。尤其是 approval/request 监听器只负责提醒, 永远不会替你做决定,它总是调用 next() 转发请求,审批链路的行为与未安装本插件时完全一致。

功能

触发器触发时机默认
approval权限确认请求(沙箱升级、需要批准的操作等)开
questionask_user_question 提问 / exit_plan_mode 计划待审批开
turnComplete回合完成(agent 回复完毕,等待你的下一步输入)开
goal目标完成 / 目标受阻开
error会话出错开
workflowtool_workflow 运行结束开

通知渠道(channel):

  • auto(默认):macOS → osascript 系统通知;Windows → PowerShell 弹窗;其他平台 → notify-send
  • osascript / notify-send / powershell:强制指定渠道
  • bell:终端响铃(\x07),零依赖兜底
  • custom:执行 customCommand 模板(占位符 {title} {body} {app})
  • none:关闭

零运行时依赖(仅两个 @deepseek-ai 包:settings 与 schemastery),可在任意 profile(web / headless / 自定义)使用。

所有选项也都可以在 Web 界面直接修改:设置 → 通知 标签页(见下文「设置页」)。 改动写入设置文件后立即生效,无需重启。

安装

以 web profile 为例(其他 profile 同理):

# 1. 把插件装进 profile 的依赖。
#    本地目录会被 pnpm 链接进 node_modules;git URL 或已发布的 npm 包名也可以。
dsh plugin --profile web add /path/to/dsh-notify
#    或从本仓库安装:
dsh plugin --profile web add git+https://github.com/knownothing114/dsh-notify.git
#    或(发布到 npm 后):dsh plugin --profile web add dsh-notify

该命令会安装依赖并自动注册 bundle。请确认 profile 清单的 dsh.profile.bundles 中已包含 dsh-notify;若你的 dsh 版本没有自动追加,请手动添加:

// ~/.dsh/profiles/web/package.json
{
  "dsh": {
    "profile": {
      "bundles": [
        "@deepseek-ai/dsh-base",
        "@deepseek-ai/dsh-web-app",
        "dsh-notify"          // ← 追加这一行
      ]
    }
  }
}
# 2. 重启 dsh web(插件在启动时装载;HMR 只热载配置,不加载新插件包)

配置

插件默认配置已内置,通常无需改动。如需调整,在 profile 的 cordis.patch.yml (或 --patch 覆盖层)中按行 id dsh-notify 覆盖。覆盖会整体替换该行的 config, 插件会在代码内与默认值做深合并,所以可以只写要改的键:

# ~/.dsh/profiles/web/cordis.patch.yml
- id: dsh-notify
  config:
    channel: auto        # auto | osascript | notify-send | powershell | bell | custom | none
    appName: dsh         # 通知里显示的来源名称(custom 模板的 {app})
    sound: true          # macOS 通知是否带提示音
    minIntervalMs: 3000  # 两次通知的最小间隔(防轰炸)
    rootsOnly: true      # 只提醒根会话(忽略子代理/后台子任务)
    verbose: false       # 同时在 dsh 日志里打印每条通知
    customCommand: ""    # channel 为 custom 时的命令模板,如:
                         #   terminal-notifier -message {body} -title {title}
    triggers:
      approval: true
      question: true
      turnComplete: true
      goal: true
      error: true
      workflow: true
    enabled: true        # 总开关

设置页(Web「通知」标签页)

使用 web profile 时,插件会在 设置 中注册一个独立的 「通知」 标签页。它展示上面 配置小节里的全部选项,并可以通过表单修改(保存 / 放弃 / 整体「恢复默认」):

  • 总开关、通知渠道、来源名称、提示音、最小通知间隔、仅根会话、记录日志、自定义命令
  • 六个触发器开关

配置优先级(高者生效):设置文件($DSH_HOME/settings.yaml,由标签页写入、热生效) → profile 补丁(cordis.patch.yml 的 config:)→ 内置默认值。主机插件在每次通知时 实时读取配置,因此标签页里的改动立即生效。

浏览器端实现位于 dist/client.js(dsh 客户端模块格式的预构建 bundle,由宿主在 /plugins/dsh-notify/client.js 提供);主机端注册 notify 设置命名空间。 首次安装或升级插件包需要重启 dsh web;此后标签页内的改动无需重启。

说明:dsh 的 API 代理默认只向 Web 界面暴露白名单内的设置命名空间(模型提供方 + 显式 许可列表)。因此插件会包装代理的 settings 处理器,让 notify 命名空间可以通过标准 settings RPC 读写——其他命名空间仍保持核心白名单行为。

工作原理(事件映射)

触发器监听的事件
approval主机侧 approval/request 瀑布(被动监听,return next() 转发,不参与决策)
question / 计划审批session/event 中的 tool/call(工具名 ask_user_question / exit_plan_mode),提问正文从工具参数中提取
turnCompletesession/event 中的 turn/end(reason.kind === "completed")
goalgoal/changed(操作 complete / block),正文含目标描述
erroragent/error
workflowsession/event 中的 tool-workflow/run-end(stopReason 为 completed 之外的失败也会提醒)

所有监听器注册在根上下文,按 dsh 的作用域路由规则可以收到全部 agent/会话事件; rootsOnly 通过 ctx.agents.roots() 过滤掉子代理的噪音。通知发送使用 spawn 分离进程, 永不阻塞 agent 循环,失败只记日志。

卸载

dsh plugin --profile web remove dsh-notify
# 并从 ~/.dsh/profiles/web/package.json 的 bundles 中移除 "dsh-notify",重启

常见问题

  • 没有弹通知? 先确认 channel 检测结果与系统匹配:macOS 上手动设 channel: osascript 试一条(也可设 verbose: true 看日志里是否打印了通知); Linux 需要 notify-send(libnotify);检查系统勿扰模式/通知权限。
  • 提醒太频繁? 调大 minIntervalMs,或按需关闭某个 triggers 项。
  • 子代理刷屏? 保持 rootsOnly: true。
  • 改了配置没生效? cordis.patch.yml 的改动由 HMR 热载;新增/移除插件、改 package.json 的 bundles 需要重启 dsh web。

开发

cd dsh-notify
npm install   # 安装 @deepseek-ai/dsh-settings 与 @deepseek-ai/schemastery
npm test      # node --test:纯函数单元测试 + apply() 接线冒烟测试 + 客户端表单测试(30 个用例)

项目结构

├── lib/index.mjs            主机插件(事件监听、设置命名空间、apiProxy 暴露包装)
├── dist/client.js           浏览器 bundle(设置 → 通知 标签页),由 /plugins/dsh-notify/client.js 提供
├── cordis.patch.yml         bundle 补丁,挂载插件行
├── docs/
│   ├── README.zh-CN.md      简体中文文档
│   ├── README.ja.md         日本語ドキュメント
│   └── third-party-settings-namespace-exposure.md   开发者笔记:第三方设置命名空间如何暴露给 Web 设置页
├── test/                    node --test 测试套件(单元 / 渲染 / 交互 / 集成)
└── package.json             插件清单(exports、dsh.bundle / dsh.client 声明)

许可证

MIT