Перейти к основному содержимому
S

dsh-whale-reminder

shawnzhanggy/dsh-whale-reminder

Windows session-end reminder for DeepSeek Harness: an in-window unread badge that lists session names and jumps to the session when clicked, two Web Audio chimes, taskbar flashing, and a tray badge on the whale icon; only visible sessions are counted, and the settings page has seven options including a zh/en switch.

Установка

dsh plugin --profile web add github:shawnzhanggy/dsh-whale-reminder

README

dsh-whale-reminder

会话结束后提醒你 —— 不再守着窗口等结果。

DeepSeek Harness 桌面版(Windows)插件:一轮会话跑完后,系统通知 + 声音 + 窗口内浮层 + 任务栏闪烁 + 托盘徽章五路提醒,QQ/微信式未读体验。

解决的问题

DeepSeek Harness 桌面版一轮会话跑完后不会主动叫你,你只能自己反复切回来瞄进度。本插件在任务完成、需要你回答、或出错时主动提醒:Windows 系统通知横幅、任务栏闪烁、托盘徽章、窗口内浮层与提示音,QQ/微信式未读体验。系统通知拥有独立应用身份,可在 Windows「设置 → 系统 → 通知」里单独开关,不影响宿主应用本身的通知。

安装

本插件只支持 Windows 桌面端(依赖 Win32 任务栏/托盘 API 与 WinRT 通知)。

它装进桌面端的 desktop profile。先把 DSH 完全退出(含系统托盘),然后在终端执行:

dsh plugin --profile desktop add dsh-whale-reminder

装完重新打开 DSH 即可。也可以不离开 DSH:在会话里让宿主内置的 plugin_manager 装,效果相同。

