dsh-web
zhu1090093659
DeepSeek Harness (DSH) Web 插件聚合生态 · 万物皆插件,通过创意工坊分发||DeepSeek Harness (DSH) Web Plugin Aggregation Ecosystem · Everything is a plugin, distributed via the Creative Workshop
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:printz1/dsh-notify
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
在「需要你介入」或「任务跑完」时提醒你,这样你可以把 DSH 丢在后台去干别的。
提醒方式与时机全部可以在 设置 → 通知 里改,不用碰配置文件。
零第三方依赖、零构建步骤:Host 半侧是一个空的 cordis 插件,全部逻辑都在浏览器半侧。
Desktop / in-page notifications for the DeepSeek Harness (
dsh) Web GUI: notify on approval requests,ask_user_question, turn end, background-job end and session errors — with a full settings page (Settings → 通知) for per-scene toggles, per-session mute, quiet hours, minimum duration, throttling, system notification / in-page toast / sound channels. Zero runtime dependencies, no build step.
# 从 GitHub
dsh plugin --profile web add github:printz1/dsh-notify
# 本地开发时(软链,改完文件即时生效)
dsh plugin --profile web add link:/path/to/dsh-notify
装完重启 dsh 后端,然后刷新浏览器页面(客户端 bundle 是页面加载时才拉的)。
自检:node tools/verify-install.mjs 验宿主认不认这个包,node tools/selftest.mjs 验行为。
卸载:
dsh plugin --profile web remove dsh-notify,然后重启后端。
| 场景 | 来源 | 通知标题 | 默认 |
|---|---|---|---|
| 需要你审批 | ctx.uiSession.pendingInteractions |
DSH · 需要你审批 |
开 |
| 模型在等你回答 | 同上(question / plan-review) |
DSH · 模型在等你回答 / 计划等你审阅 |
开 |
| 一轮指令结束 | api-session/status 由 running 变 idle |
DSH · 任务已结束 |
开 |
| 后台任务结束 | sessions.list 的 jobsBySession 差分 |
DSH · 后台任务已完成 / 被中断 / 失败 |
开 |
| 会话出错 | api-session/error |
DSH · 任务出错了 |
开 |
| 子会话(subagent)结束 | 同「一轮指令结束」 | DSH · 任务已结束 |
关 |
点通知 / 点气泡都会 focus 窗口并切到对应会话。
| 项 | 默认 | 说明 |
|---|---|---|
| 启用通知 | 开 | 总开关,关掉后下面全部不生效 |
| 系统通知 | 开 | 浏览器 / Windows 通知中心;右侧按钮显示授权状态并可申请权限 |
| 页面内气泡 | 关 | DSH 页面右上角弹一条,不依赖浏览器授权;系统通知被拒时的替代方案 |
| 提示音 | 关 | 两声短促合成音(Web Audio,不引外部音频文件),旁边有「试听」 |
每个场景一个开关,另有三个细分项:
| 项 | 默认 | 说明 |
|---|---|---|
| 盯屏时也提醒 | 关 | 默认:页面在前台且聚焦时静默,免得每轮对话都响一次 |
| 免打扰时段 | 空 | 如 23:00-08:00(跨天自动识别,可逗号分隔多段),时段内完全不提醒 |
| 只提醒运行超过(秒) | 0 | 短任务不打扰;页面加载时已在跑的任务不受此限制 |
| 同一会话提醒间隔(秒) | 0 | 只作用于「一轮结束」和「后台任务」;审批 / 提问 / 出错永不节流 |
[系统+气泡]),刷新页面清空浏览器要求「用户手势」才能申请通知权限,所以系统通知第一次要手点一次:
设置 → 通知,在「系统通知」那一行点 请求权限如果被拒过:点地址栏左侧的图标 → 网站设置 → 通知 → 允许,再回来点「请求权限」。
http://127.0.0.1:3080 属于安全上下文,通知 API 可用。
不想授权也行:把「页面内气泡」打开即可,它不依赖任何授权。
两个可见渠道都关掉时,会退回闪烁标签页标题(🔔 …),切回标签页自动恢复。
localStorage 的 dsh-notify:config 一个键(JSON)。不走 DSH 官方设置系统,
因为它的命名空间是白名单制,第三方客户端插件读不到自己的。
0.1.x 的三个旧键(dsh-notify:enabled / :scenes / :notify-when-focused)
在首次加载时自动迁移进新配置,之后不再读取。
想直接改也行(改完刷新页面):
// 例:只在后台提醒,且夜间勿扰
localStorage.setItem('dsh-notify:config', JSON.stringify({
enabled: true, system: true, toast: false, sound: false,
scenes: { approval: true, question: true, turnEnd: true, job: true,
jobFailuresOnly: false, error: true, subagent: false },
notifyWhenFocused: false, quietHours: '23:00-08:00',
minDurationSec: 0, throttleSec: 0, mutedSessions: []
}))
非法值会被规整(布尔回落默认、数字夹紧到 0..86400、静音名单只留字符串),不必担心写坏。
dsh-notify/
├─ package.json # dsh.bundle.patch + dsh.client 双面声明
├─ cordis.patch.yml # 插入一行 `name: dsh-notify` 到 web profile 的插件树
├─ lib/index.js # Host 半侧:空的 apply()(合法插件入口,零副作用)
├─ lib/client.js # 浏览器半侧:全部逻辑(通知链路 + 头部按钮 + 设置面板)
├─ tools/selftest.mjs # 行为自检:假 DOM/假 ctx 里跑 122 项断言
├─ tools/verify-install.mjs # 安装自检:宿主认不认这个客户端包(30 项)
└─ README.md
cordis.patch.yml 里那行的 name 必须是裸包名(dsh-notify)。客户端模块扫描用
exactPackageSpecifier(),带子路径的三段写法直接返回 undefined。lib/client.js 里 window.__ModuleLoader__.load({ id }) 的 id 必须与包名逐字相同
—— 引导图里的 entry id 就是包名。dsh.client.inject 留空。它声明的是模块图依赖(本插件要 require 哪些 DSH 客户端包),
本插件只 require('react');remote / sessions / uiSession / slots 全走 cordis
服务注入(exports.inject),cordis 会让插件在依赖服务就绪前停在 PENDING,
所以不需要也不应该在 dsh.client.inject 里列 @deepseek-ai/dsh-client-ui-slots
这类不是 Loader 行的包。会话头部右上从右到左是 headerCorner(single,已被 sidebar-right 占用)→
headerUtilities(list,现有 open-in-app order -10、session-log-download order 0)
→ headerActions(在标题旁)。本插件挂 headerUtilities、取 order: 10 排到最右。
早先挂在侧栏底部的
sidebar.footer.action:那是个不换行的横向 flex 行,而重启后端 (width: calc(100% + 8px))和 cordis 面板(width: 100%)各自声明满宽,第三个成员必然 被挤出侧栏右边缘裁掉 —— 这就是「太靠右、看不清」的根因。已弃用该位置。
settings.sectionsettings.section 是 list 槽(root 作用域),每个条目就是设置弹窗左侧的一页
(现有 general 0 / models 10 / plugins 15 / agent-presets 20),本插件取 30 排在最后,
注册项 label: '通知' 就是导航文字。面板里的开关/输入框直接用 DSH 的 CSS 变量手写,
不依赖 @deepseek-ai/dsh-client-ui-primitives(该包没有独立类型,属未公开内部)。
两个脚本,各管一段,都不用开浏览器:
node tools/selftest.mjs
在 Node 里用假的 window / document / Notification / AudioContext + 假的 client ctx
真跑 lib/client.js,122 项断言覆盖:五个通知场景与子会话过滤、渠道三选与兜底、
免打扰时段、时长下限、节流、静音会话、前台静音、总开关、场景开关、旧配置迁移、
设置面板(注册项/分组/11 个开关/文本数字输入/静音名单/恢复默认/诊断按钮/日志)、
头部按钮(槽位/order/尺寸/SVG/状态)、单个订阅抛错不影响其它场景。
node tools/verify-install.mjs
客户端包被宿主忽略时不会报错,只是页面上什么都不出现 —— 所以单独验这一条链路:
裸包名判定(含「带子路径会被静默忽略」的对照)、dsh.client 声明过宿主的校验、
exports["./client"] 能解析到真实文件、bundle 自报 id 与行名逐字一致、
Host 半侧导出 apply() 且零 import、bundle 能在无 DOM 环境执行并导出 apply/inject。
最后直接 import 宿主的 stripClientSuffix / orderByModuleGraph 真货做交叉验证。
宿主的校验函数是逐字抄过来的,宿主升级后这里不会自动跟 —— 所以那两条真导入的交叉验证 是关键:它们会跟着宿主一起变。30 项全绿只说明「宿主会认这个包」,不代表页面渲染正常。
| 现象 | 原因 / 处理 |
|---|---|
| 头部没有铃铛按钮 | 后端没重启;或没打开任何会话(该槽位是会话级作用域);或 dsh --profile web --dump-config \| grep -A1 'id: notify' 里没有这一行 |
| 设置里没有「通知」页 | 后端没重启;或客户端 bundle 没重新拉取(必须刷新页面) |
| 有按钮但从不弹 | 没点过授权;或页面正前台聚焦(见「盯屏时也提醒」);或总开关关了;或该会话被静音;或落在免打扰时段 |
| 系统通知通不了 | 设置 → 通知 看「系统通知」那行的状态;被拒就去站点设置放开;实在不行改用「页面内气泡」 |
| 想确认它加载了 | 浏览器控制台看 window.__DSH_BOOT__ 里有没有 dsh-notify 行;或看「最近通知」有没有记录 |
| 改代码后没变化 | 软链是实时的,但需要重启后端 + 刷新页面;node --check lib/client.js 先确认语法 |
dsh plugin --profile web remove dsh-notify
然后重启后端。localStorage 里的 dsh-notify:* 可自行清掉。
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: notifications、web-ui。