dsh-turn-ding 0.1.0 → 0.1.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.
Files changed (4) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +74 -105
  3. package/index.json +7 -3
  4. package/package.json +7 -2
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Arron
3
+ Copyright (c) 2026 Arron Gao
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,96 +1,76 @@
1
1
  # dsh-turn-ding
2
2
 
3
- DSH 的「会话跑完了」提醒插件:**Windows 任务栏图标右上角显示未读数字徽标 + 可选提示音**,效果等同于 Codex 的完成提醒。
3
+ > 会话跑完时,在 Windows 任务栏的 DSH 图标上显示未读数字徽标,并播放一声提示音。
4
4
 
5
- > 结论先行:DSH 目前(0.2.1-alpha.2 / 桌面版 0.2.2-rc.1)**没有**这个功能。主进程不暴露任何 badge/托盘计数 IPC,官方插件目录里也没有相关插件。本插件补上这个缺口。
5
+ [![npm version](https://img.shields.io/npm/v/dsh-turn-ding.svg)](https://www.npmjs.com/package/dsh-turn-ding)
6
+ [![license](https://img.shields.io/npm/l/dsh-turn-ding.svg)](./LICENSE)
7
+ [![platform](https://img.shields.io/badge/platform-Windows-0078D6.svg)](https://www.npmjs.com/package/dsh-turn-ding)
6
8
 
7
- ---
9
+ DSH 没有内置「会话完成提醒」:任务栏图标不会累计未读数,也没有完成提示音。`dsh-turn-ding` 补上这个缺口——每个会话正常结束时徽标 +1 并响一声,回到窗口自动清零,效果类似 Codex 的完成提醒。
8
10
 
9
- ## 一、它做了什么
11
+ ## 功能
10
12
 
11
- | 能力 | 实现位置 | 说明 |
12
- | --- | --- | --- |
13
- | 数字徽标 | `lib/badge-server.ps1` | `ITaskbarList3.SetOverlayIcon` 把一张 32×32 的红底白字圆图贴到 DSH 任务栏按钮右上角 |
14
- | 提示音 | `lib/badge-server.ps1` | `System.Media.SoundPlayer` 播放指定 `.wav` |
15
- | 判定「完成」 | `lib/index.js` | 监听 `session/event`,只认 `turn/end` 且 `reason.kind === 'completed'` |
16
- | 每个会话完成都计数 | `lib/badge-server.ps1` | DSH 是一个窗口装多个会话,"窗口在前台"不等于"你正在看这个会话",所以每次都加 1 |
17
- | 回到前台自动清零 | `lib/badge-server.ps1` | 500ms 轮询,检测到「后台→前台」的切换就清徽标;一直盯着屏幕时徽标约 10s 后自动淡出 |
18
- | 自愈 | `lib/badge-server.ps1` | 每 ~6s 重绘一次,Explorer 重启/窗口隐藏后徽标不会丢 |
19
- | 句柄重绑定 | `lib/badge-server.ps1` | 窗口句柄失效自动重新查找并补画 |
13
+ - 任务栏图标右上角的红底白字数字徽标(超过 99 显示 `99+`)
14
+ - 完成时播放系统提示音,音效可替换
15
+ - 只在会话**正常完成**(`turn/end` + `completed`)时计数;中断、报错、耗尽 token、子会话都不计
16
+ - DSH 是一窗多会话,因此即使窗口在前台也照常计数
17
+ - 回到窗口(后台 → 前台)自动清零;一直停留时约 10 秒后自动淡出
18
+ - Explorer 重启、窗口隐藏后徽标可自愈重绘
19
+
20
+ ## 环境要求
20
21
 
21
- `aborted` / `error` / `max-tokens` / `interrupted` / `forked` 这几种"中途结束"**不会**计数;子会话(subagent)默认也忽略。
22
+ | | |
23
+ | --- | --- |
24
+ | 系统 | Windows(`win32`,见 `os` 字段) |
25
+ | DSH | `>=0.2.1-alpha.2 <0.4.0` |
26
+ | 运行时 | Node >= 20、PowerShell 5.1+(Windows 自带,无需 `pwsh`) |
22
27
 
23
- ## 二、安装(给使用者)
28
+ ## 安装
24
29
 
25
- ### 方式 A:插件页直接装(推荐,最简单)
30
+ ### 从 npm 安装(推荐)
26
31
 
27
- 在 DSH 侧栏打开「插件」→「安装第三方插件 / 添加插件」,输入包名点安装:
32
+ DSH 侧栏「插件 → 安装第三方插件」输入包名:
28
33
 
29
34
  ```
30
35
  dsh-turn-ding
31
36
  ```
32
37
 
33
- 桌面版需**完全退出** DSH 后再装/更新,装好重新打开。等价于命令行:
38
+ 或用命令行(`desktop` 换成你使用的 profile):
34
39
 
35
40
  ```bash
36
41
  dsh plugin --profile desktop add dsh-turn-ding
37
- dsh plugin --profile web add dsh-turn-ding
38
42
  ```
39
43
 
40
- > 终端里没有 `dsh` 的话,先在桌面版菜单选「管理 dsh 命令」。
44
+ > 桌面版需**完全退出 DSH** 后安装或更新,装好重新打开。
45
+ > 终端里找不到 `dsh` 时,先在桌面版菜单选「管理 dsh 命令」。
41
46
 
42
- ### 方式 B:在「发现」里浏览安装(0.2.2 实验功能)
47
+ ### 从「发现」安装(DSH 0.2.2+ 实验功能)
43
48
 
44
- DSH `0.2.2` 及以上可在「插件 → 实验性插件」启用**自定义插件索引**(`0.2.1` 系列叫「自定义插件市场」),启用后插件页多出「已安装」「发现」两个标签。在「发现」里「管理索引源 / 添加索引源」填入本仓库的 `index.json` 地址,列表里点安装即可。索引只是省掉手输包名这一步,装的还是同一个 npm 包。
49
+ 在「插件 → 实验性插件」启用**自定义插件索引**,再到「发现 → 添加索引源」填入本仓库 `index.json` 的公开地址:
45
50
 
46
51
  ```
47
- https://raw.githubusercontent.com/<你的GitHub用户名>/dsh-turn-ding/main/index.json
52
+ https://raw.githubusercontent.com/arrongao/dsh-turn-ding/main/index.json
48
53
  ```
49
54
 
50
- GitHub 直连不通时可用 jsDelivr CDN 镜像(可能比最新发布晚约 12 小时):
55
+ 索引只是省掉手输包名这一步,装的仍是同一个 npm 包。
51
56
 
52
- ```
53
- https://cdn.jsdelivr.net/gh/<你的GitHub用户名>/dsh-turn-ding@main/index.json
54
- ```
55
-
56
- ### 方式 C:离线 / 本地目录
57
+ ### 离线 / 本地目录
57
58
 
58
59
  ```bash
59
60
  dsh plugin --profile desktop add "D:/path/to/dsh-turn-ding"
60
- # 或把 npm pack 出来的 tgz 当包名:
61
- dsh plugin --profile desktop add "file:D:/path/to/dsh-turn-ding-0.1.0.tgz"
61
+ dsh plugin --profile desktop add "file:D:/path/to/dsh-turn-ding-0.1.1.tgz"
62
62
  ```
63
63
 
64
- ### 本地开发时的安装记录(本机 desktop profile)
65
-
66
- 本机是通过本地 `link:` 装进 desktop profile 的:
67
-
68
- ```bash
69
- DSH="D:/Users/saiwa/AppData/Local/Programs/DeepSeek Harness/resources/runtime/cli/bin/dsh.cmd"
70
- "$DSH" plugin --profile desktop add "D:/projects/arron/DSH-Plugins/dsh-turn-ding"
71
- ```
72
-
73
- 注意:`plugin` 子命令必须在**桌面应用完全退出**时运行(它要改 profile 的 `package.json` 并跑 pnpm)。`--dump-config`、boot 这类子命令对 `desktop` profile 是被硬拒的(`profile "desktop" is managed exclusively by the Electron application`),`plugin` 子命令例外放行。
74
-
75
- 装完的效果写在这两个文件里:
76
-
77
- - `C:\\Users\\saiwa\\.dsh\\profiles\\desktop\\package.json`
78
- - `dependencies` 里加 `"dsh-turn-ding": "link:D:\\\\projects\\\\arron\\\\DSH-Plugins\\\\dsh-turn-ding"`
79
- - `dsh.profile.bundles` 末尾加 `"dsh-turn-ding"`
80
- - `C:\\Users\\saiwa\\.dsh\\profiles\\desktop\\pnpm-lock.yaml` 里的 `dsh-turn-ding: version: link:...`
81
-
82
- 回滚:把 `package.json.bak-turn-ding` 覆盖回去即可(同一目录下已备份)。
64
+ ## 配置
83
65
 
84
- ## 三、配置
85
-
86
- 在 `C:\\Users\\saiwa\\.dsh\\profiles\\desktop\\cordis.patch.yml` 里给这一行加 `config`:
66
+ 在对应 profile 的 `cordis.patch.yml`(Windows 默认 `%USERPROFILE%\.dsh\profiles\desktop\cordis.patch.yml`)里,给插件行加上 `config`:
87
67
 
88
68
  ```yaml
89
69
  - id: turn-ding
90
70
  name: 'dsh-turn-ding'
91
71
  config:
92
72
  sound: true
93
- soundFile: 'C:\\Windows\\Media\\Windows Notify System Generic.wav'
73
+ soundFile: 'C:\Windows\Media\Windows Notify System Generic.wav'
94
74
  badge: true
95
75
  ignoreSubagents: true
96
76
  ```
@@ -98,79 +78,68 @@ DSH="D:/Users/saiwa/AppData/Local/Programs/DeepSeek Harness/resources/runtime/cl
98
78
  | 字段 | 默认 | 说明 |
99
79
  | --- | --- | --- |
100
80
  | `sound` | `true` | 是否播放提示音 |
101
- | `soundFile` | `C:\\Windows\\Media\\Windows Notify System Generic.wav` | 任意本地 `.wav` |
102
- | `badge` | `true` | 是否画数字徽标 |
103
- | `ignoreSubagents` | `true` | 是否忽略子会话的 turn 结束 |
104
-
105
- 常用替代音效:`Windows Notify.wav`、`Windows Ding.wav`、`ding.wav`、`chimes.wav`、`Windows Notify Email.wav`,都在 `C:\\Windows\\Media\\`。
106
-
107
- ## 四、为什么是这个架构
81
+ | `soundFile` | `C:\Windows\Media\Windows Notify System Generic.wav` | 任意本地 `.wav` 路径 |
82
+ | `badge` | `true` | 是否显示数字徽标 |
83
+ | `ignoreSubagents` | `true` | 是否忽略子会话的结束事件 |
108
84
 
109
- 排查过三条路,只有第三条通:
85
+ 其它可选系统音效位于 `C:\Windows\Media\`,例如 `Windows Ding.wav`、`chimes.wav`。留空即使用上表默认值。
110
86
 
111
- 1. **Electron 主进程通道** —— 不通。`apps/desktop/src/ipc.ts:8-34` 的 `DESKTOP_IPC` 白名单里没有 badge/tray/overlay/notification 任何一项;preload 只暴露 `browser / deviceInfo / keyboard / shortcuts / updates`,且仅 `dsh-app://app` origin 可用。已安装的 `app.asar` 里 `setBadgeCount` / `setOverlayIcon` 出现次数为 **0**。
112
- 2. **渲染层 `navigator.setAppBadge()`** —— 理论可行(该 Electron 构建确实含 Chromium BadgeService),但无法在本机实机验证,且窗口隐藏到托盘时任务栏按钮消失、徽标也随之失效。
113
- 3. **host 侧 Win32**(采用)—— host 是独立 Node 子进程(`host-process.ts:186-201`,`ELECTRON_RUN_AS_NODE=1`),拿不到 `BrowserWindow`,但**能按进程找到目标窗口的 HWND**,于是可以调 `ITaskbarList3.SetOverlayIcon`。这条路已用真实截图逐像素验证。
87
+ ## 工作原理
114
88
 
115
- `lib/index.js` 只负责「监听事件 + 通过 stdin 行协议驱动辅助进程」;所有 Win32/COM 调用都在 `lib/badge-server.ps1` 里。辅助进程常驻(不是每次完成都起一个),有 `ready` 握手和 pending 队列,启动失败会降级成「没有徽标」而不是报错。
89
+ - `lib/index.js` 监听 `session/event`,识别正常完成的 turn,通过 stdin 行协议驱动一个常驻辅助进程。
90
+ - `lib/badge-server.ps1` 用 Win32 `ITaskbarList3.SetOverlayIcon` 绘制徽标,用 `System.Media.SoundPlayer` 播放音效,并轮询处理焦点变化与窗口句柄重绑定。
116
91
 
117
- ## 五、验证记录
92
+ DSH 的插件 host 是独立 Node 进程,拿不到 `BrowserWindow`,因此徽标由辅助进程按窗口句柄直接绘制到任务栏按钮上。
118
93
 
119
- | 测试 | 命令 | 结果 |
120
- | --- | --- | --- |
121
- | host 半边逻辑 | `node test/host-harness.mjs` | 只注册 `session/event`;aborted/error/subagent 全部忽略;两次 completed 各触发一次;dispose 干净 |
122
- | 辅助进程协议 | `node test/server-proto.mjs` | `ready` → `ping/pong` → `set`/`notify`/`clear` → `bye`,exit 0 |
123
- | 端到端 | `node test/e2e-badge.mjs` | 真 ctx + 真 PowerShell + 真任务栏:idle → 1 次完成 → 2 次完成,徽标依次变 `1`、`2`;再灌 aborted/error/subagent 三个事件,**像素零变化** |
124
- | 自动清零 | `node test/autoclear.mjs` | 把目标指向当前前台进程,`set 4` 后 3.5s 内回 `autoclear` |
125
- | 前台也计数(回归) | `node test/focus-regression.mjs` | 窗口在前台时连发两次 `notify` → `count=1`、`count=2`,截图确认徽标「2」 |
126
- | 对照截图 | `node test/proof-badge.mjs` | clear 与 badge 两张任务栏截图 diff bbox = `(1781, 11, 1813, 42)`,正好 32px 宽的徽标区 |
127
- | 整 profile boot | `node test/verify-desktop-profile.mjs` | 用真实 desktop 配置克隆 boot,web 服务正常起来,唯一失败项是既有的 `experimental-inspector`(与本插件无关);进程列表里抓到插件真正拉起了 `badge-server.ps1` |
128
- | 插件市场索引 | 用实装 `parseMarketIndex()` 校验 `index.json` | `VALID`,安装目标解析为 `dsh-turn-ding@0.1.0` |
94
+ ## 开发
129
95
 
130
- 截图见 `test/e2e-2-two.png`(徽标「2」)、`test/proof-badge3.png`(徽标「3」)。
96
+ ```bash
97
+ npm pack --dry-run # 确认将要发布的文件
98
+ node test/host-harness.mjs # host 事件判定逻辑
99
+ node test/e2e-badge.mjs # 端到端徽标绘制
100
+ node test/focus-regression.mjs # "前台也计数"回归测试
101
+ ```
131
102
 
132
- ## 六、发布(给维护者)
103
+ 仓库 `test/` 下另有辅助进程协议、自动清零、索引校验等脚本;截图为本地生成产物,不纳入版本控制。
133
104
 
134
- 本插件就是一个普通的 npm 包,`dsh.bundle.patch` 是「这是 DSH 插件」的唯一标记,`package.json` 里**没有** `private: true`。发布流程:
105
+ ### 发布(维护者)
135
106
 
136
107
  ```bash
137
- # 0. 首次:登录 npm(本机默认源是 npmmirror,publish 需显式指定官方源)
138
108
  npm login --registry=https://registry.npmjs.org/
139
-
140
- # 1. 改版本号、确认打包内容(files 白名单:lib/、cordis.patch.yml、README.md、LICENSE)
141
- npm version patch # 0.1.0 → 0.1.1
109
+ npm version patch
142
110
  npm pack --dry-run
143
-
144
- # 2. 发布
145
111
  npm publish --registry=https://registry.npmjs.org/ --access public
146
-
147
- # 3. 同步刷新 index.json 里对应版本的 version / publishTimestamp(Unix 秒),
148
- # 让「发现」里出现新版本;改完用官方校验器复验一次。
149
112
  ```
150
113
 
151
- `publishTimestamp` 用 `date +%s` 取当前 Unix 秒,必须落在 `[0, 10^11)`;`version` 必须是精确 SemVer。改完 `index.json` 后,用 `@deepseek-ai/dsh-plugin-market-index` 的 `parseMarketIndex(doc, indexUrl)` 校验,通过再推到 GitHub。
114
+ 发布后同步 `index.json` 中的 `version` 与 `publishTimestamp`(Unix 秒),用 `@deepseek-ai/dsh-plugin-market-index` 的 `parseMarketIndex()` 校验通过,再更新托管地址。
152
115
 
153
- `os: ["win32"]` 会阻止在非 Windows 机器上安装,避免用户装了却没有效果。`engines.dsh` 仅作声明(安装器实际只校验 `peerDependencies`,本包故意不写)。
116
+ > 若 `~/.npmrc` 指向了镜像源,publish 需显式加 `--registry=https://registry.npmjs.org/`。开启两步验证的账号发布时需输入 OTP,或改用 Automation token 免去验证码。
154
117
 
155
- ## 七、已知限制
118
+ `os: ["win32"]` 会阻止在非 Windows 机器上安装。`engines.dsh` 仅作声明:安装器按 `peerDependencies` 做兼容校验,本包不设该字段。
156
119
 
157
- - **Windows only**。macOS/Linux 需要另一套实现(`app.dock.setBadge` 在 host 侧拿不到,得换方案)。`os: ["win32"]` 已经把这一点写进 manifest。
158
- - **需要重启 DSH** 才会加载(同名包换版本也要重启,host 会报 restart-required)。
159
- - **关闭到托盘时**任务栏按钮不存在,徽标自然看不见;重新显示窗口后会自愈重绘。
160
- - 依赖 `powershell.exe`。PowerShell 5.1 即可(本机已验证),不需要 `pwsh` 7。
161
- - 徽标是 **overlay 图标**,跟 Windows 通知中心里那个数字不是同一个东西——后者需要 Toast,本插件不做。
120
+ ## 已知限制
162
121
 
163
- ## 八、文件
122
+ - 仅支持 Windows;macOS / Linux 需要另一套实现。
123
+ - 安装或更换版本后需重启 DSH 才会加载。
124
+ - 窗口隐藏到托盘时任务栏按钮不存在,徽标不可见;重新显示窗口后会自愈重绘。
125
+ - 徽标是任务栏 **overlay 图标**,不是 Windows 通知中心里的 Toast 数字。
126
+
127
+ ## 项目结构
164
128
 
165
129
  ```
166
130
  dsh-turn-ding/
167
- ├── package.json # dsh.bundle.patch 是"这是 DSH 插件"的唯一标记
168
- ├── cordis.patch.yml # - insert: [{ id: turn-ding, name: dsh-turn-ding }]
169
- ├── index.json # 插件市场「发现」用的格式 1 索引(发布后托管到可访问的 URL)
170
- ├── LICENSE # MIT
131
+ ├── package.json # dsh.bundle.patch 是"这是 DSH 插件"的标记
132
+ ├── cordis.patch.yml # 插件注入声明
133
+ ├── index.json # 「发现」用的格式 1 索引(托管到公开 URL 后使用)
171
134
  ├── README.md
135
+ ├── LICENSE
136
+ ├── .gitignore
172
137
  ├── lib/
173
- │ ├── index.js # host 半边:事件监听 + 辅助进程生命周期
174
- │ └── badge-server.ps1 # Win32 半边:COM overlay + 提示音 + 轮询维护
175
- └── test/ # 上面那张表里的验证脚本与截图
138
+ │ ├── index.js # host 侧:事件监听与辅助进程生命周期
139
+ │ └── badge-server.ps1 # Win32 侧:徽标绘制、提示音、轮询维护
140
+ └── test/ # 验证脚本(截图为本地生成,不入库)
176
141
  ```
142
+
143
+ ## 许可证
144
+
145
+ [MIT](./LICENSE)
package/index.json CHANGED
@@ -26,15 +26,19 @@
26
26
  "en": "Shows an unread number badge on the Windows taskbar icon and plays a chime whenever a DeepSeek Harness session finishes.",
27
27
  "zh": "每当一个 DeepSeek Harness 会话完成,就在 Windows 任务栏图标右上角显示未读数字徽标,并播放提示音。"
28
28
  },
29
- "author": "Arron",
29
+ "author": "Arron Gao",
30
+ "homepage": "https://github.com/arrongao/dsh-turn-ding#readme",
31
+ "repository": {
32
+ "url": "https://github.com/arrongao/dsh-turn-ding"
33
+ },
30
34
  "metadata": {
31
35
  "keywords": ["badge", "notification", "taskbar", "windows", "completion"],
32
36
  "labels": ["windows-only"]
33
37
  },
34
38
  "versions": [
35
39
  {
36
- "version": "0.1.0",
37
- "publishTimestamp": 1794631126,
40
+ "version": "0.1.1",
41
+ "publishTimestamp": 1794650620,
38
42
  "source": {
39
43
  "type": "npm",
40
44
  "registry": "https://registry.npmjs.org/"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-turn-ding",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Windows taskbar unread badge and completion chime for DeepSeek Harness turns",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -24,8 +24,13 @@
24
24
  "windows",
25
25
  "taskbar"
26
26
  ],
27
- "author": "Arron",
27
+ "author": "Arron Gao <arron.gaoxc@gmail.com>",
28
28
  "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/arrongao/dsh-turn-ding.git"
32
+ },
33
+ "homepage": "https://github.com/arrongao/dsh-turn-ding#readme",
29
34
  "os": [
30
35
  "win32"
31
36
  ],