DSH Plugins Marketplace

DSH Plugins

Plugins

/

Tools & Capabilities

/

dsh-notify-whale

L

dsh-notify-whale

Manifest valid

Whale Song (dsh-notify-whale): A hardened fork of the DSH notification plugin. Fixed 5 bugs, including the upstream HTTP channel being completely unable to deliver on Node 22/24, and added pending approval/question notifications and event-level ringtones. AI-led modifications.

hasBundlePatch

鲸吟 · dsh-notify-whale

DSH(DeepSeek Harness)通知插件:会话结束时推手机,卡在审批或提问等你操作时也推。

中文名 鲸吟;项目代号与 npm 包名均为 dsh-notify-whale。

  • macOS:系统通知中心(osascript,零依赖)
  • Windows:Toast 通知(PowerShell + WinRT,含 PNG 图标)
  • 手机:Bark(iOS)/ ntfy(Android·iOS)/ Server酱 / 任意 Webhook

纯 ESM .mjs、无构建步骤,基于 DSH 内置的 Cordis 插件体系。

这是一个加固 fork

上游:DeepseekHarnessPlugins/Notification(包名 dsh-task-notify,MIT)。

上游原版在 Node 22 / 24 上 HTTP 通道完全无法投递——不是配置问题,是代码问题(见下面「修了什么」第 1、2 条)。本 fork 修复后在真实 DSH 上跑通并验证:安卓(ntfy)+ iPhone(Bark)双端实测可收。

按 MIT 许可发布,保留原作者版权声明(见 LICENSE)。

⚙️ 本项目由 AI 主导修改

本仓库的代码改动、测试与文档由 AI 编程代理完成(跑在 DSH 上),人类负责决策、验收与发布。改动方向与取舍记录在提交信息与本文件中。

具体来说:上游只提供基础骨架——下面「修了什么」里的 5 个 bug 的定位与修复、2 项新能力的设计与实现、以及 154 项测试的补齐,都是 AI 在真实 DSH 上复现问题后改的。每一处修改都附根因说明与实测证据;拿不出证据的结论不会写进来(例如「上游在 Node 22/24 上 HTTP 通道完全发不出去」是实测复现的,不是读代码推测的)。

在上游与本 fork 之间选择时:本 fork 的价值在于它是"真跑过"的版本,而不是"功能更多"。


与上游的差异

修掉的 5 个必现 bug

#现象根因与修法
1ntfy 通道报 Cannot convert argument to a ByteString标题被放进 X-Title 头,而 Node 的 fetch/undici 强制 header 值为 Latin-1,中文标题必然抛错。→ 改用 ntfy 官方 JSON 发布(POST 到服务端根 URL,{topic,message,title,icon} 放 body,UTF-8 安全)
2所有 HTTP 通道(bark / ntfy / serverchan / webhook)静默发不出去send() 只把 headers / body 传给 httpPost,而后者是 fetch(url, {...init}) —— 没有 method → 变成「带 body 的 GET」→ undici 直接拒绝。→ 显式传 method: "POST"
3正文永远取不到会话标题,只会显示兜底文案插件读 agent.session.events,但 DSH 的 Session 没有 events 属性(运行时核对:'events' in Session.prototype === false)。公开 API 是方法 snapshotEvents() → 守卫永不成立,取标题 / 取用户消息两条路径从未执行过。→ 改调 snapshotEvents();兜底同时剥掉 session- 前缀并优先输出 header.cwd 的项目名
4任务出错、被手动停止也报「任务完成」本版 DSH 的 AgentStatus 只有 idle / running——出错和手动停止时 agent 同样回到 idle,标题因此恒为「任务完成」。这是误导性通知,比不通知更糟。→ 新增 latestTurnEndReason() 读取最后一条 turn/end 的 reason,据此决定标题(时序已核对:turn/end 在 turn 的 finally 里 append,早于 agent/status: idle 派发)
5🐛 某些活跃会话的「完成」通知被静默丢弃(症状:只有「待回答」,从无「任务完成」)isRootAgent() 拿 session.header.parentSession 当"子代理"标志。但它的真实语义是上下文续接来源——DSH 续接/派生上下文时会带上它,而这类会话 delegationDepth 仍为 0、origin 也不是 subagent,是有真实人类交互的顶层会话(实测对象:129 条人类提问、104 个回合,完成通知 0 条)。→ 删除该判据。
安全性实测:本机 118 个会话中,origin === 'subagent' 与 delegationDepth > 0 完全等集(各 37 个),二者已是完整判据;删除后只放行 5 个「上下文续接」会话,不含任何真子代理,即该判据纯属误伤

