@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/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
- schema: z.string(),
200
- init: () => '',
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
- return text || state
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: 1,
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: { kind: 'plugin', plugin: PLUGIN_ID, form: 'notice', summary: notice.summary },
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.8",
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
+ }