DeepSeek Harness 插件

yimengsuper2432/dsh-notice

Star 数 ★ 0 分类 通知与集成 收录于 2026-11-02

DSH 每轮任务结束时弹一条系统通知:完成 / 出错 / 中断分别开关,可设最短耗时、子任务静默、只在窗口不在前台时提示。Windows / macOS / Linux 通用,页面开着走页面通道,否则回退 PowerShell toast / osascript / notify-send(Linux 原生回退需装 libnotify);页面 / Electron 通道的通知可点击把 DSH 拉回前台,PowerShell 与 notify-send 的通知点不动。

安装

# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)

dsh plugin --profile web add github:yimengsuper2432/dsh-notice

装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。

README

dsh-notice

每一轮跑完,让电脑替你说一声

DeepSeek Harness 每跑完一轮(模型停手、等你说下一句话)就弹一条系统通知:哪个项目、第几轮、用了多久、最后一句说了什么。点一下通知能把 DSH 窗口拉回前台。

切去干别的事、或者让它跑十几分钟的时候,不用一直盯着屏幕。

为什么需要它

DSH 桌面版自带的通知只做应用级提示:有新版本可升级、更新需要重启。它没有「这一轮任务跑完了」的提醒——而那恰好是最需要被提醒的一格。

自己盯着的代价很直接:

场景 没有它
让模型跑一个长任务,切去写文档 每一两分钟切回来瞄一眼,全在看进度条
同时开几个会话 忘了哪个跑完了,回来发现早就停在那儿
出错 / 被中断 以为还在跑,其实十分钟前就停了
一轮只花三秒 弹一条通知反而打断你

这四条对应插件里的四组开关:按结束原因分别开关、只在窗口不在前台时提醒、最短耗时门槛、子任务默认静默。

通知长什么样

三行模板:标题行带会话标题,正文第一行是「模型 · 轮数 · 用时」,第二行起是返回内容。

[任务处理完成通知] 已完成
deepseek-v4.1-flash-1017 · 第 2 轮 · 用时 5.3 秒
通知模板已经照你给的三行改好了:第一行 [会话标题] 已完成,……
  • 会话标题取自 DSH 的 session/title 事件(侧栏里显示的那个名字);还没有标题时退回项目目录名。
  • 模型取自每轮请求的 request/header 里的 config.model;拿不到就不占位,第二行只留「第 N 轮 · 用时」。
  • 返回内容是这一轮助手最后一条文本,压成一行后按 snippetChars(本插件默认 90 字)截断;出错时换成错误原因。
  • 状态词跟着结束原因走:已完成 / 出错 / 中断。

一条通知是怎么走出来的

flowchart LR
    A["一轮结束:模型停手"] --> B{"结束原因开着吗"}
    B -- 关闭 --> Z["不打扰"]
    B -- 开着 --> C{"短于 minSeconds"}
    C -- 是 --> Z
    C -- 否 --> D{"窗口在前台"}
    D -- 是 --> Z
    D -- 否 --> E{"preferClient 且有页面连着"}
    E -- 是 --> F["页面通道:渲染进程弹系统通知"]
    E -- 否 --> G["本机原生命令:powershell / osascript / notify-send"]
    F --> H["点一下 → DSH 回到前台"]
    G --> H

两条通道:页面通道 + 本机原生命令

桌面版的宿主是一个 ELECTRON_RUN_AS_NODE 起的独立 Node 进程,不是 Electron 主进程:require("electron") 拿不到 Notification,拉 powershell 这类子进程还可能被进程策略拦掉(典型症状:接口返回「已发送」,屏幕上什么都没有,也没有任何报错)。

所以真正稳的一条路是页面通道:

  1. 页面(渲染进程)加载时用 EventSource 挂到 GET /api/dsh-notice-v1/events;
  2. 宿主判完「该提示了」就把标题/正文推给连着的页面;
  3. 页面用 Web Notification 弹——在桌面版里落到的就是这台机器的系统通知。

preferClient(默认 true)开着时,只要有一个页面连着就走这条路,设置页会显示「已连接的页面:N」;关掉它、或者窗口根本没开(纯 dsh web / 终端里跑),才回退到本机原生命令。

点通知能不能回到 DSH,取决于前台到底由谁去抢:渲染进程里的 window.focus() 只是一句请求,窗口最小化或被别的程序盖住时它拉不回前台。所以页面被点中时会再调一次 POST /api/dsh-notice-v1/focus,由宿主真正去抢——Electron 宿主走 BrowserWindow(restore() + show() + focus()),纯 Node 宿主在 Windows 上交 lib/focus.ps1(ShowWindow(SW_RESTORE) + SetForegroundWindow,前面先用 Alt 键和 AttachThreadInput 解开前台锁),macOS 上用 osascript 激活。这条路径也能单独测:curl -X POST http://127.0.0.1:<端口>/api/dsh-notice-v1/focus。

