dsh-completion-reminder
v1.8.0
Published
DSH client plugin — notify the user when an agent finishes. 10 directly-reachable channels incl. Feishu bots; settings live inside DSH's dialog; persistent config.
Maintainers
Readme
DSH Completion Reminder
为 DeepSeek Harness (DSH) Web GUI 增加 Agent 完成提醒 功能的插件。 当 agent 停止生成(成功 / 主动停止 / 出错)时,弹一个通知给用户。
- 🌐 默认走 浏览器原生通知(
window.Notification,首次使用需要用户授权) - ⚙️ 直接在 DSH 自己的 「设置 → 插件 → 🔔 完成提醒」 里配置(与「可配置」同级 tab)
- 🔒 凭证按渠道筛选:选 Telegram 只显示 2 项,选 Bark 只显示 1–2 项,不会一下子蹦出 11 个无关字段
- 🎨 暗色 / 亮色主题都正常(
color-scheme: light dark+ 显式前景色,再无「白底白字」) - 💾 配置保存在本浏览器
localStorage,不会上传任何服务器 - 🧪 配置面板自带 「发送测试通知」 按钮,方便验证渠道是否通
- 🪟 标签页可见时默认静默(不打断工作),可通过开关关闭
- ⏱ 内置 5 秒冷却,避免连续 agent 完成时刷屏
10 种通知渠道(全部可直连)
| 渠道 | 适用人群 | 配置字段(按当前渠道只显示需要的) |
|------|----------|--------------------|
| 浏览器通知(默认) | 任何浏览器 | 无(需授权通知权限) |
| Server酱 | 微信推送 | SendKey |
| 飞书机器人 | 飞书群 | Webhook 地址 / 签名密钥(可选) |
| Bark (iOS) | iPhone 用户 | Bark Key / Bark Server(可选) |
| Pushover | 跨平台推送服务 | App Token / User Key / Device(可选) |
| Telegram | Telegram 用户 | Bot Token / Chat ID |
| Discord | Discord 频道 | Webhook URL |
| Slack | Slack 工作区 | Webhook URL |
| 通用 Webhook | 自建服务 | URL |
| 自定义 | 完全自定义 | 占位(customSend(payload)) |
本插件只收录浏览器可直连的渠道。钉钉与企业微信群机器人接口不返回 CORS 头(钉钉还强制 application/json,会触发被拒的预检),网页端物理上 无法直连,已在 v1.7.0 移除——需要这两家建议走 Server酱或自建通用 Webhook 转发。飞书接口自带 CORS 头,直连可用。
工作原理
1. 完成检测
DSH composer 卡片 <div data-composer-card="true"> 内的主按钮 aria-label 会在
"Stop generating" / "Send message"(中文 UI 是 "停止生成" / "发送消息")之间切换。
插件用 MutationObserver 监听这个属性变化:
- 检测到
Stop generating→ 记录开始时间 - 检测到
Send message→ 触发完成事件 - 根据
data-phase(active/settling/hero)和最后一条data-role="assistant"消息的文本/类名,判断success/stopped/error - 派发到当前渠道,调用
Notification/fetch发送
所有匹配都用 稳定属性(data-*、aria-label、type),不依赖 CSS-modules 哈希后的 class 名。
2. 设置面板
通过 DSH 的 ctx.slots.inject('settings.plugins.tab', ...) API,插件把自己注册成
DSH 「插件」section 里与「可配置」同级的一个 tab:
DSH 设置弹窗 → 插件
├─ 可配置 ← DSH 自带(编辑插件配置)
├─ 🔔 完成提醒 ← 本插件settings.section 同样被注册作为兜底(旧版本或非标准 host 仍能找到入口)。
- 通知渠道下拉(切换渠道时,凭证区实时刷新)
- 当前渠道只显示需要的字段(不需要在 11 个无关字段里翻找)
- 行为开关(成功 / 停止 / 出错 / 焦点抑制 / 自动请求权限 / 冷却)
- 「发送测试通知」 / 「重置」 / 「请求权限」三个动作
没多出任何悬浮按钮,UI 与 DSH 原生设置完全一致。
3. 降级
如果加载时 DSH host 不支持 ctx.slots(极旧版本或非标准 host),
插件会退回到「DOM 检测 + 浏览器通知」基础模式,
并显示一条底部提示引导用户去设置面板。
快速开始
安装 / 升级
dsh plugin --profile web update dsh-completion-reminder
dsh web # 重启配置
- 打开 DSH → 点击左上角「⚙ 设置」→ 进入「插件」section
- 在 tab 栏里点击「🔔 完成提醒」
- 选择通知渠道(如
Telegram) - 填入对应的 token / id(凭证区只显示当前渠道需要的字段)
- 点击「发送测试通知」验证渠道通不通
- 关闭弹窗 → 自动保存到 localStorage
程序化 API
DSHCompletionReminder.configure({
provider: 'telegram',
providers: { telegramBotToken: '...', telegramChatId: '...' },
suppressWhenFocused: false,
cooldownMs: 3000,
onNotify: (payload, provider) => console.log('delivered via', provider, payload),
onError: (err, provider) => console.warn('failed via', provider, err),
});
DSHCompletionReminder.activate();
DSHCompletionReminder.deactivate();
DSHCompletionReminder.requestBrowserPermission();公开 API
| 方法 / 属性 | 说明 |
|------|------|
| DSHCompletionReminder.configure(opts) | 合并配置(与 localStorage 持久值叠加) |
| DSHCompletionReminder.activate() | 启动 DOM 观察 + 注册设置入口 |
| DSHCompletionReminder.deactivate() | 停止一切,清理 UI |
| DSHCompletionReminder.requestBrowserPermission() | 手动触发浏览器通知权限请求 |
| DSHCompletionReminder.apply(ctx, opts) | DSH Cordis Loader 入口 |
| DSHCompletionReminder.renderPanelInto(hostEl) | 把配置面板渲染到任意 DOM 容器(主要用于测试) |
| DSHCompletionReminder.DEFAULTS | 默认配置(只读) |
项目结构
dsh-completion-reminder/
├── package.json # npm 包配置,含 dsh.bundle.patch 与 dsh.client 声明
├── cordis.patch.yml # 包自带的 loader 注册 patch
├── tsconfig.json # TypeScript 配置
├── src/
│ ├── index.ts # 服务端入口(桩)
│ ├── client.ts # 客户端插件(DOM 检测 + 9 渠道 + 设置面板)
│ ├── react.d.ts # 极简 React 类型(运行时通过 DSH module 系统 require('react'))
│ └── types.ts # 类型定义 & 默认值
├── lib/
│ ├── index.js # 服务端入口
│ └── client.js # DSH __ModuleLoader__ 格式的客户端插件
├── dist/
│ └── dsh-completion-reminder.js # 独立脚本(可直接 <script> 加载)
├── scripts/
│ ├── build-plugin.js # 构建脚本(tsc + import 转换为 require + ModuleLoader 包装)
│ └── clean.js # 清理 lib/ 和 dist/
└── probes/ # 离线 smoke test(jsdom)发布流程
npm version patch # 或 minor / major
git push origin main --tagsCI 自动完成构建、npm 发布、GitHub Release。
版本历史
- v1.8.0 — 体验打磨(基于用户反馈的优化):
- 通知标题去掉 emoji(✅⏹⚠️ → 纯文字「DSH Agent 已完成/已停止/出错」), 与渠道去表情的方向统一;面板底部存储警告也去掉 ⚠️
- 飞书升级为可点击卡片:从纯文本改为 post 富文本,DSH 链接变成可点
「打开 DSH」;并修正飞书签名公式(之前 key/msg 写反且签名误塞进请求体,
开过「签名校验」的飞书机器人其实一直发不出去——现在按官方算法把签名放
进 URL 参数
timestamp/sign) - Discord 消息里的 DSH 链接改为 markdown 可点形式
- 浏览器通知点击行为:点击 OS 通知会聚焦当前窗口并新标签页打开跳转链接
- 完成检测加轻量兜底:万一主逻辑依赖的 composer 按钮 aria-label 契约因 DSH 改版失效,会以「新出现的 assistant 消息」作为完成信号(带冷却去重, 不抢主逻辑、不流式误报)
- v1.7.0 — 按用户要求移除需要本地转发的渠道:
- 移除钉钉机器人与企业微信机器人(两家接口不允许浏览器直连, 见 v1.6.0 实测结论),并删除随附的 relay.mjs 转发服务
- 保留飞书机器人(接口自带 CORS 头,直连可用)
- 迁移保护:旧配置里存着 dingtalk/wecom 的用户升级后自动回落到 浏览器通知,不会在每次 agent 完成时报"未知渠道"
- v1.6.0 — 国内渠道真实可达性修复(用户反馈"钉钉通知失败"的根因):
- 实测发现钉钉接口拒收 text/plain(errcode 43004,必须 application/json), 而其响应无任何 CORS 头、OPTIONS 预检也不放行 → 浏览器直连不可能; 企业微信响应同样无 CORS 头。v1.5.0 的"text/plain 简单请求"方案对这两家无效
- 飞书改为标准 application/json CORS 直连——实测其响应带完整 CORS 头 (acao:*),浏览器可发可读,零配置可用
- 新增零依赖本地转发小服务
relay/relay.mjs(纯 node 内置模块, 仅绑定 127.0.0.1):node relay.mjs一条命令,钉钉/企微把 「本地转发地址」填为http://127.0.0.1:8765即通;签名仍在插件端计算, 密钥不出机器;上游业务错误码(errcode/code)原样透出
- v1.5.0 — 渠道扩充 + 修复"刷新后设置重置":
- 新增国内渠道:钉钉机器人(支持加签)、飞书机器人(支持签名校验)、 企业微信群机器人
- 渠道名去掉所有 emoji 表情
- 修复刷新重置:构建脚本内联 types 的方式从手工拷贝改为自动提取 lib/types.js 并按 client 实际 import 解构——手工拷贝曾漏掉 STORAGE_KEY, 导致 localStorage 读写全部抛 ReferenceError 被吞、持久化从未生效
- 渠道发送失败现在会以页内 toast 提示具体原因(不再静默)
- 多标签页同源配置实时同步(storage 事件);面板底部显示当前站点与 存储可用性,便于自查 localhost 与 127.0.0.1 配置互不相通的问题
- v1.4.0 — 手势安全的浏览器授权流程 + 单选组渠道选择器 + 去标题 emoji
- v1.3.1 — 修复设置入口从未出现的根因:插件现在导出
inject = ['slots'], cordis Loader 会等 slots 服务就绪才调用apply(对齐 dshmarket 的做法)。 之前 apply 跑在服务提供之前,ctx.slots为 undefined,注册被静默跳过。 另:槽位组件改为 dshmarket 同款「普通函数组件 + callback ref」,去掉 forwardRef/useRef 依赖;新增window.__DSH_COMPLETION_REMINDER_DEBUG诊断对象;settings.sectionorder 调整为 45(紧随「插件」「插件市场」)。 - v1.3.0 — 设置面板进入「DSH 设置 → 插件」section 的 tab 栏(与「可配置」同级)
- v1.2.0 — 凭证按渠道筛选 + 暗色主题修复
- v1.1.0 — 真实 DSH DOM 锚点
- v1.0.0 — 初始版本(class 名匹配,实际 DSH 上不可用)
自查
若升级后仍看不到入口,在浏览器控制台(F12)执行:
window.__DSH_COMPLETION_REMINDER_DEBUG正常应显示 { hasSlots: true, pluginsTab: 'ok', section: 'ok', … }。
许可
MIT
