跳到主要内容

dsh-task-notify

已验证

dsh-task-notify · v0.4.0 · MIT · Web 界面

DSH task completion system notifications (host-side node-notifier)

安装

dsh plugin add dsh-task-notify

用 dsh --profile default --dump-config 确认 layer 已生效 —— 参见安装指南。

源码

发布到 npm 但没有公开仓库。安装前请检查包内容。

标签

作者

说明文档

🔔 dsh-task-notify

DSH(DeepSeek Harness)插件:任务完成 · 系统弹窗通知

模型回答完你的请求,系统立即弹出原生通知——切到别的窗口刷剧、写代码时,再也不怕错过 DSH 的完成信号。

系统通知 · 零侵入 · 防打扰 · 可配置

npm version npm downloads License DSH Gitee


✨ 特性一览

特性 说明
🪟 原生系统通知 host 端 node-notifier:Windows 通知中心 / macOS 通知 / Linux 原生通知
✅ 准确的完成信号 监听 turn/end (completed),只在模型真正回答完时弹;失败/中断不误报
⏳ 等待授权提醒 运行中需要用户批准时同样弹窗提醒回到界面;授权结果不再重复通知
💬 等待回答提醒 模型暂停询问、需要你作答时同样弹窗提醒回到界面
📝 回复预览 通知正文带模型回答的开头文本(长度可配置)
🧘 防打扰设计 默认仅在页面不在前台时弹;秒回的小问答不弹;任务完成默认跳过子代理(授权提醒不受限)
🎛️ 7 项可配置 设置页「任务通知」区块可视化调整,或 cordis patch 覆盖
🛡️ 安全 全部 API 经 Host 头信任围栏;与 /api 网关同源校验
📦 一键安装 dsh plugin add 自动装依赖 + 自动挂载,零配置

📦 安装

前置要求

要求 说明
DSH 已安装且 dsh web 可正常运行(首次运行会自动初始化 ~/.dsh/profiles/web)
Node.js ≥ 20
pnpm ≥ 10

方式一:npm 安装(推荐)

dsh plugin --profile web add dsh-task-notify

dsh plugin add 自动完成三步:① 安装依赖(node-notifier、schemastery 自动带上);② 检测 dsh.bundle 声明自动挂载;③ 无需手动改任何配置。

方式二:本地开发(link)

cd ~/.dsh/profiles/web
pnpm add "dsh-task-notify@link:<插件目录绝对路径>"

卸载

dsh plugin --profile web remove dsh-task-notify

生效

  • host 端(监听逻辑)改动 → 重启 dsh web
  • client 端(设置面板)改动 → 硬刷新浏览器(Ctrl/Cmd+Shift+R)

🔄 更新(本地 link / 开发安装)

本仓库通常以 link 安装(package.json 里 dsh-task-notify: link:<插件目录>),DSH 直接引用本地目录的 lib/。更新步骤:

# 1. 在插件目录拉取/修改源码后,重新构建
cd <插件目录绝对路径>
pnpm install     # 首次或依赖变更后
pnpm build       # 重建 host 端 tsc + client 端 tsdown → lib/

# 2. 重启 DSH 宿主,让 host 端新逻辑生效(client 端改动则硬刷新浏览器)
dsh web --port 8080

因为是 link 连接,pnpm build 产出的 lib/ 会被 DSH 立即读取,无需重装依赖或重新 pnpm add。 若更换了插件目录路径,用「方式二」重新执行一次 pnpm add "dsh-task-notify@link:<新路径>"。


🚀 快速使用

# 1. 安装
dsh plugin --profile web add dsh-task-notify

# 2. 重启
dsh web --port 8080

# 3. 使用 —— 让 DSH 跑一个任务,完成后系统弹窗:
#    标题:任务完成 · <工作目录名>
#    正文:模型回答的开头 120 字

💡 默认 onlyWhenBlurred: true——页面在前台时不弹(防打扰)。想测试效果,先把 DSH 页面切到后台/最小化再跑任务。


⚙️ 配置

设置页(推荐)

DSH 设置 → 「任务通知」区块,可视化调整全部选项。

cordis patch 覆盖