「发送诊断」卡片会把宿主的真实身份(Node 还是 Electron、PowerShell 找没找到)、最近一次子进程的错误和脚本自己写的日志都显示出来,还带一个「诊断一次」按钮,点一下就知道问题卡在「没拉起子进程」还是「拉起来了但系统没弹」。

发送后端

三个平台共用一套 Electron 主通道,各自再带一个原生回退;auto 按平台自动拼链路。

后端 平台 场景 / 表现
client(首选) 任意 页面开着时由渲染进程弹系统通知,最稳;不依赖子进程
electron Windows / macOS / Linux 宿主是 Electron 主进程时直接用 Notification:系统通知署名 DeepSeek Harness,点一下回到窗口
powershell Windows 纯 Node 宿主(dsh web)时先发 WinRT toast(DSH 自己的 AppUserModelID),失败再退托盘气泡;标题/正文走 base64 传 lib/notify.ps1,避开命令行中文编码问题
osascript macOS display notification,标题和正文走 argv 传参,不拼进脚本文本,中文和引号都安全
notify-send Linux libnotify 的系统通知,--app-name=DeepSeek Harness;没装就一路退到 none
none 任意 调试用:不发,只记失败

backend 默认 auto,链路按平台取:

  • Windows:electron → powershell
  • macOS:electron → osascript
  • Linux:electron → notify-send
  • 其它平台:只有 electron

onlyWhenUnfocused 依赖 Electron 的窗口 isFocused():桌面版判断准确;走页面通道时由页面用 document.hasFocus() 判断;两者都判断不出时按「不在前台」处理(照常提示)。

配置

两层:cordis.patch.yml 里的 config 是默认值,<DSH_HOME>/dsh-notice.json(设置页保存的)覆盖它。

键 默认 说明
enabled true 总开关
onCompleted true 正常完成时提示
onError true 出错时提示
onAborted false 被中断时提示
includeSubagents false 子任务也提示
minSeconds 0 短于这么多秒的一轮不提示
onlyWhenUnfocused true 只在窗口不在前台时提示
silent false 静音
snippetChars 90 正文里带多少字的回复摘要,0 = 不带(lib/index.js 里的兜底默认是 200,patch 层设成 90)
backend auto auto / electron / powershell / osascript / notify-send / none
preferClient true 页面开着时交给页面弹系统通知(桌面版最稳的一条路)

改设置页任意一项都会立刻落盘到 dsh-notice.json,不用重启。

本机接口

  • GET /api/dsh-notice-v1/state —— 配置、平台、各后端就绪状态、宿主身份、最近一次发送、计数
  • GET /api/dsh-notice-v1/events —— SSE 通道:页面挂着收通知(data: {"title","body",…})
  • POST /api/dsh-notice-v1/config —— 改配置(部分字段),落盘并返回新状态
  • POST /api/dsh-notice-v1/focus —— 把 DSH 窗口拉回前台(页面点通知时调它)
  • POST /api/dsh-notice-v1/test —— 立刻发一条测试通知(有页面走页面通道)
  • POST /api/dsh-notice-v1/probe —— 只走本机原生命令,等 2.6 秒把子进程结果一并返回(诊断用)

接口只接受本机回环地址请求。

安装

插件目录放进 <DSH_HOME>/plugins/dsh-notice,profile 的 package.json 加 "dsh-notice": "link:<绝对路径>" 与 dsh.profile.bundles 条目,再用运行时自带的 node + pnpm 在 profile 目录 install,重启 DSH 生效。

Linux 上想用原生回退,装一下 libnotify:Debian/Ubuntu apt install libnotify-bin,Fedora dnf install libnotify,Arch pacman -S libnotify。macOS 自带 osascript,无需安装。

已知边界

  • 只覆盖「一轮结束」:权限确认、工具报错这类中途事件不会单独通知。
  • 页面通道要窗口开着:窗口全关时只能靠原生命令,Linux 上没装 libnotify 就退到 none(设置页会显示「未就绪」)。
  • 通知内容取最后一轮文本:长回答只截 snippetChars 个字,摘要不换行。
  • 原生回退的通知点不动窗口:powershell 的 WinRT toast 和 Linux 的 notify-send 只负责弹,系统不提供点击回调;要「点一下回到 DSH」,得让页面通道生效(保持窗口开着)。
  • 接口只服务本机:只接受回环地址请求,不对外暴露。
  • 发送失败不重试、不打断任务:只记一笔失败原因,供「发送诊断」查看。

自检

node --check lib/index.js
node --check lib/client.js
node test.mjs

License

MIT

内容来自项目 README(GitHub)↗

链接

同类插件

查看整个分类 →

社区评论

评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。