dsh-session-guard 3.2.3 → 3.2.4

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/CHANGELOG.md CHANGED
@@ -1,206 +1,216 @@
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
- ## 0.4.0 — 2026-09-18 (mis-versioned; superseded by 3.0.0)
10
-
11
- ### Fixed
12
-
13
- - **Version identity.** This line was published as `0.4.0` while `dsh.plugin.json` and this
14
- changelog already said `3.0.0` — one artifact with two version numbers. `package.json` is now
15
- `3.0.0`, so the package version, the manifest version and the changelog agree. `0.4.0` is kept
16
- here as a historical record because npm versions are immutable; `dist-tag dsh-0.1.5` should be
17
- repointed to `3.0.0` once it is published.
18
- - **Docs.** README/INSTALL (zh/en/ja/ko) no longer describe the sibling line as living on `main`.
19
- The 0.1.2 line's release branch is **`legacy/0.1.2`** (npm dist-tag `dsh-0.1.2`, version `0.3.1`);
20
- `main` is frozen at `0.2.0-beta.1`. The duplicated branch fragment in the INSTALL.zh/ja/ko install
21
- command is fixed, explicit dist-tag install commands are documented, and "2.x / 3.x" is
22
- now marked as a **line nickname** rather than a version number.
23
-
24
- ### Notes
25
-
26
- - **No source changes** relative to `3.0.0`; `0.4.0` is a packaging-only publish of the same tree.
27
-
28
- ## 3.0.0 — 2026-09-14
29
-
30
- ### Changed
31
-
32
- - **DSH v0.1.5-rc.2 dedicated line (`compat/0.1.5`).** `engines.dsh` and the `dsh-client-*`
33
- peer ranges narrow to `>=0.1.5-rc.2 <0.2.0-0` (strict-semver prerelease matching means the
34
- old `>=0.1.0-rc.7` range never matches `0.1.5-rc.2`); `dsh.plugin.json` gains `engines.dsh`.
35
- The 2.x / 0.2.x line on `main` keeps serving DSH 0.1.0-rc.7 … 0.1.2-rc.1.
36
- - **`session.events` → `snapshotEvents()`.** DSH 0.1.5 removed the `session.events` array
37
- accessor (compatibility-guide §20.3). `pause-gate.js` now reads session events through a
38
- dual-path helper: `snapshotEvents()` first, the legacy `events` array as a defensive
39
- fallback, `null` (fail-open) when neither exists. Affects `findToolOutcome` and
40
- `lastUserPrompt` only; event-type matching is unchanged.
41
-
42
- ### Unchanged
43
-
44
- - Zero changes on every other integration seam: the self-held webServer prefix route
45
- (`/session-guard/rpc`), `settings.register`, the `settings.plugin.item` card slot,
46
- client injections, and `llm.listConfigurableProviders()` are all verified intact against
47
- the published 0.1.5-rc.2 bundle (`tools/check-api-drift.ps1`, 12/12 required assertions).
48
-
49
- ### Pending
50
-
51
- - Live smoke on a real DSH 0.1.5-rc.2 host (same status as the perm-gate 0.1.5 line).
52
-
53
- ## 0.2.0-beta.2 — 2026-09-13
54
-
55
- ### Fixed (DSH 0.1.5 compat — `compat/0.1.5` branch)
56
-
57
- - **Dual-path resume enqueue.** DSH 0.1.5 turns the Inbox into an agent-loop read-only
58
- projection, so `agent.followup` may no longer exist. The resume flow now tries
59
- `agent.followup` first, falls back to `agent.send`, and degrades to a warn (never throws)
60
- when neither is available — a failed enqueue can no longer break resume.
61
- - **Resume messages carry `source.form: 'instructions'`** per the 0.1.5 `ContextFormed`
62
- message-source contract (`kind: 'plugin'` is a built-in kind; older DSH versions ignore
63
- the extra field).
64
- - **`webServer.register` is wrapped in try/catch**: a failed route registration now logs an
65
- error instead of throwing out of `apply` and breaking host plugin loading.
66
- - Verified against the 0.1.5-rc.2 source: the `WebRoute` contract (exact/prefix + SSE) is
67
- unchanged, so client `fetch('/session-guard/...')` paths need no `/api` prefix.
68
-
69
- ## 0.2.0-beta.1 — 2026-09-10
70
-
71
- ### Added
72
-
73
- - **Step-level gate (`agent/pre-step`).** During peak hours the turn is now held **before** the
74
- next step's model request instead of being interrupted at a turn boundary: the session keeps
75
- running until the next `agent/pre-step`, where the gate holds it (setting `stepLevelPause`, on by
76
- default). The turn resumes **in place** off-peak — no followup message needed. Hold conditions:
77
- peak (Beijing time) + not weekend + `step > 1` + official target provider (`providerGuard`) +
78
- not request-held + not bypassed in this peak window. New module `src/step-gate.js` (pure
79
- `decideStepHold` + hold / release / abort / timeout engine).
80
- - **`stepResume` port + RPC + `/resume`.** `sessionGuard.stepResume(sessionId, {bypass})`,
81
- `POST /session-guard/rpc {action:'stepResume'}` and `/resume` all release the gate; a manual
82
- resume also stops gating that session for the rest of the peak window.
83
- - **Timeout escalation.** `stepGateTimeoutMs` (default 300000) releases the gate and escalates to a
84
- turn-level **force** pause, so a long peak neither deadlocks nor drips one step every five minutes.
85
- - **"⏸ Pause session" button** (client, slot `conversation.input.right`, id `session-guard-pause`,
86
- order 20 — left of input-traffic's freeze button). It polls `/session-guard/state` once a second,
87
- stays disabled while nothing is held, and calls `stepResume` when it is. The status badge moved to
88
- order 40 and now reports the number of step-held sessions.
89
- - **New settings**: `stepLevelPause`, `stepGateTimeoutMs`.
90
- - **New state**: `GET /session-guard/state` now returns `paused: { step, turn }` and
91
- `stepGate: { held, since, bypass }`; `/status` returns `stepHeld`; `/diag` returns `stepGate`.
92
- The service port's `state().paused` stays boolean for compatibility (new field `pausedStep`).
93
-
94
- ### Fixed
95
-
96
- - **Deadlock between a held step and a turn-level pause.** `pauseTask` / `resumeTask` /
97
- `cancelTask` now release the step gate first: a step hold sits at `agent/pre-step`, where no
98
- `assistant/message` or `tool/result` can ever arrive, so a `safe` pause used to wait forever and
99
- never persisted `paused`.
100
-
101
- ### Changed
102
-
103
- - **Peak entry no longer interrupts running turns** when `stepLevelPause` is on (`onEnterPeak` arms
104
- the step gate instead of calling `stopNextTurn`); with it off the previous turn-level behaviour is
105
- unchanged.
106
- - input-traffic's freeze button label is now **"Freeze & append"** (`冻结追加` / `凍結して追加` /
107
- `동결 후 추가`), and its resume label **"Resume & append"** (`恢复追加` / `再開して追加` /
108
- `재개 후 추가`) — it freezes the turn and keeps queued messages, distinct from the pause button.
109
- - **The pause button is a toggle now**: "Pause session" / "Resume session" (no disabled grey state).
110
- Clicking "Pause session" calls the new `stepPause` action, which holds the session at the **next
111
- step boundary** (step 1 included, regardless of peak or provider); "Resume session" calls
112
- `stepResume`. New port method `sessionGuard.stepPause(sessionId)`.
113
- - **SSE push**: new route `GET /session-guard/events?session=<id>` pushes step-gate state changes the
114
- moment they happen, so peak auto-holds flip the button to "Resume session" without waiting for a
115
- poll; the 10s `/session-guard/state` poll remains as a fallback. `/state` now reports
116
- `paused.manual` and `stepGate.manual`.
117
- - **Styling aligned** with input-traffic's composer button (24px height, 6px radius, 12px font, the
118
- same border/hover/pressed tokens) for both the pause button and the status badge; styles are
119
- injected once via `<style data-plugin-css="session-guard-client">`.
120
-
121
- ## Unreleased
122
-
123
- ### Added
124
-
125
- - **Official-source two-dimensional guard (peak × target provider).** Peak hours now block only
126
- requests whose target route is a DeepSeek official source; local/third-party providers keep
127
- running. Verdict order: explicit `officialProviders` id list → live `baseURL` endpoint →
128
- catalog builtin endpoint (pi-ai's `deepseek`) → builtin id (`deepseek-official`); each verdict
129
- reports `matchedBy`. New modules: `src/provider.js` (pure), `src/provider-directory.js`,
130
- `src/deferrals.js`, `src/request-guard.js`, `src/targets.js`, `src/wiring.js`.
131
- - **Request-level backstop (`agent/request`).** Covers sessions started after peak entry and
132
- sessions switched to an official source mid-run — the 30s tick only handled sessions that were
133
- already `running` at the transition. Default `hold` mode suspends the request without an error
134
- and releases it at the exact off-peak instant (`msUntilOffPeak`); `error` mode throws a
135
- recognizable `PEAK_DEFERRED` failure and records a deferral for off-peak resume.
136
- - **New settings**: `providerGuard`, `officialProviders`, `officialBaseURLs`, `deferredResume`,
137
- `deferredResumeText`, `deferredMode`, `deferredMaxHoldMs` (default 6h), `guardSubagents`.
138
- - **New routes**: `GET /session-guard/provider?provider=<id>` (verdict diagnostics);
139
- `/session-guard/status` now reports `providerGuard` / `held` / `deferred`;
140
- `/session-guard/state` reports the session's last target.
141
- - **Drift guard** `tools/check-api-drift.ps1` asserting the required APIs exist on
142
- `dsh-v0.1.1-rc.2` / `dsh-v0.1.2-rc.1` / `dsh-v0.1.3-alpha.2` / `dsh-v0.1.5-alpha.1`.
143
-
144
- ### Changed
145
-
146
- - **DSH dual-version support (0.1.0-rc.7 … 0.1.2-rc.1).** One artifact now covers both
147
- `dsh-v0.1.1-rc.2` and `dsh-v0.1.2-rc.1`. The `tool/result` call-id dual read
148
- (`content[].toolCallId` first, `source.callId` fallback — both forms appear in replay logs of
149
- both versions) is extracted to the dependency-free `src/tool-call-id.js` with unit tests.
150
- `dsh.client.inject` no longer names `@deepseek-ai/dsh-client-runtime` (removed in 0.1.2) or
151
- `@deepseek-ai/dsh-client-ui-slots` (not a dynamic client row); peer ranges widened to
152
- `>=0.1.0-rc.7 <0.2.0-0` and the removed package dropped. Added `engines.dsh` and a
153
- version-compatibility table to the README (ZH/EN).
154
- - **Settings surface stays on the intersection API**: `settings.register` + `settings.get` only;
155
- `installSection` (0.1.2+) and the removed `installSettingsSection` are never used. Optional
156
- APIs (`model/selection`, `llm.listConfigurableProviders`, `settings.get`) are feature-probed and
157
- degrade instead of throwing.
158
- - **`src/retry.js` short-circuits only the exact `PEAK_DEFERRED` sentinel.** 429 / `RATE_LIMIT` /
159
- `TRANSPORT` / timeout failures remain transient, so DSH's global retry (`dsh-llm-retry` on
160
- `agent/request-error`) and this plugin's own retry semantics are unchanged. `dsh-llm-retry`
161
- itself is never touched.
162
- - Badge distinguishes "peak · official only" from "peak · all paused".
163
-
164
- ## 0.1.4 — 2026-09-09
165
-
166
- ### Changed
167
-
168
- - **Public beta release** of the dual-version line (`0.1.4-beta.1`): version metadata, README
169
- compatibility table and package metadata aligned for the beta channel.
170
-
171
- ## 0.1.3 — 2026-09-09
172
-
173
- ### Fixed
174
-
175
- - **package.json encoding restored**: description was corrupted (GB2312 bytes misread as UTF-8); rewritten with correct Chinese text.
176
- - **Missing metadata**: added `repository`, `homepage` fields.
177
- - **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`.
178
- - Added `dsh.plugin.json` manifest.
179
-
180
- ## 0.1.2 — 2026-08-28
181
-
182
- ### Fixed
183
-
184
- - **Peak timezone fixed**: 峰谷判定固定北京时间 (`BILLING_TIMEZONE`),周末判定用配置时区。
185
-
186
- ## 0.1.1 — 2026-08-24
187
-
188
- ### Added
189
-
190
- - **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.
191
- - **Freeze/gate yield**: retry skips when `isFrozen(sessionId)` is true (queueLocked / paused / taskControl paused), never bypasses the session gate.
192
-
193
- ### Changed
194
-
195
- - `sessionGuard` redundant port now exposes `state(sessionId)` returning `{ queueLocked, lockReason, paused, taskControlAvailable, taskControl }`.
196
- - HTTP route `GET /session-guard/diag` returns runtime diagnostics including retry state.
197
-
198
- ### Fixed
199
-
200
- - Weekend detection now uses `Intl.DateTimeFormat` with the configured timezone instead of bare `getUTCDay()`, fixing an 8-hour boundary bug for Beijing timezone.
201
-
202
- ## 0.1.0 — 2026-08-18
203
-
204
- ### Added
205
-
206
- - 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
+
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).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-session-guard",
3
- "version": "3.2.3",
3
+ "version": "3.2.4",
4
4
  "publishConfig": {
5
5
  "tag": "dsh-0.1.7"
6
6
  },