@game25011/dsh-notify-toast 0.0.0-stage → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,29 @@
1
+ # AI 参与说明 / AI Disclosure
2
+
3
+ ## 中文
4
+
5
+ ### AI 参与范围
6
+
7
+ 本项目的主要代码(Host、Web Client、PowerShell/C# 原生 helper 及多数测试/文档)**由 AI 编程助手生成**。人类维护者负责需求定义、调试、测试设计与验收、发布及后续维护,并对最终代码质量负责。
8
+
9
+ AI 生成的内容可能存在错误、遗漏或不适用于特定环境的实现。欢迎通过 issue 或 pull request 反馈问题、提出改进;维护者将结合项目实际情况进行评估和处理。
10
+
11
+ ### 责任与许可
12
+
13
+ - 本项目依据 **MIT License** 发布,不提供超出许可证约定范围的任何保证。
14
+ - AI 工具不是本项目的作者、版权持有者或责任主体;人类维护者以项目发布者身份承担维护责任。
15
+ - 本文仅用于说明项目的开发过程,不构成法律意见。
16
+
17
+ ## English
18
+
19
+ ### Scope of AI Involvement
20
+
21
+ **Most of the code in this project — Host, Web Client, PowerShell/C# native helpers, and most tests/docs — was generated by AI coding assistants.** The human maintainer is responsible for defining requirements, debugging, designing and validating tests, managing releases, and ongoing maintenance, as well as for the quality of the final code.
22
+
23
+ AI-generated content may contain errors, omissions, or implementations that are unsuitable for particular environments. Issues and pull requests are welcome; the maintainer will evaluate and address them in the context of the project.
24
+
25
+ ### Responsibility and License
26
+
27
+ - This project is released under the **MIT License**, with no warranties beyond those provided by the license.
28
+ - AI tools are not authors, copyright holders, or responsible parties for this project; the human maintainer accepts maintenance responsibility as the project publisher.
29
+ - This document describes the development process only and does not constitute legal advice.
package/CHANGELOG.md ADDED
@@ -0,0 +1,82 @@
1
+ # Changelog
2
+
3
+ ## 0.4.1 — 2026-11-04
4
+
5
+ - 修复审批通知漏发:`approval/request` 是 waterfall,UI 审批应答器可能先处理并短路;观察者改为 `prepend + global`,发布事件后始终 `next()` 委托,不改变审批结果。
6
+ - 补充 host probe 对审批观察者顺序和委托行为的回归检查。
7
+
8
+ ## 0.4.0 — 2026-11-01
9
+
10
+ - 新增 Windows 任务栏未读角标:DSH 在后台且有完成结果时,在 DSH 任务栏图标上显示未读根会话数;设置页可关闭。
11
+ - 计数采用方案 B:不同根会话各算 1 个,同一会话完成多次只算 1 个;合并完成事件携带 `sessionIds`,避免多会话被合并后少计。
12
+ - 角标显示上限为 3:1–3 显示深灰底、白字、蓝色细环的数字角标,超过 3 显示红色圆点;数字使用 Segoe UI Black 20,并按实际字形路径几何居中(GraphicsPath),增大占幅;回到 DSH(窗口聚焦/点击任务栏)后清除。
13
+ - Host 新增 `taskbar-badge` RPC 与任务栏 helper(`ITaskbarList3::SetOverlayIcon`);优先使用首次编译缓存的小型独立 C# EXE(实测热路径约 55–85 ms、约 14 MB 瞬时内存),PowerShell 保留为回退;不增加常驻后台进程,不联网。任务栏 helper 缓存只保留最近 8 个。
14
+ - 配置新增 `taskbarBadgeEnabled`(默认开启);测试补充 badge 计数/聚焦清除,合并测试覆盖 `sessionIds`。
15
+
16
+ ## 0.3.0 — 2026-10-20
17
+
18
+ - 原生进度条底部只保留一条 bar + 单个静态「自动关闭」说明,不再显示百分比、剩余秒数或重复标签;声音改为 native helper 提交成功后再播放,改善弹窗与提示音同步;移除 toast 的 `dsh://open` 协议启动,避免点击通知另起 DSH 实例。
19
+ - Goal 模式汇总:goal active+armed 期间不逐轮发完成通知;在 complete/paused/blocked/round-limit/disarmed 后按 `roundsStarted` 增量只发一条汇总;新增默认开启的“目标模式结束后汇总”设置;完成用进度标题,暂停/受阻用中性标题;提问/授权仍即时提醒。
20
+ - 新增 AI 参与说明(`AI-DISCLOSURE.md` 与 README 双语声明):说明大部分代码由 AI 编程助手生成,人类维护者负责需求、调试、测试、验收和发布。
21
+ - 提示音新增可选「弹一下」:来自 uisfx 0.4.0 的 CC0 音频(rubber/notification),内嵌到 Client,无需联网或新增依赖;默认仍是「叮咚」;源文件与许可见 `THIRD_PARTY_NOTICES.md`。
22
+ - 标题改为自动场景文案:单步「DeepSeek 搞定了一小步」、2–4 步「DeepSeek 一口气推进了 N 步」、≥5 步「DeepSeek 火力全开,连推了 N 步」、提问「DeepSeek 想问你一个问题」、授权「DeepSeek 需要你的授权」、全部根会话完成「所有任务均已完成」;删除自定义完成标题输入。
23
+ - 删除 DSH 内应用内倒计时卡片及相关设置;改为 Windows 原生通知:Host 通过 PowerShell/C#/WinRT helper 显示真实 Windows toast,带动态 `<progress>` 进度条;到期停止更新,短暂缓冲后 `Hide()` 收回横幅(`ExpirationTime` 继续约束通知中心保留),时间只作近似;helper 不可用时自动回退 Web Notification。
24
+ - Host 新增 `native-notify` RPC、loopback 激活回调 server、`activate` 事件;点击原生通知尽量回到对应会话;回调失败时不承诺 session 定位。
25
+ - 新增 native helper 编译缓存(`%LOCALAPPDATA%\\dsh-notify-toast\\native-cache`)与版本 0.3.0;启动预热减少首条通知延迟;同 kind 通知改用唯一 tag,旧 helper 允许自然退出;移除旧 in-app overlay/`native-and-inapp` 主路径死代码,同时保留旧配置到 `native-progress` 的迁移;测试更新为 94 项单测 + 25 项 client smoke。
26
+
27
+ ## 0.2.0 — 2026-10-19
28
+
29
+ - 完成通知标题改为中性文案「DSH 有新的回复」/「DSH has a new reply」,不再对每轮回复声称「完成了一项任务」;多轮合并时显示「DSH 有 N 轮新回复」。新增可配置的「本轮回复通知标题」(留空使用默认文案),并保留「全部完成后改写标题」的独立语义。
30
+ - 新增可选「系统通知 + 应用内卡片」显示方式:应用内卡片支持 3–60 秒可调显示时长、底部倒计时进度条(默认开)、悬停/键盘暂停(默认开)、多条堆叠与手动关闭;设置页提供预览按钮。
31
+ - 明确能力边界:Windows 原生 toast 的显示时长由系统控制,插件不能自定义任意时长或内嵌进度条;这些设置仅作用于应用内卡片。
32
+ - 测试:新增完成标题/配置字段与应用内卡片测试;`npm test` 74/74、client smoke 24/24 通过。
33
+ - 审核修复:应用内卡片点击不再误删原生通知记录;页面隐藏/恢复时显式暂停计时;标题输入保留末尾空格;卡片支持 Enter/Space;旧 Host(<0.2.0)隐藏新设置并提示重启。
34
+
35
+ ## 0.1.1 — 2026-10-19
36
+
37
+ - 设置导航新增铃铛图标:宿主 `settings.section` 不投影 icon 字段,客户端像插件市场一样按本地化 label 认领自己的导航行,隐藏宿主齿轮并用 CSS mask 画 16px 单色铃铛;locale 切换重新认领,`ctx.effect` 卸载时清理标记与样式。
38
+ - 新增 `test/nav-icon.test.mjs`(5 项):`node --test test/*.test.mjs` 现为 **73/73**;client smoke **23/23**;Host 半未改,host probe 未重跑。
39
+ - 2026-10-19 本人重启桌面验收:设置导航行显示铃铛,确认合格。
40
+
41
+ ## 未发布(0.1.0 发布前修正)
42
+
43
+ - 新增可选「全部完成后改写标题」:多个根会话同时运行、全部成功结束后,把最后结束的会话标题改为可配置文案(默认「所有任务均已完成」);只有一个会话运行时不生效。
44
+ - 安全:RPC 回退路由在 Connection 缺少 `requestRejection` 时改为 fail-closed(403),并补回归测试(当前总计 68/68)。
45
+ - 文档:对齐「toast 不主动自动关闭」、4 种提示音、`host-probe` / `probe-rpc` 命令说明;移除作者本机绝对路径。
46
+ - 开源准备:新增 `.gitignore`、`.editorconfig`;`package.json` 补 `author` 与 `engines.node`;`host-probe` 支持参数 / `DSH_PROFILE_DIR` / `DSH_HOME`。
47
+ - 文案:设置页「系统通知」提示改为如实描述仅走 Windows toast;客户端死代码(应用内兜底卡片)保留并注明未启用。
48
+
49
+ ### 开源仓库准备(0.1.0 发布前)
50
+
51
+ - `package.json` 补 `repository` / `homepage` / `bugs` / `publishConfig.access=public`;版本保持 `0.1.0`;`files` 白名单、`engines.dsh` 与 `engines.node >= 20` 保持不变。
52
+ - `dsh-plugin.json` 公共 id 从个人命名空间改为中性 `dsh.notify-toast`;版本与 `package.json` 同步;仅保留 Host facet(Web Client 半由 `package.json` 的 `dsh.client` 声明)。
53
+ - 新增 `README.en.md`、`CONTRIBUTING.md`、`SECURITY.md`、`CODE_OF_CONDUCT.md`、GitHub Issue/PR 模板、GitHub Actions CI(Windows/Ubuntu × Node 22/24)与 `docs/RELEASING.md` 发布手册。
54
+ - README 增加 npm/license/DSH/Windows/CI 徽章、截图待补说明、安装/配置/兼容性/隐私/已知限制/故障排查入口、MIT 归属与非官方声明(Not affiliated with DeepSeek)。
55
+ - `.gitignore` 增加 `release/`、`.npmrc` 等;移除过期 `release/` 目录与 tgz 构建产物;清除文档中的本机绝对路径。
56
+
57
+ ## 0.1.0 — 2026-10-18
58
+
59
+ - 首个版本:Host 侧监听 `approval/request`、`user-questions/request`、根会话 `turn/end(completed)`,
60
+ 通过同源长轮询把需要处理的事件推给 Web 客户端。
61
+ - Windows 原生 toast(`silent: true`),仅在窗口未聚焦时展示;点击通知经 Host `koffi` user32 置前窗口并定位会话。
62
+ - 正文只截取已有日志内容(提问原文 / 工具名+目的 / 最后回复首段),Markdown/代码块清洗,默认 40 字、20–60 可配。
63
+ - 完成通知按可配置间隔合并(默认 2500 ms),子代理完成不触发。
64
+ - Web Audio 合成 4 种轻提示音(叮咚/风铃/清铃/轻点),默认「叮咚」;音量 0–100,可关闭、可在设置页「试听」;
65
+ 首次用户手势解锁,且通知到达时即使 AudioContext 仍挂起也会先排程、再 resume,不再因 resume 被拒而静默丢音。
66
+ 设置页新增「提示音引擎」状态行(已就绪/待解锁/未初始化),便于诊断无声问题。
67
+ - 设置页(`settings.section`):启用/提问/授权/完成开关、正文长度、隐私模式、提示音、音量、合并间隔、测试通知;
68
+ 配置经官方 `ctx.settings`(volatile Config)持久化,即时生效。
69
+ - 原生 toast 可诊断:设置页新增「系统通知」计数(尝试/创建/显示/失败 + 最近错误)、「测试系统通知」按钮与权限提示;
70
+ 修复「测试系统通知」误传 3 个参数导致的 `NotificationOptions` TypeError(正常通知路径不受影响)。
71
+ 原生 toast 不主动自动关闭(Windows 横幅收起后条目保留在通知中心,稍后点击仍有效);构造前对 `permission==='default'` 再请求一次权限。
72
+ 通知坚持使用 Windows 原生 toast(系统右下角),不做应用内弹框。
73
+ - 点击回窗修复(含窗口最小化):原实现按父进程 PID 取第一个可见顶层窗口,Electron 主进程同时拥有
74
+ `DDE Server Window` / `MSCTFIME UI` / `Default IME` 等同 PID 窗口,可能把 `ShowWindow/SetForegroundWindow`
75
+ 作用在错误窗口上。现按窗口类 `Chrome_WidgetWin*` + 标题「DeepSeek Harness」打分并逐个候选尝试
76
+ `ShowWindow(SW_RESTORE)` + `SetForegroundWindow`,每次验证前台窗口;toast 不再主动 `close()`(保留在通知中心可点);
77
+ 点击后 focus RPC 失败自动重试 3 次。设置页「系统通知」新增 `点击 / 置前成功 / 置前失败` 计数与最近错误。
78
+ - 降级:通知权限拒绝、Host 路由不可用、`settings` 缺失、koffi 加载失败均不崩溃并在设置页显示状态。
79
+ - 兼容修复:DSH 0.2.1-rc.2 的官方 `connection.rpc.handle` 在该版本内部抛 `cannot get property "webServer" without inject`;
80
+ 插件自动回退为同路径 `webServer` 前缀路由,并复用官方 `connection.requestRejection` 同源/认证栅栏与一元 RPC 信封。
81
+ - 兼容修复:Desktop Host 进程可能没有 `DSH_PROFILE_DIR`;schemastery 解析新增 Host cwd(= profile 目录)、
82
+ `DSH_HOME`/常见 home 布局与 DSH 安装包内副本等多级回退,设置页显示 `configSource`。
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dsh-notify-toast contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.en.md ADDED
@@ -0,0 +1,275 @@
1
+ # Lightweight Native Notifications (Windows)
2
+
3
+ **Lightweight · Native · Extensible · Quiet**
4
+
5
+ English | [中文](./README.md)
6
+
7
+ [![CI](https://github.com/game25011/dsh-notify-toast/actions/workflows/ci.yml/badge.svg)](https://github.com/game25011/dsh-notify-toast/actions/workflows/ci.yml) ![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg) ![DSH](https://img.shields.io/badge/DSH-0.2.1--rc.2-blue) ![Platform: Windows 10/11](https://img.shields.io/badge/platform-Windows%2010%2F11-0078D4)
8
+
9
+ > An unofficial, MIT-licensed Windows 10/11 plugin for DSH that provides native Windows background toast notifications without disturbing focus, featuring an unread taskbar badge that counts distinct root sessions (counting multiple completions in the same session as one, showing numbers 1–3 and a red dot for over 3). Major code was generated by an AI coding assistant, with the human maintainer responsible for requirements, debugging, testing, and release.
10
+
11
+ - Source/local package: `dsh-notify-toast` · Version: `0.4.1` · License: MIT
12
+ - npm status: **not published**. Do not run `npm install dsh-notify-toast`; that npm name belongs to a different project.
13
+ - Chinese display name: 桌面通知(Windows 原生 toast); the npm package name, directory, and row id stay ASCII `dsh-notify-toast` (a documented naming exception).
14
+ - Works with: DeepSeek Harness Desktop `0.2.1-rc.2` (Electron shell, `desktop` profile), Windows 10/11
15
+ - Form factor: official DSH bundle (Host + Web Client), installed and removed through the official plugin manager
16
+ - Status: 0.4.1 fixes missed approval notifications. 0.4.0 adds a taskbar unread badge (scheme B: distinct root sessions); 0.3.0 native progress toast, automatic banner retraction, click-to-session, bar-only styling and a simple goal aggregation run were verified on a real device; goal edge cases remain to be re-tested; optional "rewrite the title when all tasks are done" remains available (default off)
17
+
18
+ ![Windows native progress toast](docs/assets/native-toast.png)
19
+
20
+ ## 0.4.1 update
21
+
22
+ Fixes missed approval notifications: DSH's `approval/request` is a waterfall and the UI approval answerer may claim and short-circuit it. The plugin observer now uses `prepend + global`, publishes the notification, and always delegates with `next()`; it never changes the approval outcome.
23
+
24
+ ## Maintenance direction
25
+
26
+ The goal is a **lightweight, native, extensible and quiet** Windows notification layer, maintained for the long term.
27
+
28
+ - **Lightweight**: no resident tray or background service; helpers start only when needed.
29
+ - **Native**: uses Windows native toast and taskbar overlay APIs.
30
+ - **Extensible**: MIT-licensed, with separated Host/Client/native helper layers and an open `docs/INTERFACE.md`. Users can tune settings, fork the project, or add notification kinds, sounds and routes through the interfaces. There is no in-app scripting or third-party runtime extension API yet; deep customization requires code changes.
31
+ - **Continuously maintained**: compatibility, installation reliability and real feedback come first; no feature-count race.
32
+
33
+ ## AI-assisted development
34
+
35
+ Most of this project’s code — Host, Web Client, PowerShell/C# native helpers, and most tests/docs — was generated by AI coding assistants; the human maintainer is responsible for requirements, debugging, testing, releases, and maintenance. AI-generated content may be wrong, and issues and pull requests are welcome. This project is licensed under the MIT License; AI tools are not authors, copyright holders, or responsible parties, and this disclosure is not legal advice. See [AI-DISCLOSURE.md](AI-DISCLOSURE.md).
36
+
37
+ ---
38
+
39
+ ## Features
40
+
41
+ | Capability | Behavior |
42
+ |---|---|
43
+ | Needs an answer / confirmation | Triggered by `user-questions/request`; title "DeepSeek has a question for you"; body is the first N characters of the question itself. |
44
+ | Needs approval | Triggered by `approval/request`; title "DeepSeek needs your approval"; body is "tool name · short purpose". |
45
+ | Reply finished | Triggered by `turn/end(completed)` from `session/event`; root sessions only, subagent completions never notify; one step: "DeepSeek finished a step"; 2–4 steps: "DeepSeek pushed N steps in one go"; 5+ steps: "DeepSeek went all out and pushed N steps"; body is the first valid paragraph of the last assistant reply, falling back to "Click to view". |
46
+ | Goal mode summary | While a goal is `active` and `armed`, per-round completions are suppressed. One summary is sent after `complete`, `paused`, `blocked`, the round limit, or `disarmed`, counting the Goal Round delta; paused/blocked use neutral titles. Questions/approvals still notify immediately. |
47
+ | Notify only when unfocused | Re-evaluates `document.hasFocus()` / `visibilityState` when an event arrives; no toast and no sound while focused. |
48
+ | Windows native progress toast | The Host uses a PowerShell/C#/WinRT helper to create a real Windows notification with a dynamic `<progress>` bar; it updates while the notification is displayed, stops at the approximate deadline, then hides the banner after a short grace; notification-center retention is still bounded by ExpirationTime. No custom in-app window. |
49
+ | Compatibility fallback | If the native helper cannot start or show, the plugin falls back to the Web Notification path; both are silent and the plugin plays the sound once. |
50
+ | Body length | Default 40 characters (Unicode code points), configurable 20–60; longer text is truncated with "…". |
51
+ | Privacy mode | Title only; body left empty. |
52
+ | Notification sounds | Four Web Audio–synthesized presets (Ding-dong / Chime / Bell / Soft tap) plus one CC0 open-source "Bubble" asset, volume 0–100, can be turned off and previewed; unlocked after the first user gesture; silent fallback on failure. |
53
+ | Click to return | The Host first raises the DSH window with Windows `SetForegroundWindow`, then the client opens the matching session when possible; falls back to `window.focus()` when koffi is unavailable. |
54
+ | Merging | Multiple "completion" events within 2.5 s (configurable) are merged into one toast to avoid notification bursts. |
55
+ | Taskbar unread badge | While DSH is in the background, show the number of distinct root sessions with finished work on the DSH taskbar icon (scheme B); repeated completions in one session count once. Show 1–3 as a graphite numeral with a thin blue rim, and a red dot above 3; the badge clears when DSH is focused. Can be disabled in Settings. |
56
+ | Automatic reply titles | Single step: "DeepSeek finished a step"; 2–4 steps: "DeepSeek pushed N steps in one go"; 5+ steps: "DeepSeek went all out and pushed N steps"; all-done: "All tasks are done". No custom title input. |
57
+ | Rewrite title when all tasks are done | Optional (default off): when several sessions run at the same time and all of them finish successfully, the session that finished last is renamed to the configured text; does nothing when only one session is running. |
58
+ | Settings page | DSH Settings → Notifications: enable/question/approval/reply-finished/taskbar-unread-badge/goal-summary switches, notification display mode (native progress / compatibility), auto-remove delay, body length, privacy mode, sound (with preview), volume, merge interval, test notification/test system toast, and diagnostics. |
59
+ | Persistence | Official `ctx.settings` (volatile Config fields → profile patch); survives a DSH restart; no plugin-owned config file. |
60
+ | Degradation | Notification permission denied / unsupported environment / Host unavailable / `settings` missing / koffi load failure: no crash, and the settings page shows the status. |
61
+
62
+ ### What this plugin does not do
63
+
64
+ Persistent tray/background services, taskbar progress bars, taskbar flashing animations; the taskbar badge is updated by a one-shot cached C# EXE (PowerShell fallback) and does not add a resident process. The toast helper likewise only runs for the lifetime of a notification. No external network access, changes to DSH core, telemetry, or model calls.
65
+
66
+ ---
67
+
68
+ ## Installation
69
+
70
+ > Install this plugin through the **official plugin manager** or the GitHub Release. Do not edit the profile's `package.json` or `cordis.patch.yml` by hand.
71
+ >
72
+ > npm status: **not published**. Do not use `npm install dsh-notify-toast`; the npm name belongs to a different project.
73
+
74
+ > Manifest note: `dsh-plugin.json` declares only the Host facet (`facets.host`); the Web Client half is declared by `dsh.client` in `package.json` (other third-party plugins use the same structure), so no `facets.client` is declared. Official DSH 0.2.1-rc.2 plugin loading is driven by `dsh.bundle` / `dsh.client` in `package.json`.
75
+
76
+ ### Option A: In-app plugin manager (recommended)
77
+
78
+ 1. Put the delivered `dsh-notify-toast-0.4.1.tgz` anywhere on the local machine (avoid spaces in the path).
79
+ 2. Install it with the official plugin manager, either through the Agent or through the plugin management UI:
80
+ - Agent tool: `plugin_manager` → `action: install_bundle`, `target: <absolute path to the tgz>`
81
+ - CLI: only for self-managed profiles (web/headless). The official Desktop `desktop` profile is managed by the Electron application's plugin manager; use the UI or Agent method above.
82
+ 3. After installation, confirm that `dsh-notify-toast` is enabled in Settings → Plugins.
83
+ - **Restart DSH once after the first install/upgrade**: the official plugin manager can hot-insert the Host row, but already-loaded Host JavaScript modules only switch to the new code after a restart (client bundles hot-reload). The plugin never restarts the application itself.
84
+ 4. Open Settings → Notifications and click "Send test notification". The "Runtime" block shows the Host connection, transport, settings persistence, and recent reminder counters.
85
+
86
+ ### Option B: Development directory install (link)
87
+
88
+ ```text
89
+ plugin_manager → install_bundle → target: <absolute path to the plugin directory>
90
+ ```
91
+
92
+ Installing from a local directory creates a link, so DSH's HMR can pick up code changes; Host-side JavaScript changes may still require a restart if they are not hot-updated.
93
+
94
+ ### Option C: Plugin market index
95
+
96
+ This repository ships `market-index.json`. Add this custom index in the DSH plugin market/discovery page:
97
+
98
+ ```text
99
+ https://raw.githubusercontent.com/game25011/dsh-notify-toast/4a3c83e5634cf9dcac005ec2e9bbd4c4dd828596/market-index.json
100
+ ```
101
+
102
+ Then search for `dsh-notify-toast` and install the pinned Git version.
103
+ This is a **self-hosted index**; the default DSH market does not automatically list this plugin, so other users must add the same index or the official catalog must include it.
104
+
105
+ ### Upgrade
106
+
107
+ - New tgz: run `install_bundle` again (the application prompts for a restart to load the new JS modules).
108
+ - Development directory: update the code in place; restart DSH when necessary.
109
+
110
+ ### Uninstall
111
+
112
+ - In the application: disable/remove `dsh-notify-toast` in the plugin management UI.
113
+ - Agent tool: `plugin_manager` → `action: remove_bundle`, `target: dsh-notify-toast`.
114
+ - After removal: Host routes/event listeners/timers are released with the plugin fiber, the client bundle stops loading, and the settings-page entry disappears. Configuration entries already written to the profile patch no longer take effect (no background process or temporary files are left behind).
115
+
116
+ ---
117
+
118
+ ## Configuration
119
+
120
+ Location: **Settings → Notifications** (`settings.section`, id `dsh-notify-toast`).
121
+
122
+ | Setting | Range / options | Default | Notes |
123
+ |---|---|---|---|
124
+ | Notifications enabled | On/Off | On | Master switch; when off, nothing pops and nothing plays (except test notifications). |
125
+ | Questions & plan confirmation | On/Off | On | `user-questions/request` |
126
+ | Approvals | On/Off | On | `approval/request` |
127
+ | Reply finished | On/Off | On | One root-session reply; subagent completions never notify. |
128
+ | Taskbar unread badge | On/Off | On | While DSH is in the background, show distinct root sessions with finished work; repeated completions in one session count once. Show 1–3 as a graphite numeral with a thin blue rim, and a red dot above 3; clears when DSH is focused; Windows only. |
129
+ | Summarize when a goal run ends | On/Off | On | Suppresses per-round goal completions; sends one summary after completion, pause, block, round limit, or disarm. Questions/approvals still notify immediately. |
130
+ | Body length | 20–60 characters | 40 | Truncated by Unicode code point with "…" when longer. |
131
+ | Privacy mode (title only) | On/Off | Off | The body is left empty. |
132
+ | Sound | Ding-dong / Chime / Bell / Soft / Bubble (open-source) / Off | Ding-dong | The first four are synthesized with Web Audio; Bubble is an embedded uisfx CC0 audio asset with no network request. A Preview button is available in the settings page. |
133
+ | Volume | 0–100 | 60 | 0 is effectively muted. |
134
+ | Merge interval | 0–10000 ms | 2500 | Completions within this window are merged into one toast. |
135
+ | Rename the last session when all finish | On/Off | Off | Optional rewrite-title behavior: takes effect only when at least two root sessions run concurrently and all finish successfully; a single running session does not trigger it. |
136
+ | Title text | 1–96 bytes | 所有任务均已完成 (All tasks completed) | The session that finishes last is renamed to this text when the all-done feature is on. |
137
+ | Notification display | Native progress / Compatibility | Native progress | Native mode shows a Windows notification with a progress bar; falls back to Compatibility when the helper is unavailable. |
138
+ | Auto-remove delay (approx.) | 3–30 seconds | 8 s | Controls when progress updates stop and the notification-center retention window; Windows controls the actual exit, so it may be earlier or later. |
139
+
140
+ All changes take effect immediately. Persistence uses the official DSH settings (volatile Config → profile patch layer), so settings survive a restart.
141
+
142
+ ---
143
+
144
+ ## How it works
145
+
146
+ ```text
147
+ Host (lib/index.js) Client (lib/client.js)
148
+ ──────────────────────────────────────────── ────────────────────────────────────────────
149
+ approval/request ──────────────┐ settings.section page (React, plain HTML)
150
+ user-questions/request ────────┼─ clean/truncate ──┐ ├─ focus check (hasFocus + visibilityState)
151
+ session/event turn/end ────────┘ │ ├─ native toast RPC / Web Notification fallback + click to return
152
+ ▼ ├─ Web Audio synthesized sound + embedded CC0 Bubble asset
153
+ event ring buffer + long polling ┘
154
+ Host browser route /dsh-notify-toast (official RPC envelope + same-origin fence)
155
+ config / save / poll / health / test / focus / taskbar-badge
156
+ Host: native-toast.ps1 → WinRT Toast; taskbar-badge EXE → ITaskbarList3
157
+ Host: ctx.settings (volatile Config) ← save
158
+ Host: koffi user32 SetForegroundWindow ← focus
159
+ ```
160
+
161
+ - **Host detection**: listens directly to authoritative DSH events (approvals, questions, `turn/end`), reads the session log to extract the body, never calls a model, and never accesses the network.
162
+ - **Transport**: long polling under the `/dsh-notify-toast` prefix. It prefers the official `connection.rpc.handle`; on DSH 0.2.1-rc.2 that API has a bug (it reads `webServer` internally and throws `cannot get property "webServer" without inject`), so the plugin automatically falls back to a same-path `webServer` route and calls the official `connection.requestRejection` at the entry point to reuse the Host/Origin same-origin fence and browser signed-cookie authentication. Requests and responses use the official unary RPC envelope, so the client's `connection.rpc.call` code is unchanged. Settings → Host connection/transport shows the active path.
163
+ - **The client only presents**: focus is evaluated only when an event arrives; if the window is focused, the event is dropped (no toast, no sound).
164
+ - **Root-session check**: `SessionHeader.parentSession === undefined && origin !== 'subagent'`.
165
+ - **Body extraction**:
166
+ - Question: the original `request.questions[0].question`.
167
+ - Approval: the tool name plus a short purpose from `displayReason`/`reason`.
168
+ - Completion: walk back from the `turn/end` event to the nearest `assistant/message`, take its text blocks, strip Markdown/code fences/inline code/links/heading markers, collapse whitespace, and take the first paragraph; if there is no usable text → "Click to view".
169
+ - **Click to return**: the client posts (RPC) `focus` → the Host uses DSH's bundled koffi (`resources/app.asar.unpacked/.../koffi.node`) to call user32 `ShowWindow/SetForegroundWindow/AttachThreadInput` and raise the Electron main window; the client then calls `window.focus()` and opens the matching session.
170
+ - **Configuration persistence**: every `Config` field is `.volatile()`; the Host resolves `@deepseek-ai/schemastery` from the profile (preferring `DSH_PROFILE_DIR`, then the Host process cwd, i.e. the profile directory, then the copy inside the DSH installation) and reads/writes the current profile patch through `ctx.settings.describe()/update()`. Settings → settings persistence/configSource shows the status.
171
+
172
+ ### Implementation and resource footprint
173
+
174
+ - **Host** runs inside the DSH process and only listens to events, keeps a 200-entry in-memory ring buffer, long-polls, and uses settings; there is no extra resident process when idle.
175
+ - The **client** is a ~159 KB web bundle; when idle it holds one 25-second long poll plus a 5-second localStorage leader heartbeat.
176
+ - **Windows toast** is created by a one-shot PowerShell/C# helper through WinRT. One toast uses one helper that exits with the toast; at most eight are active.
177
+ - The **taskbar badge** prefers a cached standalone C# EXE compiled on first use. It calls \`ITaskbarList3::SetOverlayIcon\` directly; the warm path measured about 55–85 ms and ~14 MB transient memory. The first use compiles the EXE; the PowerShell helper remains the fallback.
178
+ - **Cache** lives in \`%LOCALAPPDATA%\\dsh-notify-toast\\native-cache\`; taskbar-helper caches retain only the eight most recent entries so old hash files do not grow without bound.
179
+ - No external network access, no model calls, no collection; the click callback is loopback-only.
180
+
181
+ ### Privacy
182
+
183
+ - No external network access; only a local loopback activation callback. No reporting, no collection, no model calls; toast bodies come only from content already present in the local session log.
184
+ - No plugin-owned config files; configuration is persisted by the official DSH settings into the profile patch.
185
+ - Notification content may contain reply excerpts: enable "Privacy mode (title only)" if you mind.
186
+
187
+ ---
188
+
189
+ ## Compatibility
190
+
191
+ | Item | Notes |
192
+ |---|---|
193
+ | DSH | `0.2.1-rc.2` (`engines.dsh: >=0.2.1-rc.2 <0.3.0`); the Host event/RPC/settings contracts this plugin relies on were tested on this version. |
194
+ | Operating system | Windows 10/11 (native toast + koffi user32 window focus); macOS/Linux untested (the plugin targets Windows). |
195
+ | Runtime form | DSH Desktop (Electron, page origin `dsh-app://app`). Under a regular browser Web profile toasts still work, but "raise the Windows window" degrades to focusing the browser itself. |
196
+ | Notification permission | The Windows notification center must allow notifications for the application; Electron Desktop grants non-media permissions by default. If disabled by the OS or group policy, the plugin degrades without crashing. |
197
+ | Focus assist | Windows Focus Assist / Do Not Disturb may suppress toasts silently (OS behavior; the plugin cannot bypass it). |
198
+
199
+ ---
200
+
201
+ ## Known limitations
202
+
203
+ 1. The page must stay open (minimizing the DSH window is fine, but the page process must not exit); if the browser is closed, there are no notifications.
204
+ 2. If notification permission is denied or the system does not support Web Notification: the settings page shows the status and native toasts are unavailable (sound and click-to-return still work); no crash.
205
+ 3. If Windows notification banners are turned off or Focus Assist is on, native toasts may go only to the notification center without a banner; the "System toast" counters and "Test system toast" in the settings page help confirm this — allow notifications for the application in Windows Settings and turn off Focus Assist.
206
+ 4. The first sound needs one user gesture on the page (Chromium autoplay policy); before it is unlocked, sound is silent while notifications still appear.
207
+ 5. Raising the window on click depends on the koffi native module bundled with DSH; if the module path changes or loading fails, the plugin falls back to `window.focus()`, which may not raise the window but still opens the session.
208
+ 6. With multiple windows/tabs, a localStorage lease (5 s heartbeat, 15 s expiry) lets only one window show toasts/play sound; under extreme lease contention, brief duplicate notifications are possible.
209
+ 7. Subagent completions never notify; questions/approvals from subagents still notify (they block tasks just the same).
210
+ 8. The "completion" body takes the first paragraph of the last assistant reply; if the reply only contains code/tool calls, the body falls back to "Click to view".
211
+ 9. Merging applies only to completions; questions/approvals are never merged (you need to handle them promptly).
212
+ 10. Windows controls the native toast exit animation and banner lifetime; the approximate auto-remove delay stops progress updates and bounds notification-center retention, not an exact banner duration. After a short grace the helper calls `Hide()` to retract the banner; the visual transition still belongs to Windows.
213
+ 11. Click-to-session on a native progress toast depends on the local activation callback; if the callback fails, the toast may only close without opening the session. The toast no longer uses the `dsh://open` protocol launch, avoiding a second DSH instance/session.
214
+ 12. The native helper writes a small C# DLL cache under `%LOCALAPPDATA%\dsh-notify-toast\native-cache` on first use; if compilation or PowerShell/WinRT is unavailable, the compatibility path is used.
215
+ 13. The plugin does not modify DSH core; if a DSH upgrade changes the event/RPC/settings contracts above, the plugin may need a matching update.
216
+ 14. The official `connection.rpc.handle` in DSH 0.2.1-rc.2 has a bug (`cannot get property "webServer" without inject`); the plugin already falls back to the same-path route plus the official `connection.requestRejection` fence. This does not change client behavior, but once DSH fixes that API the plugin will prefer the official channel.
217
+
218
+ ---
219
+
220
+ ## Troubleshooting
221
+
222
+ | Symptom | What to check |
223
+ |---|---|
224
+ | No toast at all | Settings → Notifications: check the "Notification permission / Host connection / System toast" status; click "Test system toast". If it reports "created" but no banner appears, open Windows Settings → System → Notifications, enable banners and turn off Focus Assist; also check whether the notification is in the notification center (Win+N). |
225
+ | Sound but no popup | Same as above; also make sure the application's notifications are not set to "notification center only". |
226
+ | No toast while focused | By design (no interruptions while focused); switch focus to another application or use "Send test notification" to verify. |
227
+ | Toast but no sound | Settings → Notifications → "Preview"; check whether "Sound engine" says "ready" (click the page first if it says "locked"); check the application's volume/mute in the Windows Volume Mixer and the system output device; check whether volume is 0 or sound is off. |
228
+ | Clicking the notification does not return to DSH | Check whether "Window activation" is available in the settings page; when unavailable, the plugin is in degraded mode. |
229
+ | Settings lost after restart | Check whether "Settings persistence" says "official settings"; if it shows a degraded state, `ctx.settings` is unavailable (the plugin still works with defaults). |
230
+ | No entry in the plugin list | Confirm with the official plugin manager that the bundle is installed and enabled; restart DSH if necessary. |
231
+
232
+ ---
233
+
234
+ ## Development and testing
235
+
236
+ ```text
237
+ Command Description
238
+ npm test Unit tests for text cleanup/truncation, config, merging, titles, goal aggregation and native lifecycle (94 tests)
239
+ npm run smoke Smoke test that simulates __ModuleLoader__ loading client.js (25 tests)
240
+ npm run probe RPC probe: --self-check runs pure-function checks (7 checks); --url probes the host RPC route (expects 401/403 without a cookie)
241
+ node scripts/host-probe.mjs <profileDir> Host integration probe (real profile cwd)
242
+ npm pack Build the delivery tgz
243
+ ```
244
+
245
+ - Source layout:
246
+ - [`lib/index.js`](lib/index.js) — Host half (events, browser route, settings, merging, cleanup)
247
+ - [`lib/text.js`](lib/text.js) — pure text cleanup/truncation helpers (unit-tested)
248
+ - [`lib/config.js`](lib/config.js) — defaults/validation/merge/volatile Config schema
249
+ - [`lib/native-focus.js`](lib/native-focus.js) — koffi user32 window focus
250
+ - [`lib/client.js`](lib/client.js) — Web client half (focus, toasts, sound, settings page, long polling)
251
+ - [`locale/zh.json`](locale/zh.json), [`locale/en.json`](locale/en.json) — plugin marketplace/settings-page display metadata
252
+ - [`scripts/client-smoke.mjs`](scripts/client-smoke.mjs), [`scripts/probe-rpc.mjs`](scripts/probe-rpc.mjs) — smoke tests/probes
253
+ - [`dsh-plugin.json`](dsh-plugin.json) — plugin manifest (Host facet, public id `dsh.notify-toast`); the Web Client half is declared by `dsh.client` in `package.json`; `cordis.patch.yml` is the bundle patch
254
+ - [`docs/PLAN.md`](docs/PLAN.md) — historical 0.1 plan, not shipped in the npm package; [`docs/INTERFACE.md`](docs/INTERFACE.md) — Host/Client contract; [`docs/TEST-REPORT.md`](docs/TEST-REPORT.md) — acceptance record; [`docs/RELEASING.md`](docs/RELEASING.md) — release manual
255
+
256
+ Project repository: https://github.com/game25011/dsh-notify-toast. See [CONTRIBUTING.md](CONTRIBUTING.md) for the development workflow, [SECURITY.md](SECURITY.md) for private vulnerability reporting, and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for community expectations.
257
+
258
+ ---
259
+
260
+ ## Acknowledgements
261
+
262
+ Implementation ideas were informed by the following MIT-licensed open-source plugins (the code is original; no whole sections were copied):
263
+
264
+ - [chromoany/dsh-notify-me](https://github.com/chromoany/dsh-notify-me) — focus detection, notification degradation, settings page, multi-window leader
265
+ - [BillCx330/dsh-plugin-notify-sounds](https://github.com/BillCx330/dsh-plugin-notify-sounds) — koffi user32 window focus, Connection route fence
266
+ - [Laplace-bit/dsh-bell-notify](https://github.com/Laplace-bit/dsh-bell-notify) — Web Audio synthesized sounds
267
+ - [uisfx](https://github.com/romainsimon/uisfx) — CC0 source of the Bubble sound; see [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)
268
+
269
+ ## License
270
+
271
+ MIT, see [LICENSE](./LICENSE).
272
+
273
+ ## Disclaimer
274
+
275
+ This is an unofficial community plugin for DeepSeek Harness. It is not affiliated with, endorsed by, or sponsored by DeepSeek. **Not affiliated with DeepSeek.** DeepSeek, DeepSeek Harness, and other marks are trademarks of their respective owners.