@telosmaylx/dsh-session-notify 0.1.8 → 0.1.9
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.md +583 -577
- package/lib/client.js +153 -46
- package/lib/core.js +72 -31
- package/lib/index.js +46 -10
- package/package.json +70 -70
package/lib/index.js
CHANGED
|
@@ -36,7 +36,7 @@ import { appendFileSync } from 'node:fs'
|
|
|
36
36
|
import { join } from 'node:path'
|
|
37
37
|
import { homedir } from 'node:os'
|
|
38
38
|
import { createRequire } from 'node:module'
|
|
39
|
-
import { createTurnTracker, buildNotice, isSubagentSession, officialCacheRate, officialTps } from './core.js?v=1' // v=1: 缓存破坏——HMR 重载按 URL 键控
|
|
39
|
+
import { createTurnTracker, buildNotice, isSubagentSession, officialCacheRate, officialTps, renderTitle } from './core.js?v=1' // v=1: 缓存破坏——HMR 重载按 URL 键控
|
|
40
40
|
|
|
41
41
|
/** Cordis loader 诊断用插件名。 */
|
|
42
42
|
export const name = 'session-complete-notify'
|
|
@@ -73,7 +73,9 @@ const DEFAULT_OPTIONS = {
|
|
|
73
73
|
const DEFAULT_SETTINGS = {
|
|
74
74
|
language: 'zh',
|
|
75
75
|
templates: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '' },
|
|
76
|
-
titleTemplate: '
|
|
76
|
+
titleTemplate: '', // 空 = 未自定义全局标题,各原因使用语言默认标题(如「任务已完成」「任务出错」)
|
|
77
|
+
/** 按原因定制推送标题(空 = 用 titleTemplate 或语言默认标题)。 */
|
|
78
|
+
titleTemplates: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '' },
|
|
77
79
|
includeDuration: true,
|
|
78
80
|
includeUsage: true,
|
|
79
81
|
skipSubagents: true,
|
|
@@ -89,10 +91,16 @@ function sanitizeSettings(raw) {
|
|
|
89
91
|
for (const key of Object.keys(templates)) {
|
|
90
92
|
if (typeof templatesRaw[key] === 'string') templates[key] = templatesRaw[key]
|
|
91
93
|
}
|
|
94
|
+
const titlesRaw = src.titleTemplates && typeof src.titleTemplates === 'object' ? src.titleTemplates : {}
|
|
95
|
+
const titleTemplates = { ...DEFAULT_SETTINGS.titleTemplates }
|
|
96
|
+
for (const key of Object.keys(titleTemplates)) {
|
|
97
|
+
if (typeof titlesRaw[key] === 'string') titleTemplates[key] = titlesRaw[key]
|
|
98
|
+
}
|
|
92
99
|
return {
|
|
93
100
|
language: ['zh', 'zh-tw', 'en', 'ja', 'ko'].includes(src.language) ? src.language : 'zh',
|
|
94
101
|
templates,
|
|
95
102
|
titleTemplate: typeof src.titleTemplate === 'string' ? src.titleTemplate : '',
|
|
103
|
+
titleTemplates,
|
|
96
104
|
includeDuration: typeof src.includeDuration === 'boolean' ? src.includeDuration : true,
|
|
97
105
|
includeUsage: typeof src.includeUsage === 'boolean' ? src.includeUsage : true,
|
|
98
106
|
skipSubagents: typeof src.skipSubagents === 'boolean' ? src.skipSubagents : true,
|
|
@@ -129,7 +137,14 @@ export function apply(ctx, config = {}) {
|
|
|
129
137
|
blocked: Schema.string().default(''),
|
|
130
138
|
'max-tokens': Schema.string().default(''),
|
|
131
139
|
}),
|
|
132
|
-
titleTemplate: Schema.string().default('
|
|
140
|
+
titleTemplate: Schema.string().default(''),
|
|
141
|
+
titleTemplates: Schema.object({
|
|
142
|
+
completed: Schema.string().default(''),
|
|
143
|
+
error: Schema.string().default(''),
|
|
144
|
+
aborted: Schema.string().default(''),
|
|
145
|
+
blocked: Schema.string().default(''),
|
|
146
|
+
'max-tokens': Schema.string().default(''),
|
|
147
|
+
}),
|
|
133
148
|
includeDuration: Schema.boolean().default(true),
|
|
134
149
|
includeUsage: Schema.boolean().default(true),
|
|
135
150
|
skipSubagents: Schema.boolean().default(true),
|
|
@@ -196,17 +211,23 @@ export function apply(ctx, config = {}) {
|
|
|
196
211
|
try {
|
|
197
212
|
rootRegistry.register({
|
|
198
213
|
key: SETTINGS_NS,
|
|
199
|
-
|
|
200
|
-
|
|
214
|
+
// 投影值:{ kind: 结束原因, text: 系统消息全文, title: 该原因的推送标题(host 已渲染,含 {title} 替换)}
|
|
215
|
+
schema: z.object({ kind: z.string(), text: z.string(), title: z.string() }),
|
|
216
|
+
init: () => ({ kind: '', text: '', title: '' }),
|
|
201
217
|
apply: (state, event) => {
|
|
202
218
|
if (event.type !== 'user/message') return state
|
|
203
219
|
const src = event.data?.source ?? {}
|
|
204
220
|
if (src.kind !== 'plugin' || src.plugin !== PLUGIN_ID) return state
|
|
205
221
|
const text = ((event.data?.content ?? []).map((b) => b?.text ?? '')).join('').trim()
|
|
206
|
-
|
|
222
|
+
if (!text) return state
|
|
223
|
+
return {
|
|
224
|
+
kind: typeof src.reasonKind === 'string' ? src.reasonKind : state.kind,
|
|
225
|
+
text,
|
|
226
|
+
title: typeof src.titleText === 'string' && src.titleText ? src.titleText : state.title,
|
|
227
|
+
}
|
|
207
228
|
},
|
|
208
229
|
view: (state) => state,
|
|
209
|
-
stateVersion:
|
|
230
|
+
stateVersion: 2, // 投影值从 string 升级为对象(kind/text/title)
|
|
210
231
|
})
|
|
211
232
|
fileLog('session-projections unit registered (key=session-complete-notify)')
|
|
212
233
|
} catch (err) {
|
|
@@ -250,6 +271,12 @@ export function apply(ctx, config = {}) {
|
|
|
250
271
|
} catch (projErr) {
|
|
251
272
|
warn(ctx, `投影快照读取失败: ${projErr?.message ?? projErr}`)
|
|
252
273
|
}
|
|
274
|
+
// 标题投影缺失时从会话自身兜底(header.title / title),确保默认文案能内嵌会话标题
|
|
275
|
+
if (!titleValue) {
|
|
276
|
+
const h = session?.header ?? {}
|
|
277
|
+
titleValue = (typeof h.title === 'string' && h.title.trim()) ? h.title
|
|
278
|
+
: (typeof session?.title === 'string' && session.title.trim()) ? session.title : ''
|
|
279
|
+
}
|
|
253
280
|
const notice = buildNotice(kind, event.data.reason, {
|
|
254
281
|
...state,
|
|
255
282
|
includeDuration: true, // 标签即开关:{duration} 插了才显示
|
|
@@ -258,6 +285,8 @@ export function apply(ctx, config = {}) {
|
|
|
258
285
|
tpsValue,
|
|
259
286
|
titleValue,
|
|
260
287
|
}, { language: settings.language, templates: settings.templates })
|
|
288
|
+
// 推送标题按原因渲染:titleTemplates[kind] > titleTemplate > 语言默认(如「任务已完成」)
|
|
289
|
+
const title = renderTitle(kind, { language: settings.language, titleTemplate: settings.titleTemplate, titleTemplates: settings.titleTemplates }, titleValue)
|
|
261
290
|
// 边界约束:session/event 观察者回调运行在 turn/end 那次 append 的
|
|
262
291
|
// 发布边界之内(dsh-session 在 dispatch 前 set entry.appending,
|
|
263
292
|
// finally 中复位),此时同步 append 会被拒绝:
|
|
@@ -265,7 +294,7 @@ export function apply(ctx, config = {}) {
|
|
|
265
294
|
// 推迟到微任务——微任务队列在本次同步栈(含 finally 复位)之后才跑。
|
|
266
295
|
queueMicrotask(() => {
|
|
267
296
|
if (disposed) return // 卸载窗口内已调度的微任务:fiber 已拆除,跳过追加
|
|
268
|
-
appendNotice(ctx, session, notice)
|
|
297
|
+
appendNotice(ctx, session, notice, kind, title)
|
|
269
298
|
})
|
|
270
299
|
return
|
|
271
300
|
}
|
|
@@ -290,7 +319,7 @@ export function apply(ctx, config = {}) {
|
|
|
290
319
|
}
|
|
291
320
|
|
|
292
321
|
/** 把系统消息追加进会话日志(失败只记日志,绝不抛出破坏 event 火线)。 */
|
|
293
|
-
function appendNotice(ctx, session, notice) {
|
|
322
|
+
function appendNotice(ctx, session, notice, kind, title) {
|
|
294
323
|
try {
|
|
295
324
|
session.append(
|
|
296
325
|
'user/message',
|
|
@@ -298,7 +327,14 @@ function appendNotice(ctx, session, notice) {
|
|
|
298
327
|
id: newId(),
|
|
299
328
|
role: 'user',
|
|
300
329
|
content: [{ type: 'text', text: notice.text }],
|
|
301
|
-
source: {
|
|
330
|
+
source: {
|
|
331
|
+
kind: 'plugin',
|
|
332
|
+
plugin: PLUGIN_ID,
|
|
333
|
+
form: 'notice',
|
|
334
|
+
summary: notice.summary,
|
|
335
|
+
reasonKind: typeof kind === 'string' ? kind : '', // 投影 apply 取用
|
|
336
|
+
titleText: typeof title === 'string' ? title : '', // 投影 apply 取用(host 渲染好的推送标题)
|
|
337
|
+
},
|
|
302
338
|
},
|
|
303
339
|
{ surfaceOp: 'append' },
|
|
304
340
|
)
|
package/package.json
CHANGED
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@telosmaylx/dsh-session-notify",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "DSH session completion notifier: appends a plugin system message to the session log on turn/end and pushes browser notifications (Web Notification + toast), with a fully customizable official settings panel (presets, 5-language templates, cache-hit rate & tok/s from official projections).",
|
|
5
|
-
"private": false,
|
|
6
|
-
"type": "module",
|
|
7
|
-
"main": "./lib/index.js",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"default": "./lib/index.js"
|
|
11
|
-
},
|
|
12
|
-
"./client": {
|
|
13
|
-
"default": "./lib/client.js"
|
|
14
|
-
},
|
|
15
|
-
"./core": {
|
|
16
|
-
"default": "./lib/core.js"
|
|
17
|
-
},
|
|
18
|
-
"./package.json": "./package.json"
|
|
19
|
-
},
|
|
20
|
-
"files": [
|
|
21
|
-
"lib",
|
|
22
|
-
"scripts",
|
|
23
|
-
"cordis.patch.yml",
|
|
24
|
-
"README.md",
|
|
25
|
-
"LICENSE"
|
|
26
|
-
],
|
|
27
|
-
"publishConfig": {
|
|
28
|
-
"access": "public"
|
|
29
|
-
},
|
|
30
|
-
"keywords": [
|
|
31
|
-
"deepseek-harness",
|
|
32
|
-
"dsh",
|
|
33
|
-
"dsh-plugin",
|
|
34
|
-
"session-notify",
|
|
35
|
-
"notification",
|
|
36
|
-
"completion-reminder",
|
|
37
|
-
"agent"
|
|
38
|
-
],
|
|
39
|
-
"author": "dsh-session-notify contributors",
|
|
40
|
-
"license": "MIT",
|
|
41
|
-
"repository": {
|
|
42
|
-
"type": "git",
|
|
43
|
-
"url": "git+https://github.com/TelosmaYLX/dsh-session-notify.git"
|
|
44
|
-
},
|
|
45
|
-
"homepage": "https://github.com/TelosmaYLX/dsh-session-notify#readme",
|
|
46
|
-
"bugs": {
|
|
47
|
-
"url": "https://github.com/TelosmaYLX/dsh-session-notify/issues"
|
|
48
|
-
},
|
|
49
|
-
"peerDependencies": {
|
|
50
|
-
"cordis": ">=4.0.0-rc <5"
|
|
51
|
-
},
|
|
52
|
-
"engines": {
|
|
53
|
-
"node": ">=22"
|
|
54
|
-
},
|
|
55
|
-
"dsh": {
|
|
56
|
-
"bundle": {
|
|
57
|
-
"patch": "./cordis.patch.yml"
|
|
58
|
-
},
|
|
59
|
-
"client": {
|
|
60
|
-
"inject": [
|
|
61
|
-
"@deepseek-ai/dsh-client-runtime"
|
|
62
|
-
],
|
|
63
|
-
"platform": "web"
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
"scripts": {
|
|
67
|
-
"build": "bash scripts/build.sh || node --check lib/index.js && node --check lib/core.js && node --check lib/client.js",
|
|
68
|
-
"prepublishOnly": "node --check lib/index.js && node --check lib/core.js && node --check lib/client.js"
|
|
69
|
-
}
|
|
70
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@telosmaylx/dsh-session-notify",
|
|
3
|
+
"version": "0.1.9",
|
|
4
|
+
"description": "DSH session completion notifier: appends a plugin system message to the session log on turn/end and pushes browser notifications (Web Notification + toast), with a fully customizable official settings panel (presets, 5-language templates, cache-hit rate & tok/s from official projections).",
|
|
5
|
+
"private": false,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./lib/index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"default": "./lib/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./client": {
|
|
13
|
+
"default": "./lib/client.js"
|
|
14
|
+
},
|
|
15
|
+
"./core": {
|
|
16
|
+
"default": "./lib/core.js"
|
|
17
|
+
},
|
|
18
|
+
"./package.json": "./package.json"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"lib",
|
|
22
|
+
"scripts",
|
|
23
|
+
"cordis.patch.yml",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE"
|
|
26
|
+
],
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"deepseek-harness",
|
|
32
|
+
"dsh",
|
|
33
|
+
"dsh-plugin",
|
|
34
|
+
"session-notify",
|
|
35
|
+
"notification",
|
|
36
|
+
"completion-reminder",
|
|
37
|
+
"agent"
|
|
38
|
+
],
|
|
39
|
+
"author": "dsh-session-notify contributors",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/TelosmaYLX/dsh-session-notify.git"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/TelosmaYLX/dsh-session-notify#readme",
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/TelosmaYLX/dsh-session-notify/issues"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"cordis": ">=4.0.0-rc <5"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=22"
|
|
54
|
+
},
|
|
55
|
+
"dsh": {
|
|
56
|
+
"bundle": {
|
|
57
|
+
"patch": "./cordis.patch.yml"
|
|
58
|
+
},
|
|
59
|
+
"client": {
|
|
60
|
+
"inject": [
|
|
61
|
+
"@deepseek-ai/dsh-client-runtime"
|
|
62
|
+
],
|
|
63
|
+
"platform": "web"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"scripts": {
|
|
67
|
+
"build": "bash scripts/build.sh || node --check lib/index.js && node --check lib/core.js && node --check lib/client.js",
|
|
68
|
+
"prepublishOnly": "node --check lib/index.js && node --check lib/core.js && node --check lib/client.js"
|
|
69
|
+
}
|
|
70
|
+
}
|