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.ja.md +143 -133
- package/CHANGELOG.ko.md +143 -133
- package/CHANGELOG.md +216 -206
- package/package.json +1 -1
- package/src/pause-gate.js +544 -524
- package/src/retry.js +227 -227
- package/src/tool-call-id.js +15 -11
- package/src/wiring.js +305 -305
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
|
-
##
|
|
10
|
-
|
|
11
|
-
### Fixed
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
`
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
- **
|
|
84
|
-
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
-
|
|
91
|
-
`
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
- **
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
- **
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
- **
|
|
147
|
-
`
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
`
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
`
|
|
161
|
-
|
|
162
|
-
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
###
|
|
199
|
-
|
|
200
|
-
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
-
|
|
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).
|