dsh-session-guard 3.2.5 → 4.0.1

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.
Files changed (49) hide show
  1. package/CHANGELOG.ja.md +159 -143
  2. package/CHANGELOG.ko.md +159 -143
  3. package/CHANGELOG.md +232 -216
  4. package/INSTALL.ja.md +5 -0
  5. package/INSTALL.ko.md +5 -0
  6. package/INSTALL.md +5 -0
  7. package/INSTALL.zh.md +5 -0
  8. package/LICENSE +21 -21
  9. package/README.de.md +375 -0
  10. package/README.en.md +16 -1
  11. package/README.es.md +374 -0
  12. package/README.fr.md +373 -0
  13. package/README.it.md +374 -0
  14. package/README.ja.md +16 -1
  15. package/README.ko.md +16 -1
  16. package/README.md +30 -6
  17. package/README.ru.md +374 -0
  18. package/cordis.patch.yml +10 -10
  19. package/dsh.plugin.json +16 -16
  20. package/lib/client.js +0 -345
  21. package/lib/client.js.map +1 -1
  22. package/package.json +8 -10
  23. package/src/bridge.js +136 -136
  24. package/src/client/index.ts +156 -168
  25. package/src/client/locales.ts +1 -199
  26. package/src/client/pause-button-text.ts +60 -60
  27. package/src/client/pause-button.tsx +129 -129
  28. package/src/client/scope-face.ts +20 -20
  29. package/src/client/settings-card.tsx +391 -391
  30. package/src/client/styles.ts +30 -30
  31. package/src/detect.js +27 -27
  32. package/src/gate.js +93 -93
  33. package/src/pause-gate.js +544 -544
  34. package/src/pause-store.js +101 -101
  35. package/src/retry.js +227 -227
  36. package/src/scheduler.js +42 -42
  37. package/src/step-gate.js +399 -399
  38. package/src/store.js +77 -77
  39. package/src/wiring.js +305 -305
  40. package/locale/de.json +0 -6
  41. package/locale/en.json +0 -6
  42. package/locale/es.json +0 -6
  43. package/locale/fr.json +0 -6
  44. package/locale/it.json +0 -6
  45. package/locale/ja.json +0 -6
  46. package/locale/ko.json +0 -6
  47. package/locale/ru.json +0 -6
  48. package/locale/zh.json +0 -6
  49. package/src/client/shims.d.ts +0 -21