~/.dsh/profiles/web/cordis.patch.yml:

- id: task-notify
  name: 'dsh-task-notify'
  config:
    enabled: true          # 总开关
    onlyWhenBlurred: true  # 仅页面不在前台时通知
    notifyOnError: false   # 出错/中断也通知
    maxBodyChars: 120      # 正文预览长度(字符)
    minTurnMs: 0           # 最短通知时长(毫秒),过滤秒回
    sessions: top-level    # all | top-level
    showCwd: true          # 标题显示工作目录名

配置项详解

配置项 类型 默认值 说明
enabled boolean true 总开关
onlyWhenBlurred boolean true 仅页面不在前台时通知(client 上报可见性)
notifyOnError boolean false 非正常结束也通知:error / aborted / max-tokens / blocked / interrupted
maxBodyChars number 120 正文预览截断长度(0–500)
minTurnMs number 0 回合短于此时长(毫秒)不通知,过滤快速问答
sessions 'all' | 'top-level' 'top-level' top-level 跳过子代理会话
showCwd boolean true 标题附带工作目录名,区分多会话

🧠 工作原理

┌───────────────────────────────  DSH 运行时  ───────────────────────────────┐
│                                                                             │
│  ┌─────────────────┐   append    ┌─────────────────────────────┐           │
│  │  Agent 回合执行  │ ──────────► │  Session 事件日志(持久化)   │           │
│  │  turn/end       │             │  session/event 事件流        │           │
│  └─────────────────┘             └──────────────┬──────────────┘           │
│                                                 │ ctx.on('session/event')  │
│  ┌──────────────────────────────────────────────▼──────────────┐           │
│  │              dsh-task-notify (host 端)                        │           │
│  │  · turn/end & reason.kind === 'completed' 触发               │           │
│  │  · 过滤:enabled / sessions / onlyWhenBlurred / minTurnMs    │           │
│  │  · 提取该回合最后一条 assistant 文本作正文(截断)            │           │
│  │  · node-notifier 弹原生系统通知(失败回退 msg.exe)           │           │
│  └──────────────────────────────────────────────┬──────────────┘           │
│                                                 │                           │
│  ┌──────────────────────────────────────────────▼──────────────┐           │
│  │              dsh-task-notify (client 端)                     │           │
│  │  · 监听 visibilitychange/blur/focus → POST /task-notify/api/ │           │
│  │    visibility 上报页面可见性,供 onlyWhenBlurred 门控        │           │
│  │  · 设置页「任务通知」区块 → /task-notify/api/settings.* 读写  │           │
│  └─────────────────────────────────────────────────────────────┘           │
└─────────────────────────────────────────────────────────────────────────────┘

通知时机

信号 事件 说明
任务完成 session/event → turn/end reason.kind === 'completed' = 模型回答完一轮
非正常结束 error / aborted / max-tokens / blocked / interrupted 默认不通知;notifyOnError 开启时这五种都通知(blocked、interrupted 自 DSH 0.1.5 起提供)
等待授权 approval/asked 任务运行中需要用户批准;子代理的授权同样提醒
需要回答 tool/call = ask_user_question 暂停等待用户作答时提醒;正文带问题文本
授权结果 approval/decided 不通知(授权决策须回主界面操作),仅用于摘除待办记录

兼容性

依赖 说明
DSH 版本 面向 0.2.0-rc.1 开发与验证。peerDependencies 声明 ^0.2.0-rc.1,可直接通过 DSH 的插件兼容性检查(evaluatePluginCompatibility 只校验 @deepseek-ai/dsh* peer 与运行时版本的 semver 匹配),不豁免、不报警告。0.1.5-rc.2 及更早版本不适用
profile 需要 web profile。webServer 与 webRuntime 由 web bundle 提供,装进 headless / acp / sdk profile 时该行会永久停在 PENDING(不报错,也不工作)

0.2.0 迁移要点(v0.4.0)

