@telosmaylx/dsh-session-notify 0.1.10 → 0.1.11
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.
- package/README.en.md +594 -590
- package/README.ja.md +594 -590
- package/README.ko.md +594 -590
- package/README.md +594 -590
- package/README.zh-TW.md +594 -590
- package/lib/client.js +953 -184
- package/lib/core.js +64 -42
- package/lib/index.js +86 -2
- package/package.json +74 -74
- package/scripts/tmp-i18n-check.mjs +70 -0
package/README.md
CHANGED
|
@@ -1,590 +1,594 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
|
-
# dsh-session-notify
|
|
4
|
-
|
|
5
|
-
**简体中文** · [English](README.en.md) · [繁體中文](README.zh-TW.md) · [日本語](README.ja.md) · [한국어](README.ko.md)
|
|
6
|
-
|
|
7
|
-
**DSH(DeepSeek Harness)会话完成提醒插件 —— 每一轮结束,让完成状态主动找你,而不是你盯着屏幕等。**
|
|
8
|
-
|
|
9
|
-
[](https://www.npmjs.com/package/@telosmaylx/dsh-session-notify)
|
|
10
|
-
[](https://www.npmjs.com/package/@telosmaylx/dsh-session-notify)
|
|
11
|
-
[](./LICENSE)
|
|
12
|
-
[](https://www.npmjs.com/package/@telosmaylx/dsh-session-notify)
|
|
13
|
-
[](https://www.npmjs.com/package/@telosmaylx/dsh-session-notify)
|
|
14
|
-
[](https://github.com/TelosmaYLX/dsh-session-notify/pulls)
|
|
15
|
-
|
|
16
|
-
每轮对话结束时,把「已完成 / 出错 / 被阻塞 / 达到上限」连同用时、token 消耗写入会话日志,并推送浏览器系统通知与页内 toast。内置 5 种语言、可视化文案模板编辑器、自定义预设库,缓存命中率与生成速度取自官方投影,与状态栏同口径。
|
|
17
|
-
|
|
18
|
-
</div>
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## 目录
|
|
23
|
-
|
|
24
|
-
- [功能特性](#功能特性)
|
|
25
|
-
- [环境要求](#环境要求)
|
|
26
|
-
- [安装](#安装)
|
|
27
|
-
- [卸载](#卸载)
|
|
28
|
-
- [快速开始](#快速开始)
|
|
29
|
-
- [通知行为](#通知行为)
|
|
30
|
-
- [触发条件](#触发条件)
|
|
31
|
-
- [推送正文从哪来](#推送正文从哪来)
|
|
32
|
-
- [通知示例](#通知示例)
|
|
33
|
-
- [通知权限](#通知权限)
|
|
34
|
-
- [配置](#配置)
|
|
35
|
-
- [设置面板](#设置面板)
|
|
36
|
-
- [文案模板与占位符](#文案模板与占位符)
|
|
37
|
-
- [预设系统](#预设系统)
|
|
38
|
-
- [宿主配置项](#宿主配置项)
|
|
39
|
-
- [工作原理](#工作原理)
|
|
40
|
-
- [项目结构](#项目结构)
|
|
41
|
-
- [开发与调试](#开发与调试)
|
|
42
|
-
- [常见问题](#常见问题)
|
|
43
|
-
- [更新日志](#更新日志)
|
|
44
|
-
- [贡献](#贡献)
|
|
45
|
-
- [相关链接](#相关链接)
|
|
46
|
-
- [许可证](#许可证)
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
## 功能特性
|
|
51
|
-
|
|
52
|
-
### 三通道提醒,一条不漏
|
|
53
|
-
|
|
54
|
-
| 通道 | 形式 | 说明 |
|
|
55
|
-
| --- | --- | --- |
|
|
56
|
-
| 会话内系统消息 | 可折叠提示行 | 每轮结束把结束原因与用时、消耗作为插件来源的系统消息追加进会话日志,随 JSONL 落盘,恢复或回放会话后依然可见。 |
|
|
57
|
-
| 浏览器系统通知 | Web Notification | 原生弹窗。每次完成事件使用独立 `tag`(`dsh-session-notify:<timestamp>`),不与前一次互相替换,也不被折叠成一个分组条目;点击通知聚焦回窗口。 |
|
|
58
|
-
| 页内 toast | 右下角浮动弹窗 | 永远展示的保底通道:系统通知被平台静默、权限拒绝或环境不支持时仍有可见反馈。同屏最多 3 条(超出移除最旧),10 秒自动消失,点击关闭。 |
|
|
59
|
-
|
|
60
|
-
### 后台会话全覆盖
|
|
61
|
-
|
|
62
|
-
- 宿主为所有会话(含后台、未打开窗口的)维护「最近一条通知正文」的会话投影单元(key = `session-complete-notify`),推送正文跨会话一致,不依赖你恰好开着那个窗口。
|
|
63
|
-
- 客户端从会话列表快照观测所有会话的 `running` 位,`true → false` 边沿即触发推送,与官方 sidebar 提醒同策略(首次观测只记录基线,已在 idle 的会话不补发)。
|
|
64
|
-
|
|
65
|
-
### 可定制到每一句话
|
|
66
|
-
|
|
67
|
-
- **5 种语言**:简体中文、繁體中文、English、日本語、한국어 —— 通知文案、时长与用量措辞、设置面板界面全部随语言切换(切换即时重渲染)。
|
|
68
|
-
- **可视化模板编辑器**(Chip 胶囊编辑器):动态信息渲染为内联胶囊(占位符代码不露出),「+ 插入信息」在光标处插入(可插到文字中间),点击胶囊移除,每栏带实时预览(信息以示例值流入正文)。
|
|
69
|
-
- **预设系统**:内置「默认」预设作为基线;当前配置可另存为自定义预设(`localStorage` 持久化),支持自动编号的未命名预设(`未命名`、`未命名 2`…)、「来自:xxx · 已修改」来源指示、删除预设。
|
|
70
|
-
- **推送标题模板**:留空时各原因用默认标题(完成=任务已完成 / 出错=任务出错 / …);`{title}` 引用会话标题。
|
|
71
|
-
|
|
72
|
-
### 与官方口径同源
|
|
73
|
-
|
|
74
|
-
- **缓存命中率**取自官方 `tokenUsage` 投影:缓存读 /(未缓存输入 + 缓存读 + 缓存写)。
|
|
75
|
-
- **生成速度**取自官方 `sessionStats` 投影:输出 token ÷ 解码耗时。
|
|
76
|
-
- 两者与 dsh-web-ui 状态栏完全同口径,不含排队、准备、工具时间;投影不可用或数据未就绪时自动退回本地用量聚合估算。
|
|
77
|
-
|
|
78
|
-
> [!NOTE]
|
|
79
|
-
> 缓存命中率与速度只在自定义模板中通过 `{cache}`、`{tps}` 占位符插入时才显示。使用内置默认文案时,正文只含用时与消耗。
|
|
80
|
-
|
|
81
|
-
### 工程质量
|
|
82
|
-
|
|
83
|
-
- **只响应实时事件**:resume、replay 不重放旧通知,加载会话不刷屏。
|
|
84
|
-
- **自免疫循环**:插件追加的消息类型(`user/message`)与自身监听目标(`turn/*`)不相交。
|
|
85
|
-
- **零外部依赖**:宿主平面零裸 import,UserMessage 按 `dsh-llm` 的 `createUserMessage` 契约手工构造;纯逻辑层(`lib/core.js`)零依赖,可独立测试。
|
|
86
|
-
- **Cordis effect 纪律**:重试定时器包装在 `ctx.effect()` 中并返回 `clearTimeout` disposer,注册随 fiber 卸载自动撤销,HMR 热重载安全。
|
|
87
|
-
- **安装即挂载**:声明官方 `dsh.bundle` manifest,`dsh plugin add` 一条命令装完即用,无需手写 patch。
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## 环境要求
|
|
92
|
-
|
|
93
|
-
| 依赖 | 要求 |
|
|
94
|
-
| --- | --- |
|
|
95
|
-
| DSH(DeepSeek Harness) | Web profile 部署。官方 base bundle 默认包含 `@deepseek-ai/dsh-settings`(设置命名空间)与会话投影,无需额外配置 |
|
|
96
|
-
| cordis | `>=4.0.0-rc <5`(peer dependency,由宿主提供) |
|
|
97
|
-
| Node.js | `>=22`(宿主侧) |
|
|
98
|
-
| 浏览器 | 支持 Web Notification 则有系统通知;不支持、权限拒绝或被静默时由 toast 兜底 |
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## 安装
|
|
103
|
-
|
|
104
|
-
> [!WARNING]
|
|
105
|
-
> 裸 `npm install` 只会把包装进依赖树,**不会注册插件** —— 这是 DSH 官方设计(`npm install only adds the dependency; it does not register the plugin`)。自动挂载的唯一官方途径是 `dsh plugin add`:它读取包内 `dsh.bundle` manifest(本插件自 0.1.3 起声明,指向仓库根 `cordis.patch.yml`)并自动应用。
|
|
106
|
-
|
|
107
|
-
### 方式一:dsh plugin add(推荐)
|
|
108
|
-
|
|
109
|
-
安装包的同时自动应用 `cordis.patch.yml`,把插件挂载进 profile 装配(host 事件订阅 + client 启动图注入)。
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
dsh plugin --profile web add @telosmaylx/dsh-session-notify
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### 方式二:从 GitHub 仓库安装
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
dsh plugin add github:TelosmaYLX/dsh-session-notify
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
也可以在 DSH Web GUI 会话内执行:
|
|
122
|
-
|
|
123
|
-
```bash
|
|
124
|
-
dev_install_package github=TelosmaYLX/dsh-session-notify
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### 方式三:本地目录热装配(开发用)
|
|
128
|
-
|
|
129
|
-
把路径换成你的克隆目录,在 DSH Web GUI 会话内执行:
|
|
130
|
-
|
|
131
|
-
```bash
|
|
132
|
-
dev_install_package dir=/你的/克隆目录/dsh-session-notify
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### 方式四:npm 包手动安装
|
|
136
|
-
|
|
137
|
-
先打包:
|
|
138
|
-
|
|
139
|
-
```bash
|
|
140
|
-
npm pack @telosmaylx/dsh-session-notify
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
解压后指定目录安装(在 DSH Web GUI 会话内执行):
|
|
144
|
-
|
|
145
|
-
```bash
|
|
146
|
-
dev_install_package dir=/解压/目录/package
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
### 方式五:手动 cordis patch(不依赖安装器)
|
|
150
|
-
|
|
151
|
-
在 `~/.dsh/profiles/web/cordis.patch.yml` 追加:
|
|
152
|
-
|
|
153
|
-
```yaml
|
|
154
|
-
- insert:
|
|
155
|
-
- id: dsh-session-notify
|
|
156
|
-
name: '@telosmaylx/dsh-session-notify'
|
|
157
|
-
config: {}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
> [!IMPORTANT]
|
|
161
|
-
> 无论用哪种方式,装完都需要**刷新一次浏览器页面** —— 客户端 bundle 通过 `__DSH_BOOT__` 启动图注入。
|
|
162
|
-
|
|
163
|
-
## 卸载
|
|
164
|
-
|
|
165
|
-
一条命令移除插件及其挂载(自动从 `cordis.patch.yml` 移除 insert 条目):
|
|
166
|
-
|
|
167
|
-
```bash
|
|
168
|
-
dsh plugin --profile web remove @telosmaylx/dsh-session-notify
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
> [!NOTE]
|
|
172
|
-
> 手动安装(方式四/五)的用户,需同步从 `~/.dsh/profiles/web/cordis.patch.yml` 删除对应 insert 条目,再刷新页面。
|
|
173
|
-
|
|
174
|
-
### 卸载时自动清理的内容
|
|
175
|
-
|
|
176
|
-
插件实现了完整的生命周期收尾(Cordis effect 纪律),卸载/禁用/HMR 热重载时:
|
|
177
|
-
|
|
178
|
-
| 平面 | 自动释放的资源 |
|
|
179
|
-
| --- | --- |
|
|
180
|
-
| host | `session/event` 事件订阅、settings 命名空间、会话投影单元、设置注册重试定时器(`ctx.effect` 包装);置卸载标志抑制已调度的微任务追加 |
|
|
181
|
-
| client | 会话列表订阅、完成推送正文的轮询定时器、`window.__dsch_notify_debug` 调试钩子(按引用删除,防闭包泄漏)、页内 toast 容器 DOM |
|
|
182
|
-
|
|
183
|
-
### 卸载后保留的数据
|
|
184
|
-
|
|
185
|
-
- **设置配置**(语言、文案模板)留在 settings 文档,重装后自动恢复;
|
|
186
|
-
- **自定义预设**存于浏览器 `localStorage`(`dsh-scn-custom-presets`),重装后仍在;
|
|
187
|
-
- 历史会话中已追加的系统消息与 JSONL 日志**不会**被回滚(它们是会话数据的一部分,与官方侧边栏提示同语义)。
|
|
188
|
-
|
|
189
|
-
---
|
|
190
|
-
|
|
191
|
-
## 快速开始
|
|
192
|
-
|
|
193
|
-
1. 按上面任一方式安装并刷新页面。
|
|
194
|
-
2. 发起任意一轮对话,等它结束 —— 右下角弹出 toast、浏览器弹系统通知、会话日志里出现可折叠的系统提示行。
|
|
195
|
-
3. 首次收到完成事件时,浏览器会请求通知权限(每页只问一次),允许后后续完成都有系统通知。
|
|
196
|
-
4. 打开 **设置 → 插件 → 会话完成提醒**,切换语言、编辑文案模板、另存预设。保存后点「点击刷新」让宿主与客户端两侧重新读取,新配置即生效。
|
|
197
|
-
|
|
198
|
-
刚装好时,会话日志里会出现这样一行可折叠提示:
|
|
199
|
-
|
|
200
|
-
```text
|
|
201
|
-
会话「重构登录模块」已完成(用时 1 分 12 秒,消耗 1,240 输入 / 3,560 输出)。
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
> 默认文案在「会话」后内嵌会话标题标签(`{title}`);会话无标题时自动退回「会话已完成」。
|
|
205
|
-
|
|
206
|
-
---
|
|
207
|
-
|
|
208
|
-
## 通知行为
|
|
209
|
-
|
|
210
|
-
### 触发条件
|
|
211
|
-
|
|
212
|
-
每轮对话结束(`turn/end`)时按结束原因判断,命中白名单即提醒:
|
|
213
|
-
|
|
214
|
-
| 结束原因 | 含义 | 默认 |
|
|
215
|
-
| --- | --- | --- |
|
|
216
|
-
| `completed` | 会话正常完成 | 提醒 |
|
|
217
|
-
| `aborted` | 会话中止 | 提醒 |
|
|
218
|
-
| `blocked` | 会话被阻塞 | 提醒 |
|
|
219
|
-
| `error` | 会话出错(附错误详情,超长截断) | 提醒 |
|
|
220
|
-
| `max-tokens` | 达到输出 token 上限 | 提醒 |
|
|
221
|
-
| `interrupted` | 中断(崩溃恢复后由持久化后端补写的孤儿轮次关闭标记) | 不提醒(可配置加入) |
|
|
222
|
-
|
|
223
|
-
**子代理会话默认跳过**(`header.origin === 'subagent'` 或 `delegationDepth > 0`)—— 子代理由父会话编排,逐轮提醒是噪音;可在宿主配置关闭跳过。
|
|
224
|
-
|
|
225
|
-
### 推送正文从哪来
|
|
226
|
-
|
|
227
|
-
客户端在会话列表观测到 `running: true → false` 边沿时推送,正文按以下优先级获取(最长轮询 6 秒,400ms 间隔):
|
|
228
|
-
|
|
229
|
-
1. **宿主投影**(key = `session-complete-notify`)—— 每个会话都有,后台会话同样拿到全文;
|
|
230
|
-
2. **会话事件窗口里的 notice 节点**(`kind=context` + `form=notice`)—— 正在查看的会话,落盘后立即可用;
|
|
231
|
-
3. **降级** —— 「详情见会话内系统消息」+ 工作区信息(`cwd` 最后一段)。
|
|
232
|
-
|
|
233
|
-
### 通知示例
|
|
234
|
-
|
|
235
|
-
以下均由 `lib/core.js` 的 `buildNotice` 实际生成。默认文案按结束原因**差异化表达**(非清一色句式):
|
|
236
|
-
|
|
237
|
-
简体中文默认文案:
|
|
238
|
-
|
|
239
|
-
```text
|
|
240
|
-
会话「重构登录模块」已完成(用时 3 分 25 秒,消耗 12,400 输入 / 35,600 输出)。 ← 完成:括号紧凑式 + 内嵌会话标题
|
|
241
|
-
会话「重构登录模块」已中止。用时 3 分 25 秒,消耗 12,400 输入 / 35,600 输出。 ← 中止:句号拆句
|
|
242
|
-
会话「重构登录模块」被阻塞。用时 3 分 25 秒,消耗 12,400 输入 / 35,600 输出。 ← 阻塞:句号拆句
|
|
243
|
-
会话「重构登录模块」达到输出上限。用时 3 分 25 秒,消耗 12,400 输入 / 35,600 输出,建议拆分任务后重试。 ← 上限:附建议
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
> 会话无标题(`titleValue` 为空)时自动退回不带标题的句式,如「会话已完成(用时 …)」。
|
|
247
|
-
|
|
248
|
-
出错时错误详情前置(单行化,超过 40 字符截断):
|
|
249
|
-
|
|
250
|
-
```text
|
|
251
|
-
会话「重构登录模块」出错:connection timeout(用时 12 秒)。
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
English 默认文案(会话标题用双引号):
|
|
255
|
-
|
|
256
|
-
```text
|
|
257
|
-
Session "重构登录模块" completed (took 3m25s, used 12,400 in / 35,600 out).
|
|
258
|
-
Session "重构登录模块" hit the output-token cap. Took 3m25s, used 12,400 in / 35,600 out — consider splitting the task.
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
自定义模板(在设置面板编辑,本例用到全部信息位):
|
|
262
|
-
|
|
263
|
-
```text
|
|
264
|
-
{title} 干完了!用时 {duration},消耗 {usage},缓存命中 {cache},速度 {tps}
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
渲染结果:
|
|
268
|
-
|
|
269
|
-
```text
|
|
270
|
-
重构登录模块 干完了!用时 3 分 25 秒,消耗 103,600 输入 / 35,600 输出,缓存命中 96.5%,速度 92 tok/s
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
五种语言的同一事件:
|
|
274
|
-
|
|
275
|
-
```text
|
|
276
|
-
会话「重构登录模块」已完成(用时 3 分 25 秒,消耗 1,240 输入 / 3,560 输出)。
|
|
277
|
-
會話「重構登入模組」已完成(用時 3 分 25 秒,消耗 1,240 輸入 / 3,560 輸出)。
|
|
278
|
-
Session "重构登录模块" completed (took 3m25s, used 1,240 in / 3,560 out).
|
|
279
|
-
セッション「重构登录模块」完了(所要 3 分 25 秒、消費 1,240 入力 / 3,560 出力)。
|
|
280
|
-
세션「重构登录模块」 완료(소요 3분 25초, 소모 1,240 입력 / 3,560 출력)。
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
### 通知权限
|
|
284
|
-
|
|
285
|
-
| 权限状态 | 行为 |
|
|
286
|
-
| --- | --- |
|
|
287
|
-
| `default`(未决定) | 完成事件只发 toast;设置面板「通知权限」区提供「请求授权」按钮(**用户手势内请求**——Chromium 会忽略非手势的自动请求,因此插件不再自动请求) |
|
|
288
|
-
| `granted` | 按「推送方式」发系统通知(独立 tag,互不覆盖) |
|
|
289
|
-
| `denied`(被浏览器屏蔽) | 仅 toast;设置面板显示地址栏操作指引(权限图标 → 网站设置 → 通知 → 允许) |
|
|
290
|
-
| `undefined`(非安全上下文 / 不支持) | 仅 toast;建议改用「仅页内提示」 |
|
|
291
|
-
|
|
292
|
-
---
|
|
293
|
-
|
|
294
|
-
## 配置
|
|
295
|
-
|
|
296
|
-
绝大多数配置在 **DSH Web UI → 设置 → 插件 → 会话完成提醒** 面板完成(保存后点「点击刷新」生效)。仅「触发原因白名单」与「跳过子代理」两项在宿主 `cordis.patch.yml` 的 `config` 中配置。
|
|
297
|
-
|
|
298
|
-
### 设置面板
|
|
299
|
-
|
|
300
|
-
面板在官方「设置 → 插件」面板中注册(`settings.plugin.item` keyed slot,key = `session-complete-notify`),样式逐值复刻原生插件卡片(12px 圆角、展开收起、旋转 chevron、footer 状态位 + 弃置 ghost + 主色保存按钮):
|
|
301
|
-
|
|
302
|
-
| 区域 | 内容 |
|
|
303
|
-
| --- | --- |
|
|
304
|
-
| 预设 | 下拉选择内置或自定义预设;「新增」把当前配置另存为自定义预设;当前预设可「删除」 |
|
|
305
|
-
| 语言 | 5 种语言单选,切换即时重渲染整个面板 |
|
|
306
|
-
| 推送方式 | 三选一:双通道(系统通知 + 页内提示,默认)/ 仅系统通知 / 仅页内提示 |
|
|
307
|
-
|
|
|
308
|
-
|
|
|
309
|
-
|
|
|
310
|
-
|
|
|
311
|
-
|
|
|
312
|
-
|
|
|
313
|
-
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
>
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
>
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
>
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
|
330
|
-
|
|
|
331
|
-
| `{
|
|
332
|
-
| `{
|
|
333
|
-
| `{
|
|
334
|
-
| `{
|
|
335
|
-
| `{
|
|
336
|
-
| `{
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
│
|
|
377
|
-
│
|
|
378
|
-
│
|
|
379
|
-
│
|
|
380
|
-
│
|
|
381
|
-
│
|
|
382
|
-
│
|
|
383
|
-
│
|
|
384
|
-
│
|
|
385
|
-
│
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
│
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
│
|
|
394
|
-
│
|
|
395
|
-
│
|
|
396
|
-
│
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
-
|
|
406
|
-
-
|
|
407
|
-
-
|
|
408
|
-
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
│ ├──
|
|
421
|
-
│ │ #
|
|
422
|
-
│ │ #
|
|
423
|
-
│
|
|
424
|
-
│
|
|
425
|
-
|
|
426
|
-
│
|
|
427
|
-
│
|
|
428
|
-
|
|
429
|
-
│ ├──
|
|
430
|
-
│ ├──
|
|
431
|
-
│ ├── probe-
|
|
432
|
-
│ ├── probe-
|
|
433
|
-
│
|
|
434
|
-
├──
|
|
435
|
-
├──
|
|
436
|
-
│
|
|
437
|
-
├──
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
|
469
|
-
|
|
|
470
|
-
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
-
|
|
537
|
-
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
|
551
|
-
|
|
|
552
|
-
| **0.1.
|
|
553
|
-
| **0.1.
|
|
554
|
-
| **0.1.
|
|
555
|
-
| **0.1.
|
|
556
|
-
| **0.1.
|
|
557
|
-
| 0.1.
|
|
558
|
-
| 0.1.
|
|
559
|
-
| 0.1.
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# dsh-session-notify
|
|
4
|
+
|
|
5
|
+
**简体中文** · [English](README.en.md) · [繁體中文](README.zh-TW.md) · [日本語](README.ja.md) · [한국어](README.ko.md)
|
|
6
|
+
|
|
7
|
+
**DSH(DeepSeek Harness)会话完成提醒插件 —— 每一轮结束,让完成状态主动找你,而不是你盯着屏幕等。**
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/@telosmaylx/dsh-session-notify)
|
|
10
|
+
[](https://www.npmjs.com/package/@telosmaylx/dsh-session-notify)
|
|
11
|
+
[](./LICENSE)
|
|
12
|
+
[](https://www.npmjs.com/package/@telosmaylx/dsh-session-notify)
|
|
13
|
+
[](https://www.npmjs.com/package/@telosmaylx/dsh-session-notify)
|
|
14
|
+
[](https://github.com/TelosmaYLX/dsh-session-notify/pulls)
|
|
15
|
+
|
|
16
|
+
每轮对话结束时,把「已完成 / 出错 / 被阻塞 / 达到上限」连同用时、token 消耗写入会话日志,并推送浏览器系统通知与页内 toast。内置 5 种语言、可视化文案模板编辑器、自定义预设库,缓存命中率与生成速度取自官方投影,与状态栏同口径。
|
|
17
|
+
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 目录
|
|
23
|
+
|
|
24
|
+
- [功能特性](#功能特性)
|
|
25
|
+
- [环境要求](#环境要求)
|
|
26
|
+
- [安装](#安装)
|
|
27
|
+
- [卸载](#卸载)
|
|
28
|
+
- [快速开始](#快速开始)
|
|
29
|
+
- [通知行为](#通知行为)
|
|
30
|
+
- [触发条件](#触发条件)
|
|
31
|
+
- [推送正文从哪来](#推送正文从哪来)
|
|
32
|
+
- [通知示例](#通知示例)
|
|
33
|
+
- [通知权限](#通知权限)
|
|
34
|
+
- [配置](#配置)
|
|
35
|
+
- [设置面板](#设置面板)
|
|
36
|
+
- [文案模板与占位符](#文案模板与占位符)
|
|
37
|
+
- [预设系统](#预设系统)
|
|
38
|
+
- [宿主配置项](#宿主配置项)
|
|
39
|
+
- [工作原理](#工作原理)
|
|
40
|
+
- [项目结构](#项目结构)
|
|
41
|
+
- [开发与调试](#开发与调试)
|
|
42
|
+
- [常见问题](#常见问题)
|
|
43
|
+
- [更新日志](#更新日志)
|
|
44
|
+
- [贡献](#贡献)
|
|
45
|
+
- [相关链接](#相关链接)
|
|
46
|
+
- [许可证](#许可证)
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 功能特性
|
|
51
|
+
|
|
52
|
+
### 三通道提醒,一条不漏
|
|
53
|
+
|
|
54
|
+
| 通道 | 形式 | 说明 |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| 会话内系统消息 | 可折叠提示行 | 每轮结束把结束原因与用时、消耗作为插件来源的系统消息追加进会话日志,随 JSONL 落盘,恢复或回放会话后依然可见。 |
|
|
57
|
+
| 浏览器系统通知 | Web Notification | 原生弹窗。每次完成事件使用独立 `tag`(`dsh-session-notify:<timestamp>`),不与前一次互相替换,也不被折叠成一个分组条目;点击通知聚焦回窗口。 |
|
|
58
|
+
| 页内 toast | 右下角浮动弹窗 | 永远展示的保底通道:系统通知被平台静默、权限拒绝或环境不支持时仍有可见反馈。同屏最多 3 条(超出移除最旧),10 秒自动消失,点击关闭。 |
|
|
59
|
+
|
|
60
|
+
### 后台会话全覆盖
|
|
61
|
+
|
|
62
|
+
- 宿主为所有会话(含后台、未打开窗口的)维护「最近一条通知正文」的会话投影单元(key = `session-complete-notify`),推送正文跨会话一致,不依赖你恰好开着那个窗口。
|
|
63
|
+
- 客户端从会话列表快照观测所有会话的 `running` 位,`true → false` 边沿即触发推送,与官方 sidebar 提醒同策略(首次观测只记录基线,已在 idle 的会话不补发)。
|
|
64
|
+
|
|
65
|
+
### 可定制到每一句话
|
|
66
|
+
|
|
67
|
+
- **5 种语言**:简体中文、繁體中文、English、日本語、한국어 —— 通知文案、时长与用量措辞、设置面板界面全部随语言切换(切换即时重渲染)。
|
|
68
|
+
- **可视化模板编辑器**(Chip 胶囊编辑器):动态信息渲染为内联胶囊(占位符代码不露出),「+ 插入信息」在光标处插入(可插到文字中间),点击胶囊移除,每栏带实时预览(信息以示例值流入正文)。
|
|
69
|
+
- **预设系统**:内置「默认」预设作为基线;当前配置可另存为自定义预设(`localStorage` 持久化),支持自动编号的未命名预设(`未命名`、`未命名 2`…)、「来自:xxx · 已修改」来源指示、删除预设。
|
|
70
|
+
- **推送标题模板**:留空时各原因用默认标题(完成=任务已完成 / 出错=任务出错 / …);`{title}` 引用会话标题。
|
|
71
|
+
|
|
72
|
+
### 与官方口径同源
|
|
73
|
+
|
|
74
|
+
- **缓存命中率**取自官方 `tokenUsage` 投影:缓存读 /(未缓存输入 + 缓存读 + 缓存写)。
|
|
75
|
+
- **生成速度**取自官方 `sessionStats` 投影:输出 token ÷ 解码耗时。
|
|
76
|
+
- 两者与 dsh-web-ui 状态栏完全同口径,不含排队、准备、工具时间;投影不可用或数据未就绪时自动退回本地用量聚合估算。
|
|
77
|
+
|
|
78
|
+
> [!NOTE]
|
|
79
|
+
> 缓存命中率与速度只在自定义模板中通过 `{cache}`、`{tps}` 占位符插入时才显示。使用内置默认文案时,正文只含用时与消耗。
|
|
80
|
+
|
|
81
|
+
### 工程质量
|
|
82
|
+
|
|
83
|
+
- **只响应实时事件**:resume、replay 不重放旧通知,加载会话不刷屏。
|
|
84
|
+
- **自免疫循环**:插件追加的消息类型(`user/message`)与自身监听目标(`turn/*`)不相交。
|
|
85
|
+
- **零外部依赖**:宿主平面零裸 import,UserMessage 按 `dsh-llm` 的 `createUserMessage` 契约手工构造;纯逻辑层(`lib/core.js`)零依赖,可独立测试。
|
|
86
|
+
- **Cordis effect 纪律**:重试定时器包装在 `ctx.effect()` 中并返回 `clearTimeout` disposer,注册随 fiber 卸载自动撤销,HMR 热重载安全。
|
|
87
|
+
- **安装即挂载**:声明官方 `dsh.bundle` manifest,`dsh plugin add` 一条命令装完即用,无需手写 patch。
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 环境要求
|
|
92
|
+
|
|
93
|
+
| 依赖 | 要求 |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| DSH(DeepSeek Harness) | Web profile 部署。官方 base bundle 默认包含 `@deepseek-ai/dsh-settings`(设置命名空间)与会话投影,无需额外配置 |
|
|
96
|
+
| cordis | `>=4.0.0-rc <5`(peer dependency,由宿主提供) |
|
|
97
|
+
| Node.js | `>=22`(宿主侧) |
|
|
98
|
+
| 浏览器 | 支持 Web Notification 则有系统通知;不支持、权限拒绝或被静默时由 toast 兜底 |
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 安装
|
|
103
|
+
|
|
104
|
+
> [!WARNING]
|
|
105
|
+
> 裸 `npm install` 只会把包装进依赖树,**不会注册插件** —— 这是 DSH 官方设计(`npm install only adds the dependency; it does not register the plugin`)。自动挂载的唯一官方途径是 `dsh plugin add`:它读取包内 `dsh.bundle` manifest(本插件自 0.1.3 起声明,指向仓库根 `cordis.patch.yml`)并自动应用。
|
|
106
|
+
|
|
107
|
+
### 方式一:dsh plugin add(推荐)
|
|
108
|
+
|
|
109
|
+
安装包的同时自动应用 `cordis.patch.yml`,把插件挂载进 profile 装配(host 事件订阅 + client 启动图注入)。
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
dsh plugin --profile web add @telosmaylx/dsh-session-notify
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 方式二:从 GitHub 仓库安装
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
dsh plugin add github:TelosmaYLX/dsh-session-notify
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
也可以在 DSH Web GUI 会话内执行:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
dev_install_package github=TelosmaYLX/dsh-session-notify
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 方式三:本地目录热装配(开发用)
|
|
128
|
+
|
|
129
|
+
把路径换成你的克隆目录,在 DSH Web GUI 会话内执行:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
dev_install_package dir=/你的/克隆目录/dsh-session-notify
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### 方式四:npm 包手动安装
|
|
136
|
+
|
|
137
|
+
先打包:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npm pack @telosmaylx/dsh-session-notify
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
解压后指定目录安装(在 DSH Web GUI 会话内执行):
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
dev_install_package dir=/解压/目录/package
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 方式五:手动 cordis patch(不依赖安装器)
|
|
150
|
+
|
|
151
|
+
在 `~/.dsh/profiles/web/cordis.patch.yml` 追加:
|
|
152
|
+
|
|
153
|
+
```yaml
|
|
154
|
+
- insert:
|
|
155
|
+
- id: dsh-session-notify
|
|
156
|
+
name: '@telosmaylx/dsh-session-notify'
|
|
157
|
+
config: {}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
> [!IMPORTANT]
|
|
161
|
+
> 无论用哪种方式,装完都需要**刷新一次浏览器页面** —— 客户端 bundle 通过 `__DSH_BOOT__` 启动图注入。
|
|
162
|
+
|
|
163
|
+
## 卸载
|
|
164
|
+
|
|
165
|
+
一条命令移除插件及其挂载(自动从 `cordis.patch.yml` 移除 insert 条目):
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
dsh plugin --profile web remove @telosmaylx/dsh-session-notify
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
> [!NOTE]
|
|
172
|
+
> 手动安装(方式四/五)的用户,需同步从 `~/.dsh/profiles/web/cordis.patch.yml` 删除对应 insert 条目,再刷新页面。
|
|
173
|
+
|
|
174
|
+
### 卸载时自动清理的内容
|
|
175
|
+
|
|
176
|
+
插件实现了完整的生命周期收尾(Cordis effect 纪律),卸载/禁用/HMR 热重载时:
|
|
177
|
+
|
|
178
|
+
| 平面 | 自动释放的资源 |
|
|
179
|
+
| --- | --- |
|
|
180
|
+
| host | `session/event` 事件订阅、settings 命名空间、会话投影单元、设置注册重试定时器(`ctx.effect` 包装);置卸载标志抑制已调度的微任务追加 |
|
|
181
|
+
| client | 会话列表订阅、完成推送正文的轮询定时器、`window.__dsch_notify_debug` 调试钩子(按引用删除,防闭包泄漏)、页内 toast 容器 DOM |
|
|
182
|
+
|
|
183
|
+
### 卸载后保留的数据
|
|
184
|
+
|
|
185
|
+
- **设置配置**(语言、文案模板)留在 settings 文档,重装后自动恢复;
|
|
186
|
+
- **自定义预设**存于浏览器 `localStorage`(`dsh-scn-custom-presets`),重装后仍在;
|
|
187
|
+
- 历史会话中已追加的系统消息与 JSONL 日志**不会**被回滚(它们是会话数据的一部分,与官方侧边栏提示同语义)。
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 快速开始
|
|
192
|
+
|
|
193
|
+
1. 按上面任一方式安装并刷新页面。
|
|
194
|
+
2. 发起任意一轮对话,等它结束 —— 右下角弹出 toast、浏览器弹系统通知、会话日志里出现可折叠的系统提示行。
|
|
195
|
+
3. 首次收到完成事件时,浏览器会请求通知权限(每页只问一次),允许后后续完成都有系统通知。
|
|
196
|
+
4. 打开 **设置 → 插件 → 会话完成提醒**,切换语言、编辑文案模板、另存预设。保存后点「点击刷新」让宿主与客户端两侧重新读取,新配置即生效。
|
|
197
|
+
|
|
198
|
+
刚装好时,会话日志里会出现这样一行可折叠提示:
|
|
199
|
+
|
|
200
|
+
```text
|
|
201
|
+
会话「重构登录模块」已完成(用时 1 分 12 秒,消耗 1,240 输入 / 3,560 输出)。
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
> 默认文案在「会话」后内嵌会话标题标签(`{title}`);会话无标题时自动退回「会话已完成」。
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## 通知行为
|
|
209
|
+
|
|
210
|
+
### 触发条件
|
|
211
|
+
|
|
212
|
+
每轮对话结束(`turn/end`)时按结束原因判断,命中白名单即提醒:
|
|
213
|
+
|
|
214
|
+
| 结束原因 | 含义 | 默认 |
|
|
215
|
+
| --- | --- | --- |
|
|
216
|
+
| `completed` | 会话正常完成 | 提醒 |
|
|
217
|
+
| `aborted` | 会话中止 | 提醒 |
|
|
218
|
+
| `blocked` | 会话被阻塞 | 提醒 |
|
|
219
|
+
| `error` | 会话出错(附错误详情,超长截断) | 提醒 |
|
|
220
|
+
| `max-tokens` | 达到输出 token 上限 | 提醒 |
|
|
221
|
+
| `interrupted` | 中断(崩溃恢复后由持久化后端补写的孤儿轮次关闭标记) | 不提醒(可配置加入) |
|
|
222
|
+
|
|
223
|
+
**子代理会话默认跳过**(`header.origin === 'subagent'` 或 `delegationDepth > 0`)—— 子代理由父会话编排,逐轮提醒是噪音;可在宿主配置关闭跳过。
|
|
224
|
+
|
|
225
|
+
### 推送正文从哪来
|
|
226
|
+
|
|
227
|
+
客户端在会话列表观测到 `running: true → false` 边沿时推送,正文按以下优先级获取(最长轮询 6 秒,400ms 间隔):
|
|
228
|
+
|
|
229
|
+
1. **宿主投影**(key = `session-complete-notify`)—— 每个会话都有,后台会话同样拿到全文;
|
|
230
|
+
2. **会话事件窗口里的 notice 节点**(`kind=context` + `form=notice`)—— 正在查看的会话,落盘后立即可用;
|
|
231
|
+
3. **降级** —— 「详情见会话内系统消息」+ 工作区信息(`cwd` 最后一段)。
|
|
232
|
+
|
|
233
|
+
### 通知示例
|
|
234
|
+
|
|
235
|
+
以下均由 `lib/core.js` 的 `buildNotice` 实际生成。默认文案按结束原因**差异化表达**(非清一色句式):
|
|
236
|
+
|
|
237
|
+
简体中文默认文案:
|
|
238
|
+
|
|
239
|
+
```text
|
|
240
|
+
会话「重构登录模块」已完成(用时 3 分 25 秒,消耗 12,400 输入 / 35,600 输出)。 ← 完成:括号紧凑式 + 内嵌会话标题
|
|
241
|
+
会话「重构登录模块」已中止。用时 3 分 25 秒,消耗 12,400 输入 / 35,600 输出。 ← 中止:句号拆句
|
|
242
|
+
会话「重构登录模块」被阻塞。用时 3 分 25 秒,消耗 12,400 输入 / 35,600 输出。 ← 阻塞:句号拆句
|
|
243
|
+
会话「重构登录模块」达到输出上限。用时 3 分 25 秒,消耗 12,400 输入 / 35,600 输出,建议拆分任务后重试。 ← 上限:附建议
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
> 会话无标题(`titleValue` 为空)时自动退回不带标题的句式,如「会话已完成(用时 …)」。
|
|
247
|
+
|
|
248
|
+
出错时错误详情前置(单行化,超过 40 字符截断):
|
|
249
|
+
|
|
250
|
+
```text
|
|
251
|
+
会话「重构登录模块」出错:connection timeout(用时 12 秒)。
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
English 默认文案(会话标题用双引号):
|
|
255
|
+
|
|
256
|
+
```text
|
|
257
|
+
Session "重构登录模块" completed (took 3m25s, used 12,400 in / 35,600 out).
|
|
258
|
+
Session "重构登录模块" hit the output-token cap. Took 3m25s, used 12,400 in / 35,600 out — consider splitting the task.
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
自定义模板(在设置面板编辑,本例用到全部信息位):
|
|
262
|
+
|
|
263
|
+
```text
|
|
264
|
+
{title} 干完了!用时 {duration},消耗 {usage},缓存命中 {cache},速度 {tps}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
渲染结果:
|
|
268
|
+
|
|
269
|
+
```text
|
|
270
|
+
重构登录模块 干完了!用时 3 分 25 秒,消耗 103,600 输入 / 35,600 输出,缓存命中 96.5%,速度 92 tok/s
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
五种语言的同一事件:
|
|
274
|
+
|
|
275
|
+
```text
|
|
276
|
+
会话「重构登录模块」已完成(用时 3 分 25 秒,消耗 1,240 输入 / 3,560 输出)。
|
|
277
|
+
會話「重構登入模組」已完成(用時 3 分 25 秒,消耗 1,240 輸入 / 3,560 輸出)。
|
|
278
|
+
Session "重构登录模块" completed (took 3m25s, used 1,240 in / 3,560 out).
|
|
279
|
+
セッション「重构登录模块」完了(所要 3 分 25 秒、消費 1,240 入力 / 3,560 出力)。
|
|
280
|
+
세션「重构登录模块」 완료(소요 3분 25초, 소모 1,240 입력 / 3,560 출력)。
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### 通知权限
|
|
284
|
+
|
|
285
|
+
| 权限状态 | 行为 |
|
|
286
|
+
| --- | --- |
|
|
287
|
+
| `default`(未决定) | 完成事件只发 toast;设置面板「通知权限」区提供「请求授权」按钮(**用户手势内请求**——Chromium 会忽略非手势的自动请求,因此插件不再自动请求) |
|
|
288
|
+
| `granted` | 按「推送方式」发系统通知(独立 tag,互不覆盖) |
|
|
289
|
+
| `denied`(被浏览器屏蔽) | 仅 toast;设置面板显示地址栏操作指引(权限图标 → 网站设置 → 通知 → 允许) |
|
|
290
|
+
| `undefined`(非安全上下文 / 不支持) | 仅 toast;建议改用「仅页内提示」 |
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## 配置
|
|
295
|
+
|
|
296
|
+
绝大多数配置在 **DSH Web UI → 设置 → 插件 → 会话完成提醒** 面板完成(保存后点「点击刷新」生效)。仅「触发原因白名单」与「跳过子代理」两项在宿主 `cordis.patch.yml` 的 `config` 中配置。
|
|
297
|
+
|
|
298
|
+
### 设置面板
|
|
299
|
+
|
|
300
|
+
面板在官方「设置 → 插件」面板中注册(`settings.plugin.item` keyed slot,key = `session-complete-notify`),样式逐值复刻原生插件卡片(12px 圆角、展开收起、旋转 chevron、footer 状态位 + 弃置 ghost + 主色保存按钮):
|
|
301
|
+
|
|
302
|
+
| 区域 | 内容 |
|
|
303
|
+
| --- | --- |
|
|
304
|
+
| 预设 | 下拉选择内置或自定义预设;「新增」把当前配置另存为自定义预设;当前预设可「删除」 |
|
|
305
|
+
| 语言 | 5 种语言单选,切换即时重渲染整个面板 |
|
|
306
|
+
| 推送方式 | 三选一:双通道(系统通知 + 页内提示,默认)/ 仅系统通知 / 仅页内提示 |
|
|
307
|
+
| 通知图片 | 大图两种来源:**按原因上传**——在模板中通过「+ 插入信息 → 图片」插入 `{image}` 标签并选择本地图片(编辑器内显示为带缩略图的标签,**自动压缩至 512px 宽、按通知显示比例 16:9 居中裁切**,随各原因独立保存);**全局大图/图标**——两张上传卡片并排一行(**图标在前**,空态 = 圆角矩形 + 号,点击上传;**大图 512×288(16:9 居中裁切)、图标 128×128(1:1 方形居中裁切)**;已上传则卡片显示缩略图,**点击缩略图可全屏查看完整原图(等比未裁切)**,右上角 × 删除)。图标留空用站点默认图标,也可在模板中插入 `{icon}` 标签**按原因指定图标**(优先于全局)。仅系统通知通道生效(页内 toast 为文字卡片),「发送」测试按钮同样生效 |
|
|
308
|
+
| 标题 | 折叠区(**默认收起**,点击展开):**全局推送标题**(所有原因共用,Chip 编辑器——点「+ 插入信息」插入的信息以**胶囊标签**形式显示,点击胶囊移除;占位提示「通用推送标题,留空时则使用默认标题,优先级低于下方自定义标题」(不可选中/删除);**通知发送时标题里的信息位(用时/消耗/错误/缓存命中/速度)会替换为实际值,不再显示代码**;留空时各原因用默认标题——完成=任务已完成、出错=任务出错、中止=任务已中止、阻塞=任务被阻塞、上限=任务达到上限)+ **按原因定制标题**(5 条原因各自输入,每行带「+」插入按钮——可插入信息标签(不含图片/图标),插入到光标处;**优先于全局标题**,留空 = 用全局或语言默认标题) |
|
|
309
|
+
| 内容 | 折叠区(**默认收起**,点击展开);展开后每条结束原因(完成、出错、中止、阻塞、上限)**一行式布局**(原因标签 + Chip 编辑器 + 「+」插入按钮——菜单展开时变「−」+ **发送箭头按钮**,按钮为矩形、垂直居中):**空模板(默认预设)时编辑器显示默认文案「会话「{title}」已xx,请点击查看。」**,文字 + 内联信息胶囊,光标处插入;`{image}`/`{icon}` 标签**点击缩略图可预览大图、点 × 才删除**(防误删),其他标签点击移除;**编辑后删空则显示「留空则使用默认文案」占位(不可选中/删除)** |
|
|
310
|
+
| 跳过子代理会话 | 复选框(保存时一并写入设置文档) |
|
|
311
|
+
| 通知权限 | 状态实时显示:已授权(绿)/ 尚未授权(附「请求授权」按钮)/ 已被浏览器屏蔽(附地址栏操作指引)/ 环境不支持 |
|
|
312
|
+
| 按原因定制标题 | 折叠区(默认收起):每个结束原因一个独立标题输入框,留空 = 用全局模板或语言默认标题 |
|
|
313
|
+
| 保存 | 写入宿主设置文档(`language` / `templates` / `titleTemplate` / `titleTemplates` / `pushMode`);保存后显示「点击刷新」链接 |
|
|
314
|
+
| 重置 | 一键还原默认值(**语言保留当前选择**,标题/模板/推送方式恢复默认)并立即保存 |
|
|
315
|
+
|
|
316
|
+
> [!NOTE]
|
|
317
|
+
> 「推送方式」的取舍:`dual`(默认)同时弹 Windows 系统通知与页内 toast,toast 是保底通道,防止系统通知被平台静默(专注助手、通知横幅关闭)。但 **QQ 浏览器等国产 Chromium 壳浏览器会把 `Notification` 渲染成「浏览器内置的页内推送弹窗」**(页面顶部/角落的横幅,不经 Windows 通知中心)——此时 `dual` 会造成页内两个提示(浏览器内置弹窗 + 插件 toast)。这类浏览器请选「仅页内提示」(不再调用 `Notification`,浏览器内置弹窗不会出现,页内只有插件自己的小 toast);「仅系统通知」模式在 QQ 浏览器无效(它永远渲染为页内弹窗)。设置面板每个原因的「发送」测试按钮同样受此影响。
|
|
318
|
+
|
|
319
|
+
> [!NOTE]
|
|
320
|
+
> 系统通知(`Notification` API)能否弹出由**浏览器与站点访问方式**共同决定:Edge/Chrome 对"不熟悉"的站点会**自动屏蔽通知**(地址栏出现「通知已屏蔽」)——点击地址栏左侧权限图标 → 网站设置 → 通知 → 允许即可恢复;`http://IP` 这类非安全上下文访问时 `Notification` 根本不存在,请改用「仅页内提示」。设置面板「通知权限」区域会实时显示当前状态并给出对应操作指引(可一键请求授权)。Firefox 窗口聚焦时通知显示为页内横幅、失焦才进系统通知中心。
|
|
321
|
+
|
|
322
|
+
> [!NOTE]
|
|
323
|
+
> 面板中「跳过子代理会话」保存的是设置文档里的布尔值;宿主 `cordis.patch.yml` 的 `config.skipSubagents` 是其启动默认值,两者任一为真即跳过。
|
|
324
|
+
|
|
325
|
+
### 文案模板与占位符
|
|
326
|
+
|
|
327
|
+
每条结束原因独立一个模板输入框,**标签即开关** —— 在模板里插入对应信息标签,该项数据才会显示:
|
|
328
|
+
|
|
329
|
+
| 占位符 | 含义 | 示例值 |
|
|
330
|
+
| --- | --- | --- |
|
|
331
|
+
| `{title}` | 会话标题(推送标题模板也可用) | `重构登录模块` |
|
|
332
|
+
| `{duration}` | 本轮用时(`turn/start` 起表 → `turn/end` 结束) | `3 分 25 秒` / `3m25s` |
|
|
333
|
+
| `{usage}` | token 消耗(输入 = 未缓存 + 缓存读 + 缓存写) | `1,240 输入 / 3,560 输出` |
|
|
334
|
+
| `{error}` | 错误信息(无错误时显示 `none`;单行化,80 字符截断) | `connection timeout` |
|
|
335
|
+
| `{cache}` | 缓存命中率(官方投影口径,无数据为空) | `96.5%` |
|
|
336
|
+
| `{tps}` | 生成速度(官方投影口径,无数据为空) | `92 tok/s` |
|
|
337
|
+
| `{image}` | 自定义通知大图开关:从「+ 插入信息」插入并选择本地图片(自动压缩至 512px),按原因独立;正文渲染时剥除,不进会话日志;删除标签时该原因图片数据一并清除 | — |
|
|
338
|
+
| `{icon}` | 自定义通知图标开关:从「+ 插入信息」插入并选择本地图片(自动压缩至 128×128 方形),按原因独立;正文渲染时剥除,不进会话日志;优先于全局「通知图标」;删除标签时该原因图标数据一并清除 | — |
|
|
339
|
+
| `{label}` | 已废弃 —— 渲染时自动剥除,旧模板仍兼容(插入菜单已移除该选项) | — |
|
|
340
|
+
|
|
341
|
+
模板留空即使用内置默认文案(自动带用时与消耗)。折叠行 `summary` 与正文同源(渲染结果截断至 120 字符)—— 只看折叠行的用户也能看到真实标题与用时、消耗。
|
|
342
|
+
|
|
343
|
+
### 预设系统
|
|
344
|
+
|
|
345
|
+
- **内置预设**:仅「默认」,作为基线。
|
|
346
|
+
- **自定义预设**:保存在 `localStorage`(key = `dsh-scn-custom-presets`):
|
|
347
|
+
- 「新增」命名后保存为自定义预设;保存后可「修改」自动同步、「删除」移除;
|
|
348
|
+
- **自动编号的未命名预设**:从「默认 / 空白」直接保存时,自动生成 `未命名`、`未命名 2`、`未命名 3`…(编号取当前最大值 + 1);
|
|
349
|
+
- 表单显示「来自:xxx · 已修改」来源指示(来自预设但内容已改动时)。
|
|
350
|
+
- **保存即同步**:保存时若表单来源是自定义预设则更新该预设,否则新建或继续编号未命名预设。
|
|
351
|
+
|
|
352
|
+
### 宿主配置项
|
|
353
|
+
|
|
354
|
+
```yaml
|
|
355
|
+
- insert:
|
|
356
|
+
- id: dsh-session-notify
|
|
357
|
+
name: '@telosmaylx/dsh-session-notify'
|
|
358
|
+
config:
|
|
359
|
+
reasons: [completed, aborted, blocked, error, max-tokens]
|
|
360
|
+
skipSubagents: true
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
364
|
+
| --- | --- | --- | --- |
|
|
365
|
+
| `reasons` | `string[]` | `[completed, aborted, blocked, error, max-tokens]` | 触发提醒的 `turn/end` 原因白名单 |
|
|
366
|
+
| `skipSubagents` | `boolean` | `true` | 跳过子代理会话(`origin=subagent` 或 `delegationDepth>0`) |
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## 工作原理
|
|
371
|
+
|
|
372
|
+
插件分**宿主平面**(Node)与**客户端平面**(浏览器),中间靠会话日志(JSONL)与官方会话投影衔接:
|
|
373
|
+
|
|
374
|
+
```text
|
|
375
|
+
┌─────────────────── 宿主平面(lib/index.js,Node)──────────────────┐
|
|
376
|
+
│ │
|
|
377
|
+
│ session/event 火线 │
|
|
378
|
+
│ ├─ turn/start → tracker 起表(key: sessionId:turn) │
|
|
379
|
+
│ ├─ assistant/message → 累加该轮 token 用量 │
|
|
380
|
+
│ └─ turn/end → reason.kind ∈ reasons ? │
|
|
381
|
+
│ ├─ 子代理会话?跳过 │
|
|
382
|
+
│ ├─ 读官方投影:cache / tps / title │
|
|
383
|
+
│ ├─ 按语言+模板构建通知(summary ≤120 字) │
|
|
384
|
+
│ └─ queueMicrotask 追加系统消息 │
|
|
385
|
+
│ (避开 append 重入窗口) │
|
|
386
|
+
│ │
|
|
387
|
+
│ settings.register → 官方「设置 → 插件」命名空间(失败退避重试) │
|
|
388
|
+
│ sessionProjections → 注册投影单元(key=session-complete-notify) │
|
|
389
|
+
└──────────────────────────────┬──────────────────────────────────────┘
|
|
390
|
+
│ user/message (source: plugin, form: notice)
|
|
391
|
+
▼ JSONL 持久化 + 投影推送
|
|
392
|
+
┌─────────────────── 客户端平面(lib/client.js,浏览器)──────────────┐
|
|
393
|
+
│ │
|
|
394
|
+
│ 会话列表订阅:running true → false 边沿 → pushCompletion │
|
|
395
|
+
│ ├─ 取正文:投影 → 事件窗口 notice → 降级(轮询 ≤6s) │
|
|
396
|
+
│ ├─ Web Notification(独立 tag,点击聚焦) │
|
|
397
|
+
│ └─ 页内 toast(永远展示,≤3 条,10s 自动消失) │
|
|
398
|
+
│ │
|
|
399
|
+
│ slots.inject('settings.plugin.item') → 设置卡片(预设/语言/模板) │
|
|
400
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### 关键设计决策
|
|
404
|
+
|
|
405
|
+
- **不重放**:只处理实时事件,resume、replay 不会补发历史通知。
|
|
406
|
+
- **无自我循环**:插件追加 `user/message`,自身只监听 `turn/*`,事件类型不相交。
|
|
407
|
+
- **零外部 import**:插件从仓库目录以 realpath 加载,`@deepseek-ai/*` 无法裸解析 —— 宿主平面用 `createRequire` 锚定 profile 共享依赖枢纽(`.dsh/profiles/node_modules`)取 `schemastery`(设置 schema)与 `zod`(投影 schema);UserMessage 按 `dsh-llm` 契约手工构造(`id = crypto.randomUUID()`,deep-freeze 由 `session.append` 的 adopt 快照阶段完成)。
|
|
408
|
+
- **append 重入规避**:`session/event` 观察者回调运行在 `turn/end` 那次 append 的发布边界之内(dsh-session 在 dispatch 前置 `entry.appending`、`finally` 复位),同步 append 会被拒绝 —— 因此推迟到 `queueMicrotask`(微任务在本次同步栈含 `finally` 复位之后才执行)。
|
|
409
|
+
- **effect 纪律**:设置注册的退避重试定时器包装在 `ctx.effect()` 中并返回 `clearTimeout` disposer —— 插件在重试窗口内被卸载或热重载时定时器随 fiber 拆除,不会对已释放的 ctx 触发注册(极老环境无 `ctx.effect` API 时退化为裸定时器 + ctx 已拆除兜底捕获)。
|
|
410
|
+
- **HMR 安全**:`core.js` 导入带 `?v=1` 缓存破坏(HMR 重载按 URL 键控);设置注册遇到热重载竞态(duplicate)时自动退避重试(最多 8 次,间隔 `400ms × attempts`)。
|
|
411
|
+
- **投影注册双轨**:优先 `ctx.root.get('sessionProjections')`(最靠近宿主根的一份),拿不到时回退注入实例;只注册进注入实例时客户端可能读不到投影单元,推送正文走降级路径 —— 属尽力而为,不影响会话内系统消息。
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## 项目结构
|
|
416
|
+
|
|
417
|
+
```text
|
|
418
|
+
dsh-session-notify/
|
|
419
|
+
├── lib/
|
|
420
|
+
│ ├── index.js # 宿主平面(Node):session/event 订阅 → 系统消息落盘;
|
|
421
|
+
│ │ # settings 命名空间注册(schemastery schema,退避重试);
|
|
422
|
+
│ │ # sessionProjections 投影单元(后台会话推送正文)
|
|
423
|
+
│ ├── core.js # 纯逻辑层(零依赖,可独立测试):轮次计时与用量聚合、
|
|
424
|
+
│ │ # 5 语言文案表、时长/用量/缓存/速度格式化、
|
|
425
|
+
│ │ # 模板渲染({title}{duration}{usage}{error}{cache}{tps})
|
|
426
|
+
│ └── client.js # 浏览器平面:完成推送(系统通知 + toast)、
|
|
427
|
+
│ # 设置卡片(Chip 模板编辑器 + 预设系统 + 实时预览)
|
|
428
|
+
├── scripts/
|
|
429
|
+
│ ├── build.sh # 零构建:仅 node --check 语法校验
|
|
430
|
+
│ ├── verify-notice.mjs # 校验会话日志落盘证据(zstd 多帧逐帧解压)
|
|
431
|
+
│ ├── probe-client.mjs # 探针:客户端装配
|
|
432
|
+
│ ├── probe-client-e2e.mjs # 探针:客户端端到端
|
|
433
|
+
│ ├── probe-card-render.mjs # 探针:设置卡片渲染
|
|
434
|
+
│ ├── probe-settings-card.mjs # 探针:设置面板卡片
|
|
435
|
+
│ ├── probe-settings-check.mjs# 探针:设置面板检查
|
|
436
|
+
│ └── probe-diag-settings.mjs # 探针:settings 诊断
|
|
437
|
+
├── cordis.patch.yml # dsh.bundle manifest —— dsh plugin add 自动挂载的凭证
|
|
438
|
+
├── package.json # dsh.bundle(patch)+ dsh.client(web 注入)双 manifest;
|
|
439
|
+
│ # exports: "." / "./client" / "./core"
|
|
440
|
+
├── LICENSE # MIT
|
|
441
|
+
└── README.md # 本文档
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## 开发与调试
|
|
447
|
+
|
|
448
|
+
语法校验(零构建,`prepublishOnly` 同款检查):
|
|
449
|
+
|
|
450
|
+
```bash
|
|
451
|
+
npm run build
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
发布(发布前自动执行 `prepublishOnly` 语法校验):
|
|
455
|
+
|
|
456
|
+
```bash
|
|
457
|
+
npm publish --registry=https://registry.npmjs.org --access public
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
离线校验:解出会话日志中所有 plugin-source 事件与 `turn/end` 尾部序列(不传路径则自动选 `~/.dsh/sessions` 下最新会话):
|
|
461
|
+
|
|
462
|
+
```bash
|
|
463
|
+
node scripts/verify-notice.mjs <session.jsonl.zstd>
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### 调试入口
|
|
467
|
+
|
|
468
|
+
| 入口 | 内容 |
|
|
469
|
+
| --- | --- |
|
|
470
|
+
| `~/.dsh/session-complete-notify.log` | 宿主诊断日志:设置注册、重试与失败、投影注册、追加失败堆栈 |
|
|
471
|
+
| 浏览器 console `[dsh-session-notify-client]` | 客户端日志:权限状态、通知展示、设置保存 |
|
|
472
|
+
| `window.__dsch_notify_debug.readNotice(id)` | 手动读取指定会话的最新通知正文 |
|
|
473
|
+
| `window.__dsch_notify_debug.snapshotDebug(id)` | 会话尾部节点类型 + notice 数量 + 最近正文(前 200 字) |
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## 常见问题
|
|
478
|
+
|
|
479
|
+
<details>
|
|
480
|
+
<summary><b>npm install 之后为什么不自动挂载?</b></summary>
|
|
481
|
+
|
|
482
|
+
这是 DSH 官方设计:`npm install` 只把包装进依赖树,不注册插件。自动挂载的唯一途径是 `dsh plugin add` —— 它读取包内 `dsh.bundle` manifest(本插件自 0.1.3 起声明)并自动应用 `cordis.patch.yml`。参见[安装](#安装)。
|
|
483
|
+
|
|
484
|
+
</details>
|
|
485
|
+
|
|
486
|
+
<details>
|
|
487
|
+
<summary><b>为什么「中断」(interrupted)不提醒?</b></summary>
|
|
488
|
+
|
|
489
|
+
`interrupted` 是崩溃恢复后由持久化后端补写的孤儿轮次关闭标记,用户视角的「完成」不包含它(否则恢复会话会刷一屏误报)。确有需要可在宿主配置的 `reasons` 中加入。
|
|
490
|
+
|
|
491
|
+
</details>
|
|
492
|
+
|
|
493
|
+
<details>
|
|
494
|
+
<summary><b>后台会话(没打开窗口的)也会推送吗?</b></summary>
|
|
495
|
+
|
|
496
|
+
会。客户端从会话列表快照观测所有会话的 `running` 边沿;正文优先取宿主投影 —— 宿主为所有会话(含后台)维护投影单元,因此推送正文跨会话一致。投影不可用时降级为事件窗口或工作区信息。
|
|
497
|
+
|
|
498
|
+
</details>
|
|
499
|
+
|
|
500
|
+
<details>
|
|
501
|
+
<summary><b>保存设置后为什么提示刷新页面?</b></summary>
|
|
502
|
+
|
|
503
|
+
宿主在注册命名空间时读取一次设置,客户端 bundle 在页面加载时装配。保存后点「点击刷新」让两侧重新读取,新语言、模板即生效。
|
|
504
|
+
|
|
505
|
+
</details>
|
|
506
|
+
|
|
507
|
+
<details>
|
|
508
|
+
<summary><b>缓存命中率、速度数据从哪来?为什么有时是空的?</b></summary>
|
|
509
|
+
|
|
510
|
+
来自官方 `sessionProjections`(`tokenUsage`、`sessionStats`),与 dsh-web-ui 状态栏同口径。宿主读取投影快照失败或数据尚未就绪时,退回本地用量聚合估算,仍无数据则该项留空(标签插了也不显示)。另外,这两项只在自定义模板中通过 `{cache}`、`{tps}` 插入时才出现,默认文案不含。
|
|
511
|
+
|
|
512
|
+
</details>
|
|
513
|
+
|
|
514
|
+
<details>
|
|
515
|
+
<summary><b>通知正文里的错误信息太长、有换行怎么办?</b></summary>
|
|
516
|
+
|
|
517
|
+
摘要行(折叠行)与错误详情都会单行化并截断:摘要 120 字符、模板 `{error}` 80 字符、默认文案的错误详情 40 字符,超长以省略号结尾。
|
|
518
|
+
|
|
519
|
+
</details>
|
|
520
|
+
|
|
521
|
+
<details>
|
|
522
|
+
<summary><b>可以自定义系统通知的图标或声音吗?</b></summary>
|
|
523
|
+
|
|
524
|
+
当前版本使用浏览器默认通知样式,不注入自定义图标或声音,toast 为固定深色卡片。如需这些能力欢迎提 Issue 或 PR。
|
|
525
|
+
|
|
526
|
+
</details>
|
|
527
|
+
|
|
528
|
+
<details>
|
|
529
|
+
<summary><b>为什么 Edge 推不了系统通知?QQ 浏览器为什么只有页内横幅(内置推送弹窗)?</b></summary>
|
|
530
|
+
|
|
531
|
+
两者都是浏览器行为,插件无法强制:
|
|
532
|
+
|
|
533
|
+
- **Edge / Chrome**:对"不熟悉"的站点会**自动屏蔽通知**(地址栏出现「通知已屏蔽」)。点击地址栏左侧权限图标 → 网站设置 → 通知 → 允许即可恢复,之后正常弹 Windows 通知中心。也可在浏览器通知设置中关闭「自动屏蔽」。
|
|
534
|
+
- **QQ 浏览器等国产 Chromium 壳**:把 `Notification` 固定渲染为**浏览器内置的页内推送弹窗**(页面顶部/角落横幅,不经 Windows 通知中心),且无系统通知选项。三种推送方式的实际表现:
|
|
535
|
+
- `双通道` → 浏览器内置弹窗 + 插件 toast,页内两个提示;
|
|
536
|
+
- `仅系统通知` → 无效(QQ 浏览器永远渲染为页内弹窗);
|
|
537
|
+
- `仅页内提示` → 浏览器内置弹窗不出现,页内只有插件自带的小 toast(推荐)。
|
|
538
|
+
设置面板每个原因的「发送」测试按钮同样按此规则渲染。
|
|
539
|
+
- **Firefox**:窗口聚焦时通知显示为页内横幅,失焦/最小化才进系统通知中心;权限需在地址栏手动允许。
|
|
540
|
+
- 另注意:`http://IP` 访问(非安全上下文)时 `Notification` 不存在,任何浏览器都弹不了系统通知。
|
|
541
|
+
|
|
542
|
+
设置面板「通知权限」区域会实时显示当前状态与对应操作指引。
|
|
543
|
+
|
|
544
|
+
</details>
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
## 更新日志
|
|
549
|
+
|
|
550
|
+
| 版本 | 日期 | 变更 |
|
|
551
|
+
| --- | --- | --- |
|
|
552
|
+
| **0.1.11** | 2026-08-29 | 新增**自定义通知图片**:① 模板「+ 插入信息」新增**图片**标签——插入 `{image}` 并选择本地图片(**自动压缩至 512px 宽、按通知显示比例 16:9 居中裁切**,编辑器内显示为带缩略图的小标签),按原因独立上传、保存于设置文档(正文渲染时剥除,不进会话日志);② **通知大图/通知图标改为上传卡片**(空态 = 圆角矩形 + 号,点击上传;**大图 512×288(16:9 居中裁切)、图标 128×128(1:1 方形居中裁切)**;已上传显示缩略图,右上角 × 删除)——裁切保证上传的图完整显示在通知卡片中,不被系统按显示区域硬裁;③ **推送标题的「+ 插入信息」**可插入任意信息位(会话标题/用时/消耗/缓存命中/速度),不再只有会话标题;设置面板「通知图片」区显示**处理方式说明**(裁切比例)与**上传后的缩略图预览**;④ **按原因指定通知图标**(模板插入 `{icon}` 标签 + 本地上传,128×128 方形,优先于全局图标);⑤ **删除 `{image}`/`{icon}` 标签即清除该原因的图片/图标数据**;⑥ **布局优化:「正文模板 × 5」改为折叠区(默认收起保持面板简洁,头部显示已自定义条数,点击展开)**;⑦ **布局优化②:通知大图/图标上传卡片并排一行(中间留白);推送标题与按原因定制标题合并为「标题」折叠区(默认收起);折叠指示改为三角形图标(移除「展开/收起」文案,减少 i18n 负担)**;⑧ **交互优化:推送标题改为 Chip 编辑器(插入的信息显示为胶囊标签,不再暴露 `{title}` 等代码);通知大图/图标顺序调换(图标在前);「正文模板 × 5」改名为「内容」;图片/图标缩略图点击可全屏预览大图(lightbox),标签只有点 × 才删除(防误删)**;⑨ **预览统一为完整原图:上传时同时保存裁切版(通知用)与等比完整版(1024px,lightbox 查看原图用),卡片与标签的放大预览都显示未裁切的原始图像;折叠三角形图标放大**;⑩ **标题信息位修复:通知标题里的 `{duration}` `{usage}` `{error}` `{cache}` `{tps}` 会替换为会话实际值,不再泄漏代码文本(编辑时胶囊、发送时真实数据);「内容」改为一行式布局(原因标签 + 编辑器 + 「+/-」插入按钮 + 纸飞机发送按钮)**;⑪ **细节:移除内容行下方的实时预览(更紧凑);内容编辑器内边距收窄(compact);「+/-」与纸飞机按钮改矩形边框、垂直居中**;⑫ **删除体验修复:内容删空后不再复原为默认文案(改显示占位提示),且删空后光标自动回到末尾——按住 Backspace 可连续删除;「+/-」改用 SVG 线条图标(相对按钮边框精确居中);纸飞机图标逆时针旋转 30°**;⑬ **占位与默认文案:默认预设(空模板)时编辑器直接显示默认文案(所见即所推);编辑后删空显示「留空则使用默认文案」占位——改用 CSS 伪元素实现(与原生 input placeholder 一致:不可选中、不可删除),替换原可复制的占位文本**;⑭ **细节②:推送标题占位描述改为「通用推送标题,留空时则使用默认标题,优先级低于下方自定义标题」,空编辑器点击时光标移到最前(输入文字从最左开始,与原生 placeholder 一致);纸飞机图标再逆时针转 30°(共 60°);「内容」原因标签改为自适应宽度(编辑器紧贴标签文字);编辑器高度统一(box-sizing border-box + min-height 38px,与普通输入框一致)**;⑮ **细节③:原因标签统一为固定 70px 宽(内容与按原因定制标题一致);Backspace/Delete 删除标签改为手动删除并恢复光标到删除位置(不再跳到编辑器开头);发送按钮图标更换为铃铛(推送语义);自定义预设现在同时保存通知大图/图标(含完整预览版),默认预设保持留空**;⑯ **细节④:通知大图/图标上传卡片等高(统一 64px 高,大图 16:9 宽 114px);原因标签宽 70px → 60px;发送按钮图标由铃铛改为向右推送箭头;「标题」「内容」折叠区标题文字加粗**;⑰ **默认文案与标签:max-tokens 的显示统一改为「上限」(标签/默认标题/占位,5 语言同步);各原因默认文案改为「会话「{title}」已xx,请点击查看。」(5 语言,编辑器的 hint 与宿主实际渲染同步);按原因定制标题每行新增「+」插入按钮(同推送标题:仅信息标签,不含图片/图标,插入到光标处)**;⑱ **标签化与预设管理:按原因定制标题改为 Chip 编辑器(插入的信息以胶囊标签显示,不再暴露 `{title}` 等代码;禁止 `{image}`/`{icon}`——手输保持字面文本、发送时剥除);自定义预设新增「重命名」功能(选中自定义预设时出现重命名按钮,改名后下拉与当前预设同步)**;⑲ **细节⑤:Chip 编辑器文字垂直居中(行高与胶囊统一 20px、上下内边距 9px,单行文字在 38px 框内正中);「标题」「内容」折叠栏加底色填充区分(折叠头为圆角底色栏,展开内容区带左侧竖线缩进);全面核对 5 语言 86 个文案键(全部翻译齐全,修订 zh-tw「重新命名」、ko「放弃」两处用词)**;各原因「发送」测试按钮同样生效;仅系统通知通道生效(页内 toast 为文字卡片);⑳ **细节⑥:移除「标题」「内容」折叠头的底色填充;占位符文字颜色改为 rgba(127,127,127,0.5)(更淡,不再受主题变量影响)**;各原因「发送」测试按钮同样生效;仅系统通知通道生效(页内 toast 为文字卡片);㉑ **修复:移除「内容」各原因行之间的分隔横线;「内容」折叠区展开后头下方的横线补齐,与「标题」一致(全宽);退格/删除键删除胶囊时光标不再跳到开头(元素容器内按子节点序号取胶囊,含光标在胶囊后/编辑器末尾的场景);重命名「未命名」预设时自动升级为具名预设(换用新 id),下拉立即显示新名字**;各原因「发送」测试按钮同样生效;仅系统通知通道生效(页内 toast 为文字卡片);㉒ **修复:输入文字后占位提示不再残留(占位 CSS 选择器与状态属性对齐,输入即消失,文字从最左开始);上传/删除图片、图标后光标保持原位,不再跳到最前(重建 DOM 前保存光标偏移、重建后恢复);预设下拉框聚焦时不再出现白色选中态描边**;各原因「发送」测试按钮同样生效;仅系统通知通道生效(页内 toast 为文字卡片);㉓ **修复:删除标签(含图片/图标胶囊)后光标不再跳走或消失,可连贯连续删除——图片数据变化触发的重建改为按需执行(DOM 中已无该媒体胶囊且模板无对应标签时跳过重建,光标保留在原删除位置;仅上传/替换图片需要刷新缩略图时才重建),并修正光标偏移计算(胶囊统一按 1 个位置计,不深入内部文字)**;各原因「发送」测试按钮同样生效;仅系统通知通道生效(页内 toast 为文字卡片) |
|
|
553
|
+
| **0.1.10** | 2026-08-29 | 「推送标题」改为原生输入框(原生占位提示:不可复制、输入才消失、清空恢复;「+ 会话标题」在光标处插入 `{title}`);文档补充 QQ 浏览器内置推送弹窗说明(三种推送方式的实际表现 + 发送按钮测试同规则);**多语言 README**:中文设为主页,新增 English / 繁體中文 / 日本語 / 한국어 版本(顶部语言切换互链) |
|
|
554
|
+
| **0.1.9** | 2026-08-29 | 推送标题支持**按原因定制**(折叠区 UI,默认收起不臃肿;留空时各原因用差异化默认标题:任务已完成/任务出错/任务已中止/任务被阻塞/任务达到输出上限,5 语言);投影升级为对象(kind/text/title)承载 host 渲染好的标题;重置按钮**保留当前语言**;默认文案内嵌「会话标题」标签(会话「{title}」已完成,无标题自动回退);设置面板模板预览同步;「+插入信息」插入标签后不再自动折叠;删除当前使用的自定义预设自动切回默认;模板预览修复(点击不消失、输入才隐藏、清空恢复);每个原因新增「发送」按钮(一键发当前模板渲染的测试通知) |
|
|
555
|
+
| **0.1.8** | 2026-08-29 | 默认推送标题改为「任务已完成」(`{title}` 仍可引用会话标题);默认文案按结束原因差异化表达(完成紧凑括号式 / 中止·阻塞拆句 / 出错错误前置 / 上限附建议,5 语言);设置面板新增「重置」按钮一键还原默认 |
|
|
556
|
+
| **0.1.7** | 2026-08-29 | 修复 0.1.6 的设置卡片崩溃:`notificationPermissionRow`/`requestPermissionNow` 曾引用 Card 组件内 state(作用域外)导致渲染 ReferenceError、整个设置卡片消失;改为自包含 + 回调传参 |
|
|
557
|
+
| **0.1.6** | 2026-08-29 | 设置面板新增「通知权限」状态区(授权状态实时显示 + 一键请求授权按钮 + 被屏蔽时的地址栏操作指引);授权改为**用户手势内请求**(Chromium 忽略非手势自动请求,Edge 对不熟悉站点自动屏蔽通知的典型场景得以解决);FAQ 新增浏览器差异说明 |
|
|
558
|
+
| **0.1.5** | 2026-08-29 | 新增「推送方式」设置(双通道 / 仅系统通知 / 仅页内提示):解决 QQ 浏览器等 Chromium 壳把 `Notification` 渲染成页内横幅导致的双提示;`pushMode` 加入设置 schema 与设置面板 |
|
|
559
|
+
| **0.1.4** | 2026-08-28 | 补充完整卸载支持:`dispose` 生命周期收尾(host 置卸载标志抑制待追加微任务;client 清理正文轮询定时器、`__dsch_notify_debug` 钩子、toast 容器);卸载文档与 FAQ 同步 |
|
|
560
|
+
| **0.1.3** | 2026-08-28 | 声明官方 `dsh.bundle` manifest(`dsh plugin add` 一条命令自动挂载);settings 重试定时器改为 `ctx.effect()` 包装(Cordis effect 纪律);安装文档重排 |
|
|
561
|
+
| 0.1.2 | 2026-08-27 | 包更名至 `@telosmaylx` scope(npm 用户名作用域) |
|
|
562
|
+
| 0.1.1 | 2026-08-27 | GitHub、npm 安装方式文档化 |
|
|
563
|
+
| 0.1.0 | 2026-08-26 | 初始版本:会话内系统消息 + 浏览器推送 + 官方设置面板 |
|
|
564
|
+
|
|
565
|
+
---
|
|
566
|
+
|
|
567
|
+
## 贡献
|
|
568
|
+
|
|
569
|
+
欢迎 Issue 与 PR:
|
|
570
|
+
|
|
571
|
+
1. Fork 仓库并新建分支(`feat/xxx`)
|
|
572
|
+
2. 改动后运行 `npm run build` 做语法校验
|
|
573
|
+
3. 提交 PR,说明动机与验证方式
|
|
574
|
+
|
|
575
|
+
提交前请遵守 [Cordis 开发教程](https://deepseek-harness.github.io/deepseek-harness/develop/cordis-tutorial) 纪律:
|
|
576
|
+
|
|
577
|
+
- Cordis 之外的资源(定时器、订阅、watcher)必须包装在 `ctx.effect()` 中并返回 disposer;
|
|
578
|
+
- 配置项显式 `id` 防止编辑漂移;
|
|
579
|
+
- 插件须声明 `dsh.bundle` manifest 才能被 `dsh plugin add` 识别安装。
|
|
580
|
+
|
|
581
|
+
---
|
|
582
|
+
|
|
583
|
+
## 相关链接
|
|
584
|
+
|
|
585
|
+
- [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin) —— DSH 插件精选列表(投稿规范:`dsh.bundle` 是安装唯一凭证)
|
|
586
|
+
- [Cordis 开发教程](https://deepseek-harness.github.io/deepseek-harness/develop/cordis-tutorial) —— 插件开发全流程(01-07 章)
|
|
587
|
+
- [npm 包主页](https://www.npmjs.com/package/@telosmaylx/dsh-session-notify)
|
|
588
|
+
- [GitHub 仓库](https://github.com/TelosmaYLX/dsh-session-notify)
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
592
|
+
## 许可证
|
|
593
|
+
|
|
594
|
+
[MIT](./LICENSE) © dsh-session-notify contributors
|