package/CHANGELOG.md CHANGED
@@ -1,216 +1,232 @@
1
- # Changelog
2
-
3
- All notable changes to `dsh-session-guard` are recorded here. Versions follow semver.
4
-
5
- - [English changelog](./CHANGELOG.md)
6
- - [日本語 changelog](./CHANGELOG.ja.md)
7
- - [한국어 changelog](./CHANGELOG.ko.md)
8
-
9
- ## 3.2.4 — 2026-09-27
10
-
11
- ### Fixed
12
- - **Session format v4 adaptation (host >= 0.1.7-rc.1)**: the three session-writing paths no longer use the retired `source: { kind: 'plugin', plugin: 'session-guard' }` signature, which the v4 host rejects with `SessionFormatError` (whole round fails). All three now use the producer-owned kind:
13
- - delayed-resume notice injection (`src/wiring.js`);
14
- - auto-retry notice injection (`src/retry.js`);
15
- - pause-resume followup (`src/pause-gate.js`, ```kind: `plugin:${pluginId}````).
16
- - **tool-result v4 native adaptation (N1)**: `findToolOutcome` in `src/pause-gate.js` now reads the v4 first-class `role:'tool'` message (`toolCallId`/`isError` at message top level) first; the v3 `tool-result` block path is kept as historical fallback. Without this, a failed tool at pause time was reported as completed on resume ("do not re-run") — a silent wrong decision. `src/tool-call-id.js` reads the native top-level id first; stale 0.1.1/0.1.2-era header notes corrected to the three-shape generation table.
17
- `form` and all other fields are unchanged; the host's own v3-to-v4 migration lifts existing legacy rows, so no historical data is rewritten. Evidence: `@deepseek-ai/dsh-session-format-v3-to-v4@0.1.7-rc.2` validates only that `source.kind` is non-empty and not `'plugin'`.
18
-
19
- ## 0.4.0 — 2026-09-18 (mis-versioned; superseded by 3.0.0)
20
-
21
- ### Fixed
22
-
23
- - **Version identity.** This line was published as `0.4.0` while `dsh.plugin.json` and this
24
- changelog already said `3.0.0` — one artifact with two version numbers. `package.json` is now
25
- `3.0.0`, so the package version, the manifest version and the changelog agree. `0.4.0` is kept
26
- here as a historical record because npm versions are immutable; `dist-tag dsh-0.1.5` should be
27
- repointed to `3.0.0` once it is published.
28
- - **Docs.** README/INSTALL (zh/en/ja/ko) no longer describe the sibling line as living on `main`.
29
- The 0.1.2 line's release branch is **`legacy/0.1.2`** (npm dist-tag `dsh-0.1.2`, version `0.3.1`);
30
- `main` is frozen at `0.2.0-beta.1`. The duplicated branch fragment in the INSTALL.zh/ja/ko install
31
- command is fixed, explicit dist-tag install commands are documented, and "2.x / 3.x" is
32
- now marked as a **line nickname** rather than a version number.
33
-
34
- ### Notes
35
-
36
- - **No source changes** relative to `3.0.0`; `0.4.0` is a packaging-only publish of the same tree.
37
-
38
- ## 3.0.0 — 2026-09-14
39
-
40
- ### Changed
41
-
42
- - **DSH v0.1.5-rc.2 dedicated line (`compat/0.1.5`).** `engines.dsh` and the `dsh-client-*`
43
- peer ranges narrow to `>=0.1.5-rc.2 <0.2.0-0` (strict-semver prerelease matching means the
44
- old `>=0.1.0-rc.7` range never matches `0.1.5-rc.2`); `dsh.plugin.json` gains `engines.dsh`.
45
- The 2.x / 0.2.x line on `main` keeps serving DSH 0.1.0-rc.7 … 0.1.2-rc.1.
46
- - **`session.events` → `snapshotEvents()`.** DSH 0.1.5 removed the `session.events` array
47
- accessor (compatibility-guide §20.3). `pause-gate.js` now reads session events through a
48
- dual-path helper: `snapshotEvents()` first, the legacy `events` array as a defensive
49
- fallback, `null` (fail-open) when neither exists. Affects `findToolOutcome` and
50
- `lastUserPrompt` only; event-type matching is unchanged.
51
-
52
- ### Unchanged
53
-
54
- - Zero changes on every other integration seam: the self-held webServer prefix route
55
- (`/session-guard/rpc`), `settings.register`, the `settings.plugin.item` card slot,
56
- client injections, and `llm.listConfigurableProviders()` are all verified intact against
57
- the published 0.1.5-rc.2 bundle (`tools/check-api-drift.ps1`, 12/12 required assertions).
58
-
59
- ### Pending
60
-
61
- - Live smoke on a real DSH 0.1.5-rc.2 host (same status as the perm-gate 0.1.5 line).
62
-
63
- ## 0.2.0-beta.2 — 2026-09-13
64
-
65
- ### Fixed (DSH 0.1.5 compat — `compat/0.1.5` branch)
66
-
67
- - **Dual-path resume enqueue.** DSH 0.1.5 turns the Inbox into an agent-loop read-only
68
- projection, so `agent.followup` may no longer exist. The resume flow now tries
69
- `agent.followup` first, falls back to `agent.send`, and degrades to a warn (never throws)
70
- when neither is available — a failed enqueue can no longer break resume.
71
- - **Resume messages carry `source.form: 'instructions'`** per the 0.1.5 `ContextFormed`
72
- message-source contract (`kind: 'plugin'` is a built-in kind; older DSH versions ignore
73
- the extra field).
74
- - **`webServer.register` is wrapped in try/catch**: a failed route registration now logs an
75
- error instead of throwing out of `apply` and breaking host plugin loading.
76
- - Verified against the 0.1.5-rc.2 source: the `WebRoute` contract (exact/prefix + SSE) is
77
- unchanged, so client `fetch('/session-guard/...')` paths need no `/api` prefix.
78
-
79
- ## 0.2.0-beta.1 — 2026-09-10
80
-
81
- ### Added
82
-
83
- - **Step-level gate (`agent/pre-step`).** During peak hours the turn is now held **before** the
84
- next step's model request instead of being interrupted at a turn boundary: the session keeps
85
- running until the next `agent/pre-step`, where the gate holds it (setting `stepLevelPause`, on by
86
- default). The turn resumes **in place** off-peak — no followup message needed. Hold conditions:
87
- peak (Beijing time) + not weekend + `step > 1` + official target provider (`providerGuard`) +
88
- not request-held + not bypassed in this peak window. New module `src/step-gate.js` (pure
89
- `decideStepHold` + hold / release / abort / timeout engine).
90
- - **`stepResume` port + RPC + `/resume`.** `sessionGuard.stepResume(sessionId, {bypass})`,
91
- `POST /session-guard/rpc {action:'stepResume'}` and `/resume` all release the gate; a manual
92
- resume also stops gating that session for the rest of the peak window.
93
- - **Timeout escalation.** `stepGateTimeoutMs` (default 300000) releases the gate and escalates to a
94
- turn-level **force** pause, so a long peak neither deadlocks nor drips one step every five minutes.
95
- - **"⏸ Pause session" button** (client, slot `conversation.input.right`, id `session-guard-pause`,
96
- order 20 — left of input-traffic's freeze button). It polls `/session-guard/state` once a second,
97
- stays disabled while nothing is held, and calls `stepResume` when it is. The status badge moved to
98
- order 40 and now reports the number of step-held sessions.
99
- - **New settings**: `stepLevelPause`, `stepGateTimeoutMs`.
100
- - **New state**: `GET /session-guard/state` now returns `paused: { step, turn }` and
101
- `stepGate: { held, since, bypass }`; `/status` returns `stepHeld`; `/diag` returns `stepGate`.
102
- The service port's `state().paused` stays boolean for compatibility (new field `pausedStep`).
103
-
104
- ### Fixed
105
-
106
- - **Deadlock between a held step and a turn-level pause.** `pauseTask` / `resumeTask` /
107
- `cancelTask` now release the step gate first: a step hold sits at `agent/pre-step`, where no
108
- `assistant/message` or `tool/result` can ever arrive, so a `safe` pause used to wait forever and
109
- never persisted `paused`.
110
-
111
- ### Changed
112
-
113
- - **Peak entry no longer interrupts running turns** when `stepLevelPause` is on (`onEnterPeak` arms
114
- the step gate instead of calling `stopNextTurn`); with it off the previous turn-level behaviour is
115
- unchanged.
116
- - input-traffic's freeze button label is now **"Freeze & append"** (`冻结追加` / `凍結して追加` /
117
- `동결 후 추가`), and its resume label **"Resume & append"** (`恢复追加` / `再開して追加` /
118
- `재개 후 추가`) — it freezes the turn and keeps queued messages, distinct from the pause button.
119
- - **The pause button is a toggle now**: "Pause session" / "Resume session" (no disabled grey state).
120
- Clicking "Pause session" calls the new `stepPause` action, which holds the session at the **next
121
- step boundary** (step 1 included, regardless of peak or provider); "Resume session" calls
122
- `stepResume`. New port method `sessionGuard.stepPause(sessionId)`.
123
- - **SSE push**: new route `GET /session-guard/events?session=<id>` pushes step-gate state changes the
124
- moment they happen, so peak auto-holds flip the button to "Resume session" without waiting for a
125
- poll; the 10s `/session-guard/state` poll remains as a fallback. `/state` now reports
126
- `paused.manual` and `stepGate.manual`.
127
- - **Styling aligned** with input-traffic's composer button (24px height, 6px radius, 12px font, the
128
- same border/hover/pressed tokens) for both the pause button and the status badge; styles are
129
- injected once via `<style data-plugin-css="session-guard-client">`.
130
-
131
- ## Unreleased
132
-
133
- ### Added
134
-
135
- - **Official-source two-dimensional guard (peak × target provider).** Peak hours now block only
136
- requests whose target route is a DeepSeek official source; local/third-party providers keep
137
- running. Verdict order: explicit `officialProviders` id list → live `baseURL` endpoint →
138
- catalog builtin endpoint (pi-ai's `deepseek`) → builtin id (`deepseek-official`); each verdict
139
- reports `matchedBy`. New modules: `src/provider.js` (pure), `src/provider-directory.js`,
140
- `src/deferrals.js`, `src/request-guard.js`, `src/targets.js`, `src/wiring.js`.
141
- - **Request-level backstop (`agent/request`).** Covers sessions started after peak entry and
142
- sessions switched to an official source mid-run — the 30s tick only handled sessions that were
143
- already `running` at the transition. Default `hold` mode suspends the request without an error
144
- and releases it at the exact off-peak instant (`msUntilOffPeak`); `error` mode throws a
145
- recognizable `PEAK_DEFERRED` failure and records a deferral for off-peak resume.
146
- - **New settings**: `providerGuard`, `officialProviders`, `officialBaseURLs`, `deferredResume`,
147
- `deferredResumeText`, `deferredMode`, `deferredMaxHoldMs` (default 6h), `guardSubagents`.
148
- - **New routes**: `GET /session-guard/provider?provider=<id>` (verdict diagnostics);
149
- `/session-guard/status` now reports `providerGuard` / `held` / `deferred`;
150
- `/session-guard/state` reports the session's last target.
151
- - **Drift guard** `tools/check-api-drift.ps1` asserting the required APIs exist on
152
- `dsh-v0.1.1-rc.2` / `dsh-v0.1.2-rc.1` / `dsh-v0.1.3-alpha.2` / `dsh-v0.1.5-alpha.1`.
153
-
154
- ### Changed
155
-
156
- - **DSH dual-version support (0.1.0-rc.7 … 0.1.2-rc.1).** One artifact now covers both
157
- `dsh-v0.1.1-rc.2` and `dsh-v0.1.2-rc.1`. The `tool/result` call-id dual read
158
- (`content[].toolCallId` first, `source.callId` fallback — both forms appear in replay logs of
159
- both versions) is extracted to the dependency-free `src/tool-call-id.js` with unit tests.
160
- `dsh.client.inject` no longer names `@deepseek-ai/dsh-client-runtime` (removed in 0.1.2) or
161
- `@deepseek-ai/dsh-client-ui-slots` (not a dynamic client row); peer ranges widened to
162
- `>=0.1.0-rc.7 <0.2.0-0` and the removed package dropped. Added `engines.dsh` and a
163
- version-compatibility table to the README (ZH/EN).
164
- - **Settings surface stays on the intersection API**: `settings.register` + `settings.get` only;
165
- `installSection` (0.1.2+) and the removed `installSettingsSection` are never used. Optional
166
- APIs (`model/selection`, `llm.listConfigurableProviders`, `settings.get`) are feature-probed and
167
- degrade instead of throwing.
168
- - **`src/retry.js` short-circuits only the exact `PEAK_DEFERRED` sentinel.** 429 / `RATE_LIMIT` /
169
- `TRANSPORT` / timeout failures remain transient, so DSH's global retry (`dsh-llm-retry` on
170
- `agent/request-error`) and this plugin's own retry semantics are unchanged. `dsh-llm-retry`
171
- itself is never touched.
172
- - Badge distinguishes "peak · official only" from "peak · all paused".
173
-
174
- ## 0.1.4 — 2026-09-09
175
-
176
- ### Changed
177
-
178
- - **Public beta release** of the dual-version line (`0.1.4-beta.1`): version metadata, README
179
- compatibility table and package metadata aligned for the beta channel.
180
-
181
- ## 0.1.3 — 2026-09-09
182
-
183
- ### Fixed
184
-
185
- - **package.json encoding restored**: description was corrupted (GB2312 bytes misread as UTF-8); rewritten with correct Chinese text.
186
- - **Missing metadata**: added `repository`, `homepage` fields.
187
- - **peerDependencies corrected**: removed pinned `dsh-llm` exact version; added `cordis`, `dsh-client-runtime`, `dsh-client-locale`, `dsh-client-ui-settings`, `dsh-client-ui-slots` as optional peers matching `dsh.client.inject`.
188
- - Added `dsh.plugin.json` manifest.
189
-
190
- ## 0.1.2 — 2026-08-28
191
-
192
- ### Fixed
193
-
194
- - **Peak timezone fixed**: 峰谷判定固定北京时间 (`BILLING_TIMEZONE`),周末判定用配置时区。
195
-
196
- ## 0.1.1 — 2026-08-24
197
-
198
- ### Added
199
-
200
- - **Backend auto-retry (D9)**: `turn/end` transient failures (error/429/max-tokens) trigger adaptive-backoff `followup(retryText)` resume; permanent failures (auth/balance/model/context limit) stop; user intervention or successful turn resets consecutive failure count.
201
- - **Freeze/gate yield**: retry skips when `isFrozen(sessionId)` is true (queueLocked / paused / taskControl paused), never bypasses the session gate.
202
-
203
- ### Changed
204
-
205
- - `sessionGuard` redundant port now exposes `state(sessionId)` returning `{ queueLocked, lockReason, paused, taskControlAvailable, taskControl }`.
206
- - HTTP route `GET /session-guard/diag` returns runtime diagnostics including retry state.
207
-
208
- ### Fixed
209
-
210
- - Weekend detection now uses `Intl.DateTimeFormat` with the configured timezone instead of bare `getUTCDay()`, fixing an 8-hour boundary bug for Beijing timezone.
211
-
212
- ## 0.1.0 — 2026-08-18
213
-
214
- ### Added
215
-
216
- - Initial release: peak auto-pause (global), weekend mode, per-session freeze/resume via `sessionGuard` redundant port + RPC bridge, custom session gate (`agent.cancel keepInbox + goals.pause + session/event safe boundary + followup resume`), settings panel (Settings → Plugins → session-guard).
1
+ # Changelog
2
+
3
+ All notable changes to `dsh-session-guard` are recorded here. Versions follow semver.
4
+
5
+ - [English changelog](./CHANGELOG.md)
6
+ - [日本語 changelog](./CHANGELOG.ja.md)
7
+ - [한국어 changelog](./CHANGELOG.ko.md)
8
+ - [Changelog en français](./CHANGELOG.fr.md)
9
+ - [Changelog auf Deutsch](./CHANGELOG.de.md)
10
+ - [Changelog in italiano](./CHANGELOG.it.md)
11
+ - [Changelog на русском](./CHANGELOG.ru.md)
12
+ - [Changelog en español](./CHANGELOG.es.md)
13
+
14
+ ## 4.0.0 — 2026-09-29
15
+
16
+ ### Changed
17
+ - **DSH 0.2.0 line adaptation**: `engines.dsh` and the four `@deepseek-ai/dsh-client-*` peers move to `>=0.2.0-rc.1 <0.2.1-0` (replacing the 0.1.7 ranges); npm dist-tag `dsh-0.2.0`; manifest version aligned to `4.0.0`. The plugin-facing API surface (manifest / settings / HMR / slots / session v4) is unchanged from 0.1.7 — no runtime code changes.
18
+ - `@deepseek-ai/cordis` peer floor aligned to `^4.0.4` (the 0.2.0-rc.1 host UI packages declare `~4.0.4`; the previous `^4.0.1` accepted it but understated the floor).
19
+
20
+ ### Fixed
21
+ - `src/client/family-section.tsx` landed in version control (it had existed only in the working tree since 3.2.x, so a clean checkout could not build).
22
+ - eslint flat config: dropped the core `no-unused-vars` rule — it mis-flags TS type-signature parameters; the typescript-eslint variant is kept, and the lint baseline is green again.
23
+ - v4 source-kind static gates (`tests/source-kind.test.mjs`) are now tracked and run in `npm test` (248 tests).
24
+
25
+ ## 3.2.4 — 2026-09-27
26
+
27
+ ### Fixed
28
+ - **Session format v4 adaptation (host >= 0.1.7-rc.1)**: the three session-writing paths no longer use the retired `source: { kind: 'plugin', plugin: 'session-guard' }` signature, which the v4 host rejects with `SessionFormatError` (whole round fails). All three now use the producer-owned kind:
29
+ - delayed-resume notice injection (`src/wiring.js`);
30
+ - auto-retry notice injection (`src/retry.js`);
31
+ - pause-resume followup (`src/pause-gate.js`, ```kind: `plugin:${pluginId}````).
32
+ - **tool-result v4 native adaptation (N1)**: `findToolOutcome` in `src/pause-gate.js` now reads the v4 first-class `role:'tool'` message (`toolCallId`/`isError` at message top level) first; the v3 `tool-result` block path is kept as historical fallback. Without this, a failed tool at pause time was reported as completed on resume ("do not re-run") — a silent wrong decision. `src/tool-call-id.js` reads the native top-level id first; stale 0.1.1/0.1.2-era header notes corrected to the three-shape generation table.
33
+ `form` and all other fields are unchanged; the host's own v3-to-v4 migration lifts existing legacy rows, so no historical data is rewritten. Evidence: `@deepseek-ai/dsh-session-format-v3-to-v4@0.1.7-rc.2` validates only that `source.kind` is non-empty and not `'plugin'`.
34
+
35
+ ## 0.4.0 — 2026-09-18 (mis-versioned; superseded by 3.0.0)
36
+
37
+ ### Fixed
38
+
39
+ - **Version identity.** This line was published as `0.4.0` while `dsh.plugin.json` and this
40
+ changelog already said `3.0.0` — one artifact with two version numbers. `package.json` is now
41
+ `3.0.0`, so the package version, the manifest version and the changelog agree. `0.4.0` is kept
42
+ here as a historical record because npm versions are immutable; `dist-tag dsh-0.1.5` should be
43
+ repointed to `3.0.0` once it is published.
44
+ - **Docs.** README/INSTALL (zh/en/ja/ko) no longer describe the sibling line as living on `main`.
45
+ The 0.1.2 line's release branch is **`legacy/0.1.2`** (npm dist-tag `dsh-0.1.2`, version `0.3.1`);
46
+ `main` is frozen at `0.2.0-beta.1`. The duplicated branch fragment in the INSTALL.zh/ja/ko install
47
+ command is fixed, explicit dist-tag install commands are documented, and "2.x / 3.x" is
48
+ now marked as a **line nickname** rather than a version number.
49
+
50
+ ### Notes
51
+
52
+ - **No source changes** relative to `3.0.0`; `0.4.0` is a packaging-only publish of the same tree.
53
+
54
+ ## 3.0.0 — 2026-09-14
55
+
56
+ ### Changed
57
+
58
+ - **DSH v0.1.5-rc.2 dedicated line (`compat/0.1.5`).** `engines.dsh` and the `dsh-client-*`
59
+ peer ranges narrow to `>=0.1.5-rc.2 <0.2.0-0` (strict-semver prerelease matching means the
60
+ old `>=0.1.0-rc.7` range never matches `0.1.5-rc.2`); `dsh.plugin.json` gains `engines.dsh`.
61
+ The 2.x / 0.2.x line on `main` keeps serving DSH 0.1.0-rc.7 … 0.1.2-rc.1.
62
+ - **`session.events` → `snapshotEvents()`.** DSH 0.1.5 removed the `session.events` array
63
+ accessor (compatibility-guide §20.3). `pause-gate.js` now reads session events through a
64
+ dual-path helper: `snapshotEvents()` first, the legacy `events` array as a defensive
65
+ fallback, `null` (fail-open) when neither exists. Affects `findToolOutcome` and
66
+ `lastUserPrompt` only; event-type matching is unchanged.
67
+
68
+ ### Unchanged
69
+
70
+ - Zero changes on every other integration seam: the self-held webServer prefix route
71
+ (`/session-guard/rpc`), `settings.register`, the `settings.plugin.item` card slot,
72
+ client injections, and `llm.listConfigurableProviders()` are all verified intact against
73
+ the published 0.1.5-rc.2 bundle (`tools/check-api-drift.ps1`, 12/12 required assertions).
74
+
75
+ ### Pending
76
+
77
+ - Live smoke on a real DSH 0.1.5-rc.2 host (same status as the perm-gate 0.1.5 line).
78
+
79
+ ## 0.2.0-beta.2 — 2026-09-13
80
+
81
+ ### Fixed (DSH 0.1.5 compat — `compat/0.1.5` branch)
82
+
83
+ - **Dual-path resume enqueue.** DSH 0.1.5 turns the Inbox into an agent-loop read-only
84
+ projection, so `agent.followup` may no longer exist. The resume flow now tries
85
+ `agent.followup` first, falls back to `agent.send`, and degrades to a warn (never throws)
86
+ when neither is available — a failed enqueue can no longer break resume.
87
+ - **Resume messages carry `source.form: 'instructions'`** per the 0.1.5 `ContextFormed`
88
+ message-source contract (`kind: 'plugin'` is a built-in kind; older DSH versions ignore
89
+ the extra field).
90
+ - **`webServer.register` is wrapped in try/catch**: a failed route registration now logs an
91
+ error instead of throwing out of `apply` and breaking host plugin loading.
92
+ - Verified against the 0.1.5-rc.2 source: the `WebRoute` contract (exact/prefix + SSE) is
93
+ unchanged, so client `fetch('/session-guard/...')` paths need no `/api` prefix.
94
+
95
+ ## 0.2.0-beta.1 — 2026-09-10
96
+
97
+ ### Added
98
+
99
+ - **Step-level gate (`agent/pre-step`).** During peak hours the turn is now held **before** the
100
+ next step's model request instead of being interrupted at a turn boundary: the session keeps
101
+ running until the next `agent/pre-step`, where the gate holds it (setting `stepLevelPause`, on by
102
+ default). The turn resumes **in place** off-peak — no followup message needed. Hold conditions:
103
+ peak (Beijing time) + not weekend + `step > 1` + official target provider (`providerGuard`) +
104
+ not request-held + not bypassed in this peak window. New module `src/step-gate.js` (pure
105
+ `decideStepHold` + hold / release / abort / timeout engine).
106
+ - **`stepResume` port + RPC + `/resume`.** `sessionGuard.stepResume(sessionId, {bypass})`,
107
+ `POST /session-guard/rpc {action:'stepResume'}` and `/resume` all release the gate; a manual
108
+ resume also stops gating that session for the rest of the peak window.
109
+ - **Timeout escalation.** `stepGateTimeoutMs` (default 300000) releases the gate and escalates to a
110
+ turn-level **force** pause, so a long peak neither deadlocks nor drips one step every five minutes.
111
+ - **"⏸ Pause session" button** (client, slot `conversation.input.right`, id `session-guard-pause`,
112
+ order 20 — left of input-traffic's freeze button). It polls `/session-guard/state` once a second,
113
+ stays disabled while nothing is held, and calls `stepResume` when it is. The status badge moved to
114
+ order 40 and now reports the number of step-held sessions.
115
+ - **New settings**: `stepLevelPause`, `stepGateTimeoutMs`.
116
+ - **New state**: `GET /session-guard/state` now returns `paused: { step, turn }` and
117
+ `stepGate: { held, since, bypass }`; `/status` returns `stepHeld`; `/diag` returns `stepGate`.
118
+ The service port's `state().paused` stays boolean for compatibility (new field `pausedStep`).
119
+
120
+ ### Fixed
121
+
122
+ - **Deadlock between a held step and a turn-level pause.** `pauseTask` / `resumeTask` /
123
+ `cancelTask` now release the step gate first: a step hold sits at `agent/pre-step`, where no
124
+ `assistant/message` or `tool/result` can ever arrive, so a `safe` pause used to wait forever and
125
+ never persisted `paused`.
126
+
127
+ ### Changed
128
+
129
+ - **Peak entry no longer interrupts running turns** when `stepLevelPause` is on (`onEnterPeak` arms
130
+ the step gate instead of calling `stopNextTurn`); with it off the previous turn-level behaviour is
131
+ unchanged.
132
+ - input-traffic's freeze button label is now **"Freeze & append"** (`冻结追加` / `凍結して追加` /
133
+ `동결 후 추가`), and its resume label **"Resume & append"** (`恢复追加` / `再開して追加` /
134
+ `재개 후 추가`) — it freezes the turn and keeps queued messages, distinct from the pause button.
135
+ - **The pause button is a toggle now**: "Pause session" / "Resume session" (no disabled grey state).
136
+ Clicking "Pause session" calls the new `stepPause` action, which holds the session at the **next
137
+ step boundary** (step 1 included, regardless of peak or provider); "Resume session" calls
138
+ `stepResume`. New port method `sessionGuard.stepPause(sessionId)`.
139
+ - **SSE push**: new route `GET /session-guard/events?session=<id>` pushes step-gate state changes the
140
+ moment they happen, so peak auto-holds flip the button to "Resume session" without waiting for a
141
+ poll; the 10s `/session-guard/state` poll remains as a fallback. `/state` now reports
142
+ `paused.manual` and `stepGate.manual`.
143
+ - **Styling aligned** with input-traffic's composer button (24px height, 6px radius, 12px font, the
144
+ same border/hover/pressed tokens) for both the pause button and the status badge; styles are
145
+ injected once via `<style data-plugin-css="session-guard-client">`.
146
+
147
+ ## Unreleased
148
+
149
+ ### Added
150
+
151
+ - **Official-source two-dimensional guard (peak × target provider).** Peak hours now block only
152
+ requests whose target route is a DeepSeek official source; local/third-party providers keep
153
+ running. Verdict order: explicit `officialProviders` id list → live `baseURL` endpoint →
154
+ catalog builtin endpoint (pi-ai's `deepseek`) → builtin id (`deepseek-official`); each verdict
155
+ reports `matchedBy`. New modules: `src/provider.js` (pure), `src/provider-directory.js`,
156
+ `src/deferrals.js`, `src/request-guard.js`, `src/targets.js`, `src/wiring.js`.
157
+ - **Request-level backstop (`agent/request`).** Covers sessions started after peak entry and
158
+ sessions switched to an official source mid-run — the 30s tick only handled sessions that were
159
+ already `running` at the transition. Default `hold` mode suspends the request without an error
160
+ and releases it at the exact off-peak instant (`msUntilOffPeak`); `error` mode throws a
161
+ recognizable `PEAK_DEFERRED` failure and records a deferral for off-peak resume.
162
+ - **New settings**: `providerGuard`, `officialProviders`, `officialBaseURLs`, `deferredResume`,
163
+ `deferredResumeText`, `deferredMode`, `deferredMaxHoldMs` (default 6h), `guardSubagents`.
164
+ - **New routes**: `GET /session-guard/provider?provider=<id>` (verdict diagnostics);
165
+ `/session-guard/status` now reports `providerGuard` / `held` / `deferred`;
166
+ `/session-guard/state` reports the session's last target.
167
+ - **Drift guard** `tools/check-api-drift.ps1` asserting the required APIs exist on
168
+ `dsh-v0.1.1-rc.2` / `dsh-v0.1.2-rc.1` / `dsh-v0.1.3-alpha.2` / `dsh-v0.1.5-alpha.1`.
169
+
170
+ ### Changed
171
+
172
+ - **DSH dual-version support (0.1.0-rc.7 … 0.1.2-rc.1).** One artifact now covers both
173
+ `dsh-v0.1.1-rc.2` and `dsh-v0.1.2-rc.1`. The `tool/result` call-id dual read
174
+ (`content[].toolCallId` first, `source.callId` fallback — both forms appear in replay logs of
175
+ both versions) is extracted to the dependency-free `src/tool-call-id.js` with unit tests.
176
+ `dsh.client.inject` no longer names `@deepseek-ai/dsh-client-runtime` (removed in 0.1.2) or
177
+ `@deepseek-ai/dsh-client-ui-slots` (not a dynamic client row); peer ranges widened to
178
+ `>=0.1.0-rc.7 <0.2.0-0` and the removed package dropped. Added `engines.dsh` and a
179
+ version-compatibility table to the README (ZH/EN).
180
+ - **Settings surface stays on the intersection API**: `settings.register` + `settings.get` only;
181
+ `installSection` (0.1.2+) and the removed `installSettingsSection` are never used. Optional
182
+ APIs (`model/selection`, `llm.listConfigurableProviders`, `settings.get`) are feature-probed and
183
+ degrade instead of throwing.
184
+ - **`src/retry.js` short-circuits only the exact `PEAK_DEFERRED` sentinel.** 429 / `RATE_LIMIT` /
185
+ `TRANSPORT` / timeout failures remain transient, so DSH's global retry (`dsh-llm-retry` on
186
+ `agent/request-error`) and this plugin's own retry semantics are unchanged. `dsh-llm-retry`
187
+ itself is never touched.
188
+ - Badge distinguishes "peak · official only" from "peak · all paused".
189
+
190
+ ## 0.1.4 — 2026-09-09
191
+
192
+ ### Changed
193
+
194
+ - **Public beta release** of the dual-version line (`0.1.4-beta.1`): version metadata, README
195
+ compatibility table and package metadata aligned for the beta channel.
196
+
197
+ ## 0.1.3 — 2026-09-09
198
+
199
+ ### Fixed
200
+
201
+ - **package.json encoding restored**: description was corrupted (GB2312 bytes misread as UTF-8); rewritten with correct Chinese text.
202
+ - **Missing metadata**: added `repository`, `homepage` fields.
203
+ - **peerDependencies corrected**: removed pinned `dsh-llm` exact version; added `cordis`, `dsh-client-runtime`, `dsh-client-locale`, `dsh-client-ui-settings`, `dsh-client-ui-slots` as optional peers matching `dsh.client.inject`.
204
+ - Added `dsh.plugin.json` manifest.
205
+
206
+ ## 0.1.2 — 2026-08-28
207
+
208
+ ### Fixed
209
+
210
+ - **Peak timezone fixed**: 峰谷判定固定北京时间 (`BILLING_TIMEZONE`),周末判定用配置时区。
211
+
212
+ ## 0.1.1 — 2026-08-24
213
+
214
+ ### Added
215
+
216
+ - **Backend auto-retry (D9)**: `turn/end` transient failures (error/429/max-tokens) trigger adaptive-backoff `followup(retryText)` resume; permanent failures (auth/balance/model/context limit) stop; user intervention or successful turn resets consecutive failure count.
217
+ - **Freeze/gate yield**: retry skips when `isFrozen(sessionId)` is true (queueLocked / paused / taskControl paused), never bypasses the session gate.
218
+
219
+ ### Changed
220
+
221
+ - `sessionGuard` redundant port now exposes `state(sessionId)` returning `{ queueLocked, lockReason, paused, taskControlAvailable, taskControl }`.
222
+ - HTTP route `GET /session-guard/diag` returns runtime diagnostics including retry state.
223
+
224
+ ### Fixed
225
+
226
+ - Weekend detection now uses `Intl.DateTimeFormat` with the configured timezone instead of bare `getUTCDay()`, fixing an 8-hour boundary bug for Beijing timezone.
227
+
228
+ ## 0.1.0 — 2026-08-18
229
+
230
+ ### Added
231
+
232
+ - Initial release: peak auto-pause (global), weekend mode, per-session freeze/resume via `sessionGuard` redundant port + RPC bridge, custom session gate (`agent.cancel keepInbox + goals.pause + session/event safe boundary + followup resume`), settings panel (Settings → Plugins → session-guard).
package/INSTALL.ja.md CHANGED
@@ -4,6 +4,11 @@
4
4
  - [English installation guide](./INSTALL.md)