请使用当前桌面端内置的 plugin_manager 安装 dsh-whale-reminder,装完告诉我结果以及是否需要重启。

  • 首次安装:工具可能返回 "application":"applied",但这不保证当前窗口已经生效。若装完没出现浮层,完全退出客户端(含系统托盘)后重新打开。
  • 升级:改的是 client 半区则刷新页面(Ctrl+F5)即可;改了 host 半区(lib/*.mjs)必须完全退出重开。
  • 卸载:同一工具执行 remove_bundle。

主要功能

  • Windows 系统通知:会话结束时在通知中心弹出横幅,标题是事件类型(会话已完成/等待你的批准/等待你的回答/会话出错),正文是那一轮你输入的内容。它以自己的应用身份出现,所以在「设置 → 系统 → 通知」里能看到 鲸鱼提醒 这一条,可以单独开关、单独调声音,与宿主应用互不干扰。点击横幅会直接跳转到那条会话,并把窗口唤到最前、把光标放进输入框,可以马上接着打字。
  • 盯着 DSH 时不弹横幅:只要 DSH 是当前活动窗口,就跳过系统通知(声音与角落徽章照常),不会在你正看着屏幕时弹一条多余的横幅;被别的窗口盖住或最小化时才弹。该行为由「DSH 在前台时不弹通知」开关控制,默认开启。
  • 点击通知的动作可选三档:「点击通知时」可以选 提到最前并聚焦输入框(推荐,可以立即打字,代价是会从其他程序里抢走键盘焦点)、只提到最前,不抢键盘(窗口到最层但不打断你正在输入的内容)、只提醒,不提窗(窗口保持原样、可能还在任务栏里,只切换会话)。三档都不影响会话切换本身。
  • 智能触发:只有窗口在后台(失焦/隐藏/切到别的会话)时才出声提醒,正在看的不打扰;三个「什么时候算需要提醒」的开关可独立关闭。
  • 双音效:完成「叮—咚」、待回答「叮叮」,音量可调。
  • 窗口内常驻浮层:角落红色数字徽章,显示「N 个会话未读」,点击展开会话名列表,点会话名直接跳转到该会话,停靠角可切换四角。
  • 任务栏闪烁 + 托盘徽章:任务栏 FlashWindowEx 闪烁;托盘小鲸鱼图标叠加红色数字徽章(1–9,超 9 显示「9+」),悬停显示未读缩略文字。
  • 设置有两处入口:左侧栏「设置」面板里新增一项 鲸鱼提醒(与「技能」「费用」等插件设置并列);插件管理器里那一行的「配置」按钮也能打开同一张表单。
  • 只提醒你看得见的会话:已归档、子代理、空白会话一律不计入未读,与侧栏可见性规则保持一致。

设置项

设置页共 9 组,全部即时生效、无需重启:

分组内容
启用提醒总开关。关闭后不出声、不闪任务栏、不显示浮层、不弹通知(浮层与通知各自的开关仍然保留)
语言中文 / English,默认中文。只影响本插件(浮层、设置页、托盘 tooltip、系统通知),不跟随应用语言
提醒哪些事件正常完成 / 待回答 / 出错,三个独立开关,默认全开
什么时候算「需要提醒」窗口被隐藏 / 窗口失焦 / 焦点在别的会话,默认全开。正在看着的那条会话不打扰
声音音量0–100,默认 60,两个音效共用;旁边有 试听 按钮
浮层显示会话数1–20,默认 3,同时是 tooltip 字数上限 1–256(默认 127)
浮层停靠角落右下(默认)/左下/右上/左上
系统通知通知开关;通知带提示音(用 Windows 自带的提示音,与本插件音效相互独立,默认关);DSH 在前台时不弹通知(默认开);点击通知时三档(提到最前并聚焦输入框/只提到最前不抢键盘/只提醒不提窗,默认第一档)
测试提醒一键演练:闪任务栏 + 闪托盘 + 出声 + 浮层出现 + 弹一条通知。点这条通知同样会跳回当前会话,可用来验证点击链路

另有一批只存在于配置 schema、未渲染进设置页的进阶参数(闪烁次数与超时、轮询间隔、鼠标一动就停、最长提醒时长、忽略被打断的回合、忽略子代理、托盘闪烁间隔、虚拟主会话点、状态点过期秒数等),共 31 个字段,都带 volatile 标记,需要时可直接在 profile 配置里改。

技术要点

  • host 半区(ELECTRON_RUN_AS_NODE 的独立 Node 进程):Windows 原生能力(koffi Win32 API:FlashWindowEx、Shell_NotifyIcon*)负责任务栏闪烁与托盘徽章;系统通知走 HKCU\Software\Classes\AppUserModelId\Shawn.DSHWhaleReminder 注册独立应用身份 + PowerShell WinRT ToastNotificationManager 发送 ToastGeneric;监听 session/event 的 turn/end / approval/asked / tool/call(ask_user_question) 触发提醒。
  • 通知点击跳转:toast 用 activationType="protocol" 携带 dsh-whale-reminder://open/<会话 id>;注册表里的协议处理器是一个原生小程序 assets/activate.exe(C# 编译,不弹控制台窗口),它把收到的 id 通过 loopback HTTP 回传给正在运行的宿主(端口写在注册表命令里),宿主把这次点击广播给所有窗口(每个窗口按单调递增的序号去重,只有序号变新时才导航,刚加载的窗口只记下基线、不重放旧点击),client 半区在窗口处于后台时每 1.5 秒轮询一次,拿到新序号就调用 uiWorkspace.openSession,导航确认后再把光标放进输入框([data-composer-input])。处理器不写任何文件——早期用 .vbs + %LOCALAPPDATA% 落盘的方案在受限令牌下会静默失败,改用 HTTP 后不再受文件权限影响。不新增常驻进程,也不需要宿主配合。
  • 为什么提窗口在 activate.exe 里做:Windows 只允许「当前持有前台权限的进程」改前台,宿主是后台进程,从它那里唤窗口必然被拒(实测直接调用仅 1/3 成功)。处理器由鼠标点击直接启动、持有该权限,所以工作都在它里面做。三条实测结论决定了实现:① ShowWindowAsync 只是把请求投递给窗口线程,而处理器约 1 毫秒就退出,请求随之丢失(从 shell 启动时 12 秒重试仍无法恢复),因此恢复后必须轮询 IsIconic 确认落定;② 恢复最小化窗口本身就会带来前台,所以这条路径不再额外抬窗,也就不会闪;③ 可见但被覆盖时,SwitchToThisWindow(任务栏点击用的同一个交接)实测 3/3,而 SetForegroundWindow 只有 1/3,因此首选前者、后者只做一次静默重试;④ 但真实点击通知时,ShellExperienceHost 的通知横幅窗口会持续占用前台锁(实测 9 秒内完全不释放),期间 SetForegroundWindow、SwitchToThisWindow、HWND_TOPMOST、最小化横幅、WM_CLOSE/SC_CLOSE 全部被拒,只有注入一次真实 Alt+Tab 键击才能解除该锁——因此一旦检测到前台是通知横幅(窗口类 Windows.UI.Core.CoreWindow),就跳过全部静默尝试、直接进入解锁——它们注定被拒,而其中 BringWindowToTop 仍会改 z 序,表现为窗口先冒出来、被横幅压回去、再被抬上来,也就是用户看到的闪烁;解锁本身用「无停顿按下即松开」的 Alt+Tab(不给任务切换器绘制时间),并等前台真的离开横幅(实测:在按键的同一毫秒内就调 SetForegroundWindow 仍会被拒,表现为「闪一下但没上来」)再反复抬窗直到读回确认;⑤ 抬窗成功还不能立刻退出——前台会随「抢到前台的进程消失」被交还回去(实测:交接成功、进程退出后窗口闪一下又掉下去),所以成功后进程再存活 1 秒,期间一旦发现前台被抢走就重新抢回。所有抬窗 API 的返回值两个方向都不可信,成功与否一律靠轮询 GetForegroundWindow 读回。不做「先最小化再恢复」的重试循环:它能拿到前台(实测 8/8),但会让窗口明显弹跳,代价高于让用户再点一次,所以拒绝时只闪任务栏,横幅仍留在通知中心可再点。点击动作由宿主在 HTTP 响应里带回(clickAction:raise/show/none),选「只提到最前」时改用 SetWindowPos(SWP_NOACTIVATE) 只浮上来不抢焦点,选「只提醒」时处理器完全不碰窗口。
  • client 半区(浏览器渲染进程):shell.overlay 常驻浮层 + Web Audio 双音效 + settings.section(设置面板侧栏)与 plugins.row.config(插件管理器行)双座位共用同一张表单,通过 __whale-reminder/* 私有路由与 host 半区通信。
  • 配置持久化:走官方 Config schema(@deepseek-ai/schemastery,31 字段全 .volatile())+ settings.configure({auto:false}) + client 侧 configForms。
  • 语言:插件自带中文/English 切换(默认中文),浮层、设置页、托盘 tooltip、系统通知四处一致,不跟随应用语言。
  • 降级:系统通知不依赖 koffi,所以即使 Win32 绑定失败,通知仍能送达;反之任务栏/托盘失效也不影响通知。

设置页在哪

两个入口,同一张表单:

  • 设置面板(左下角头像菜单 → 设置,或 Ctrl+,)→ 左侧导航里的 鲸鱼提醒,位置在「归档会话」与「bili 设置」之间。
  • 插件管理器 → 找到 dsh-whale-reminder 这一行 → 右侧「配置」控件。

架构参考

复用并改造自 dsh-tray-flash@0.5.2 的已验证架构(win32/tray/dots/attention/koffi-loader/selftest-route),在此基础上新增声音、未读徽章、浮层与设置页。

限制

  • 仅 Windows 桌面版(依赖 Win32 托盘/任务栏 API 与 WinRT 通知)。macOS/Linux 上 host 半区会安静降级,只有窗口内浮层与声音可用。
  • 托盘图标定位在 Win11 溢出区可能失败(Shell_NotifyIconGetRect 无 rect),此时自动降级为任务栏闪烁兜底。
  • 系统通知需要 PowerShell 可用;被组策略禁用的机器上会自动降级为「静默不发」,其余提醒通道不受影响。通知里显示的会话语义取自你那一轮输入的第一行,会话没有人类输入时退化为会话 id 前 8 位。
  • 点击通知跳转依赖插件首次启动时写入的协议注册表项(HKCU\Software\Classes\dsh-whale-reminder,仅当前用户,无需管理员权限),以及 %LOCALAPPDATA%\dsh-whale-reminder\activate.exe 这个处理器副本(每次启动自动刷新)。若被安全软件清理掉,重启一次客户端即可自动修复;修复前的点击只会把窗口提到前台。点击后若目标会话已不存在或无法导航,客户端日志会留下 did not navigate 警告,而不是静默失败。
  • 点击横幅抬窗口分两条路:最小化时通过恢复动作拿到前台(恢复本身就会带来焦点),最大化但被盖住时走任务栏点击用的同一个交接(SwitchToThisWindow)。两条路都只做一次,不会闪最小化动画。若前面几步都被前台锁拒绝(最常见的原因是通知横幅仍占着前台),最后会注入一次无停顿的 Alt+Tab 解除锁再提窗;在少数环境下这一下仍可能看到任务切换器一闪,这是 Windows 前台权限规则决定的,无法完全避免。若连这一步也被拒(例如屏幕已锁),会安静失败、只闪任务栏、不再重试——横幅仍留在通知中心,稍后再点即可。抬窗成功后处理器会多存活约 1 秒以稳住前台,因此点完通知到可以打字之间会有一秒左右的间隔。
  • 若 DSH 已完全退出,点击通知中心里的旧横幅不会启动它(处理器只在 DSH 运行时才能把点击投递给宿主)。

许可证

MIT © 2026 shawn

Похожие плагины