变化 本插件的适配
peer 版本范围 4 个 @deepseek-ai/dsh-* peer 从 ^0.1.5-rc.2 升到 ^0.2.0-rc.1(^0.1.5-rc.2 展开为 >=0.1.5-rc.2 <0.2.0-0,天然不匹配 0.2.0-rc.1,会触发启动跳过 + 预检禁用 + 安装拒绝三层阻断)
settings.register() 被删除 改为导出 Config = PrefsSchema(Cordis Loader 模型);设置读写走 settings.describe()/update(),命名空间是 profile entry id(task-notify,必须与 cordis.patch.yml 的 id 一致)
表单只收录 .volatile() 字段 7 个配置字段全部加 .volatile()——否则 describe() 不返回本插件、update() 报 no volatile fields
volatile 字段热更新不重挂载 fiber 偏好改为事件发生时现读 describe()(apply 捕获的启动配置会过期),读不到时回退启动配置
声明 Config 后设置页自动生成原生表单 settings.configure({ auto: false }) 抑制原生页,沿用自定义「任务通知」区块,避免重复入口
schema 库 改用 DSH 维护的 @deepseek-ai/schemastery(npm schemastery 没有 .volatile())

安全设计

  • 所有 /task-notify/api/* 路由经过 Host 头信任围栏(loopback / webRuntime.trustedHosts),与 /api 网关同一套校验
  • 插件只读会话日志,不修改任何 DSH 数据
  • 通知内容截断(maxBodyChars),无敏感信息外泄

📁 项目结构

dsh-task-notify/
├── package.json           # dsh.client 声明 + 双端 exports + bundle patch
├── cordis.patch.yml       # 挂载声明(dsh plugin add 自动识别)
├── tsconfig.json          # 开发类型检查
├── tsconfig.build.json    # 构建编译(host 端 tsc → lib/)
├── tsdown.config.ts       # client bundle 打包(__ModuleLoader__ 格式)
├── README.md
├── DISTRIBUTE.md          # 发布与安装指南
└── src/
    ├── index.ts           # host 端:订阅 turn/end → node-notifier 弹窗
    ├── config.ts          # schemastery 配置 schema(7 项)
    ├── context-types.ts   # cordis Context 类型增强
    └── client/
        └── index.tsx      # client 端:设置面板 + 页面可见性上报

🛠️ 开发与构建

pnpm install      # 安装依赖
pnpm typecheck    # tsc --noEmit 类型检查
pnpm build        # tsc(host) + tsdown(client) → lib/
pnpm watch        # tsdown --watch(client 热重载)
pnpm pack         # 生成可分发 tarball

构建产物

产物 说明
lib/index.js host 端(Node,ESM)
lib/client.js client 端 bundle(window.__ModuleLoader__.load 格式,供浏览器加载)
lib/*.d.ts 类型声明

发布到 npm

# 改 package.json version → 0.1.x
npm publish

❓ 常见问题

装了但设置页没有「任务通知」区块?

硬刷新浏览器(Ctrl/Cmd+Shift+R)。client 端改动不需要重启 DSH。

任务完成了但没弹通知?

按顺序排查:

  1. 页面是否在前台?默认 onlyWhenBlurred: true,页面可见时故意不弹(防打扰)——切后台再试,或到设置页关掉该项
  2. 系统通知权限?Windows「设置 → 系统 → 通知」允许来自 PowerShell/终端的通知;macOS「系统设置 → 通知」
  3. 检查设置页「任务通知」是否启用了总开关
安装时出现 "missing peer @deepseek-ai/*" 警告?

正常现象。@deepseek-ai/* 由 DSH 运行时提供(不在 profile 的 node_modules 里),pnpm 在 profile 层检查不到所以告警,不影响运行——官方 dsh-better-sidebar 安装时同样如此。

Windows 首次弹窗没反应?

node-notifier 在 Windows 走 PowerShell toast 脚本,首次可能被 SmartScreen 拦截,放行一次即可;插件内置回退(msg.exe),实在不行会在会话日志输出 [dsh-task-notify] 警告。

子代理/后台任务完成也会弹吗?

默认不弹(sessions: top-level 跳过 delegationDepth > 0 的子代理会话)。改为 all 则所有会话都通知。


📄 许可证

MIT


dsh-task-notify · 让每一次任务完成都不被错过