Files
session-notify/README.md
T

6.5 KiB
Raw Blame History

会话通知

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,条目本身作为图标内联渲染),放进去会在左侧多出一行空面板并挤坏侧边栏。本插件第一版踩过这个坑,现已改挂到通用浮层;
  • 样式只用主题 token,不 import 任何 @deepseek-ai/dsh-client-* 包(规范要求,也是渲染不被上游改动打断的前提);
  • 宿主半不声明 inject、不注册服务、不注册路由。

上游若改动 slot 名或 hook 名:注册会静默跳过而不是把页面弄坏,插件会退化成"不提醒";这类情况请按上面的契约名核对。

验证方式(开发记录)

client.js 是纯 JavaScript、浏览器端运行,可以在 Node 里用桩模块加载器评估并驱动:

  • 模块接线:加载后返回的插件、inject 声明、注册集合(含"观察器绝不在 sidebar.* 里"这一条)、以及各组件在空状态 / 权限被拒 / 无 Notification API 下的渲染都不报错;
  • 投递规则:40 项断言覆盖上面"行为细节"里的每一条(完成提醒一次、当前会话不打扰、后台走系统通知、授权/提问各提醒一次、运行中延后、子会话跳过、历史不补发、开关生效、弹窗自动消失等)。

License

MIT