另修一处仅影响测试的上游问题:paths.test.mjs 写死了 PACKAGE_DIR.endsWith('/'),在 Windows 上必失败(fileURLToPath 在 Windows 返回以 \ 结尾)。实现本身是对的,断言已改为跟随平台分隔符。上游全套测试在本 fork 中 154 / 154 通过(含上述断言改造后的 ntfy 传输测试)。

新增的 2 个能力

5. 等待人工介入时也通知

上游只监听 agent/status。等待审批 / 等待回答期间 agent 既不是 idle 也谈不上结束,所以手机端永远收不到——人一离开电脑就一直干等。

本 fork 改为监听 session/event:

  • 会话事件 approval/asked → 「待批准:<工具>(<原因>)」
  • 工具调用 ask_user_question → 「待回答:<问题>[N 选]」

⚠️ 为什么不用 approval/request / user-questions/request:这两个是 waterfall(链式) 事件——前面任一监听器一旦认领请求,后面的监听器根本不会执行。DSH 自带的 Web 桥接器排在前面先认领,第三方插件(在 profile bundles 里排末位)永远轮不到。这是实测结论,不是推测。改用 session/event(普通事件,与监听器顺序无关,也不会干扰审批链)。

6. 事件级铃声(仅 Bark 支持自定义铃声;sound 为全局默认,sounds 按事件覆盖)


通知对照表

结果标题eventBark 铃声图标
正常完成任务完成idlefanfare绿勾
出错任务出错errorcalypso红叉
手动停止已手动停止stoppedbell灰点
被父会话中断任务已停止stoppedbell灰点
被中断任务被中断interruptedbloom灰点
输出被截断输出被截断truncatedfanfare灰点
等待审批待批准awaiting-approvalhorn灰点
等待选择 / 回答待回答awaiting-answerhorn灰点
未知 / 取不到任务完成idlefanfare绿勾

正文格式:<会话标题或项目名> · <具体事由> · HH:mm。


安装

dsh plugin --profile web add dsh-notify-whale

装完 重启 DSH(插件在 boot 时读一次配置,改配置后同样必须重启)。

从本地目录安装:dsh plugin --profile web add /path/to/dsh-notify-whale。此时 pnpm 以 link: 方式接入、不会给被链接目录装依赖,需在插件目录里单独执行一次 npm install --omit=dev(否则报 ERR_MODULE_NOT_FOUND: js-yaml)。用 npm 安装没有这个问题。

若 pnpm 报 minimumReleaseAge 供应链策略拦截(v11 内置默认),命令末尾追加 --config.minimum-release-age=0 按次放行。


配置

写入 $DSH_HOME/settings.yaml 的 task-notify: 段:

task-notify:
  enabled: true
  notifyOn: [idle, error, blocked]   # blocked 供等待类通知复用
  agents: root                       # root=只通知顶层会话 | all;等待类通知不受此项限制
  coalesceWindowMs: 2000             # 同会话窗口内合并重复通知
  desktop:
    enabled: off                     # auto | on | off(注意:写 false 会警告并回退为 auto)
    sound: true
  format:
    time: short                      # hidden | short | full —— 正文尾部时间样式
    showDuration: true               # 负载携带 durationMs 时追加「用时 X」
  icons:
    enabled: true                    # 图形图标总开关
    urlTemplate: ""                  # 远程图标 URL 模板;含 {event} 则按事件取图,如 https://host/icons/{event}.png
  ntfy:
    enabled: true
    server: https://ntfy.sh
    topic: "你的随机主题名"           # 公共服务器上 topic 就是密码,别用可猜的名字
    token: ""                        # 自建实例需要鉴权时填
  bark:
    enabled: true
    server: https://api.day.app
    deviceKey: "你的BarkKey"
    sound: "fanfare"
    sounds:
      error: calypso
      stopped: bell
      interrupted: bloom
      awaiting-approval: horn
      awaiting-answer: horn
  serverchan:
    enabled: false
    sendKey: ""
  webhook:
    enabled: false
    url: ""
    headers: {}