5
5
  - [中文安装指南](./INSTALL.zh.md)
6
6
  - [한국어 설치 안내](./INSTALL.ko.md)
7
+ - [Guide d'installation en français](./INSTALL.fr.md)
8
+ - [Installationsanleitung auf Deutsch](./INSTALL.de.md)
9
+ - [Guida all'installazione in italiano](./INSTALL.it.md)
10
+ - [Руководство по установке на русском](./INSTALL.ru.md)
11
+ - [Guía de instalación en español](./INSTALL.es.md)
7
12
  - [日本語 README](./README.ja.md)
8
13
  - [English README](./README.en.md)
9
14
  - [中文 README](./README.md)
package/INSTALL.ko.md CHANGED
@@ -4,6 +4,11 @@
4
4
  - [English installation guide](./INSTALL.md)
5
5
  - [中文安装指南](./INSTALL.zh.md)
6
6
  - [日本語インストールガイド](./INSTALL.ja.md)
7
+ - [Guide d'installation en français](./INSTALL.fr.md)
8
+ - [Installationsanleitung auf Deutsch](./INSTALL.de.md)
9
+ - [Guida all'installazione in italiano](./INSTALL.it.md)
10
+ - [Руководство по установке на русском](./INSTALL.ru.md)
11
+ - [Guía de instalación en español](./INSTALL.es.md)
7
12
  - [한국어 README](./README.ko.md)
8
13
  - [English README](./README.en.md)
9
14
  - [中文 README](./README.md)
package/INSTALL.md CHANGED
@@ -6,6 +6,11 @@ This guide uses only the official DSH `dsh plugin` command.
6
6
  - [中文安装指南](./INSTALL.zh.md)
7
7
  - [日本語インストールガイド](./INSTALL.ja.md)
8
8
  - [한국어 설치 안내](./INSTALL.ko.md)
9
+ - [Guide d'installation en français](./INSTALL.fr.md)
10
+ - [Installationsanleitung auf Deutsch](./INSTALL.de.md)
11
+ - [Guida all'installazione in italiano](./INSTALL.it.md)
12
+ - [Руководство по установке на русском](./INSTALL.ru.md)
13
+ - [Guía de instalación en español](./INSTALL.es.md)
9
14
  - [English README](./README.en.md)
10
15
  - [中文 README](./README.md)
11
16
  - [日本語 README](./README.ja.md)
package/INSTALL.zh.md CHANGED
@@ -4,6 +4,11 @@
4
4
  - [English installation guide](./INSTALL.md)
5
5
  - [日本語インストールガイド](./INSTALL.ja.md)
6
6
  - [한국어 설치 안내](./INSTALL.ko.md)
7
+ - [Guide d'installation en français](./INSTALL.fr.md)
8
+ - [Installationsanleitung auf Deutsch](./INSTALL.de.md)
9
+ - [Guida all'installazione in italiano](./INSTALL.it.md)
10
+ - [Руководство по установке на русском](./INSTALL.ru.md)
11
+ - [Guía de instalación en español](./INSTALL.es.md)
7
12
  - [中文 README](./README.md)
8
13
  - [English README](./README.en.md)
9
14
  - [日本語 README](./README.ja.md)
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 dsh-session-guard contributors
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dsh-session-guard contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.