@telosmaylx/dsh-session-notify 0.1.7 → 0.1.8
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 +12 -5
- package/lib/client.js +47 -14
- package/lib/core.js +62 -1
- package/lib/index.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
- **5 种语言**:简体中文、繁體中文、English、日本語、한국어 —— 通知文案、时长与用量措辞、设置面板界面全部随语言切换(切换即时重渲染)。
|
|
66
66
|
- **可视化模板编辑器**(Chip 胶囊编辑器):动态信息渲染为内联胶囊(占位符代码不露出),「+ 插入信息」在光标处插入(可插到文字中间),点击胶囊移除,每栏带实时预览(信息以示例值流入正文)。
|
|
67
67
|
- **预设系统**:内置「默认」预设作为基线;当前配置可另存为自定义预设(`localStorage` 持久化),支持自动编号的未命名预设(`未命名`、`未命名 2`…)、「来自:xxx · 已修改」来源指示、删除预设。
|
|
68
|
-
-
|
|
68
|
+
- **推送标题模板**:默认「任务已完成」;`{title}` 引用会话标题。
|
|
69
69
|
|
|
70
70
|
### 与官方口径同源
|
|
71
71
|
|
|
@@ -228,15 +228,18 @@ dsh plugin --profile web remove @telosmaylx/dsh-session-notify
|
|
|
228
228
|
|
|
229
229
|
### 通知示例
|
|
230
230
|
|
|
231
|
-
以下均由 `lib/core.js` 的 `buildNotice`
|
|
231
|
+
以下均由 `lib/core.js` 的 `buildNotice` 实际生成。默认文案按结束原因**差异化表达**(非清一色句式):
|
|
232
232
|
|
|
233
233
|
简体中文默认文案:
|
|
234
234
|
|
|
235
235
|
```text
|
|
236
|
-
会话已完成(用时 3 分 25 秒,消耗 12,400 输入 / 35,600 输出)。
|
|
236
|
+
会话已完成(用时 3 分 25 秒,消耗 12,400 输入 / 35,600 输出)。 ← 完成:括号紧凑式
|
|
237
|
+
会话已中止。用时 3 分 25 秒,消耗 12,400 输入 / 35,600 输出。 ← 中止:句号拆句
|
|
238
|
+
会话被阻塞。用时 3 分 25 秒,消耗 12,400 输入 / 35,600 输出。 ← 阻塞:句号拆句
|
|
239
|
+
会话达到输出上限。用时 3 分 25 秒,消耗 12,400 输入 / 35,600 输出,建议拆分任务后重试。 ← 上限:附建议
|
|
237
240
|
```
|
|
238
241
|
|
|
239
|
-
|
|
242
|
+
出错时错误详情前置(单行化,超过 40 字符截断):
|
|
240
243
|
|
|
241
244
|
```text
|
|
242
245
|
会话出错:connection timeout(用时 12 秒)。
|
|
@@ -246,6 +249,7 @@ English 默认文案:
|
|
|
246
249
|
|
|
247
250
|
```text
|
|
248
251
|
Session completed (took 3m25s, used 12,400 in / 35,600 out).
|
|
252
|
+
Session hit the output-token cap. Took 3m25s, used 12,400 in / 35,600 out — consider splitting the task.
|
|
249
253
|
```
|
|
250
254
|
|
|
251
255
|
自定义模板(在设置面板编辑,本例用到全部信息位):
|
|
@@ -294,11 +298,12 @@ Session completed (took 3m25s, used 1,240 in / 3,560 out).
|
|
|
294
298
|
| 预设 | 下拉选择内置或自定义预设;「新增」把当前配置另存为自定义预设;当前预设可「删除」 |
|
|
295
299
|
| 语言 | 5 种语言单选,切换即时重渲染整个面板 |
|
|
296
300
|
| 推送方式 | 三选一:双通道(系统通知 + 页内提示,默认)/ 仅系统通知 / 仅页内提示 |
|
|
297
|
-
| 推送标题 |
|
|
301
|
+
| 推送标题 | 默认「任务已完成」;`{title}` 引用会话标题 |
|
|
298
302
|
| 模板 × 5 | 每条结束原因(完成、出错、中止、阻塞、输出上限)独立一个 Chip 编辑器:文字 + 内联信息胶囊,光标处插入、点击移除、实时预览 |
|
|
299
303
|
| 跳过子代理会话 | 复选框(保存时一并写入设置文档) |
|
|
300
304
|
| 通知权限 | 状态实时显示:已授权(绿)/ 尚未授权(附「请求授权」按钮)/ 已被浏览器屏蔽(附地址栏操作指引)/ 环境不支持 |
|
|
301
305
|
| 保存 | 写入宿主设置文档(`language` / `templates` / `titleTemplate` / `pushMode`);保存后显示「点击刷新」链接 |
|
|
306
|
+
| 重置 | 一键把上述所有设置还原为默认值(语言中文、标题「任务已完成」、模板清空、双通道)并立即保存 |
|
|
302
307
|
|
|
303
308
|
> [!NOTE]
|
|
304
309
|
> 「推送方式」的取舍:`dual`(默认)同时弹 Windows 系统通知与页内 toast,toast 是保底通道,防止系统通知被平台静默(专注助手、通知横幅关闭)。但 QQ 浏览器等 Chromium 壳浏览器会把 `Notification` 渲染成页内横幅而非 Windows 通知中心——此时 `dual` 会造成页内两个提示。这类浏览器请选「仅页内提示」(不再调用 `Notification`,页内只有一个小 toast)。
|
|
@@ -530,6 +535,8 @@ node scripts/verify-notice.mjs <session.jsonl.zstd>
|
|
|
530
535
|
|
|
531
536
|
| 版本 | 日期 | 变更 |
|
|
532
537
|
| --- | --- | --- |
|
|
538
|
+
| **0.1.8** | 2026-08-29 | 默认推送标题改为「任务已完成」(`{title}` 仍可引用会话标题);默认文案按结束原因差异化表达(完成紧凑括号式 / 中止·阻塞拆句 / 出错错误前置 / 上限附建议,5 语言);设置面板新增「重置」按钮一键还原默认 |
|
|
539
|
+
| **0.1.7** | 2026-08-29 | 修复 0.1.6 的设置卡片崩溃:`notificationPermissionRow`/`requestPermissionNow` 曾引用 Card 组件内 state(作用域外)导致渲染 ReferenceError、整个设置卡片消失;改为自包含 + 回调传参 |
|
|
533
540
|
| **0.1.6** | 2026-08-29 | 设置面板新增「通知权限」状态区(授权状态实时显示 + 一键请求授权按钮 + 被屏蔽时的地址栏操作指引);授权改为**用户手势内请求**(Chromium 忽略非手势自动请求,Edge 对不熟悉站点自动屏蔽通知的典型场景得以解决);FAQ 新增浏览器差异说明 |
|
|
534
541
|
| **0.1.5** | 2026-08-29 | 新增「推送方式」设置(双通道 / 仅系统通知 / 仅页内提示):解决 QQ 浏览器等 Chromium 壳把 `Notification` 渲染成页内横幅导致的双提示;`pushMode` 加入设置 schema 与设置面板 |
|
|
535
542
|
| **0.1.4** | 2026-08-28 | 补充完整卸载支持:`dispose` 生命周期收尾(host 置卸载标志抑制待追加微任务;client 清理正文轮询定时器、`__dsch_notify_debug` 钩子、toast 容器);卸载文档与 FAQ 同步 |
|
package/lib/client.js
CHANGED
|
@@ -45,7 +45,7 @@ window.__ModuleLoader__.load({
|
|
|
45
45
|
title: '会话完成提醒', subtitle: '完成推送的语言与文案模板(保存后刷新生效)',
|
|
46
46
|
preset: '预设', choosePreset: '选择预设…', language: '语言',
|
|
47
47
|
fields: { completed: '完成', error: '出错', aborted: '中止', blocked: '阻塞', 'max-tokens': '输出上限' },
|
|
48
|
-
titleLabel: '推送标题', titleHint: '
|
|
48
|
+
titleLabel: '推送标题', titleHint: '默认「任务已完成」;插入 {title} 使用会话标题',
|
|
49
49
|
kindLabels: { completed: '会话已完成', error: '会话出错', aborted: '会话已中止', blocked: '会话被阻塞', 'max-tokens': '会话达到输出上限' },
|
|
50
50
|
tokens: { title: '会话标题', label: '完成标签', duration: '用时', usage: '消耗', error: '错误', cache: '缓存命中', tps: '速度 TPS' },
|
|
51
51
|
samples: { title: '示例会话', label: '会话已完成', duration: '12 秒', usage: '1,240 输入 / 3,560 输出', error: '连接超时', cache: '96.5%', tps: '92 tok/s' },
|
|
@@ -54,7 +54,7 @@ window.__ModuleLoader__.load({
|
|
|
54
54
|
insertInfo: '+ 插入信息', insertTitle: '在光标处插入信息', preview: '预览:',
|
|
55
55
|
skipSubagents: '跳过子代理会话',
|
|
56
56
|
pushMode: '推送方式', pushDual: '系统通知 + 页内提示', pushSystem: '仅系统通知', pushToast: '仅页内提示',
|
|
57
|
-
discard: '放弃', save: '保存', saving: '保存中…', saved: '已保存 ✓ · 刷新页面后生效', saveFailed: '保存失败:', refresh: '点击刷新',
|
|
57
|
+
discard: '放弃', save: '保存', saving: '保存中…', saved: '已保存 ✓ · 刷新页面后生效', saveFailed: '保存失败:', refresh: '点击刷新', reset: '重置', resetDone: '已重置为默认值 · 刷新页面后生效',
|
|
58
58
|
permTitle: '通知权限', permGranted: '已授权:系统通知可用', permDefault: '尚未授权', permDenied: '已被浏览器屏蔽', permUnsupported: '当前环境不支持系统通知',
|
|
59
59
|
permDefaultHint: '点击「请求授权」;若浏览器未弹出询问,请用地址栏权限图标手动允许', permDeniedHint: '浏览器阻止了本网站的通知:点击地址栏左侧权限图标 → 网站设置 → 通知 → 允许,然后刷新页面', permUnsupportedHint: '系统通知需要 HTTPS 或 localhost 访问;可改用「仅页内提示」', permRequest: '请求授权',
|
|
60
60
|
saveAs: '新增', update: '修改', remove: '删除', presetNamePlaceholder: '预设名称', confirm: '确定', cancel: '取消', customSaved: '自定义预设已保存', customUpdated: '自定义预设已更新', customDeleted: '自定义预设已删除', saveAsTitle: '将当前配置另存为自定义预设', updateTitle: '更新当前自定义预设', removeTitle: '删除当前自定义预设', fromPreset: '来自:', modifiedSuffix: ' · 已修改',
|
|
@@ -65,7 +65,7 @@ window.__ModuleLoader__.load({
|
|
|
65
65
|
title: '會話完成提醒', subtitle: '完成推送的語言與文案模板(儲存後重新整理生效)',
|
|
66
66
|
preset: '預設', choosePreset: '選擇預設…', language: '語言',
|
|
67
67
|
fields: { completed: '完成', error: '出錯', aborted: '中止', blocked: '阻塞', 'max-tokens': '輸出上限' },
|
|
68
|
-
titleLabel: '推送標題', titleHint: '
|
|
68
|
+
titleLabel: '推送標題', titleHint: '預設「任務已完成」;插入 {title} 使用會話標題',
|
|
69
69
|
kindLabels: { completed: '會話已完成', error: '會話出錯', aborted: '會話已中止', blocked: '會話被阻塞', 'max-tokens': '會話達到輸出上限' },
|
|
70
70
|
tokens: { title: '會話標題', label: '完成標籤', duration: '用時', usage: '消耗', error: '錯誤', cache: '快取命中', tps: '速度 TPS' },
|
|
71
71
|
samples: { title: '範例會話', label: '會話已完成', duration: '12 秒', usage: '1,240 輸入 / 3,560 輸出', error: '連線逾時', cache: '96.5%', tps: '92 tok/s' },
|
|
@@ -74,7 +74,7 @@ window.__ModuleLoader__.load({
|
|
|
74
74
|
insertInfo: '+ 插入資訊', insertTitle: '在游標處插入資訊', preview: '預覽:',
|
|
75
75
|
skipSubagents: '跳過子代理會話',
|
|
76
76
|
pushMode: '推送方式', pushDual: '系統通知 + 頁內提示', pushSystem: '僅系統通知', pushToast: '僅頁內提示',
|
|
77
|
-
discard: '放棄', save: '儲存', saving: '儲存中…', saved: '已儲存 ✓ · 重新整理頁面後生效', saveFailed: '儲存失敗:', refresh: '點擊重新整理',
|
|
77
|
+
discard: '放棄', save: '儲存', saving: '儲存中…', saved: '已儲存 ✓ · 重新整理頁面後生效', saveFailed: '儲存失敗:', refresh: '點擊重新整理', reset: '重置', resetDone: '已重置為預設值 · 重新整理頁面後生效',
|
|
78
78
|
permTitle: '通知權限', permGranted: '已授權:系統通知可用', permDefault: '尚未授權', permDenied: '已被瀏覽器封鎖', permUnsupported: '目前環境不支援系統通知',
|
|
79
79
|
permDefaultHint: '點擊「請求授權」;若瀏覽器未彈出詢問,請用網址列權限圖示手動允許', permDeniedHint: '瀏覽器封鎖了本網站的通知:點擊網址列左側權限圖示 → 網站設定 → 通知 → 允許,然後重新整理頁面', permUnsupportedHint: '系統通知需要 HTTPS 或 localhost 存取;可改用「僅頁內提示」', permRequest: '請求授權',
|
|
80
80
|
saveAs: '新增', update: '修改', remove: '刪除', presetNamePlaceholder: '預設名稱', confirm: '確定', cancel: '取消', customSaved: '自訂預設已儲存', customUpdated: '自訂預設已更新', customDeleted: '自訂預設已刪除', saveAsTitle: '將當前設定另存為自訂預設', updateTitle: '更新目前自訂預設', removeTitle: '刪除目前自訂預設', fromPreset: '來自:', modifiedSuffix: ' · 已修改',
|
|
@@ -85,7 +85,7 @@ window.__ModuleLoader__.load({
|
|
|
85
85
|
title: 'Session completion alert', subtitle: 'Language & message templates for completion pushes (refresh after save)',
|
|
86
86
|
preset: 'Preset', choosePreset: 'Choose preset…', language: 'Language',
|
|
87
87
|
fields: { completed: 'Completed', error: 'Error', aborted: 'Aborted', blocked: 'Blocked', 'max-tokens': 'Token cap' },
|
|
88
|
-
titleLabel: 'Push title', titleHint: '
|
|
88
|
+
titleLabel: 'Push title', titleHint: 'Defaults to "Task completed"; insert {title} for the session title',
|
|
89
89
|
kindLabels: { completed: 'Session completed', error: 'Session failed', aborted: 'Session aborted', blocked: 'Session blocked', 'max-tokens': 'Session hit the output-token cap' },
|
|
90
90
|
tokens: { title: 'Session title', label: 'Label', duration: 'Duration', usage: 'Usage', error: 'Error', cache: 'Cache hit', tps: 'Speed TPS' },
|
|
91
91
|
samples: { title: 'Example session', label: 'Session completed', duration: '12s', usage: '1,240 in / 3,560 out', error: 'connection timeout', cache: '96.5%', tps: '92 tok/s' },
|
|
@@ -94,7 +94,7 @@ window.__ModuleLoader__.load({
|
|
|
94
94
|
insertInfo: '+ Insert info', insertTitle: 'Insert info at cursor', preview: 'Preview: ',
|
|
95
95
|
skipSubagents: 'Skip subagent sessions',
|
|
96
96
|
pushMode: 'Push channel', pushDual: 'System + in-page', pushSystem: 'System only', pushToast: 'In-page only',
|
|
97
|
-
discard: 'Discard', save: 'Save', saving: 'Saving…', saved: 'Saved ✓ · refresh page to apply', saveFailed: 'Save failed: ', refresh: 'Refresh',
|
|
97
|
+
discard: 'Discard', save: 'Save', saving: 'Saving…', saved: 'Saved ✓ · refresh page to apply', saveFailed: 'Save failed: ', refresh: 'Refresh', reset: 'Reset', resetDone: 'Reset to defaults ✓ · refresh page to apply',
|
|
98
98
|
permTitle: 'Notification permission', permGranted: 'Granted: system notifications available', permDefault: 'Not yet granted', permDenied: 'Blocked by browser', permUnsupported: 'System notifications not supported here',
|
|
99
99
|
permDefaultHint: 'Click "Request"; if the browser shows no prompt, allow via the address-bar permissions icon', permDeniedHint: 'This browser blocked notifications for this site: click the address-bar permissions icon → Site settings → Notifications → Allow, then reload', permUnsupportedHint: 'System notifications require HTTPS or localhost; use "In-page only" instead', permRequest: 'Request',
|
|
100
100
|
saveAs: 'New', update: 'Edit', remove: 'Delete', presetNamePlaceholder: 'Preset name', confirm: 'OK', cancel: 'Cancel', customSaved: 'Custom preset saved', customUpdated: 'Custom preset updated', customDeleted: 'Custom preset deleted', saveAsTitle: 'Save current config as custom preset', updateTitle: 'Update current custom preset', removeTitle: 'Delete current custom preset', fromPreset: 'From: ', modifiedSuffix: ' · modified',
|
|
@@ -105,7 +105,7 @@ window.__ModuleLoader__.load({
|
|
|
105
105
|
title: 'セッション完了通知', subtitle: '完了プッシュの言語とメッセージテンプレート(保存後に再読み込みで反映)',
|
|
106
106
|
preset: 'プリセット', choosePreset: 'プリセットを選択…', language: '言語',
|
|
107
107
|
fields: { completed: '完了', error: 'エラー', aborted: '中止', blocked: 'ブロック', 'max-tokens': 'トークン上限' },
|
|
108
|
-
titleLabel: 'プッシュタイトル', titleHint: '
|
|
108
|
+
titleLabel: 'プッシュタイトル', titleHint: 'デフォルトは「タスク完了」;{title} でセッションタイトルを使用',
|
|
109
109
|
kindLabels: { completed: 'セッション完了', error: 'セッションエラー', aborted: 'セッション中止', blocked: 'セッションがブロックされました', 'max-tokens': '出力トークン上限に到達' },
|
|
110
110
|
tokens: { title: 'セッションタイトル', label: '完了ラベル', duration: '所要時間', usage: '消費', error: 'エラー', cache: 'キャッシュヒット', tps: '速度 TPS' },
|
|
111
111
|
samples: { title: 'サンプルセッション', label: 'セッション完了', duration: '12 秒', usage: '1,240 入力 / 3,560 出力', error: '接続タイムアウト', cache: '96.5%', tps: '92 tok/s' },
|
|
@@ -114,7 +114,7 @@ window.__ModuleLoader__.load({
|
|
|
114
114
|
insertInfo: '+ 情報を挿入', insertTitle: 'カーソル位置に情報を挿入', preview: 'プレビュー:',
|
|
115
115
|
skipSubagents: 'サブエージェントセッションをスキップ',
|
|
116
116
|
pushMode: '通知チャネル', pushDual: 'システム+ページ内', pushSystem: 'システムのみ', pushToast: 'ページ内のみ',
|
|
117
|
-
discard: '破棄', save: '保存', saving: '保存中…', saved: '保存しました ✓ · ページを再読み込み', saveFailed: '保存失敗:', refresh: '再読み込み',
|
|
117
|
+
discard: '破棄', save: '保存', saving: '保存中…', saved: '保存しました ✓ · ページを再読み込み', saveFailed: '保存失敗:', refresh: '再読み込み', reset: 'リセット', resetDone: 'デフォルトに戻しました ✓ · ページを再読み込み',
|
|
118
118
|
permTitle: '通知権限', permGranted: '許可済み:システム通知が利用可能', permDefault: '未許可', permDenied: 'ブラウザがブロック', permUnsupported: 'この環境ではシステム通知を利用できません',
|
|
119
119
|
permDefaultHint: '「許可をリクエスト」をクリック。ブラウザに確認が出ない場合は、アドレスバーの権限アイコンから手動で許可', permDeniedHint: 'このサイトの通知がブロックされています:アドレスバー左の権限アイコン → サイト設定 → 通知 → 許可 → ページを再読み込み', permUnsupportedHint: 'システム通知には HTTPS または localhost が必要です。「ページ内のみ」を推奨', permRequest: '許可をリクエスト',
|
|
120
120
|
saveAs: '新規', update: '編集', remove: '削除', presetNamePlaceholder: 'プリセット名', confirm: '決定', cancel: 'キャンセル', customSaved: 'カスタムプリセットを保存しました', customUpdated: 'カスタムプリセットを更新しました', customDeleted: 'カスタムプリセットを削除しました', saveAsTitle: '現在の設定をカスタムプリセットとして保存', updateTitle: '現在のカスタムプリセットを更新', removeTitle: '現在のカスタムプリセットを削除', fromPreset: '由来:', modifiedSuffix: ' · 変更あり',
|
|
@@ -125,7 +125,7 @@ window.__ModuleLoader__.load({
|
|
|
125
125
|
title: '세션 완료 알림', subtitle: '완료 푸시의 언어 및 메시지 템플릿(저장 후 새로고침 시 적용)',
|
|
126
126
|
preset: '프리셋', choosePreset: '프리셋 선택…', language: '언어',
|
|
127
127
|
fields: { completed: '완료', error: '오류', aborted: '중단', blocked: '차단', 'max-tokens': '토큰 한도' },
|
|
128
|
-
titleLabel: '푸시 제목', titleHint: '
|
|
128
|
+
titleLabel: '푸시 제목', titleHint: '기본값은 「작업 완료」;{title} 로 세션 제목 사용',
|
|
129
129
|
kindLabels: { completed: '세션 완료', error: '세션 오류', aborted: '세션 중단됨', blocked: '세션 차단됨', 'max-tokens': '출력 토큰 한도 도달' },
|
|
130
130
|
tokens: { title: '세션 제목', label: '완료 라벨', duration: '소요 시간', usage: '소모', error: '오류', cache: '캐시 히트', tps: '속도 TPS' },
|
|
131
131
|
samples: { title: '예시 세션', label: '세션 완료', duration: '12초', usage: '1,240 입력 / 3,560 출력', error: '연결 시간 초과', cache: '96.5%', tps: '92 tok/s' },
|
|
@@ -134,7 +134,7 @@ window.__ModuleLoader__.load({
|
|
|
134
134
|
insertInfo: '+ 정보 삽입', insertTitle: '커서 위치에 정보 삽입', preview: '미리보기: ',
|
|
135
135
|
skipSubagents: '하위 에이전트 세션 건너뛰기',
|
|
136
136
|
pushMode: '알림 채널', pushDual: '시스템+페이지 내', pushSystem: '시스템만', pushToast: '페이지 내만',
|
|
137
|
-
discard: '취소', save: '저장', saving: '저장 중…', saved: '저장됨 ✓ · 새로고침 후 적용', saveFailed: '저장 실패: ', refresh: '새로고침',
|
|
137
|
+
discard: '취소', save: '저장', saving: '저장 중…', saved: '저장됨 ✓ · 새로고침 후 적용', saveFailed: '저장 실패: ', refresh: '새로고침', reset: '초기화', resetDone: '기본값으로 초기화됨 ✓ · 새로고침 후 적용',
|
|
138
138
|
permTitle: '알림 권한', permGranted: '허용됨: 시스템 알림 사용 가능', permDefault: '아직 허용되지 않음', permDenied: '브라우저에서 차단됨', permUnsupported: '이 환경에서는 시스템 알림을 사용할 수 없음',
|
|
139
139
|
permDefaultHint: '「권한 요청」클릭. 브라우저에 확인이 없으면 주소 표시줄 권한 아이콘에서 수동 허용', permDeniedHint: '이 사이트의 알림이 차단되었습니다: 주소 표시줄 왼쪽 권한 아이콘 → 사이트 설정 → 알림 → 허용 후 새로고침', permUnsupportedHint: '시스템 알림은 HTTPS 또는 localhost가 필요합니다. 「페이지 내만」사용 권장', permRequest: '권한 요청',
|
|
140
140
|
saveAs: '추가', update: '수정', remove: '삭제', presetNamePlaceholder: '프리셋 이름', confirm: '확인', cancel: '취소', customSaved: '사용자 지정 프리셋 저장됨', customUpdated: '사용자 지정 프리셋 업데이트됨', customDeleted: '사용자 지정 프리셋 삭제됨', saveAsTitle: '현재 구성을 사용자 지정 프리셋으로 저장', updateTitle: '현재 사용자 지정 프리셋 업데이트', removeTitle: '현재 사용자 지정 프리셋 삭제', fromPreset: '출처: ', modifiedSuffix: ' · 수정됨',
|
|
@@ -217,9 +217,9 @@ window.__ModuleLoader__.load({
|
|
|
217
217
|
return 'dual'
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
/**
|
|
220
|
+
/** 推送标题:默认「任务已完成」;用户模板可用 {title} 引用会话标题;无通知时附带完成标记。 */
|
|
221
221
|
function pushTitle(name, suffix) {
|
|
222
|
-
var tpl = '
|
|
222
|
+
var tpl = '任务已完成'
|
|
223
223
|
try {
|
|
224
224
|
if (notifyScope) {
|
|
225
225
|
var st = notifyScope.getSnapshot()
|
|
@@ -227,7 +227,7 @@ window.__ModuleLoader__.load({
|
|
|
227
227
|
}
|
|
228
228
|
} catch (e) { /* 默认 */ }
|
|
229
229
|
var out = String(tpl).replaceAll('{title}', name).trim()
|
|
230
|
-
if (out === '') out =
|
|
230
|
+
if (out === '') out = '任务已完成'
|
|
231
231
|
return out + (suffix || '')
|
|
232
232
|
}
|
|
233
233
|
|
|
@@ -505,9 +505,17 @@ window.__ModuleLoader__.load({
|
|
|
505
505
|
|
|
506
506
|
/** 系统预设:仅保留「默认」(作为基线,其余以自定义预设承载)。 */
|
|
507
507
|
var PRESETS = [
|
|
508
|
-
{ id: 'default', labelKey: 'default', language: 'zh', titleTemplate: '', templates: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '' } },
|
|
508
|
+
{ id: 'default', labelKey: 'default', language: 'zh', titleTemplate: '任务已完成', templates: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '' } },
|
|
509
509
|
]
|
|
510
510
|
|
|
511
|
+
/** 重置目标:与宿主 DEFAULT_SETTINGS 一致(设置面板可编辑字段子集)。 */
|
|
512
|
+
var DEFAULT_FLAT = {
|
|
513
|
+
language: 'zh',
|
|
514
|
+
titleTemplate: '任务已完成',
|
|
515
|
+
pushMode: 'dual',
|
|
516
|
+
templates: { completed: '', error: '', aborted: '', blocked: '', 'max-tokens': '' },
|
|
517
|
+
}
|
|
518
|
+
|
|
511
519
|
/** 本地存储的用户自定义预设库。 */
|
|
512
520
|
var CUSTOM_PRESETS_KEY = 'dsh-scn-custom-presets'
|
|
513
521
|
function loadCustomPresets() {
|
|
@@ -1072,6 +1080,27 @@ window.__ModuleLoader__.load({
|
|
|
1072
1080
|
})
|
|
1073
1081
|
}
|
|
1074
1082
|
|
|
1083
|
+
/** 一键重置:把设置还原为默认值(与宿主 DEFAULT_SETTINGS 一致)并立即保存。 */
|
|
1084
|
+
function resetAll() {
|
|
1085
|
+
var def = DEFAULT_FLAT
|
|
1086
|
+
setNote(t.saving)
|
|
1087
|
+
var tasks = [
|
|
1088
|
+
scope.set('language', def.language),
|
|
1089
|
+
scope.set('templates', def.templates),
|
|
1090
|
+
scope.set('titleTemplate', def.titleTemplate),
|
|
1091
|
+
scope.set('pushMode', def.pushMode),
|
|
1092
|
+
]
|
|
1093
|
+
Promise.all(tasks).then(function () {
|
|
1094
|
+
setDraft(null)
|
|
1095
|
+
setNote(t.resetDone)
|
|
1096
|
+
setJustSaved(true)
|
|
1097
|
+
log('settings reset to defaults')
|
|
1098
|
+
}).catch(function (e) {
|
|
1099
|
+
setNote(t.saveFailed + (e && e.message ? e.message : e))
|
|
1100
|
+
log('settings reset failed: ' + (e && e.message ? e.message : e))
|
|
1101
|
+
})
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1075
1104
|
function discard() {
|
|
1076
1105
|
setDraft(null)
|
|
1077
1106
|
setNote('')
|
|
@@ -1277,6 +1306,10 @@ window.__ModuleLoader__.load({
|
|
|
1277
1306
|
}, t.refresh)
|
|
1278
1307
|
: null,
|
|
1279
1308
|
),
|
|
1309
|
+
h('button', {
|
|
1310
|
+
type: 'button', disabled: note === t.saving, onClick: resetAll,
|
|
1311
|
+
style: Object.assign({}, GHOST, { opacity: note === t.saving ? 0.4 : 1 }),
|
|
1312
|
+
}, t.reset),
|
|
1280
1313
|
h('button', {
|
|
1281
1314
|
type: 'button', disabled: !dirty || note === t.saving, onClick: discard,
|
|
1282
1315
|
style: Object.assign({}, GHOST, { opacity: dirty ? 1 : 0.4 }),
|
package/lib/core.js
CHANGED
|
@@ -25,6 +25,57 @@ function tableFor(language) {
|
|
|
25
25
|
return LABELS[language] || LABELS.zh
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* 各语言默认正文句式(templates 留空时的回退文案)。
|
|
30
|
+
* 按 reason 差异化表达,避免清一色「(用时 X,消耗 Y)」:
|
|
31
|
+
* - completed:括号紧凑式;aborted/blocked:句号拆句;error:错误详情前置;
|
|
32
|
+
* - max-tokens:句号拆句 + 建议;generic:兜底。
|
|
33
|
+
* 占位符:{label} 标签、{errBlock} 错误详情块(含分隔符,无错误为空)、{dur} 用时、{use} 消耗。
|
|
34
|
+
* 仅当用时与消耗都有数据时启用;数据不全回退到 buildNotice 的 parts 拼接逻辑(自动省略缺失项)。
|
|
35
|
+
*/
|
|
36
|
+
const DEFAULT_PHRASES = {
|
|
37
|
+
zh: {
|
|
38
|
+
completed: '{label}(用时 {dur},消耗 {use})。',
|
|
39
|
+
aborted: '{label}。用时 {dur},消耗 {use}。',
|
|
40
|
+
blocked: '{label}。用时 {dur},消耗 {use}。',
|
|
41
|
+
error: '{label}{errBlock}(用时 {dur},消耗 {use})。',
|
|
42
|
+
'max-tokens': '{label}。用时 {dur},消耗 {use},建议拆分任务后重试。',
|
|
43
|
+
generic: '{label}。用时 {dur},消耗 {use}。',
|
|
44
|
+
},
|
|
45
|
+
'zh-tw': {
|
|
46
|
+
completed: '{label}(用時 {dur},消耗 {use})。',
|
|
47
|
+
aborted: '{label}。用時 {dur},消耗 {use}。',
|
|
48
|
+
blocked: '{label}。用時 {dur},消耗 {use}。',
|
|
49
|
+
error: '{label}{errBlock}(用時 {dur},消耗 {use})。',
|
|
50
|
+
'max-tokens': '{label}。用時 {dur},消耗 {use},建議拆分任務後重試。',
|
|
51
|
+
generic: '{label}。用時 {dur},消耗 {use}。',
|
|
52
|
+
},
|
|
53
|
+
en: {
|
|
54
|
+
completed: '{label} (took {dur}, used {use}).',
|
|
55
|
+
aborted: '{label}. Took {dur}, used {use}.',
|
|
56
|
+
blocked: '{label}. Took {dur}, used {use}.',
|
|
57
|
+
error: '{label}{errBlock} (took {dur}, used {use}).',
|
|
58
|
+
'max-tokens': '{label}. Took {dur}, used {use} — consider splitting the task.',
|
|
59
|
+
generic: '{label}. Took {dur}, used {use}.',
|
|
60
|
+
},
|
|
61
|
+
ja: {
|
|
62
|
+
completed: '{label}(所要 {dur}、消費 {use})。',
|
|
63
|
+
aborted: '{label}。所要 {dur}、消費 {use}。',
|
|
64
|
+
blocked: '{label}。所要 {dur}、消費 {use}。',
|
|
65
|
+
error: '{label}{errBlock}(所要 {dur}、消費 {use})。',
|
|
66
|
+
'max-tokens': '{label}。所要 {dur}、消費 {use}。タスクの分割をおすすめします。',
|
|
67
|
+
generic: '{label}。所要 {dur}、消費 {use}。',
|
|
68
|
+
},
|
|
69
|
+
ko: {
|
|
70
|
+
completed: '{label}(소요 {dur}, 소모 {use})。',
|
|
71
|
+
aborted: '{label}. 소요 {dur}, 소모 {use}.',
|
|
72
|
+
blocked: '{label}. 소요 {dur}, 소모 {use}.',
|
|
73
|
+
error: '{label}{errBlock}(소요 {dur}, 소모 {use}).',
|
|
74
|
+
'max-tokens': '{label}. 소요 {dur}, 소모 {use} — 작업 분할을 권장합니다.',
|
|
75
|
+
generic: '{label}. 소요 {dur}, 소모 {use}.',
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
|
|
28
79
|
/**
|
|
29
80
|
* 按语言取 reason 标签。
|
|
30
81
|
* @param {string} kind
|
|
@@ -218,6 +269,7 @@ export function buildNotice(kind, reasonData, { startedAt, endedAt, usage = null
|
|
|
218
269
|
const templates = custom.templates ?? {}
|
|
219
270
|
const label = labelFor(kind, language)
|
|
220
271
|
const detail = detailFor(reasonData, language)
|
|
272
|
+
const errText = plainError(reasonData)
|
|
221
273
|
let summary = `${label}${detail}`
|
|
222
274
|
const durationLine = includeDuration ? formatDuration(endedAt - startedAt, language) : null
|
|
223
275
|
const usageLine = includeUsage ? summarizeUsage(usage, language) : null
|
|
@@ -229,6 +281,7 @@ export function buildNotice(kind, reasonData, { startedAt, endedAt, usage = null
|
|
|
229
281
|
if (usageLine) parts.push(`${L.use} ${usageLine}`)
|
|
230
282
|
const suffix = parts.length ? `(${parts.join(',')})` : ''
|
|
231
283
|
const template = templates[kind]
|
|
284
|
+
const phraseTpl = (DEFAULT_PHRASES[language] && DEFAULT_PHRASES[language][kind]) || (DEFAULT_PHRASES[language] && DEFAULT_PHRASES[language].generic) || ''
|
|
232
285
|
let text
|
|
233
286
|
if (typeof template === 'string' && template.trim() !== '') {
|
|
234
287
|
// 自定义模板:占位符替换,保持 summary 与正文一致的语义
|
|
@@ -236,11 +289,19 @@ export function buildNotice(kind, reasonData, { startedAt, endedAt, usage = null
|
|
|
236
289
|
label,
|
|
237
290
|
duration: durationLine ?? '',
|
|
238
291
|
usage: usageLine ?? '',
|
|
239
|
-
error:
|
|
292
|
+
error: errText || 'none', // 无报错时显示 none,而非空串
|
|
240
293
|
cache: cacheLine,
|
|
241
294
|
tps: tpsLine,
|
|
242
295
|
title: typeof titleValue === 'string' ? titleValue : '',
|
|
243
296
|
})
|
|
297
|
+
} else if (durationLine && usageLine && phraseTpl) {
|
|
298
|
+
// 默认句式(用时+消耗都有时启用,按 reason 差异化表达)
|
|
299
|
+
const errBlock = errText ? L.sep + errText : ''
|
|
300
|
+
text = phraseTpl
|
|
301
|
+
.replaceAll('{label}', label)
|
|
302
|
+
.replaceAll('{errBlock}', errBlock)
|
|
303
|
+
.replaceAll('{dur}', durationLine)
|
|
304
|
+
.replaceAll('{use}', usageLine)
|
|
244
305
|
} else if (language === 'en') {
|
|
245
306
|
text = `${summary}${suffix ? ` (${parts.join(', ')}).` : '.'}`
|
|
246
307
|
} else if (language === 'ja') {
|
package/lib/index.js
CHANGED
|
@@ -73,7 +73,7 @@ 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
77
|
includeDuration: true,
|
|
78
78
|
includeUsage: true,
|
|
79
79
|
skipSubagents: true,
|
|
@@ -129,7 +129,7 @@ export function apply(ctx, config = {}) {
|
|
|
129
129
|
blocked: Schema.string().default(''),
|
|
130
130
|
'max-tokens': Schema.string().default(''),
|
|
131
131
|
}),
|
|
132
|
-
titleTemplate: Schema.string().default(''),
|
|
132
|
+
titleTemplate: Schema.string().default('任务已完成'),
|
|
133
133
|
includeDuration: Schema.boolean().default(true),
|
|
134
134
|
includeUsage: Schema.boolean().default(true),
|
|
135
135
|
skipSubagents: Schema.boolean().default(true),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@telosmaylx/dsh-session-notify",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
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
5
|
"private": false,
|
|
6
6
|
"type": "module",
|