@telosmaylx/dsh-session-notify 0.1.9 → 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 -0
- package/README.ja.md +594 -0
- package/README.ko.md +594 -0
- package/README.md +594 -583
- package/README.zh-TW.md +594 -0
- package/lib/client.js +953 -191
- package/lib/core.js +64 -42
- package/lib/index.js +86 -2
- package/package.json +74 -70
- package/scripts/tmp-i18n-check.mjs +70 -0
package/README.ja.md
ADDED
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# dsh-session-notify
|
|
4
|
+
|
|
5
|
+
[简体中文](README.md) · [English](README.en.md) · [繁體中文](README.zh-TW.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
|
+
各ターンの会話終了時に、「完了 / エラー / ブロック / 上限到達」を所要時間・トークン消費とともにセッションログへ書き込み、ブラウザのシステム通知とページ内トーストをプッシュします。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
|
+
### 3 チャンネルで通知、取りこぼしなし
|
|
53
|
+
|
|
54
|
+
| チャンネル | 形式 | 説明 |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| セッション内システムメッセージ | 折りたたみ可能な通知行 | 各ターン終了時に、終了理由・所要時間・消費量をプラグイン由来のシステムメッセージとしてセッションログへ追加し、JSONL とともに保存。セッションを復元・リプレイした後も表示されます。 |
|
|
57
|
+
| ブラウザシステム通知 | Web Notification | ネイティブポップアップ。各完了イベントで独立した `tag`(`dsh-session-notify:<timestamp>`)を使用するため、前回と置き換わらず、グループ項目に折りたたまれません。通知をクリックするとウィンドウにフォーカスが戻ります。 |
|
|
58
|
+
| ページ内トースト | 右下のフローティングポップアップ | 常に表示されるセーフティネット。システム通知がプラットフォームにサイレント化されたり、権限が拒否されたり、環境が非対応の場合でも、目に見えるフィードバックを提供します。同画面に最大 3 件(超えた場合は最古のものを削除)、10 秒で自動的に消え、クリックで閉じます。 |
|
|
59
|
+
|
|
60
|
+
### バックグラウンドセッションを完全カバー
|
|
61
|
+
|
|
62
|
+
- ホストはすべてのセッション(バックグラウンド、未表示ウィンドウを含む)について「最新の通知本文」のセッションプロジェクションを維持します(key = `session-complete-notify`)。プッシュ本文はセッション間で一貫し、たまたまそのウィンドウを開いているかどうかに依存しません。
|
|
63
|
+
- クライアントはセッションリストのスナップショットから全セッションの `running` ビットを監視し、`true → false` のエッジでプッシュをトリガーします。公式サイドバー通知と同じ戦略です(初回監視ではベースラインを記録するだけで、すでに idle のセッションには追って送信しません)。
|
|
64
|
+
|
|
65
|
+
### 一言一句までカスタマイズ可能
|
|
66
|
+
|
|
67
|
+
- **5 言語**:簡体中文、繁體中文、English、日本語、한국어 —— 通知メッセージ、所要時間・消費量の表現、設定パネルの UI がすべて言語に応じて切り替わります(切り替え時に即再レンダリング)。
|
|
68
|
+
- **ビジュアルテンプレートエディタ**(Chip カプセルエディタ):動的情報をインラインカプセルとしてレンダリング(プレースホルダーコードは露出しません)。「+ 情報を挿入」でカーソル位置に挿入(テキストの途中にも挿入可)、カプセルをクリックで削除、各欄にリアルタイムプレビュー(情報がサンプル値として本文に流れ込みます)。
|
|
69
|
+
- **プリセットシステム**:「デフォルト」プリセットをベースラインとして内蔵。現在の設定をカスタムプリセットとして保存可能(`localStorage` に永続化)。自動採番される無名プリセット(`未命名`、`未命名 2`…)、「出自:xxx · 変更あり」の出所表示、プリセット削除に対応。
|
|
70
|
+
- **プッシュタイトルテンプレート**:空欄の場合は各理由でデフォルトタイトルを使用(完了=タスク完了 / エラー=タスクエラー / …)。`{title}` はセッションタイトルを参照します。
|
|
71
|
+
|
|
72
|
+
### 公式の口径と同じソース
|
|
73
|
+
|
|
74
|
+
- **キャッシュヒット率**は公式 `tokenUsage` プロジェクションから取得:キャッシュ読み込み /(非キャッシュ入力 + キャッシュ読み込み + キャッシュ書き込み)。
|
|
75
|
+
- **生成速度**は公式 `sessionStats` プロジェクションから取得:出力トークン ÷ デコード所要時間。
|
|
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` の 1 コマンドでインストール完了後すぐ使用可能。手書きの 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 対応ならシステム通知あり。非対応、権限拒否、サイレント化の場合はトーストでフォールバック |
|
|
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
|
+
### 方法 1: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
|
+
### 方法 2: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
|
+
### 方法 3:ローカルディレクトリのホットインストール(開発用)
|
|
128
|
+
|
|
129
|
+
パスを自分のクローン先ディレクトリに置き換え、DSH Web GUI のセッション内で実行します:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
dev_install_package dir=/あなたの/クローン先/dsh-session-notify
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### 方法 4: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
|
+
### 方法 5: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
|
+
> どの方法でも、インストール後は**ブラウザのページを 1 回リロード**する必要があります —— クライアント bundle は `__DSH_BOOT__` 起動グラフから注入されるためです。
|
|
162
|
+
|
|
163
|
+
## アンインストール
|
|
164
|
+
|
|
165
|
+
1 コマンドでプラグインとそのマウントを削除します(`cordis.patch.yml` から insert エントリを自動的に削除):
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
dsh plugin --profile web remove @telosmaylx/dsh-session-notify
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
> [!NOTE]
|
|
172
|
+
> 手動インストール(方法 4 / 5)の場合は、`~/.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` デバッグフック(参照で削除、クロージャリーク防止)、ページ内トーストコンテナの DOM |
|
|
182
|
+
|
|
183
|
+
### アンインストール後も保持されるデータ
|
|
184
|
+
|
|
185
|
+
- **設定構成**(言語、メッセージテンプレート)は settings ドキュメントに残り、再インストール後に自動復元されます。
|
|
186
|
+
- **カスタムプリセット**はブラウザの `localStorage`(`dsh-scn-custom-presets`)に保存され、再インストール後も残ります。
|
|
187
|
+
- 過去のセッションに追加済みのシステムメッセージと JSONL ログは**ロールバックされません**(これらはセッションデータの一部であり、公式サイドバー通知と同じ意味づけです)。
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## クイックスタート
|
|
192
|
+
|
|
193
|
+
1. 上記いずれかの方法でインストールし、ページをリロードします。
|
|
194
|
+
2. 任意の 1 ターンの会話を開始し、終了を待ちます —— 右下にトーストが表示され、ブラウザにシステム通知が届き、セッションログに折りたたみ可能なシステム通知行が現れます。
|
|
195
|
+
3. 初めて完了イベントを受け取ったとき、ブラウザが通知権限を要求します(ページごとに 1 回のみ)。許可すると、以降の完了でシステム通知が届きます。
|
|
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` | 出力トークン上限に到達 | 通知 |
|
|
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
|
+
5 言語での同じイベント:
|
|
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`(未決定) | 完了イベントではトーストのみ送信。設定パネルの「通知権限」エリアに「許可をリクエスト」ボタンを提供(**ユーザージェスチャ内でリクエスト**——Chromium はジェスチャ以外の自動リクエストを無視するため、プラグインは自動リクエストを行いません) |
|
|
288
|
+
| `granted` | 「プッシュ方式」に従ってシステム通知を送信(独立した tag、互いに上書きしません) |
|
|
289
|
+
| `denied`(ブラウザでブロック) | トーストのみ。設定パネルにアドレスバーの操作ガイドを表示(権限アイコン → サイト設定 → 通知 → 許可) |
|
|
290
|
+
| `undefined`(非セキュアコンテキスト / 非対応) | トーストのみ。「ページ内表示のみ」への切り替えを推奨 |
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## 設定
|
|
295
|
+
|
|
296
|
+
ほとんどの設定は **DSH Web UI → 設定 → プラグイン → セッション完了通知** パネルで行います(保存後、「クリックでリロード」を押すと有効になります)。「トリガー理由のホワイトリスト」と「サブエージェントをスキップ」の 2 項目のみ、ホストの `cordis.patch.yml` の `config` で設定します。
|
|
297
|
+
|
|
298
|
+
### 設定パネル
|
|
299
|
+
|
|
300
|
+
パネルは公式の「設定 → プラグイン」パネルに登録されます(`settings.plugin.item` keyed slot、key = `session-complete-notify`)。スタイルはネイティブプラグインカードを 1 つ 1 つ再現しています(12px の角丸、開閉、回転する chevron、footer のステータス表示 + ゴーストボタン + メインカラーの保存ボタン):
|
|
301
|
+
|
|
302
|
+
| エリア | 内容 |
|
|
303
|
+
| --- | --- |
|
|
304
|
+
| プリセット | ドロップダウンで内蔵またはカスタムプリセットを選択。「新規作成」で現在の設定をカスタムプリセットとして保存。現在のプリセットは「削除」可能 |
|
|
305
|
+
| 言語 | 5 言語の単一選択。切り替えでパネル全体が即再レンダリング |
|
|
306
|
+
| プッシュ方式 | 3 択:デュアルチャンネル(システム通知 + ページ内表示、デフォルト)/ システム通知のみ / ページ内表示のみ |
|
|
307
|
+
| 通知メディア | 大きな画像の 2 つのソース:**理由ごとのアップロード**——テンプレート内で「+ 情報を挿入 → 画像」から `{image}` トークンを挿入しローカル画像を選択(エディタ内ではサムネイル付きチップとして表示、**512px 幅・通知表示比率 16:9 で中央クロップ**に自動圧縮、理由ごとに保存)。**グローバルの画像/アイコン**——2 つのアップロードカードを横並び 1 行に配置(**アイコンが先**。空欄は角丸の「+」タイルで、クリックでアップロード。**画像 512×288(16:9 中央クロップ)、アイコン 128×128(1:1 正方形中央クロップ)**。アップロード後はカードにサムネイルが表示され、**クリックで全画面プレビュー(等比・未クロップの元画像)**、右上の × で削除)。アイコンは空欄ならサイト既定のアイコン、またはテンプレートに `{icon}` トークンを挿入して**理由ごとのアイコン**を指定(グローバルより優先)。システム通知チャネルのみ有効(ページ内トーストはテキストカード)。「送信」テストボタンも同様に適用 |
|
|
308
|
+
| タイトル | 折りたたみセクション(**既定で折りたたみ**、クリックで展開):**グローバルプッシュタイトル**(全理由共通。Chip エディタ——「+ 情報を挿入」で挿入した情報は**カプセルタグ**として表示され、クリックで削除。**通知送信時はタイトル内の情報トークン(所要時間/消費/エラー/キャッシュヒット/速度)が実際の値に置き換えられ、コードが露出しません**。空欄の場合は各理由でデフォルトタイトル——完了=タスク完了、エラー=タスクエラー、中止=タスク中止、ブロック=タスクブロック、上限=出力上限に到達)+ **理由ごとのタイトル**(5 つの理由それぞれに入力。空欄 = グローバルまたは言語デフォルトを使用) |
|
|
309
|
+
| コンテンツ | 折りたたみセクション(**既定で折りたたみ**、クリックで展開)。展開すると各終了理由(完了、エラー、中止、ブロック、出力上限)ごとに**1 行レイアウト**(理由ラベル + Chip エディタ + 「+」挿入ボタン——メニュー展開中は「−」に変化 + **紙飛行機の送信ボタン**。ボタンは角丸矩形で垂直中央揃え):**テンプレートが空(既定プリセット)のときはエディタにデフォルト文面を表示**。テキスト + インライン情報カプセル、カーソル位置に挿入;`{image}`/`{icon}` チップは**サムネイルクリックで大図をプレビュー、× クリックでのみ削除**(誤削除防止)、他のチップはクリックで削除;**編集後に空にすると「空欄の場合はデフォルトの文面を使用」のプレースホルダーを表示(選択・削除不可)** |
|
|
310
|
+
| サブエージェントセッションをスキップ | チェックボックス(保存時に設定ドキュメントへ一緒に書き込み) |
|
|
311
|
+
| 通知権限 | 状態をリアルタイム表示:許可済み(緑)/ 未許可(「許可をリクエスト」ボタン付き)/ ブラウザにブロック済み(アドレスバーの操作ガイド付き)/ 環境が非対応 |
|
|
312
|
+
| 理由別のタイトルカスタマイズ | 折りたたみエリア(デフォルトで収納):終了理由ごとに独立したタイトル入力欄。空欄=グローバルテンプレートまたは言語デフォルトのタイトルを使用 |
|
|
313
|
+
| 保存 | ホストの設定ドキュメントに書き込み(`language` / `templates` / `titleTemplate` / `titleTemplates` / `pushMode`)。保存後「クリックでリロード」リンクを表示 |
|
|
314
|
+
| リセット | 1 クリックでデフォルト値に復元(**言語は現在の選択を保持**、タイトル / テンプレート / プッシュ方式はデフォルトに戻す)し、即座に保存 |
|
|
315
|
+
|
|
316
|
+
> [!NOTE]
|
|
317
|
+
> 「プッシュ方式」の取舍:`dual`(デフォルト)は Windows システム通知とページ内トーストを同時に表示します。トーストはセーフティネットとして、システム通知がプラットフォームにサイレント化されるのを防ぎます(集中アシスタント、通知バナー無効化など)。ただし **QQ ブラウザなどの国産 Chromium シェルブラウザは `Notification` を「ブラウザ内蔵のページ内プッシュポップアップ」としてレンダリングします**(ページ上部 / 隅のバナーで、Windows 通知センターを経由しません)—— この場合、`dual` ではページ内に 2 つの通知(ブラウザ内蔵ポップアップ + プラグインのトースト)が表示されます。このようなブラウザでは「ページ内表示のみ」を選択してください(`Notification` を呼び出さないため、ブラウザ内蔵ポップアップは表示されず、ページ内にはプラグインの小さなトーストのみ表示されます)。「システム通知のみ」モードは QQ ブラウザでは無効です(常にページ内ポップアップとしてレンダリングされます)。設定パネルの各理由の「送信」テストボタンも同様の影響を受けます。
|
|
318
|
+
|
|
319
|
+
> [!NOTE]
|
|
320
|
+
> システム通知(`Notification` API)が表示されるかどうかは、**ブラウザとサイトへのアクセス方法**の両方で決まります。Edge / Chrome は「馴染みのない」サイトへの通知を**自動的にブロック**します(アドレスバーに「通知がブロックされました」と表示)。アドレスバー左の権限アイコン → サイト設定 → 通知 → 許可で復元できます。`http://IP` のような非セキュアコンテキストでのアクセス時は `Notification` 自体が存在しないため、「ページ内表示のみ」に切り替えてください。設定パネルの「通知権限」エリアは現在の状態をリアルタイム表示し、対応する操作ガイドを提供します(1 クリックで権限をリクエスト可能)。Firefox ではウィンドウにフォーカスがある間は通知がページ内バナーとして表示され、フォーカスが外れて初めてシステム通知センターに入ります。
|
|
321
|
+
|
|
322
|
+
> [!NOTE]
|
|
323
|
+
> パネルの「サブエージェントセッションをスキップ」は設定ドキュメント内のブール値を保存します。ホスト `cordis.patch.yml` の `config.skipSubagents` は起動時のデフォルト値であり、どちらか一方でも true ならスキップされます。
|
|
324
|
+
|
|
325
|
+
### メッセージテンプレートとプレースホルダー
|
|
326
|
+
|
|
327
|
+
各終了理由ごとに独立したテンプレート入力欄があります。**ラベルがスイッチ**です —— テンプレートに対応する情報ラベルを挿入して初めて、そのデータが表示されます:
|
|
328
|
+
|
|
329
|
+
| プレースホルダー | 意味 | 例の値 |
|
|
330
|
+
| --- | --- | --- |
|
|
331
|
+
| `{title}` | セッションタイトル(プッシュタイトルテンプレートでも使用可) | `重构登录模块` |
|
|
332
|
+
| `{duration}` | 本ターンの所要時間(`turn/start` で計測開始 → `turn/end` で終了) | `3 分 25 秒` / `3m25s` |
|
|
333
|
+
| `{usage}` | トークン消費(入力 = 非キャッシュ + キャッシュ読み込み + キャッシュ書き込み) | `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 のステータスバーと同じ口径です。ホストがプロジェクションスナップショットの読み取りに失敗した場合やデータが未準備の場合は、ローカルの使用量集計による推定にフォールバックし、それでもデータがない場合はその項目を空にします(ラベルを挿入しても表示されません)。また、この 2 項目はカスタムテンプレートで `{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
|
+
現在のバージョンはブラウザデフォルトの通知スタイルを使用し、カスタムアイコンやサウンドは注入しません。トーストは固定のダークカードです。これらの機能が必要な場合は、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 通知センターを経由せず)、システム通知のオプションもありません。3 つのプッシュ方式の実際の挙動:
|
|
535
|
+
- `デュアルチャンネル` → ブラウザ内蔵ポップアップ + プラグイントースト。ページ内に 2 つの通知。
|
|
536
|
+
- `システム通知のみ` → 無効(QQ ブラウザでは常にページ内ポップアップとしてレンダリング)。
|
|
537
|
+
- `ページ内表示のみ` → ブラウザ内蔵ポップアップは表示されず、ページ内にはプラグインの小さなトーストのみ(推奨)。
|
|
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」を折りたたみセクションに変更(既定で折りたたみ、パネルをコンパクトに。ヘッダーにカスタマイズ済みの数を表示、クリックで展開)**。⑦ **レイアウト改善②:通知イメージ/アイコンのアップロードカードを横並び 1 行に配置(間に余白);プッシュタイトルと理由ごとのタイトルを「タイトル」の折りたたみセクションに統合(既定で折りたたみ);折りたたみインジケーターを三角形アイコンに変更(「展開/折りたたむ」の文言を削除、i18n 負担を軽減)**。⑧ **操作改善:プッシュタイトルを Chip エディタに変更(挿入した情報はカプセルタグとして表示され、`{title}` などのコードが露出しない);画像/アイコンのカード順を入れ替え(アイコンが先);「本文テンプレート × 5」を「コンテンツ」に改名;画像/アイコンのサムネイルクリックで全画面プレビュー(ライトボックス)、タグは × クリックでのみ削除(誤削除防止)**。⑨ **プレビューを元画像に統一:アップロード時にクロップ版(通知用)と等比の完全版(1024px、ライトボックスの原図表示用)の両方を保存し、カードとタグの拡大プレビューはいずれも未クロップの元画像を表示。折りたたみの三角形アイコンを拡大**。⑩ **タイトルの情報トークン修正:通知タイトル内の `{duration}` `{usage}` `{error}` `{cache}` `{tps}` はセッションの実際の値に置き換えられ、コードが露出しません(編集時はカプセル、送信時は実データ)。「コンテンツ」を 1 行レイアウトに変更(理由ラベル + エディタ + 「+/-」挿入ボタン + 紙飛行機の送信ボタン)**。⑪ **詳細:コンテンツ行下のリアルタイムプレビューを削除(よりコンパクトに);コンテンツのエディタ内余白を縮小(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}」完了。クリックして表示。」に変更(5 言語、エディタのヒントとホスト側レンダリングを同期);理由別タイトルの各行に「+」挿入ボタンを追加(プッシュタイトルと同様:情報トークンのみ、画像/アイコンなし、カーソル位置に挿入)**。⑱ **タグ化とプリセット管理:理由別タイトルを Chip エディタに変更(挿入した情報はカプセルタグとして表示され、{title} などのコードが露出しない;{image}{icon} は禁止——手入力時はリテラルテキストのまま、送信時に剥除);カスタムプリセットに「名前を変更」機能を追加(カスタムプリセット選択時に表示、変更後はドロップダウンと現在のプリセットが同期)**。⑲ **詳細⑤:Chip エディタの文字を垂直中央に配置(行の高さとカプセルを 20px に統一、上下パディング 9px、38px ボックス内で単行テキストが中央に表示);「タイトル」「コンテンツ」の折りたたみバーに背景色を追加(ヘッダーは角丸の色付きバー、展開領域は左ボーダー付きインデント);5 言語 86 キーの i18n を全面的に確認(すべて翻訳済み、zh-TW「名前を変更」と ko「破棄」の表現を修正)**。「送信」テストボタンも同様に適用。システム通知チャネルのみ有効(ページ内トーストはテキストカード);⑳ **詳細⑥:「タイトル」「コンテンツ」の折りたたみヘッダーの背景塗りを削除;プレースホルダー文字色を rgba(127,127,127,0.5) に変更(より淡く、テーマ変数の影響を受けない)**。「送信」テストボタンも同様に適用。システム通知チャネルのみ有効(ページ内トーストはテキストカード);㉑ **修正:「コンテンツ」の各理由行間の区切り線を削除;「コンテンツ」を展開した際のヘッダー直下の線を「タイトル」と同様(全幅)に補完;Backspace/Delete でのチップ削除時、カーソルが先頭に飛ばないよう修正(要素コンテナ内では子ノードのインデックスからチップを特定、チップ直後・エディタ末尾のケースを含む);「未命名」プリセットの名前変更時は自動的に具名プリセットへ昇格(新しい id に置換)し、ドロップダウンに即座に新名を表示**。「送信」テストボタンも同様に適用。システム通知チャネルのみ有効(ページ内トーストはテキストカード);㉒ **修正:文字入力後にプレースホルダーが残らないように(プレースホルダー CSS セレクタと状態属性を整合、入力すると即消え、文字は左端から);画像/アイコンのアップロード・削除後もカーソル位置を維持(DOM 再構築前にカーソルオフセットを保存し、再構築後に復元);プリセットのドロップダウンをフォーカスしても白い選択状態の枠線が出ないように**。「送信」テストボタンも同様に適用。システム通知チャネルのみ有効(ページ内トーストはテキストカード);㉓ **修正:チップ(画像/アイコン含む)削除後もカーソルが飛ばず消えず、連続削除が可能に——画像データ変更による再構築を必要なときだけ実行(DOM 内に対応するメディアチップがなくテンプレートにも該当タグがない場合は再構築をスキップし、カーソルを削除位置に維持。アップロード/置き換えでサムネイル更新が必要な場合のみ再構築)、カーソルオフセット計算も修正(チップは一律 1 位置として数え、内部文字には入らない)**。「送信」テストボタンも同様に適用。システム通知チャネルのみ有効(ページ内トーストはテキストカード) |
|
|
553
|
+
| **0.1.10** | 2026-08-29 | 「プッシュタイトル」をネイティブ入力欄に変更(ネイティブのプレースホルダー:コピー不可、入力すると消え、空にすると復元。「+ セッションタイトル」でカーソル位置に `{title}` を挿入)。ドキュメントに QQ ブラウザの内蔵プッシュポップアップの説明を追記(3 つのプッシュ方式の実際の挙動 + 送信ボタンのテストも同じ規則) |
|
|
554
|
+
| **0.1.9** | 2026-08-29 | プッシュタイトルが**理由別のカスタマイズ**に対応(折りたたみエリア UI、デフォルトで収納され冗長にならない。空欄時は各理由で異なるデフォルトタイトル:タスク完了 / タスクエラー / タスク中止 / タスクブロック / タスクが出力上限に到達、5 言語)。プロジェクションをオブジェクト(kind/text/title)にアップグレードし、host がレンダリングしたタイトルを保持。リセットボタンが**現在の言語を保持**。デフォルトメッセージに「セッションタイトル」ラベルを埋め込み(セッション「{title}」が完了、タイトルなしは自動フォールバック)。設定パネルのテンプレートプレビューを同期。「+ 情報を挿入」でラベル挿入後に自動折りたたみしなくなった。使用中のカスタムプリセットを削除すると自動的にデフォルトへ戻る。テンプレートプレビューを修正(クリックで消えない、入力でのみ非表示、空にすると復元)。各理由に「送信」ボタンを追加(現在のテンプレートでレンダリングしたテスト通知を 1 クリックで送信) |
|
|
555
|
+
| **0.1.8** | 2026-08-29 | デフォルトのプッシュタイトルを「タスク完了」に変更(`{title}` は引き続きセッションタイトルを参照可)。デフォルトメッセージを終了理由ごとに異なる表現に(完了=コンパクトな括弧式 / 中止・ブロック=文を分ける / エラー=エラー前置 / 上限=アドバイス付き、5 言語)。設定パネルに「リセット」ボタンを追加し、1 クリックでデフォルトに復元 |
|
|
556
|
+
| **0.1.7** | 2026-08-29 | 0.1.6 の設定カードのクラッシュを修正:`notificationPermissionRow`/`requestPermissionNow` が Card コンポーネント内の state(スコープ外)を参照していたため、レンダリング時に ReferenceError が発生し、設定カード全体が消えていた。自己完結型 + コールバックで引数を渡す方式に変更 |
|
|
557
|
+
| **0.1.6** | 2026-08-29 | 設定パネルに「通知権限」ステータスエリアを追加(許可状態のリアルタイム表示 + 1 クリック権限リクエストボタン + ブロック時のアドレスバー操作ガイド)。権限リクエストを**ユーザージェスチャ内での要求**に変更(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` の 1 コマンドで自動マウント)。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
|