配置优先级:cordis patch 显式传参 > settings.yaml > 环境变量(DSH_TASK_NOTIFY_*)> 内置默认。

架构与事件契约详见 SPEC.md。


验证

node self-test.mjs                     # 向全部启用通道发一条样例通知
node self-test.mjs --channel ntfy      # 只测单个通道

成功时静默(只有非 2xx 才 warn)。想确认服务端真的收到,从服务端反查:

curl -s "https://<你的ntfy>/<topic>/json?poll=1"

另有交互式菜单可直接编辑配置并当场发测试通知:

npm run menu

已知边界

  • 本版 DSH 的 AgentStatus 只有 idle / running,所以 notifyOn 里的 error / blocked 不会由 agent/status 触发;成败判断走 turn/end,blocked 走等待类路径。
  • 自建 ntfy 若开了 deny-all,手机端(ntfy App)必须配置访问凭据,否则订阅被 403 拒掉、表现为一直「Reconnecting」。
  • 自建服务端请用域名而非 IP:家用宽带 IPv6 前缀会变。
  • Bark 自定义铃声仅 iOS;ntfy 的铃声只能在手机 App 侧设置(其发布协议没有 sound 参数)。
  • self-test.mjs 是独立进程、读磁盘最新配置。它通过不代表运行中的 DSH 宿主进程已加载新配置——改完配置必须重启,并用一次真实事件验证。

License

MIT。本 fork 保留上游版权:

Copyright (c) 2026 DeepseekHarnessPlugins
Copyright (c) 2026 Lon-dawn (dsh-notify-whale fork)

Comments

Loading…

From the same category

reactive-resume

DeepSeek Harness plugin for Reactive Resume: bridges your resumes and job applications into a Harness session over MCP.

Tools & CapabilitiesManifest valid

★ 41.7k

↓ 156/wk

MIT

Aug 24, 2026

dsh plugin --profile web add dsh-plugin-reactive-resume

by Tencent

Let AI agents use your real, logged-in browser without interrupting your work. CLI + extension for browser automation across any shell-capable AI agent.

Tools & CapabilitiesManifest valid

★ 8.6k

↓ 6.1k/wk

MIT

TypeScript

Oct 10, 2026

dsh plugin --profile terminal add @wxg-prc-cpg/browser-skill-dsh-plugin

by yjh051108

dsh-routing-suite — injector + router-standard kit: install the runtime injector first, then the task-aware reasoning-mode router preset (measured P1-P23).

Tools & CapabilitiesManifest valid

★ 7k

MIT

JavaScript

Sep 18, 2026

dsh plugin --profile web add @dsh-external/dsh-super-injector

by Q00

Agent OS: the agent gets smarter on its own. We just hold the line: Interview-gated, staged evaluation, budgeted evolution loop. MCP server, 14 runtimes: Claude Code, Codex CLI, Gemini CLI, OpenCode,

Tools & CapabilitiesManifest valid

★ 6.2k

MIT

Python

Oct 7, 2026

Index only — not installable

by dsh-market

The plugin market inside DeepSeek Harness — browse, search, one-click install · DSH 可视化插件市场

Tools & CapabilitiesManifest valid

★ 6.1k

↓ 112.4k/wk

MIT

TypeScript

Oct 10, 2026

dsh plugin --profile web add dshmarket

by superdesigndev

OpenRouter for agent tools. Join community here: https://discord.gg/6mQYYfFMAn

Tools & CapabilitiesManifest valid

★ 5k

NOASSERTION

Python

Oct 11, 2026

dsh plugin --profile web add treg-dsh