前言¶
DSH 跑一个长任务时,人常离开窗口去别处。审批来了要确认权限,提问来了要选答案,任务跑完要看结果——这几类事件如果只在页面里体现,人不在就错过了。已有做法是靠辅助进程发通知,系统会把横幅归属到那个脚本运行器上,点回去也落不到 DSH 会话。
下面介绍的 tommy00748-tech/dsh-native-notifications 换一种方式:通知由 DSH 页面自己发出来,操作系统把它归属到 DeepSeek Harness,点一下横幅回到会话,并且可以选或自己写铃声。
这是什么¶
DSH 插件,目录页归在「客户端」分类,维护者 tommy00748-tech。解决的问题是:让 DSH 在需要人介入或跑完一轮时,弹一条归属正确、可点击回到会话的桌面通知,避免人一直盯着窗口或错过审批。
仓库显示 0 星,许可证 MIT,npm 包名 dsh-native-notifications。
触发哪些事件¶
插件监听以下 Harness 事件,事件含义和默认开关见 README 的表格:
| Harness event | 横幅内容 | 默认 |
|---|---|---|
agent/status → idle after a turn(root session) |
任务完成 · 用时 … | on |
approval/request 在 approvalDelayMs 后仍挂着 |
需要你确认权限 · tool · reason | on |
user-questions/request 仍挂着 |
正在等待你的选择 · question | on |
agent/error |
执行出错 · message | on |
deepseek-account/model-sign-in-required / session-expired |
需要登录 / 登录已过期 | on |
subagent/end、workflow/end |
child agent / workflow finished | off |
横幅标题用会话名称,正文示例:
<会话名称>
任务完成 · 用时 5 分 43 秒,可以回来查看结果了。
几个防噪逻辑:
- 被自动处理掉的审批(例如 Auto 权限预设里的 LLM reviewer)不会响,横幅会延迟,只在请求还在等你时触发。
- 出错之后那一轮完成的通知被抑制,一次失败不会响两次。
- 目标轮次和后续 turn 很快回到
running,完成通知要在会话空闲超过idleGraceMs后才触发。 - 队友、子代理和 workflow 子进程按
onlyRootSessions过滤,多智能体长跑只在 root session 真结束时响一次。
铃声配置¶
铃声由插件用 Web Audio 合成,没有音频文件,也不用系统默认音,系统音会被抑制,不会响两次。所有预设共用同一套动机,含义可辨:完成是上行的 do-mi-so,”需要你”是两声高频短音,出错下行。
打开 Settings → General → Notification sound,可选预设:
| preset | 音色 |
|---|---|
| Playful bubbles(默认) | triangle 主体,带小幅上滑和一个高音闪烁 |
| Soft bell | sine 主体,加一个轻的八度泛音 |
| Bright pluck | 短 triangle 拨弦,没有滑音 |
| Custom | 自己的音符序列,用 playful 音色播放 |
| Muted | 无声 |
这一行有 Preview 按钮。Custom 用文本框输入,最多八个以空格或逗号分隔的音符,可以是音名(C6 E6 G#6、Bb5)也可以是频率(1046.5 1318.5):
C6 E6 G6 ← do-mi-so
G6 G6 ← double boop
1046.5 1318.5 ← 同上两个音符的频率写法
偏好存页面 localStorage 的 dsh-native-notifications:sound,所以是按设备/浏览器生效的,下一次横幅即生效,不需要走 Host 往返。
安装与启用¶
安装命令来自仓库 README,按 profile 区分 Web 和桌面:
# from GitHub
dsh plugin --profile web add github:tommy00748-tech/dsh-native-notifications
dsh plugin --profile desktop add github:tommy00748-tech/dsh-native-notifications
# from npm(npm 发布后可用)
dsh plugin --profile web add dsh-native-notifications
# from a local checkout
dsh plugin --profile desktop add link:/absolute/path/to/dsh-native-notifications
装完在 Settings → Plugins 确认 desktop-notifications 那一行是启用的,bundle patch 会插入并默认启用它。没有构建步骤、没有依赖、没有原生模块:Host 半部分是普通 ESM,Client 半部分是一个纯 JS bundle。
要求:
- 有提供 Web UI 的 DSH profile(
desktop或web); - 页面在安装时自动加载 Client 半部分(Host graph 重建会同步给已连接的页面);如果手工拷贝后横幅一直没出现,重载一次窗口;
- 操作系统里要为 DeepSeek Harness 允许桌面通知(macOS 在 System Settings → Notifications)。Electron 会授予页面权限,但 OS 层面的允许是独立的。
配置项¶
所有开关都在那一行的 config 上,默认值连同说明写在 cordis.patch.yml 里。注意 patch 会整体替换 config,所以只想改一个字段时要把想保留的字段一并写回去:
- id: desktop-notifications
config:
notifyComplete: true
notifyQuestion: false # do not ring for questions
idleGraceMs: 2000
onlyRootSessions: true
delivery: client # client | osascript | both
可用字段:notifyComplete、notifyApproval、notifyQuestion、notifyError、notifyAccount、onlyWhenUnfocused、silent、idleGraceMs、errorSuppressMs、approvalDelayMs、onlyRootSessions、notifyOnMount、logPath。
delivery: osascript 是给页面无法展示 Web 通知的宿主的遗留回退,macOS 下这类横幅归属到 Script Editor,默认关闭。
诊断日志¶
每次横幅和每次客户端上报都会追加到审计日志,默认 ~/.dsh/dsh-native-notifications.log,可用 logPath 改路径。日志样例:
2026-11-05T08:58:26.102Z mounted :: pid=9027 :: delivery=client :: epoch=... :: platform=darwin
2026-11-05T08:58:26.178Z client :: boot :: permission=granted protocol=dsh-app: path=/ visibility=hidden sound=cute chime=v5-robust
2026-11-05T08:59:47.177Z banner :: 能不能做个DSH原生的通知插件 :: 任务完成 · 用时 5 分 43 秒,可以回来查看结果了。
2026-11-05T08:59:47.186Z client :: shown :: kind=complete permission=granted
2026-11-05T08:59:47.188Z client :: sound :: kind=complete preset=cute
针对”为什么没弹横幅”,按日志判断:
- 没有
client :: boot→ Client 半部分没加载,重载窗口; client :: permission :: denied→ 系统/浏览器不允许通知;client :: suppressed→onlyWhenUnfocused跳过了已聚焦的窗口;- 有
banner ::但没有client :: shown→ 页面没轮询到(看poll-failed/unauthorized); - 有
client :: shown但没有client :: sound→ 铃声没响(音频仍被锁,或静音了)。
想直接发一条通知验证 osascript 通道:
node scripts/notify-test.mjs "title" "body"
工作原理¶
一个 bundle,两半:
- Host(
index.js)监听上面那些事件,维护一个小的环状缓冲区存横幅事件。它在ctx.webServer上提供两个同源路由:/native-notifications/events(长轮询)和/native-notifications/report(客户端诊断),和 Host 其他 Web 路由一样用ctx.connection.requestRejection做门禁,所以只有已认证页面能读。 - Client(
client.js,无渲染、始终挂载)长轮询这两个路由,通过平台通知 API(new Notification(...))展示每个事件,点击时聚焦 DSH 并调用uiWorkspace.openSession(sessionId)。游标和 Host epoch 存在localStorage,所以重载不会重放旧横幅,Host 重启从”现在”开始。
长轮询在 wait + 10s 后中断并重试,所以 Host 重挂不会卡住客户端。插件不追加 session 事件、不 import Harness Client 包,只贡献一个 bundle 行和一个 Settings 行。
兼容性¶
README 标明在 dsh 0.2.1-rc.5 和 0.2.2-rc.1 上测试过。运行时兼容性检查读的是顶层 engines.dsh 字段,package.json 里是 >=0.2.1-rc.5 <0.3.0,Node 要求 >=20。
适用场景与注意¶
适合需要在 DSH 上跑长任务、又不想一直守着窗口的人,以及团队里跑多智能体长任务、希望只在 root session 结束时响一次的场景。如果你的宿主页面无法展示 Web 通知,delivery: osascript 是备选,但要接受横幅归属到 Script Editor。
两点提醒:通知以当前 DSH 进程的权限发出,OS 层面要为 DeepSeek Harness 打开通知授权;插件来源是社区维护的 GitHub 仓库(社区目录站上也有它的条目,该目录与 DeepSeek / 幻方无官方从属关系),装之前建议先过一遍源码和 MIT 许可证。
结尾¶
一句话回顾:它把 DSH 的审批、提问、完成、出错和登录横幅归到 DeepSeek Harness 名下,可选或自定义合成铃声,并提供审计日志方便排查没响的原因。目录页在 https://www.skillhub.cn/plugins/tommy00748-tech/dsh-native-notifications,仓库在 https://github.com/tommy00748-tech/dsh-native-notifications。