2097aeaa76ff1cf1e8d231c7a657561c54caadf6
会话通知
DeepSeek Harness(DSH)插件:会话需要你注意时提醒你——窗口不在前台时用系统通知,窗口在前台时用应用内轻弹窗。
Windows / macOS / Linux 三个平台走的是同一条通知通道(渲染进程的 Web Notification API),插件里没有平台分支。
提醒什么
| 触发 | 通知标题 |
|---|---|
| 会话从「运行中」变为「空闲」(一轮回答结束) | 会话已完成 |
待处理的工具授权请求(approval) |
需要授权 |
待处理的提问 / 计划确认(question / plan-review) |
需要回答 |
每条只提醒一次:同一会话的同一轮只报一次完成,同一个待处理请求只报一次;请求消失后再来才会再报。
走哪个通道
| 状态 | 行为 |
|---|---|
| DSH 窗口不在前台 | 系统通知(这是插件唯一能拿到的系统通知通道,三个平台一致)。点通知:窗口回到前台并跳到该会话 |
| DSH 窗口在前台,且不是你正在看的那个会话 | 应用内轻弹窗:右上角悬浮,点「查看」跳过去,6 秒自动消失,鼠标悬停时不消失,Esc 关掉最上面一条 |
| DSH 窗口在前台,且就是你正在看的那个会话 | 不打扰(你在看,不需要弹) |
设置
设置 → 通用 → 会话通知:
- 显示系统通知权限状态;
- 未授权时点「允许通知」请求权限(浏览器要求必须由你手动点击才能弹权限框),授权后自动发一条测试通知;
- 已授权时点「测试通知」随时验证;
- 权限被系统层关闭时,按平台给出开启路径(Windows / macOS 的通知设置、Linux 桌面环境的通知设置);
- 三个开关分别控制完成 / 授权 / 提问三类提醒(默认全开;开关状态存在当前页面内存里,刷新回到默认——本插件不写配置文件)。
安装
在 DSH 的 插件 → 添加插件 里填本目录的绝对路径即可(plugin_manager 也会做同样的安装):
D:\DeepSeek Harness Plugins\dsh-session-notify
安装后:
- 浏览器半随页面加载,刷新页面即生效;
- 宿主半为空壳(不改任何 DSH 状态),如需重启才生效,完全退出 DSH 再打开即可;
- 本插件没有第三方依赖,不需要 pnpm 下载,也不需要构建步骤。
卸载:插件页里移除 @dsh-plugin/session-notify(它同时是 profile 的一个 bundle)。
平台说明与验证范围
- 通道是跨平台统一的:插件的提醒都通过页面(Electron 渲染进程)的
Notification构造器发出,Windows 通知中心 / macOS 通知中心 / Linux 通知守护(libnotify、GNOME、KDE)都由系统把它转成原生通知;应用内轻弹窗是纯 DOM,与平台无关。 - 宿主半拿不到系统通知:DSH Desktop 的宿主进程是纯 Node 进程(不是 Electron 主进程),没有 Electron 的
Notification可用,所以插件的所有提醒都在浏览器半产生——这也正是"三个平台一套代码"的原因。 - 已验证:Windows 上的安装、三个 slot 条目注册、以及 22 条投递规则(见下)的离线验证;设置行与轻弹窗的文案/交互按 DSH 自带的 toast 与 switch 组件对齐。
- 未验证:macOS 与 Linux 上的实际弹窗效果本机无法测试。结构上它们与 Windows 共用同一条通道、同一份代码,只有"权限被系统关闭时显示的开启路径"是分平台的。
- 提醒只在 DSH 进程运行、页面打开时产生:DSH 完全退出期间结束的会话不会再补发通知。
行为细节(都已验证)
- 只有观测到「运行中 → 空闲」的转变才提醒:打开应用时已经在跑的会话只建立基线,不补发;历史里早已结束的会话不会被翻出来提醒。
- 子智能体会话不单独提醒(
origin === 'subagent'),归属它的主会话结束时才提醒。 - 新会话(空白会话)完成不提醒。
- 授权/提问在会话仍在运行时被延后提醒:先记下,等这一轮真正停下来再报,避免在模型还在跑的时候就打扰你。
- 节流:1.5 秒内只投递一条,多个会话同时完成不会刷屏;完成提醒前有 400ms 的确认窗口,如果那一轮马上又跑起来就不报。
- 同一会话的完成提醒会覆盖上一条(通知带
tag),不堆叠。
兼容性
基于 DeepSeek Harness 0.2.0-rc.2 编写,遵循 DSH 插件规范:dsh.manifestVersion: 1、dsh.bundle.patch 声明宿主行、dsh.client 声明 platform: "web" 的浏览器半。
依赖的都是稳定契约:
- 浏览器半只依赖 slot 的标准 props(
useSessions、useSessionStatus)读取会话状态,这是 DSH 官方给插件读会话数据的方式;不轮询、不自己订阅会话事件、不读别的插件的 DOM; - 只往两个官方 slot 注册:
settings.general.item(设置行)与shell.overlay(两个条目:轻弹窗层 + 无渲染的观察器,内容永远是null); - 不要把"无渲染"条目放进
sidebar.panellist:该 slot 的宿主会把每个条目的 id 当成一个左侧面板按钮(entriesOfSlot('sidebar.panellist')→ 面板列表,按钮文字取options.label ?? options.id,条目本身作为图标内联渲染),放进去会在左侧多出一行空面板并挤坏侧边栏。本插件第一版踩过这个坑,现已改挂到通用浮层; - 文案必须注册字典:
ctx.locale.register('session-notify', { zh, en }),否则locale.bind(ns)在查不到该命名空间时会把 key 原样返回——界面上就会显示成settings.title这样的原始键(本插件第二版踩过这个坑)。注册会在 locale 修订号上打点,已经渲染出来的条目会自动换上文案,不需要刷新; - 另外自带一份本地字典兜底:即使拿不到框架的
t、或 locale 服务没有保存注册,也会渲染中文/英文文案而不是原始键; - 样式只用主题 token,不 import 任何
@deepseek-ai/dsh-client-*包(规范要求,也是渲染不被上游改动打断的前提); - 宿主半不声明
inject、不注册服务、不注册路由。
上游若改动 slot 名或 hook 名:注册会静默跳过而不是把页面弄坏,插件会退化成"不提醒";这类情况请按上面的契约名核对。
验证方式(开发记录)
client.js 是纯 JavaScript、浏览器端运行,可以在 Node 里用桩模块加载器评估并驱动:
- 模块接线:加载后返回的插件、
inject声明、注册集合(含"观察器绝不在sidebar.*里"这一条); - 国际化:字典已注册且中英键集合一致、设置行与弹窗渲染出的每个字符串都不是原始键、拿不到框架
t时本地字典兜底、locale 服务不保存注册时仍然有文案; - 渲染健壮性:各组件在空状态 / 权限被拒 / 无 Notification API 下渲染都不报错;
- 投递规则:完成提醒一次、当前会话不打扰、后台走系统通知、授权/提问各提醒一次、运行中延后、子会话跳过、空白会话跳过、历史不补发、开关生效、弹窗自动消失等。
合计 44 项断言。
License
Languages
JavaScript
100%