dsh-client-auto-continue 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -12
- package/README.zh.md +12 -13
- package/docs/screenshots/04-ai-disclosure.png +0 -0
- package/lib/client.js +3 -4
- package/lib/client.js.map +2 -2
- package/package.json +10 -10
- package/scripts/patch-expose.mjs +12 -7
- package/src/client/engine.ts +4 -1
- package/src/client/index.ts +4 -5
- package/src/client/locales.ts +1 -1
- package/docs/screenshots/Screenshot 2026-08-15 at 14.38.48.png +0 -0
package/README.md
CHANGED
|
@@ -41,8 +41,8 @@ For [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (`dsh we
|
|
|
41
41
|
- **Adaptive backoff** — consecutive failures wait longer each time (cooldown × factor: 20s → 40s → 80s…), capped at the max backoff, instead of hammering a broken upstream
|
|
42
42
|
- **Templated continue text** — `continueText` supports `{code}` `{message}` `{status}` `{tool}` `{turn}` `{errorCount}` `{sessionTitle}` `{elapsed}` placeholders, so the resume message can carry the failure context ("继续 (git push failed: UPSTREAM)"); a **separate template** fires on `max-tokens` (e.g. "继续输出, 不要重复已生成的内容")
|
|
43
43
|
- **Idempotency guard** — before resuming, the plugin inspects the last tool call: if its result is unconfirmed (the turn died mid-tool, e.g. a `git push` that may have gone through), the resume message tells the model to check state first and not to rerun; if the tool is confirmed done, it says so and asks not to repeat it; a failed tool gets no guard (retrying it is the point). Both guard texts are configurable (`{tool}` / `{result}` placeholders)
|
|
44
|
-
- **Pause** — a global **Pause auto-continue** toggle in the settings card stops everything (live + scan) instantly; per-session pauses (e.g. via a notification button) suspend only one session until they expire
|
|
45
|
-
- **Notification buttons** — notifications carry **Resume now** (send immediately, ignoring cooldown
|
|
44
|
+
- **Pause** — a global **Pause auto-continue** toggle in the settings card stops everything (live + scan) instantly; per-session pauses (e.g. via a notification button) suspend only one session until they expire. The **Resume now** notification button is the one explicit exception: pressing it is the user asking for exactly one send, pause or not
|
|
45
|
+
- **Notification buttons** — notifications carry **Resume now** (send immediately, ignoring cooldown, the consecutive cap and any pause) and **Pause this session 1h** actions
|
|
46
46
|
- **Stats panel** — the settings card shows today's auto-continue count, recoveries, failures, permanent skips and give-ups, broken down by error code, with a one-click reset
|
|
47
47
|
- **Browser notifications** — optional alerts when auto-continue fires, gives up, or hits a permanent error; the browser asks for permission on first use, and nothing is shown again after a denial
|
|
48
48
|
|
|
@@ -125,12 +125,12 @@ dsh web
|
|
|
125
125
|
|
|
126
126
|
> Switching from a manual install to `dsh plugin add`? Remove the manual `insert` entry first — the bundle patch registers the row and a duplicate would conflict.
|
|
127
127
|
|
|
128
|
-
> **
|
|
129
|
-
>
|
|
130
|
-
>
|
|
131
|
-
>
|
|
132
|
-
>
|
|
133
|
-
>
|
|
128
|
+
> **Note (DSH ≥ 0.1.0-rc.7):** upstream made settings exposure **registry-driven**
|
|
129
|
+
> — every namespace a plugin registers is served to the web settings surface,
|
|
130
|
+
> so the settings card just works, no vendor patch needed. Only DSH 0.1.0-rc.6
|
|
131
|
+
> and earlier gate exposure behind a hardcoded allowlist in
|
|
132
|
+
> `@deepseek-ai/dsh-host-apiproxy`; on those versions, run the idempotent
|
|
133
|
+
> vendor patch once (and re-run after reinstalling dsh):
|
|
134
134
|
>
|
|
135
135
|
> ```sh
|
|
136
136
|
> npx --yes --package dsh-client-auto-continue patch-expose
|
|
@@ -144,7 +144,7 @@ dsh web
|
|
|
144
144
|
> own. If you installed from this repository instead, the same script is
|
|
145
145
|
> `node scripts/patch-expose.mjs` at the repo root. The auto-continue engine
|
|
146
146
|
> itself works without this patch — it only gates the GUI settings section;
|
|
147
|
-
>
|
|
147
|
+
> on rc.6 and earlier, configure everything directly in `~/.dsh/settings.yaml`
|
|
148
148
|
> (see [Configuration](#configuration)).
|
|
149
149
|
|
|
150
150
|
### Verify & uninstall
|
|
@@ -234,7 +234,7 @@ auto-continue:
|
|
|
234
234
|
The plugin is browser-only and touches **no files, credentials, or network beyond the dsh host**:
|
|
235
235
|
|
|
236
236
|
- It opens the same two read-only event streams the web UI already uses (no extra server, no third-party endpoints)
|
|
237
|
-
- The only write
|
|
237
|
+
- The engine's **only automatic write** is `sessions.prompt` — the same call the Send button makes — with the text you configured (saving the settings card writes the `auto-continue` section of `~/.dsh/settings.yaml` through the normal settings API, exactly like any other setting)
|
|
238
238
|
- Browser storage is limited to small `localStorage` keys: cross-tab coordination stamps, per-session pauses, and the daily stats counters
|
|
239
239
|
- Browser notifications are opt-in (`notify` setting) and permission is requested on first use only
|
|
240
240
|
|
|
@@ -246,12 +246,12 @@ The plugin is browser-only and touches **no files, credentials, or network beyon
|
|
|
246
246
|
npm run typecheck # tsc --noEmit
|
|
247
247
|
npm run build # lib/client.js + lib/index.js + lib/types
|
|
248
248
|
npm run watch # rebuild on change; host HMR hot-reloads without a page refresh
|
|
249
|
-
npm run test # node tests/simulate.mjs —
|
|
249
|
+
npm run test # node tests/simulate.mjs — 29 behavioral scenarios
|
|
250
250
|
```
|
|
251
251
|
|
|
252
252
|
While `npm run watch` runs, the profile's client-hmr row polls `lib/client.js` every 500 ms and hot-reloads the plugin in the browser — no server restart needed for code changes.
|
|
253
253
|
|
|
254
|
-
CI runs [dsh-plugin-check](https://github.com/omdsh-dev/dsh-plugin-check) on every push
|
|
254
|
+
CI runs [dsh-plugin-check](https://github.com/omdsh-dev/dsh-plugin-check) on every push to `main` and every pull request, and gates releases — the tag workflow refuses to publish while the check fails.
|
|
255
255
|
|
|
256
256
|
---
|
|
257
257
|
|
package/README.zh.md
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
<br>
|
|
21
21
|
<img src="https://img.shields.io/badge/TypeScript-3178C6?style=flat&logo=typescript&logoColor=fff" alt="TypeScript">
|
|
22
22
|
<img src="https://img.shields.io/badge/esbuild-FFCF00?style=flat&logo=esbuild&logoColor=000" alt="esbuild">
|
|
23
|
-
<img src="https://img.shields.io/badge/
|
|
23
|
+
<img src="https://img.shields.io/badge/GUI--configurable-0ea5e9?style=flat" alt="GUI configurable">
|
|
24
24
|
</p>
|
|
25
25
|
|
|
26
26
|
<p align="center">
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
- **自适应退避** — 连续失败时等待时间递增(冷却 × 系数: 20s → 40s → 80s…), 有上限, 不再对故障上游狂轰滥炸
|
|
42
42
|
- **模板化继续文本** — `continueText` 支持 `{code}` `{message}` `{status}` `{tool}` `{turn}` `{errorCount}` `{sessionTitle}` `{elapsed}` 占位符, 续跑消息可携带失败上下文(如「继续 (git push 失败: UPSTREAM)」); 达到 `max-tokens` 时使用**另一套模板**(如「继续输出, 不要重复已生成的内容」)
|
|
43
43
|
- **幂等护栏** — 续跑前检查上一步工具调用: 结果未确认(回合在工具执行中途夭折, 如 `git push` 可能已经推上去了)时, 续跑消息会提示模型先确认状态、不要重复执行; 工具已确认成功时说明已完成、请勿重复; 工具失败则不加护栏(重试本来就是目的)。两段护栏文本都可配置(支持 `{tool}` / `{result}` 占位符)
|
|
44
|
-
- **暂停** — 设置卡片里的全局 **暂停自动继续** 开关可立即停掉一切(实时 + 扫描); 会话级暂停(如通过通知按钮)只挂起单个会话,
|
|
45
|
-
- **通知按钮** — 通知带 **立即续跑**(
|
|
44
|
+
- **暂停** — 设置卡片里的全局 **暂停自动继续** 开关可立即停掉一切(实时 + 扫描); 会话级暂停(如通过通知按钮)只挂起单个会话, 到期自动恢复。唯一的显式例外是通知里的 **立即续跑** 按钮——按下它等于用户明确要求发送这一次, 不受暂停限制
|
|
45
|
+
- **通知按钮** — 通知带 **立即续跑**(无视冷却、连续上限与暂停, 马上发送)和 **暂停该会话 1 小时** 按钮
|
|
46
46
|
- **统计面板** — 设置卡片展示今日自动继续次数、恢复成功、继续后失败、永久性跳过、达上限停止, 按错误码分布, 可一键清零
|
|
47
47
|
- **浏览器通知** — 可选: 自动继续成功 / 放弃 / 遇到永久性错误时弹出提醒; 首次使用时请求权限, 被拒绝后不再打扰
|
|
48
48
|
|
|
@@ -125,11 +125,10 @@ dsh web
|
|
|
125
125
|
|
|
126
126
|
> 从手动安装切换到 `dsh plugin add` 时, 请先删掉手动加的 `insert` 条目——包自带的 bundle patch 会注册插件行, 重复注册会冲突。
|
|
127
127
|
|
|
128
|
-
>
|
|
129
|
-
>
|
|
130
|
-
>
|
|
131
|
-
>
|
|
132
|
-
> 没有任何插件相关的硬编码字符串。执行一次即可, 重新安装 dsh 后重跑:
|
|
128
|
+
> **说明(DSH ≥ 0.1.0-rc.7):** 上游已把设置暴露改成**注册表驱动**——插件注册的
|
|
129
|
+
> 任何命名空间都会直接出现在 webui 设置区, 设置卡片开箱即用, 无需任何供应商补丁。
|
|
130
|
+
> 仅 DSH 0.1.0-rc.6 及更早版本仍在 `@deepseek-ai/dsh-host-apiproxy` 里用硬编码白名单
|
|
131
|
+
> 门禁暴露; 这些版本需要执行一次幂等的供应商补丁(重新安装 dsh 后重跑):
|
|
133
132
|
>
|
|
134
133
|
> ```sh
|
|
135
134
|
> npx --yes --package dsh-client-auto-continue patch-expose
|
|
@@ -140,8 +139,8 @@ dsh web
|
|
|
140
139
|
> 无需猜测 profile 路径), 并覆盖所有可达的 dsh 安装: profile 链接副本、全局
|
|
141
140
|
> `npm i -g @deepseek-ai/dsh` 安装、以及当前目录的安装。若是从本仓库安装,
|
|
142
141
|
> 同一脚本在仓库根目录执行 `node scripts/patch-expose.mjs` 即可。自动续跑引擎
|
|
143
|
-
> 本身不依赖这个补丁——它只影响 GUI 设置区是否可见;
|
|
144
|
-
> `~/.dsh/settings.yaml` 里配置全部参数(见 [配置](#配置))。
|
|
142
|
+
> 本身不依赖这个补丁——它只影响 GUI 设置区是否可见; 在 rc.6 及更早版本上,
|
|
143
|
+
> 可以直接在 `~/.dsh/settings.yaml` 里配置全部参数(见 [配置](#配置))。
|
|
145
144
|
|
|
146
145
|
### 验证与卸载
|
|
147
146
|
|
|
@@ -230,7 +229,7 @@ auto-continue:
|
|
|
230
229
|
插件是纯浏览器端, **不触碰任何文件、凭据, 也不访问 dsh 宿主以外的网络**:
|
|
231
230
|
|
|
232
231
|
- 只复用 webui 本身就在用的两条只读事件流(无额外服务、无第三方端点)
|
|
233
|
-
-
|
|
232
|
+
- 引擎**唯一会自动执行的写入**是 `sessions.prompt`——与点「发送」按钮完全相同的调用, 内容为你配置的文本(设置卡片里保存配置会通过常规设置 API 写入 `~/.dsh/settings.yaml` 的 `auto-continue` 段落, 与任何其他设置一样)
|
|
234
233
|
- 浏览器存储仅限于少量 `localStorage` 键: 跨标签页协调时间戳、会话级暂停、每日统计计数
|
|
235
234
|
- 浏览器通知是可选开启的(`notify` 设置), 仅在首次使用时请求一次权限
|
|
236
235
|
|
|
@@ -242,12 +241,12 @@ auto-continue:
|
|
|
242
241
|
npm run typecheck # tsc --noEmit
|
|
243
242
|
npm run build # lib/client.js + lib/index.js + lib/types
|
|
244
243
|
npm run watch # 监听变更自动重建; 宿主 HMR 免刷新热重载
|
|
245
|
-
npm run test # node tests/simulate.mjs —
|
|
244
|
+
npm run test # node tests/simulate.mjs — 29 个行为场景
|
|
246
245
|
```
|
|
247
246
|
|
|
248
247
|
`npm run watch` 运行时, profile 的 client-hmr 行每 500ms 轮询 `lib/client.js` 并在浏览器中热重载插件——改代码无需重启服务。
|
|
249
248
|
|
|
250
|
-
CI
|
|
249
|
+
CI 在每次推送到 `main` 及每个 PR 时跑 [dsh-plugin-check](https://github.com/omdsh-dev/dsh-plugin-check) 体检, 并作为发布的前置条件——体检失败时 tag 流程拒绝发布。
|
|
251
250
|
|
|
252
251
|
---
|
|
253
252
|
|
|
Binary file
|
package/lib/client.js
CHANGED
|
@@ -515,7 +515,7 @@ var AutoContinueRunner = class {
|
|
|
515
515
|
case "host/agent-error":
|
|
516
516
|
if (this.state(frame.sessionId).subagent) break;
|
|
517
517
|
this.log(`host/agent-error(${frame.sessionId}): ${frame.message}`);
|
|
518
|
-
if (
|
|
518
|
+
if (!isTransientAgentError(frame.message)) {
|
|
519
519
|
this.log(`跳过 ${frame.sessionId}: 永久性 agent 错误 — ${frame.message}`);
|
|
520
520
|
bumpStat({ skipped: 1 });
|
|
521
521
|
if (this.getConfig().notify) {
|
|
@@ -946,7 +946,7 @@ var zh = {
|
|
|
946
946
|
"stats.recovered": "恢复成功",
|
|
947
947
|
"stats.failed": "继续后仍失败",
|
|
948
948
|
"stats.gaveUp": "停止(达上限)",
|
|
949
|
-
"stats.byCode": "
|
|
949
|
+
"stats.byCode": "按错误码统计",
|
|
950
950
|
"stats.empty": "今天还没有自动继续记录。",
|
|
951
951
|
"stats.reset": "清零",
|
|
952
952
|
"pause.title": "已暂停会话",
|
|
@@ -1935,8 +1935,7 @@ function apply(ctx) {
|
|
|
1935
1935
|
() => ctx.slots.register(
|
|
1936
1936
|
{
|
|
1937
1937
|
name: "settings.plugin.item",
|
|
1938
|
-
|
|
1939
|
-
order: 90,
|
|
1938
|
+
key: SETTINGS_NS,
|
|
1940
1939
|
locale: NS,
|
|
1941
1940
|
inject: () => controller.inject()
|
|
1942
1941
|
},
|
package/lib/client.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["src/client/index.ts", "src/client/engine.ts", "src/client/locales.ts", "src/client/settings-card.tsx", "src/client/settings-form.ts", "src/client/styles.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Auto-continue plugin, browser half.\n *\n * - Runs the auto-continue engine over the live mux + host event streams.\n * - Registers the `auto-continue` settings card into the plugin-configuration\n * section (`settings.plugin.item`), editing the same namespace the engine\n * reads — every behavior knob is configurable from the GUI.\n */\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';\nimport type { ConnectionHandle } from '@deepseek-ai/dsh-client-connection/client';\n// Type-only: pulls the locale plugin's Context merge (ctx.locale).\nimport type {} from '@deepseek-ai/dsh-client-locale/client';\n// Type-only: pulls the settings-surface SlotMap merge and ctx.settingsScope.\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client';\n// Type-only: pulls the `settings.plugin.item` SlotMap merge.\nimport type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client';\nimport { AutoContinueRunner, resolveConfig, type AutoContinueSettings } from './engine.ts';\nimport { en, zh, type SettingsCardKey } from './locales.ts';\nimport {\n AutoContinueSettingsCard,\n AutoContinueSettingsCardController,\n} from './settings-card.tsx';\n\n/** 客户端根上下文的 connection 服务(由 dsh-client-connection 挂载)。 */\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n connection: ConnectionHandle;\n }\n}\n\n/** Dictionary namespace owned by this plugin. */\nconst NS = 'auto-continue';\n\n/** Settings namespace the engine reads and the settings card edits. */\nconst SETTINGS_NS = 'auto-continue';\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** auto-continue settings-card copy. */\n 'auto-continue': SettingsCardKey;\n }\n}\n\n/** Services required by this plugin. */\nexport const inject = ['slots', 'locale', 'connection', 'settingsScope'];\n\n// 浏览器侧辅助(设置卡片与模拟测试共用): 暂停控制与统计读取。\nexport {\n fillTemplate,\n pauseSession,\n pausedSessions,\n readTodayStats,\n resetTodayStats,\n sessionPauseUntil,\n unpauseSession,\n} from './engine.ts';\n\n/** 当前 runner(HMR 重载时先销毁旧的再建新的)。 */\nlet current: AutoContinueRunner | null = null;\n\n/**\n * Plugin body: mount the engine and the settings card.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'auto-continue: dictionaries');\n\n // Engine: reads the settings scope live, so GUI changes apply immediately.\n const scope = ctx.settingsScope.bind<AutoContinueSettings>({ namespace: SETTINGS_NS });\n current?.dispose();\n current = new AutoContinueRunner(ctx.connection.api, () => resolveConfig(scope.getSnapshot().value));\n\n // Plugin configuration card: one staged form over the `auto-continue`\n // settings namespace, contributed to the plugin-configuration section\n // (Settings → Plugins). Registered through the public `settings.plugin.item`\n // slot — no hardcoded section order, label or path anywhere — so the card\n // shows up in the plugin list like any other plugin's config card.\n const controller = new AutoContinueSettingsCardController(scope);\n ctx.slots.inject('settings.plugin.item', () =>\n ctx.slots.register(\n {\n name: 'settings.plugin.item',\n id: 'auto-continue',\n order: 90,\n locale: NS,\n inject: () => controller.inject(),\n },\n AutoContinueSettingsCard,\n ),\n );\n}\n", "/**\n * Auto-continue engine — browser half core.\n *\n * Watches the two live event streams of the dsh web GUI (mux + host):\n * - turns ended for a non-human reason (`turn/end` reason ∈ error / interrupted / max-tokens)\n * - host-reported agent failures with no turn position (`host/agent-error`)\n * After a grace period it sends a queued prompt (default 「继续」) to that\n * session — exactly equivalent to the user typing it manually.\n *\n * All behavior is driven by the `auto-continue` settings namespace (see the\n * plugin's settings card); every knob below is user-configurable there.\n */\n\nimport type {\n HostFrame,\n IApiClient,\n MuxFrame,\n SessionId,\n SessionSummary,\n} from '@deepseek-ai/dsh-client-connection/client';\nimport type { SessionEvent } from '@deepseek-ai/dsh-session/types';\n\n/** The `auto-continue` settings section (all fields optional on the wire; the host schema carries defaults). */\nexport interface AutoContinueSettings {\n /** Text automatically sent after an interruption. */\n continueText?: string;\n /** Text sent when the output token ceiling is reached (same placeholders as `continueText`). */\n continueTextMaxTokens?: string;\n /** Idempotency guard: inspect the last tool call before resuming and steer the model. */\n guardTools?: boolean;\n /** Guard text appended when the last tool call has no confirmed result (it may have partially executed). */\n guardPendingText?: string;\n /** Guard text appended when the last tool call completed successfully (don't rerun it). */\n guardDoneText?: string;\n /** Grace period after an interruption before auto-sending (ms). */\n graceMs?: number;\n /** Minimum interval between two auto-continues per session (ms). */\n cooldownMs?: number;\n /** Max consecutive auto-continues per session before stopping. */\n maxConsecutive?: number;\n /** Scan recently interrupted sessions on page load / reconnect. */\n scanOnBoot?: boolean;\n /** Max sessions the scan checks (most recently updated). */\n scanLimit?: number;\n /** Scan only considers interruptions inside this window (ms). */\n freshMs?: number;\n /** Delay before scanning after a reconnect (ms). */\n reconnectScanDelayMs?: number;\n /** SSE reconnect backoff (ms). */\n reconnectBackoffMs?: number;\n /** Log `[auto-continue]` lines to the browser console. */\n verbose?: boolean;\n /** Classify failures: auto-continue transient errors only; permanent ones (auth/balance/model) are skipped and notified. */\n classify?: boolean;\n /** Cooldown multiplier per consecutive failure (adaptive backoff). */\n backoffFactor?: number;\n /** Cap on the effective backoff interval (ms). */\n backoffMaxMs?: number;\n /** Show browser notifications for auto-continue events. */\n notify?: boolean;\n /** Globally pause auto-continue: no live or scan send, queued pending sends cancelled. */\n paused?: boolean;\n}\n\n/** Fully resolved configuration (built-in defaults + user overrides). */\nexport type AutoContinueConfig = Required<AutoContinueSettings>;\n\n/** Built-in defaults — must match the host schema defaults in src/index.ts. */\nexport const DEFAULT_CONFIG: AutoContinueConfig = {\n continueText: '继续',\n continueTextMaxTokens: '继续',\n guardTools: true,\n guardPendingText: '(上一步工具「{tool}」可能未完成, 先确认状态再继续, 不要重复执行)',\n guardDoneText: '(上一步工具「{tool}」已完成, 结果: {result}; 不要重复执行, 直接继续)',\n graceMs: 3000,\n cooldownMs: 20000,\n maxConsecutive: 3,\n scanOnBoot: true,\n scanLimit: 8,\n freshMs: 15 * 60 * 1000,\n reconnectScanDelayMs: 5000,\n reconnectBackoffMs: 3000,\n verbose: true,\n classify: true,\n backoffFactor: 2,\n backoffMaxMs: 300000,\n notify: false,\n paused: false,\n};\n\nfunction numberOr(value: unknown, fallback: number): number {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : fallback;\n}\n\nfunction booleanOr(value: unknown, fallback: boolean): boolean {\n return typeof value === 'boolean' ? value : fallback;\n}\n\n/** Resolve a (possibly partial / not-yet-loaded) settings section to a full config. */\nexport function resolveConfig(section: AutoContinueSettings | undefined): AutoContinueConfig {\n const value = section ?? {};\n const text =\n typeof value.continueText === 'string' && value.continueText.trim() !== ''\n ? value.continueText\n : DEFAULT_CONFIG.continueText;\n const maxTokensText =\n typeof value.continueTextMaxTokens === 'string' && value.continueTextMaxTokens.trim() !== ''\n ? value.continueTextMaxTokens\n : DEFAULT_CONFIG.continueTextMaxTokens;\n const guardPendingText =\n typeof value.guardPendingText === 'string' && value.guardPendingText.trim() !== ''\n ? value.guardPendingText\n : DEFAULT_CONFIG.guardPendingText;\n const guardDoneText =\n typeof value.guardDoneText === 'string' && value.guardDoneText.trim() !== ''\n ? value.guardDoneText\n : DEFAULT_CONFIG.guardDoneText;\n return {\n continueText: text,\n continueTextMaxTokens: maxTokensText,\n guardTools: booleanOr(value.guardTools, DEFAULT_CONFIG.guardTools),\n guardPendingText,\n guardDoneText,\n graceMs: numberOr(value.graceMs, DEFAULT_CONFIG.graceMs),\n cooldownMs: numberOr(value.cooldownMs, DEFAULT_CONFIG.cooldownMs),\n maxConsecutive: Math.max(1, numberOr(value.maxConsecutive, DEFAULT_CONFIG.maxConsecutive)),\n scanOnBoot: booleanOr(value.scanOnBoot, DEFAULT_CONFIG.scanOnBoot),\n scanLimit: Math.max(1, numberOr(value.scanLimit, DEFAULT_CONFIG.scanLimit)),\n freshMs: numberOr(value.freshMs, DEFAULT_CONFIG.freshMs),\n reconnectScanDelayMs: numberOr(value.reconnectScanDelayMs, DEFAULT_CONFIG.reconnectScanDelayMs),\n reconnectBackoffMs: numberOr(value.reconnectBackoffMs, DEFAULT_CONFIG.reconnectBackoffMs),\n verbose: booleanOr(value.verbose, DEFAULT_CONFIG.verbose),\n classify: booleanOr(value.classify, DEFAULT_CONFIG.classify),\n backoffFactor: Math.max(1, numberOr(value.backoffFactor, DEFAULT_CONFIG.backoffFactor)),\n backoffMaxMs: numberOr(value.backoffMaxMs, DEFAULT_CONFIG.backoffMaxMs),\n notify: booleanOr(value.notify, DEFAULT_CONFIG.notify),\n paused: booleanOr(value.paused, DEFAULT_CONFIG.paused),\n };\n}\n\n/**\n * 视为「非人为中断」的回合结束原因, 用于启动/重连扫描。\n * - `interrupted` 只由崩溃修复在宿主重载时写入(loop 永不实时发出), 因此仅在扫描路径处理;\n * - 实时事件路径只对 `error` / `max-tokens` 自动续跑;\n * - `aborted`(用户停止)与 `blocked`(策略拒绝)永不自动继续。\n */\ntype NonHumanReason = 'error' | 'interrupted' | 'max-tokens';\n\nfunction isNonHumanReason(kind: string): kind is NonHumanReason {\n return kind === 'error' || kind === 'interrupted' || kind === 'max-tokens';\n}\n\n/** 一次回合失败的机器可读事实(turn/end error 的 LlmFailure 载荷)。 */\nexport interface FailureFacts {\n /** 稳定机器路由码(如 UPSTREAM、RATE_LIMIT_EXCEEDED、INVALID_API_KEY)。 */\n code: string;\n /** 人类可读的失败描述。 */\n message: string;\n /** 供应商 HTTP 状态码(可用时)。 */\n status?: number;\n}\n\n/**\n * 错误分类: 该失败是否值得自动继续。\n * 永久性失败(认证/余额/模型不存在/上下文超限等)重试也不会成功, 应跳过并通知用户;\n * 其余(网络、超时、5xx、429 等)视为临时性失败, 允许自动恢复。\n */\nexport function isTransientFailure(failure: FailureFacts): boolean {\n const haystack = `${failure.code} ${failure.message}`.toLowerCase();\n const status = failure.status;\n if (status !== undefined && (status === 401 || status === 403)) return false;\n const permanent =\n /auth|unauthor|forbidden|credential|api[_-]?key|permission/i.test(haystack) ||\n /insufficient.*(balance|quota)|billing|payment|quota.*exceeded.*(?!retry)/i.test(haystack) ||\n /model.*not[_-]?found|unknown[_-]?model|model[_-]?not[_-]?found|not.*support.*model/i.test(haystack) ||\n /context.*(length|limit|overflow|exceed)|token.*limit|max.*context/i.test(haystack) ||\n /invalid[_-]?request|bad[_-]?request/i.test(haystack);\n return !permanent;\n}\n\n/**\n * host/agent-error 消息分类: 仅明确属于网络/传输类的临时错误才自动继续。\n * 其余(序列化失败、配置/宿主内部错误等)视为永久性——重试无益, 且用户停止导致的\n * 序列化失败(如 Windows 下 abort 的 DOMException reason)绝不能自动续跑。\n */\nexport function isTransientAgentError(message: string): boolean {\n return /network|timeout|timed ?out|econn|etimedout|socket|5\\d\\d|\\b429\\b|upstream|temporar/i.test(message);\n}\n\n/** 通知上的一个操作按钮(action 标识 + 显示文案)。 */\nexport interface NotifyAction {\n /** 稳定动作标识, 点击时经 onAction 回调传出。 */\n action: string;\n /** 按钮显示文案。 */\n title: string;\n}\n\n/** 通知的可选行为: 操作按钮列表与点击回调。 */\nexport interface NotifyOptions {\n actions?: NotifyAction[];\n onAction?: (action: string) => void;\n}\n\n/** 浏览器通知(不可用时静默跳过); 点击通知聚焦窗口, 操作按钮走 onAction。 */\nfunction notify(title: string, body: string, options?: NotifyOptions): void {\n try {\n const N = (globalThis as { Notification?: unknown }).Notification as\n | (new (t: string, o: { body: string; actions?: NotifyAction[] }) => unknown)\n | undefined;\n if (typeof N === 'undefined') return;\n const permission = (N as unknown as { permission?: string }).permission;\n const create = (): void => {\n const instance = new N(title, {\n body,\n ...(options?.actions !== undefined && options.actions.length > 0\n ? { actions: options.actions }\n : {}),\n });\n const target = instance as {\n onclick?: (() => void) | null;\n onaction?: ((event: { action: string }) => void) | null;\n };\n target.onclick = () => {\n try {\n (globalThis as { focus?: () => void }).focus?.();\n } catch {\n /* ignore */\n }\n };\n if (options?.onAction !== undefined) {\n target.onaction = (event) => options.onAction?.(event.action);\n }\n };\n if (permission === 'granted') {\n create();\n } else if (permission === 'default') {\n // 首次使用时请求一次权限, 用户拒绝后不再打扰。\n void (N as unknown as { requestPermission?: () => Promise<string> }).requestPermission?.()\n .then((result) => {\n if (result === 'granted') create();\n })\n .catch(() => {});\n }\n } catch {\n /* 通知失败不影响核心逻辑 */\n }\n}\n\n/** 把毫秒格式化为人类可读的经过时长(如 65s → 1m5s)。 */\nfunction formatElapsed(ms: number | undefined): string {\n if (ms === undefined || !Number.isFinite(ms) || ms < 0) return '';\n if (ms < 1000) return `${Math.round(ms)}ms`;\n const s = Math.round(ms / 1000);\n if (s < 60) return `${s}s`;\n return `${Math.floor(s / 60)}m${s % 60 > 0 ? `${s % 60}s` : ''}`;\n}\n\n/** 模板填充所需的上下文(全部可选, 缺失的占位符填为空串)。 */\nexport interface TemplateContext {\n /** 失败事实(错误码/消息/HTTP 状态), 对应 {code}/{message}/{status}。 */\n facts?: FailureFacts;\n /** 失败前最后一次工具调用的名称, 对应 {tool}。 */\n tool?: string;\n /** 失败回合的编号, 对应 {turn}。 */\n turn?: number;\n /** 连续失败次数(含本次), 对应 {errorCount}。 */\n errorCount?: number;\n /** 会话标题(来自 session.list 投影, 可用时), 对应 {sessionTitle}。 */\n sessionTitle?: string;\n /** 自失败发生以来的毫秒数, 对应 {elapsed}。 */\n elapsedMs?: number;\n /** 上一步工具结果摘要(截断), 对应 {result}(护栏模板用)。 */\n result?: string;\n}\n\n/** 用失败事实与回合信息填充 continueText 模板占位符({code}/{message}/{status}/{tool}/{turn}/{errorCount}/{sessionTitle}/{elapsed}/{result})。 */\nexport function fillTemplate(template: string, ctx: TemplateContext): string {\n return template\n .replace(/\\{code\\}/g, ctx.facts?.code ?? '')\n .replace(/\\{message\\}/g, ctx.facts?.message ?? '')\n .replace(/\\{status\\}/g, ctx.facts?.status !== undefined ? String(ctx.facts.status) : '')\n .replace(/\\{tool\\}/g, ctx.tool ?? '')\n .replace(/\\{turn\\}/g, ctx.turn !== undefined ? String(ctx.turn) : '')\n .replace(/\\{errorCount\\}/g, ctx.errorCount !== undefined ? String(ctx.errorCount) : '')\n .replace(/\\{sessionTitle\\}/g, ctx.sessionTitle ?? '')\n .replace(/\\{elapsed\\}/g, formatElapsed(ctx.elapsedMs))\n .replace(/\\{result\\}/g, ctx.result ?? '');\n}\n\n// ---------- 幂等护栏: 上一步工具调用的执行状态 ----------\n\n/** 工具结果摘要的最大长度(护栏模板 {result} 用)。 */\nconst TOOL_RESULT_CAP = 160;\n\n/** 从任意内容块里递归收集文本(结果为模型可见的工具输出)。 */\nfunction extractText(blocks: unknown, cap: number): string {\n let out = '';\n const walk = (value: unknown): void => {\n if (out.length >= cap) return;\n if (Array.isArray(value)) {\n for (const item of value) walk(item);\n return;\n }\n if (typeof value !== 'object' || value === null) return;\n const record = value as Record<string, unknown>;\n if (record['type'] === 'text' && typeof record['text'] === 'string') {\n out += record['text'];\n return;\n }\n for (const child of Object.values(record)) walk(child);\n };\n walk(blocks);\n return out.slice(0, cap);\n}\n\n/** 上一步工具调用的判定结果: 是否已确认完成, 以及文本摘要。 */\nexport interface ToolResultFacts {\n /** 工具是否成功完成(内部失败或 isError 视为未成功)。 */\n ok: boolean;\n /** 工具输出的文本摘要(截断)。 */\n excerpt: string;\n}\n\n/** 从 tool/result 事件载荷提取成功与否与文本摘要。 */\nfunction toolResultFacts(data: {\n error?: { name?: string; code?: string };\n message?: { content?: Array<{ type?: string; content?: unknown; isError?: boolean }> };\n}): ToolResultFacts {\n const failed = data.error !== undefined || data.message?.content?.[0]?.isError === true;\n return { ok: !failed, excerpt: extractText(data.message?.content?.[0]?.content, TOOL_RESULT_CAP) };\n}\n\n/** 自适应退避: 同一会话连续失败时的有效冷却间隔。 */\nexport function effectiveCooldown(\n consecutive: number,\n base: number,\n factor: number,\n max: number,\n): number {\n // consecutive = 已连续自动继续的次数; 第 1 次后开始按 factor 递增\n const multiplier = Math.pow(factor, consecutive);\n return Math.min(Math.max(base, base * multiplier), Math.max(base, max));\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** 浏览器当前 IANA 时区; 不可用时省略(宿主允许省略)。 */\nfunction clientTimeZone(): string | undefined {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone || undefined;\n } catch {\n return undefined;\n }\n}\n\n/** 跨标签页互斥与冷却记录(仅浏览器本地, 不落盘到宿主)。 */\nconst lockPrefix = 'dsh-auto-continue:';\nconst lockKey = (sessionId: SessionId) => `${lockPrefix}lock:${sessionId}`;\nconst stampKey = (sessionId: SessionId) => `${lockPrefix}last:${sessionId}`;\n\n/** 尝试独占本次发送: 两个标签页同时触发时只有一个成功。 */\nfunction claimSend(sessionId: SessionId): boolean {\n try {\n const token = `${Date.now()}-${Math.random().toString(36).slice(2)}`;\n localStorage.setItem(lockKey(sessionId), token);\n return localStorage.getItem(lockKey(sessionId)) === token;\n } catch {\n return true; // 存储不可用(隐私模式等)时放行\n }\n}\n\nfunction releaseSend(sessionId: SessionId): void {\n try {\n localStorage.removeItem(lockKey(sessionId));\n } catch {\n /* ignore */\n }\n}\n\n/** 读/写「上次自动发送」时间戳(跨标签页冷却)。 */\nfunction readLastSend(sessionId: SessionId): number {\n try {\n return Number(localStorage.getItem(stampKey(sessionId)) ?? 0) || 0;\n } catch {\n return 0;\n }\n}\n\nfunction writeLastSend(sessionId: SessionId, at: number): void {\n try {\n localStorage.setItem(stampKey(sessionId), String(at));\n } catch {\n /* ignore */\n }\n}\n\n// ---------- 会话级暂停(仅浏览器本地, 跨标签页共享) ----------\n\nconst pauseKey = (sessionId: SessionId) => `${lockPrefix}pause:${sessionId}`;\n\n/** 暂停某会话: 到 `until` 之前, 引擎不会为该会话自动继续(通知按钮等调用)。 */\nexport function pauseSession(sessionId: SessionId, ms: number): void {\n try {\n localStorage.setItem(pauseKey(sessionId), String(Date.now() + ms));\n } catch {\n /* ignore */\n }\n}\n\n/** 解除某会话的暂停。 */\nexport function unpauseSession(sessionId: SessionId): void {\n try {\n localStorage.removeItem(pauseKey(sessionId));\n } catch {\n /* ignore */\n }\n}\n\n/** 会话暂停的截止时间戳; 0 表示未暂停。 */\nexport function sessionPauseUntil(sessionId: SessionId): number {\n try {\n return Number(localStorage.getItem(pauseKey(sessionId)) ?? 0) || 0;\n } catch {\n return 0;\n }\n}\n\n/** 当前生效(未过期)的暂停会话列表; 顺带清理过期条目。 */\nexport function pausedSessions(): { sessionId: SessionId; until: number }[] {\n const out: { sessionId: SessionId; until: number }[] = [];\n const now = Date.now();\n try {\n for (let i = 0; i < localStorage.length; i += 1) {\n const key = localStorage.key(i);\n if (key === null || !key.startsWith(`${lockPrefix}pause:`)) continue;\n const sessionId = key.slice(lockPrefix.length + 'pause:'.length) as SessionId;\n const until = Number(localStorage.getItem(key) ?? 0) || 0;\n if (until > now) out.push({ sessionId, until });\n else localStorage.removeItem(key);\n }\n } catch {\n /* ignore */\n }\n return out;\n}\n\n// ---------- 统计(仅浏览器本地; 按本地日期分桶, 最多保留 90 天) ----------\n\n/** 一天的自动继续统计。 */\nexport interface DayStats {\n /** 本地日期 YYYY-MM-DD。 */\n date: string;\n /** 自动发送次数。 */\n sent: number;\n /** 因永久性错误跳过的次数。 */\n skipped: number;\n /** 发送后回合成功完成(恢复成功)的次数。 */\n recovered: number;\n /** 发送后再次失败的次数。 */\n failed: number;\n /** 达到连续上限而停止的次数(按停止事件计)。 */\n gaveUp: number;\n /** 按错误码计数的失败分布。 */\n byCode: Record<string, number>;\n}\n\nconst statsKey = `${lockPrefix}stats`;\nconst STATS_MAX_DAYS = 90;\n\nfunction todayKey(): string {\n const d = new Date();\n const mm = String(d.getMonth() + 1).padStart(2, '0');\n const dd = String(d.getDate()).padStart(2, '0');\n return `${d.getFullYear()}-${mm}-${dd}`;\n}\n\nfunction readStats(): DayStats[] {\n try {\n const raw = localStorage.getItem(statsKey);\n if (raw === null) return [];\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n return parsed.filter(\n (item): item is DayStats =>\n typeof item === 'object' && item !== null && typeof item.date === 'string',\n );\n } catch {\n return [];\n }\n}\n\nfunction writeStats(list: DayStats[]): void {\n try {\n localStorage.setItem(statsKey, JSON.stringify(list));\n } catch {\n /* ignore */\n }\n}\n\n/** 累加今日统计(引擎内部记账)。 */\nfunction bumpStat(delta: {\n sent?: number;\n skipped?: number;\n recovered?: number;\n failed?: number;\n gaveUp?: number;\n code?: string;\n}): void {\n const list = readStats();\n let day = list.find((item) => item.date === todayKey());\n if (day === undefined) {\n day = { date: todayKey(), sent: 0, skipped: 0, recovered: 0, failed: 0, gaveUp: 0, byCode: {} };\n list.unshift(day);\n }\n if (delta.sent !== undefined) day.sent += delta.sent;\n if (delta.skipped !== undefined) day.skipped += delta.skipped;\n if (delta.recovered !== undefined) day.recovered += delta.recovered;\n if (delta.failed !== undefined) day.failed += delta.failed;\n if (delta.gaveUp !== undefined) day.gaveUp += delta.gaveUp;\n if (delta.code !== undefined) day.byCode[delta.code] = (day.byCode[delta.code] ?? 0) + 1;\n writeStats(list.slice(0, STATS_MAX_DAYS));\n}\n\n/** 今日统计(设置卡片展示用)。 */\nexport function readTodayStats(): DayStats {\n const today = todayKey();\n const found = readStats().find((item) => item.date === today);\n return (\n found ?? { date: today, sent: 0, skipped: 0, recovered: 0, failed: 0, gaveUp: 0, byCode: {} }\n );\n}\n\n/** 清零今日统计。 */\nexport function resetTodayStats(): void {\n writeStats(readStats().filter((item) => item.date !== todayKey()));\n}\n\n/** 每会话运行时状态。 */\ninterface SessionState {\n /** 连续自动「继续」次数; 成功回合或用户手动介入后归零。 */\n consecutive: number;\n /** 上次自动「继续」时间戳。 */\n lastAutoAt: number;\n /** 上次自动「继续」尝试(成功或失败)时间戳; 防止失败场景下的快速重试循环。 */\n lastAttemptAt: number;\n /** 我们上次自动发送的文本(用于识别自己的回显)。 */\n lastSentText: string;\n /** 宽限期定时器(进行中的待发送)。 */\n pendingTimer: number | undefined;\n /** 宿主权威 running 位(来自 host/session-status 与回合事件)。 */\n running: boolean | undefined;\n /** 当前排队消息数(来自 session/queue 帧)。 */\n queued: number;\n /** 子代理会话(host/session-added 带 parentSessionId)。 */\n subagent: boolean;\n /** 最近一次回合失败的事实(用于分类与模板填充)。 */\n lastFailure: FailureFacts | undefined;\n /** 最近一次失败的发生时间(模板 {elapsed} 与恢复统计用)。 */\n lastFailureAt: number;\n /** 失败前最后一次工具调用的名称(模板 {tool} 与幂等护栏用)。 */\n lastTool: string | undefined;\n /** 上一步工具调用的结果状态: 'pending' = 已发起未见结果(可能已部分执行)。 */\n lastToolResult: 'pending' | ToolResultFacts | undefined;\n /** 失败回合的编号(模板 {turn})。 */\n lastTurn: number | undefined;\n /** 我们最近一次自动发送的时间戳; 0 = 没有待确认的恢复。 */\n pendingRecoveryAt: number;\n}\n\nconst freshState = (): SessionState => ({\n consecutive: 0,\n lastAutoAt: 0,\n lastAttemptAt: 0,\n lastSentText: '',\n pendingTimer: undefined,\n running: undefined,\n queued: 0,\n subagent: false,\n lastFailure: undefined,\n lastFailureAt: 0,\n lastTool: undefined,\n lastToolResult: undefined,\n lastTurn: undefined,\n pendingRecoveryAt: 0,\n});\n\n/** 自动发送后, 在该窗口内出现的回合结束才计入恢复统计。 */\nconst RECOVERY_WINDOW_MS = 10 * 60 * 1000;\n\n/** 判定一条 user/message 是否是我们自己自动发送的回显。 */\nfunction isOurEcho(state: SessionState, event: SessionEvent): boolean {\n if (event.type !== 'user/message') return false;\n const message = event.data;\n if (message.source.kind !== 'user') return false;\n if (state.lastSentText === '') return false;\n if (Date.now() - state.lastAutoAt > 30000) return false;\n const text = message.content\n .filter((part): part is { type: 'text'; text: string } => part.type === 'text')\n .map((part) => part.text)\n .join('');\n return text === state.lastSentText;\n}\n\n/** SSE 帧外壳: `{ rpcId, payload }`。 */\ntype FrameEnvelope<T> = { payload: T };\n\n/**\n * 事件流泵: 带指数退避的 SSE 重连循环。\n * - 从未收到任何帧(宿主未就绪): 退避重试, 不触发扫描\n * - 曾连上后断开: 重连, 并通过 onReconnect 通知外层(宿主可能崩溃重启过)\n */\nasync function pumpStream<T>(\n open: (signal: AbortSignal) => AsyncIterable<FrameEnvelope<T>>,\n onFrame: (payload: T) => void,\n onReconnect: () => void,\n getBackoff: () => number,\n log: (message: string) => void,\n signal: AbortSignal,\n): Promise<void> {\n let backoff = getBackoff();\n while (!signal.aborted) {\n let connected = false;\n try {\n for await (const envelope of open(signal)) {\n connected = true;\n onFrame(envelope.payload);\n }\n if (signal.aborted) return;\n } catch (error) {\n if (signal.aborted) return;\n log(`stream error: ${error instanceof Error ? error.message : String(error)}`);\n }\n if (!connected) {\n // 从未连上(宿主未就绪): 指数退避重试\n await sleep(backoff);\n backoff = Math.min(backoff * 2, 15000);\n continue;\n }\n // 曾连上后断开 → 重连并触发外层扫描\n backoff = getBackoff();\n onReconnect();\n await sleep(backoff);\n }\n}\n\n/** 插件主体: 一条 mux 流 + 一条 host 流 + 启动/重连扫描。 */\nexport class AutoContinueRunner {\n private readonly states = new Map<SessionId, SessionState>();\n private readonly muxAbort = new AbortController();\n private readonly hostAbort = new AbortController();\n private disposed = false;\n private reconnectScans = 0;\n\n /**\n * @param api - shared wire client (ctx.connection.api).\n * @param getConfig - read the current resolved configuration (settings scope).\n */\n constructor(\n private readonly api: IApiClient,\n private readonly getConfig: () => AutoContinueConfig,\n ) {\n const config = this.getConfig();\n void this.runMux();\n void this.runHost();\n if (config.scanOnBoot) {\n // 启动时连接可能尚未建立, 循环重试直到成功。\n void this.bootScanLoop();\n }\n this.log(\n `已启动(文本=\"${config.continueText}\", 宽限 ${config.graceMs}ms, ` +\n `冷却 ${config.cooldownMs}ms, 最多连续 ${config.maxConsecutive} 次)`,\n );\n }\n\n private log(message: string): void {\n if (this.getConfig().verbose) console.info(`[auto-continue] ${message}`);\n }\n\n dispose(): void {\n this.disposed = true;\n this.muxAbort.abort();\n this.hostAbort.abort();\n for (const state of this.states.values()) {\n if (state.pendingTimer !== undefined) clearTimeout(state.pendingTimer);\n }\n this.states.clear();\n }\n\n private state(sessionId: SessionId): SessionState {\n let state = this.states.get(sessionId);\n if (state === undefined) {\n state = freshState();\n this.states.set(sessionId, state);\n }\n return state;\n }\n\n private runMux(): Promise<void> {\n return pumpStream<MuxFrame>(\n (signal) => this.api.events.mux({}, signal),\n (payload) => this.onMuxFrame(payload),\n () => this.scheduleReconnectScan(),\n () => this.getConfig().reconnectBackoffMs,\n (m) => this.log(m),\n this.muxAbort.signal,\n );\n }\n\n private runHost(): Promise<void> {\n return pumpStream<HostFrame>(\n (signal) => this.api.events.host({}, signal),\n (payload) => this.onHostFrame(payload),\n () => this.scheduleReconnectScan(),\n () => this.getConfig().reconnectBackoffMs,\n (m) => this.log(m),\n this.hostAbort.signal,\n );\n }\n\n // ---------- mux 帧 ----------\n\n private onMuxFrame(frame: MuxFrame): void {\n switch (frame.type) {\n case 'session/event':\n if (frame.event.type === 'tool/call') {\n const name = frame.event.data.name;\n if (typeof name === 'string') {\n const state = this.state(frame.sessionId);\n state.lastTool = name;\n state.lastToolResult = 'pending'; // 已发起, 尚未见结果\n }\n } else if (frame.event.type === 'tool/result') {\n const state = this.state(frame.sessionId);\n if (state.lastToolResult === 'pending') {\n state.lastToolResult = toolResultFacts(frame.event.data);\n }\n }\n this.onSessionEvent(frame.sessionId, frame.event);\n break;\n case 'session/queue':\n this.state(frame.sessionId).queued = frame.items.length;\n if (frame.items.length > 0) this.cancelPending(frame.sessionId, '出现排队消息');\n break;\n case 'stream/error':\n this.log(`mux stream/error: ${frame.error.code} ${frame.error.message}`);\n break;\n default:\n break; // session/subscribed、approval/*、question/*、session/jobs、session/projection 与本插件无关\n }\n }\n\n private onSessionEvent(sessionId: SessionId, event: SessionEvent): void {\n const state = this.state(sessionId);\n switch (event.type) {\n case 'turn/start':\n state.running = true;\n // 新回合开始: 清空上一步工具调用状态, 避免跨回合误用护栏\n state.lastTool = undefined;\n state.lastToolResult = undefined;\n this.cancelPending(sessionId, '宿主自行开启新回合');\n break;\n case 'turn/end': {\n state.running = false;\n this.cancelPending(sessionId, '收到新的 turn/end');\n const reason = event.data.reason;\n if (reason.kind === 'completed') {\n // 成功回合: 恢复健康状态, 并确认上一次自动发送的效果\n state.consecutive = 0;\n state.lastFailure = undefined;\n this.noteRecovery(sessionId, 'completed');\n } else if (reason.kind === 'aborted') {\n // 用户主动停止: 不自动继续, 视为用户介入\n state.consecutive = 0;\n state.pendingRecoveryAt = 0;\n } else if (reason.kind === 'blocked') {\n // 策略拒绝: 不自动继续\n } else if (reason.kind === 'interrupted') {\n // 实时路径的 interrupted 仅来自崩溃修复重载(loop 从不实时发出);\n // 用户手动停止在 DSH 中标记为 aborted, 不走到这里。实时流里出现\n // interrupted 视为异常中断, 不自动继续——宿主崩溃孤儿回合由扫描恢复。\n state.consecutive = 0;\n state.pendingRecoveryAt = 0;\n } else if (reason.kind === 'error') {\n // 记录失败事实(分类与模板填充用), 然后按类型处理\n const error = reason.error;\n state.lastFailure = {\n code: typeof error.code === 'string' ? error.code : 'UNKNOWN',\n message: typeof error.message === 'string' ? error.message : String(error),\n ...(typeof error.status === 'number' ? { status: error.status } : {}),\n };\n state.lastTurn = event.data.turn;\n state.lastFailureAt = Date.now();\n this.noteRecovery(sessionId, 'error');\n this.onTurnFailure(sessionId, 'turn/end:error', state.lastFailure);\n } else if (reason.kind === 'max-tokens') {\n state.lastFailureAt = Date.now();\n this.noteRecovery(sessionId, 'error');\n this.schedule(sessionId, 'turn/end:max-tokens');\n }\n break;\n }\n case 'user/message':\n if (isOurEcho(state, event)) break; // 我们自己的回显\n if (event.data.source.kind === 'user') {\n // 用户手动介入\n state.consecutive = 0;\n this.cancelPending(sessionId, '用户手动发送消息');\n }\n break;\n default:\n break;\n }\n }\n\n // ---------- host 帧 ----------\n\n private onHostFrame(frame: HostFrame): void {\n switch (frame.type) {\n case 'host/session-status':\n this.state(frame.sessionId).running = frame.running;\n if (frame.running) this.cancelPending(frame.sessionId, '宿主报告会话开始运行');\n break;\n case 'host/session-added':\n this.state(frame.sessionId).subagent = frame.parentSessionId !== undefined;\n break;\n case 'host/agent-error':\n if (this.state(frame.sessionId).subagent) break;\n this.log(`host/agent-error(${frame.sessionId}): ${frame.message}`);\n if (this.getConfig().classify && !isTransientAgentError(frame.message)) {\n // 永久性 agent 错误(序列化失败/配置错误等): 跳过并通知, 避免把用户停止等\n // 场景误判为可恢复中断后自动续跑。\n this.log(`跳过 ${frame.sessionId}: 永久性 agent 错误 — ${frame.message}`);\n bumpStat({ skipped: 1 });\n if (this.getConfig().notify) {\n notify(\n 'dsh-auto-continue: 未自动继续',\n `${frame.sessionId}: 永久性 agent 错误 ${frame.message.slice(0, 120)}`,\n this.notifyOptions(frame.sessionId),\n );\n }\n break;\n }\n this.schedule(frame.sessionId, 'host/agent-error');\n break;\n case 'host/session-removed':\n this.cancelPending(frame.sessionId, '会话已移除');\n this.states.delete(frame.sessionId);\n break;\n default:\n break;\n }\n }\n\n // ---------- 调度 ----------\n\n /** 回合失败入口: 先做错误分类, 永久性失败跳过并通知, 临时性失败走正常调度。 */\n private onTurnFailure(sessionId: SessionId, reason: string, failure: FailureFacts): void {\n const config = this.getConfig();\n if (config.classify && !isTransientFailure(failure)) {\n const summary = `${failure.code}${failure.status !== undefined ? ` (HTTP ${failure.status})` : ''}`;\n this.log(`跳过 ${sessionId}(${reason}): 永久性失败 ${summary} — ${failure.message}`);\n bumpStat({ skipped: 1, code: failure.code });\n if (config.notify) {\n notify(\n 'dsh-auto-continue: 未自动继续',\n `${sessionId}: 永久性错误 ${summary},需要人工处理`,\n this.notifyOptions(sessionId),\n );\n }\n return;\n }\n this.schedule(sessionId, reason);\n }\n\n /** 通知操作按钮与回调(「立即续跑」/「暂停该会话 1 小时」)。 */\n private notifyOptions(sessionId: SessionId): NotifyOptions {\n return {\n actions: [\n { action: 'resume', title: '立即续跑' },\n { action: 'pause1h', title: '暂停该会话 1 小时' },\n ],\n onAction: (action) => this.onNotifyAction(sessionId, action),\n };\n }\n\n private onNotifyAction(sessionId: SessionId, action: string): void {\n if (action === 'resume') {\n this.log(`通知按钮: 立即续跑 ${sessionId}`);\n void this.resumeNow(sessionId);\n } else if (action === 'pause1h') {\n this.log(`通知按钮: 暂停 ${sessionId} 1 小时`);\n pauseSession(sessionId, 60 * 60 * 1000);\n this.cancelPending(sessionId, '通知按钮暂停该会话');\n }\n }\n\n /** 恢复结果记账: 自动发送后窗口内的回合结束, 判定恢复成功或失败。 */\n private noteRecovery(sessionId: SessionId, outcome: 'completed' | 'error'): void {\n const state = this.state(sessionId);\n if (state.pendingRecoveryAt === 0) return;\n if (Date.now() - state.pendingRecoveryAt > RECOVERY_WINDOW_MS) {\n state.pendingRecoveryAt = 0; // 窗口过期, 不再归属这次发送\n return;\n }\n state.pendingRecoveryAt = 0;\n bumpStat(outcome === 'completed' ? { recovered: 1 } : { failed: 1 });\n this.log(`恢复结果(${sessionId}): ${outcome === 'completed' ? '成功' : '失败'}`);\n }\n\n /** 立即为该会话发送一次自动继续(无视冷却与连续上限; 由通知按钮触发)。 */\n async resumeNow(sessionId: SessionId): Promise<void> {\n if (this.disposed) return;\n const state = this.state(sessionId);\n if (state.subagent) return;\n if (state.pendingTimer !== undefined) {\n clearTimeout(state.pendingTimer);\n state.pendingTimer = undefined;\n }\n await this.fire(sessionId, 'manual:notification', true);\n }\n\n /** 本会话当前生效的冷却间隔(自适应退避)。 */\n private cooldownFor(state: SessionState): number {\n const config = this.getConfig();\n return effectiveCooldown(\n state.consecutive,\n config.cooldownMs,\n config.backoffFactor,\n config.backoffMaxMs,\n );\n }\n\n private schedule(sessionId: SessionId, reason: string): void {\n const state = this.state(sessionId);\n const config = this.getConfig();\n if (state.subagent) return; // 子代理会话由父代理处理, 不抢跑\n if (config.paused) {\n this.log(`跳过 ${sessionId}(${reason}): 全局暂停中`);\n return;\n }\n if (Date.now() < sessionPauseUntil(sessionId)) {\n this.log(`跳过 ${sessionId}(${reason}): 会话暂停中`);\n return;\n }\n if (state.pendingTimer !== undefined) return; // 已有待发送\n if (Date.now() - state.lastAttemptAt < this.cooldownFor(state)) return; // 冷却期(含失败尝试, 自适应退避)\n if (state.consecutive >= config.maxConsecutive) {\n this.log(\n `跳过 ${sessionId}(${reason}): 已连续自动继续 ${state.consecutive} 次, 等待用户介入或成功回合`,\n );\n return;\n }\n if (state.queued > 0) return; // 已有排队消息, 宿主会自行唤醒\n const timer = setTimeout(() => {\n if (state.pendingTimer !== timer) return;\n state.pendingTimer = undefined;\n void this.fire(sessionId, reason);\n }, config.graceMs);\n state.pendingTimer = timer;\n const template = reason.includes('max-tokens') ? config.continueTextMaxTokens : config.continueText;\n this.log(\n `检测到非人为中断 ${sessionId}(${reason}), ${config.graceMs}ms 后自动发送「${template}」`,\n );\n }\n\n private cancelPending(sessionId: SessionId, why: string): void {\n const state = this.state(sessionId);\n if (state.pendingTimer === undefined) return;\n clearTimeout(state.pendingTimer);\n state.pendingTimer = undefined;\n this.log(`取消 ${sessionId} 的自动继续(${why})`);\n }\n\n private async fire(sessionId: SessionId, reason: string, force = false): Promise<void> {\n if (this.disposed) return;\n const state = this.state(sessionId);\n const config = this.getConfig();\n // 权威 running 检查: 优先用 host 帧, 未知时回退到 session.list\n if (state.running === undefined) {\n const running = await this.runningViaList(sessionId);\n if (running === undefined || running) {\n this.log(`跳过 ${sessionId}: 无法确认空闲(${running === undefined ? '未知' : '运行中'})`);\n return;\n }\n } else if (state.running) {\n this.log(`跳过 ${sessionId}: 会话仍在运行`);\n return;\n }\n if (state.queued > 0) {\n this.log(`跳过 ${sessionId}: 已有排队消息`);\n return;\n }\n // 跨标签页冷却(自适应退避); 通知按钮的强制续跑不受冷却约束\n if (!force && Date.now() - readLastSend(sessionId) < this.cooldownFor(state)) {\n this.log(`跳过 ${sessionId}: 其他标签页刚发送过`);\n return;\n }\n if (!claimSend(sessionId)) {\n this.log(`跳过 ${sessionId}: 其他标签页正在发送`);\n return;\n }\n // 模板填充: continueText 可含 {code}/{message}/{status}/{tool}/{turn}/{errorCount}/{sessionTitle}/{elapsed} 占位符\n const template = reason.includes('max-tokens') ? config.continueTextMaxTokens : config.continueText;\n let sessionTitle: string | undefined;\n if (template.includes('{sessionTitle}')) {\n sessionTitle = this.titles.get(sessionId);\n if (sessionTitle === undefined) {\n const info = await this.fetchSessionInfo(sessionId);\n sessionTitle = info?.title;\n }\n }\n const text = this.buildContinueText(config, state, template, sessionTitle);\n const zone = clientTimeZone();\n state.lastAttemptAt = Date.now(); // 先记账: 无论成败, 本次尝试都进入冷却\n try {\n const response = await this.api.sessions.prompt({\n sessionId,\n mode: 'queue',\n content: [{ type: 'text', text }],\n ...(zone === undefined ? {} : { clientTimeZone: zone }),\n });\n if (response.result.ok) {\n const now = Date.now();\n state.consecutive += 1;\n state.lastAutoAt = now;\n state.lastSentText = text;\n state.pendingRecoveryAt = now; // 等待窗口内的下一个回合结束来判定恢复结果\n writeLastSend(sessionId, now);\n bumpStat({ sent: 1, ...(state.lastFailure !== undefined ? { code: state.lastFailure.code } : {}) });\n this.log(`已自动发送「${text}」到 ${sessionId}(${reason}), 第 ${state.consecutive} 次连续`);\n if (config.notify) {\n notify(\n 'dsh-auto-continue: 已自动继续',\n `${sessionId}: 已发送「${text}」(第 ${state.consecutive} 次连续)`,\n this.notifyOptions(sessionId),\n );\n }\n if (state.consecutive >= config.maxConsecutive) {\n bumpStat({ gaveUp: 1 });\n this.log(`达到连续上限 ${config.maxConsecutive} 次, 停止自动继续 ${sessionId}`);\n if (config.notify) {\n notify(\n 'dsh-auto-continue: 已停止自动继续',\n `${sessionId}: 连续失败 ${state.consecutive} 次, 需要人工介入`,\n this.notifyOptions(sessionId),\n );\n }\n }\n } else {\n this.log(\n `发送失败 ${sessionId}: ${response.result.error.code} ${response.result.error.message}`,\n );\n }\n } catch (error) {\n this.log(`发送异常 ${sessionId}: ${error instanceof Error ? error.message : String(error)}`);\n } finally {\n releaseSend(sessionId);\n }\n }\n\n /**\n * 组装本次续跑消息: 模板填充 + 幂等护栏。\n * 护栏依据上一步工具调用的执行状态附加指引, 防止重跑副作用操作:\n * - 结果未确认(可能已部分执行)→ 提示先确认状态、不要重复执行\n * - 已确认成功 → 提示已完成、不要重复执行\n * - 已失败 → 不加护栏(重试工具本来就是目的)\n */\n private buildContinueText(\n config: AutoContinueConfig,\n state: SessionState,\n template: string,\n sessionTitle: string | undefined,\n ): string {\n let text = fillTemplate(template, {\n facts: state.lastFailure,\n tool: state.lastTool,\n turn: state.lastTurn,\n errorCount: state.consecutive + 1,\n sessionTitle,\n elapsedMs: state.lastFailureAt > 0 ? Date.now() - state.lastFailureAt : undefined,\n });\n if (!config.guardTools) return text;\n const guard = this.currentGuard(state);\n if (guard.kind === 'pending') {\n text += ` ${fillTemplate(config.guardPendingText, { tool: guard.tool, result: guard.result })}`;\n } else if (guard.kind === 'done') {\n text += ` ${fillTemplate(config.guardDoneText, { tool: guard.tool, result: guard.result })}`;\n }\n return text;\n }\n\n /** 上一步工具调用的护栏状态(实时路径, 由 mux 帧维护)。 */\n private currentGuard(state: SessionState): {\n kind: 'none' | 'pending' | 'done' | 'failed';\n tool?: string;\n result?: string;\n } {\n if (state.lastTool === undefined || state.lastToolResult === undefined) return { kind: 'none' };\n if (state.lastToolResult === 'pending') return { kind: 'pending', tool: state.lastTool };\n if (state.lastToolResult.ok) {\n return { kind: 'done', tool: state.lastTool, result: state.lastToolResult.excerpt };\n }\n return { kind: 'failed', tool: state.lastTool };\n }\n\n /** 会话标题缓存(来自 session.list 投影, {sessionTitle} 占位符用)。 */\n private readonly titles = new Map<SessionId, string>();\n\n /** 查一次 session.list, 顺带缓存该会话的标题。 */\n private async fetchSessionInfo(\n sessionId: SessionId,\n ): Promise<{ running: boolean | undefined; title: string | undefined } | undefined> {\n try {\n const response = await this.api.sessions.list({});\n if (!response.result.ok) return undefined;\n const item = response.result.value.items.find(\n (summary: SessionSummary) => summary.sessionId === sessionId,\n );\n if (item === undefined) return undefined;\n // `title` 投影由 @deepseek-ai/dsh-session-title 声明; 此处用局部断言避免引入额外依赖。\n const title = (item.projections?.values as { title?: string | null } | undefined)?.title;\n if (typeof title === 'string' && title !== '') this.titles.set(sessionId, title);\n return { running: item.running, title: typeof title === 'string' ? title : undefined };\n } catch {\n return undefined;\n }\n }\n\n private async runningViaList(sessionId: SessionId): Promise<boolean | undefined> {\n const info = await this.fetchSessionInfo(sessionId);\n return info?.running;\n }\n\n // ---------- 启动/重连扫描 ----------\n\n private scheduleReconnectScan(): void {\n this.reconnectScans += 1;\n const scan = this.reconnectScans;\n setTimeout(() => {\n if (scan !== this.reconnectScans || this.disposed) return;\n void this.scanLoop(6, this.getConfig().reconnectScanDelayMs);\n }, this.getConfig().reconnectScanDelayMs);\n }\n\n private async bootScanLoop(): Promise<void> {\n await this.scanLoop(Infinity, 3000);\n }\n\n /** 反复尝试扫描, 直到成功(宿主就绪)或达到次数上限。 */\n private async scanLoop(attempts: number, delayMs: number): Promise<void> {\n for (let attempt = 0; attempt < attempts && !this.disposed; attempt += 1) {\n try {\n if (await this.scanInterrupted()) return;\n } catch (error) {\n if (this.disposed) return;\n // 宿主未就绪时每 3s 重试; 只节流记录日志, 避免刷屏。\n if (attempt % 10 === 0) {\n this.log(\n `扫描失败(${attempt + 1}/${attempts === Infinity ? '∞' : attempts}): ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n }\n if (attempt + 1 < attempts) await sleep(delayMs);\n }\n }\n\n /**\n * 扫描最近中断过的会话: 最后回合以非人为原因结束, 且其后没有新回合或用户消息。\n * @returns 是否成功完成一次扫描(宿主就绪)。\n */\n private async scanInterrupted(): Promise<boolean> {\n const config = this.getConfig();\n if (config.paused) return true; // 全局暂停: 不做任何扫描\n const response = await this.api.sessions.list({});\n if (!response.result.ok) return false;\n const items = response.result.value.items;\n for (const summary of items) {\n const title = (summary.projections?.values as { title?: string | null } | undefined)?.title;\n if (typeof title === 'string' && title !== '') this.titles.set(summary.sessionId, title);\n }\n const candidates = items\n .filter((summary) => !summary.running && summary.parentSessionId === undefined)\n .slice(0, config.scanLimit);\n const now = Date.now();\n for (const summary of candidates) {\n if (this.disposed) return true;\n const state = this.state(summary.sessionId);\n if (state.pendingTimer !== undefined) continue;\n if (state.consecutive >= config.maxConsecutive) continue;\n if (now - state.lastAttemptAt < this.cooldownFor(state)) continue;\n if (now < sessionPauseUntil(summary.sessionId)) continue; // 会话暂停中\n let events;\n try {\n const page = await this.api.sessions.history({\n sessionId: summary.sessionId,\n maxMessages: 30,\n });\n if (!page.result.ok) continue;\n events = page.result.value.events;\n } catch {\n continue; // 会话可能刚被移除\n }\n // 从尾部找最后一个 turn/end(在分支内完成收窄)\n let lastEnd: SessionEvent<'turn/end'> | undefined;\n for (let i = events.length - 1; i >= 0; i -= 1) {\n const event = events[i]?.event;\n if (event !== undefined && event.type === 'turn/end') {\n lastEnd = event;\n break;\n }\n }\n if (lastEnd === undefined) continue;\n const reason = lastEnd.data.reason;\n if (!isNonHumanReason(reason.kind)) continue;\n if (lastEnd.time < now - config.freshMs) continue; // 太久远, 不翻旧账\n // 该 turn/end 之后不能有新回合或用户消息(说明已被处理)\n let superseded = false;\n for (const entry of events) {\n const event = entry.event;\n if (event.seq <= lastEnd.seq) continue;\n if (event.type === 'turn/start') superseded = true;\n if (event.type === 'user/message' && event.data.source.kind === 'user') superseded = true;\n if (superseded) break;\n }\n if (superseded) continue;\n // 幂等护栏: 从历史事件里重建上一步工具调用的执行状态\n this.applyGuardFromEvents(state, events, lastEnd.seq);\n this.log(`扫描发现中断 ${summary.sessionId}(turn/end:${reason.kind}), 安排自动继续`);\n this.schedule(summary.sessionId, `scan:turn/end:${reason.kind}`);\n }\n return true;\n }\n\n /** 从历史事件恢复上一步工具调用状态(扫描路径的幂等护栏)。 */\n private applyGuardFromEvents(\n state: SessionState,\n events: { event: SessionEvent }[],\n untilSeq: number,\n ): void {\n state.lastTool = undefined;\n state.lastToolResult = undefined;\n let call: SessionEvent<'tool/call'> | undefined;\n for (const entry of events) {\n const event = entry.event;\n if (event.seq >= untilSeq) continue;\n if (event.type === 'tool/call') call = event;\n }\n if (call === undefined) return;\n state.lastTool = call.data.name;\n state.lastToolResult = 'pending';\n for (const entry of events) {\n const event = entry.event;\n if (event.seq <= call.seq || event.seq >= untilSeq) continue;\n if (event.type === 'tool/result') {\n state.lastToolResult = toolResultFacts(event.data);\n break;\n }\n }\n }\n}\n", "/**\n * `auto-continue` namespace dictionaries: copy for the plugin settings card\n * registered into the `settings.plugin.item` seat of the plugin-configuration\n * section. Includes the card-chrome keys the card component reads.\n */\n\n/** 简体中文词典(键集的事实来源)。 */\nexport const zh = {\n 'card.title': '自动继续',\n 'card.description': '请求因网络等原因(非人为)中断后, 自动发送「继续」续跑。',\n 'field.paused': '暂停自动继续',\n 'field.pausedHint': '全局暂停: 实时与扫描都不会再自动发送, 已排队的待发送也会取消。',\n 'field.continueText': '继续文本',\n 'field.continueTextHint': '中断后自动发送的消息内容。',\n 'field.continueTextMaxTokens': '超限时的继续文本',\n 'field.continueTextMaxTokensHint': '达到输出 token 上限时自动发送的文本, 支持与继续文本相同的占位符。',\n 'field.guardTools': '幂等护栏',\n 'field.guardToolsHint': '续跑前检查上一步工具调用: 结果未确认时提示先确认状态, 已成功时提示不要重复执行, 避免重复 commit/调 API。',\n 'field.guardPendingText': '结果未确认时的护栏文本',\n 'field.guardPendingTextHint': '上一步工具可能已部分执行时附加到继续文本之后, 支持 {tool} 占位符。',\n 'field.guardDoneText': '工具已成功时的护栏文本',\n 'field.guardDoneTextHint': '上一步工具已确认成功时附加到继续文本之后, 支持 {tool} 与 {result}(结果摘要)占位符。',\n 'field.graceMs': '宽限期 (ms)',\n 'field.graceMsHint': '检测到中断后等待的时长; 期间宿主自行恢复则取消。',\n 'field.cooldownMs': '冷却时间 (ms)',\n 'field.cooldownMsHint': '同一会话两次自动「继续」的最小间隔, 失败尝试也计入。',\n 'field.maxConsecutive': '最大连续次数',\n 'field.maxConsecutiveHint': '同一会话连续自动「继续」的上限; 超过后停止, 直到用户手动介入或出现成功回合。',\n 'field.scanOnBoot': '启动/重连扫描',\n 'field.scanOnBootHint': '页面启动或重连时扫描最近中断的会话并自动续跑(如浏览器关闭期间宿主崩溃)。',\n 'field.scanLimit': '扫描会话数',\n 'field.scanLimitHint': '最多检查多少个最近更新的会话(不含运行中与子代理会话)。',\n 'field.freshMs': '扫描时间窗 (ms)',\n 'field.freshMsHint': '扫描只处理该时间窗内的中断。',\n 'field.reconnectScanDelayMs': '重连扫描延迟 (ms)',\n 'field.reconnectScanDelayMsHint': '重连后等待宿主完成恢复再扫描。',\n 'field.reconnectBackoffMs': '重连退避 (ms)',\n 'field.reconnectBackoffMsHint': '事件流断开后的重连间隔。',\n 'field.verbose': '详细日志',\n 'field.verboseHint': '在浏览器控制台输出 [auto-continue] 日志。',\n 'field.classify': '错误分类',\n 'field.classifyHint': '仅自动恢复临时性错误(网络/超时/5xx 等); 认证/余额/模型不存在等永久性错误跳过并通知。',\n 'field.backoffFactor': '退避系数',\n 'field.backoffFactorHint': '连续失败时冷却间隔的倍率(如 2 表示 20s→40s→80s 递增)。',\n 'field.backoffMaxMs': '最大退避间隔 (ms)',\n 'field.backoffMaxMsHint': '自适应退避的上限, 防止等待过久。',\n 'field.notify': '浏览器通知',\n 'field.notifyHint': '自动继续成功/放弃/遇到永久性错误时弹出浏览器通知, 通知带「立即续跑」与「暂停该会话 1 小时」按钮。',\n 'stats.title': '今日统计',\n 'stats.sent': '自动继续',\n 'stats.skipped': '跳过(永久错误)',\n 'stats.recovered': '恢复成功',\n 'stats.failed': '继续后仍失败',\n 'stats.gaveUp': '停止(达上限)',\n 'stats.byCode': '错误码分布',\n 'stats.empty': '今天还没有自动继续记录。',\n 'stats.reset': '清零',\n 'pause.title': '已暂停会话',\n 'pause.none': '没有暂停中的会话。',\n 'pause.clearAll': '全部解除',\n 'pause.unpause': '解除',\n 'pause.minutes': '分钟',\n 'chrome.collapse': '收起设置',\n 'chrome.expand': '展开设置',\n 'chrome.unsaved': '未保存',\n 'chrome.readOnly': '当前部署的设置只读。',\n 'chrome.saveFailed': '部署未接受这些值, 已保留供你修改。',\n 'chrome.discard': '放弃',\n 'chrome.saving': '保存中…',\n 'chrome.save': '保存',\n 'chrome.overridden': '已覆盖',\n 'chrome.reset': '恢复默认',\n 'chrome.invalidNumber': '请输入数字, 留空则使用默认值。',\n 'chrome.inherit': '继承',\n 'chrome.on': '开',\n 'chrome.off': '关',\n} satisfies Record<string, string>;\n\n/** 本插件的键联合。 */\nexport type SettingsCardKey = keyof typeof zh;\n\n/** English dictionary, checked complete against the zh key set. */\nexport const en: Record<SettingsCardKey, string> = {\n 'card.title': 'Auto continue',\n 'card.description': 'When a request is interrupted by a non-human cause, automatically send 「继续」 to resume.',\n 'field.paused': 'Pause auto-continue',\n 'field.pausedHint': 'Globally pause: no live or scan auto-send fires, and queued pending sends are cancelled.',\n 'field.continueText': 'Continue text',\n 'field.continueTextHint': 'Message automatically sent after an interruption.',\n 'field.continueTextMaxTokens': 'Continue text (max tokens)',\n 'field.continueTextMaxTokensHint': 'Text sent when the output token ceiling is reached; same placeholders as the continue text.',\n 'field.guardTools': 'Idempotency guard',\n 'field.guardToolsHint': 'Before resuming, inspect the last tool call: if its result is unconfirmed, tell the model to check state first; if it succeeded, tell it not to rerun — avoids duplicate commits / API calls.',\n 'field.guardPendingText': 'Guard text (unconfirmed result)',\n 'field.guardPendingTextHint': 'Appended when the last tool may have partially executed; supports the {tool} placeholder.',\n 'field.guardDoneText': 'Guard text (tool succeeded)',\n 'field.guardDoneTextHint': 'Appended when the last tool is confirmed done; supports {tool} and {result} (result excerpt).',\n 'field.graceMs': 'Grace period (ms)',\n 'field.graceMsHint': 'Wait after an interruption; cancelled if the host recovers on its own.',\n 'field.cooldownMs': 'Cooldown (ms)',\n 'field.cooldownMsHint': 'Minimum interval between auto-continues per session; failed attempts count too.',\n 'field.maxConsecutive': 'Max consecutive',\n 'field.maxConsecutiveHint': 'Max consecutive auto-continues per session; stops until a user intervenes or a turn completes.',\n 'field.scanOnBoot': 'Scan on load / reconnect',\n 'field.scanOnBootHint': 'Scan recently interrupted sessions on page load or reconnect (e.g. the host crashed while the browser was closed).',\n 'field.scanLimit': 'Scan limit',\n 'field.scanLimitHint': 'How many most-recently-updated sessions to check (running / subagent sessions excluded).',\n 'field.freshMs': 'Scan window (ms)',\n 'field.freshMsHint': 'Only interruptions inside this window are considered.',\n 'field.reconnectScanDelayMs': 'Reconnect scan delay (ms)',\n 'field.reconnectScanDelayMsHint': 'Wait for the host to finish recovering before scanning after a reconnect.',\n 'field.reconnectBackoffMs': 'Reconnect backoff (ms)',\n 'field.reconnectBackoffMsHint': 'Interval between event-stream reconnect attempts.',\n 'field.verbose': 'Verbose logs',\n 'field.verboseHint': 'Log [auto-continue] lines to the browser console.',\n 'field.classify': 'Classify errors',\n 'field.classifyHint': 'Auto-resume transient failures only (network/timeout/5xx…); auth, balance and model errors are skipped and notified.',\n 'field.backoffFactor': 'Backoff factor',\n 'field.backoffFactorHint': 'Cooldown multiplier per consecutive failure (2 = 20s→40s→80s…).',\n 'field.backoffMaxMs': 'Max backoff (ms)',\n 'field.backoffMaxMsHint': 'Cap on the adaptive backoff interval.',\n 'field.notify': 'Browser notifications',\n 'field.notifyHint': 'Notify when auto-continue fires, gives up, or hits a permanent error; notifications carry \"Resume now\" and \"Pause this session 1h\" buttons.',\n 'stats.title': \"Today's stats\",\n 'stats.sent': 'Auto-continued',\n 'stats.skipped': 'Skipped (permanent)',\n 'stats.recovered': 'Recovered',\n 'stats.failed': 'Failed after',\n 'stats.gaveUp': 'Gave up (cap)',\n 'stats.byCode': 'By error code',\n 'stats.empty': 'No auto-continue activity today.',\n 'stats.reset': 'Reset',\n 'pause.title': 'Paused sessions',\n 'pause.none': 'No sessions paused.',\n 'pause.clearAll': 'Clear all',\n 'pause.unpause': 'Resume',\n 'pause.minutes': 'min',\n 'chrome.collapse': 'Hide settings',\n 'chrome.expand': 'Show settings',\n 'chrome.unsaved': 'Unsaved',\n 'chrome.readOnly': 'This deployment stores settings read-only.',\n 'chrome.saveFailed': 'The deployment did not accept these values; they were left for you to correct.',\n 'chrome.discard': 'Discard',\n 'chrome.saving': 'Saving…',\n 'chrome.save': 'Save',\n 'chrome.overridden': 'Overridden',\n 'chrome.reset': 'Reset to default',\n 'chrome.invalidNumber': 'Enter a number, or leave blank to use the default.',\n 'chrome.inherit': 'Inherit',\n 'chrome.on': 'On',\n 'chrome.off': 'Off',\n};\n", "/**\n * The auto-continue settings card: edits the `auto-continue` namespace fields\n * from the plugin-configuration section (the `settings.plugin.item` seat).\n *\n * Self-contained card chrome (disclosure header, staged fields, save/discard\n * footer) following the plugin-card store pattern of the DSH plugin\n * configuration section; styles live in `styles.ts` and use the DSH design\n * tokens so the card follows the active theme.\n */\nimport { useEffect, useState, type ReactNode } from 'react';\nimport { createSnapshotStore, type SettingsScope, type SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client';\nimport type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';\nimport {\n pausedSessions,\n readTodayStats,\n resetTodayStats,\n unpauseSession,\n type AutoContinueSettings,\n} from './engine.ts';\nimport type { SettingsCardKey } from './locales.ts';\nimport {\n booleanField,\n CardForm,\n numberField,\n textField,\n type CardActions,\n type CardFieldState,\n type CardShell,\n} from './settings-form.ts';\nimport { injectStyles } from './styles.ts';\n\n// Styles must land during factory materialization so the module system's\n// style bookkeeping (HMR) owns them.\ninjectStyles();\n\n/** What the auto-continue card renders. */\nexport interface AutoContinueSettingsCardState extends CardShell {\n paused: CardFieldState;\n continueText: CardFieldState;\n continueTextMaxTokens: CardFieldState;\n guardTools: CardFieldState;\n guardPendingText: CardFieldState;\n guardDoneText: CardFieldState;\n graceMs: CardFieldState;\n cooldownMs: CardFieldState;\n maxConsecutive: CardFieldState;\n scanOnBoot: CardFieldState;\n scanLimit: CardFieldState;\n freshMs: CardFieldState;\n reconnectScanDelayMs: CardFieldState;\n reconnectBackoffMs: CardFieldState;\n verbose: CardFieldState;\n classify: CardFieldState;\n backoffFactor: CardFieldState;\n backoffMaxMs: CardFieldState;\n notify: CardFieldState;\n}\n\n/** The registration-side face the card's slot entry injects. */\nexport interface AutoContinueSettingsCardFace extends CardActions {\n hooks: {\n /** Card snapshot bound by the renderer as useAutoContinueSettingsCard. */\n autoContinueSettingsCard: SnapshotStore<AutoContinueSettingsCardState>;\n };\n}\n\n/** Bridges the `auto-continue` scope onto the card's staged form. */\nexport class AutoContinueSettingsCardController {\n private readonly form: CardForm<AutoContinueSettings>;\n private readonly store: SnapshotStore<AutoContinueSettingsCardState>;\n\n /**\n * @param scope - the bound settings scope for the `auto-continue` namespace.\n */\n constructor(scope: SettingsScope<AutoContinueSettings>) {\n this.form = new CardForm(scope, [\n booleanField('paused'),\n textField('continueText'),\n textField('continueTextMaxTokens'),\n booleanField('guardTools'),\n textField('guardPendingText'),\n textField('guardDoneText'),\n numberField('graceMs', 0),\n numberField('cooldownMs', 0),\n numberField('maxConsecutive', 1),\n booleanField('scanOnBoot'),\n numberField('scanLimit', 1),\n numberField('freshMs', 0),\n numberField('reconnectScanDelayMs', 0),\n numberField('reconnectBackoffMs', 0),\n booleanField('verbose'),\n booleanField('classify'),\n numberField('backoffFactor', 1),\n numberField('backoffMaxMs', 0),\n booleanField('notify'),\n ]);\n this.store = this.form.bind(() => this.projection(), createSnapshotStore);\n }\n\n private projection(): AutoContinueSettingsCardState {\n return {\n ...this.form.shell(),\n paused: this.form.field('paused'),\n continueText: this.form.field('continueText'),\n continueTextMaxTokens: this.form.field('continueTextMaxTokens'),\n guardTools: this.form.field('guardTools'),\n guardPendingText: this.form.field('guardPendingText'),\n guardDoneText: this.form.field('guardDoneText'),\n graceMs: this.form.field('graceMs'),\n cooldownMs: this.form.field('cooldownMs'),\n maxConsecutive: this.form.field('maxConsecutive'),\n scanOnBoot: this.form.field('scanOnBoot'),\n scanLimit: this.form.field('scanLimit'),\n freshMs: this.form.field('freshMs'),\n reconnectScanDelayMs: this.form.field('reconnectScanDelayMs'),\n reconnectBackoffMs: this.form.field('reconnectBackoffMs'),\n verbose: this.form.field('verbose'),\n classify: this.form.field('classify'),\n backoffFactor: this.form.field('backoffFactor'),\n backoffMaxMs: this.form.field('backoffMaxMs'),\n notify: this.form.field('notify'),\n };\n }\n\n /**\n * Build the face the card's slot registration injects.\n * @returns the card's snapshot and its form actions.\n */\n inject(): AutoContinueSettingsCardFace {\n return { hooks: { autoContinueSettingsCard: this.store }, ...this.form.actions() };\n }\n}\n\n/** Props the renderer binds for the auto-continue plugin-configuration card. */\nexport type AutoContinueSettingsCardProps =\n PropsRuntime<'settings.plugin.item'> & PropsLocale<'auto-continue'> & InjectFace<AutoContinueSettingsCardFace>;\n\n/** Card chrome: a disclosure header naming the plugin and what its settings govern, the controls, and the save that writes them. */\nfunction SettingsCard(props: {\n t: (key: SettingsCardKey) => string;\n titleKey: SettingsCardKey;\n descriptionKey: SettingsCardKey;\n state: CardShell;\n onSave: () => void;\n onDiscard: () => void;\n children: ReactNode;\n}) {\n const [open, setOpen] = useState(false);\n const { state } = props;\n if (!state.available) return null;\n const title = props.t(props.titleKey);\n const blocked = !state.dirty || state.invalid || state.saving;\n return (\n <li className={open ? 'dshAcCard dshAcCardOpen' : 'dshAcCard'}>\n <button\n type=\"button\"\n className=\"dshAcHeader\"\n aria-expanded={open}\n aria-label={`${props.t(open ? 'chrome.collapse' : 'chrome.expand')}: ${title}`}\n title={props.t(props.descriptionKey)}\n onClick={() => setOpen(!open)}\n >\n <span className=\"dshAcHeadText\">\n <span className=\"dshAcName\">{title}</span>\n <span className=\"dshAcDescription\">{props.t(props.descriptionKey)}</span>\n </span>\n {state.dirty ? (\n <span className=\"dshAcPending\" title={props.t('chrome.unsaved')}>\n {props.t('chrome.unsaved')}\n </span>\n ) : null}\n <span className={open ? 'dshAcChevron dshAcChevronOpen' : 'dshAcChevron'}>▾</span>\n </button>\n {open ? (\n <div className=\"dshAcBody\">\n {!state.writable ? (\n <p className=\"dshAcReadOnly\" role=\"status\">{props.t('chrome.readOnly')}</p>\n ) : null}\n {props.children}\n <div className=\"dshAcFooter\">\n {state.failed ? (\n <p className=\"dshAcFailed\" role=\"status\">{props.t('chrome.saveFailed')}</p>\n ) : null}\n <button\n type=\"button\"\n className=\"dshAcDiscard\"\n disabled={!state.dirty || state.saving}\n onClick={props.onDiscard}\n >\n {props.t('chrome.discard')}\n </button>\n <button type=\"button\" className=\"dshAcSave\" disabled={blocked} onClick={props.onSave}>\n {props.t(!state.saving ? 'chrome.save' : 'chrome.saving')}\n </button>\n </div>\n </div>\n ) : null}\n </li>\n );\n}\n\n/** Props every field control needs regardless of its value type. */\ninterface FieldProps {\n id: string;\n label: string;\n hint: string;\n text: string;\n overridden: boolean;\n invalid: boolean;\n disabled: boolean;\n t: (key: SettingsCardKey) => string;\n onEdit: (text: string) => void;\n onReset: () => void;\n}\n\n/** A staged value field; `numeric` only hints the keypad, which drafts a field accepts is decided by its spec. */\nfunction ValueField(props: FieldProps & { numeric?: boolean; placeholder?: string }) {\n return (\n <div className=\"dshAcField\">\n <div className=\"dshAcHead\">\n <label className=\"dshAcLabel\" htmlFor={props.id}>{props.label}</label>\n {props.overridden ? (\n <span className=\"dshAcBadges\">\n <span className=\"dshAcBadge\">{props.t('chrome.overridden')}</span>\n <button type=\"button\" className=\"dshAcReset\" disabled={props.disabled} onClick={props.onReset}>\n {props.t('chrome.reset')}\n </button>\n </span>\n ) : null}\n </div>\n <input\n id={props.id}\n className={props.invalid ? 'dshAcInput dshAcInputInvalid' : 'dshAcInput'}\n type=\"text\"\n inputMode={props.numeric === true ? 'numeric' : undefined}\n aria-invalid={props.invalid || undefined}\n value={props.text}\n placeholder={props.placeholder ?? ''}\n disabled={props.disabled}\n onChange={(event) => props.onEdit(event.target.value)}\n />\n <p className={props.invalid ? 'dshAcInvalid' : 'dshAcHint'}>\n {props.invalid ? props.t('chrome.invalidNumber') : props.hint}\n </p>\n </div>\n );\n}\n\n/** A staged boolean field: inherit / on / off. */\nfunction BooleanField(props: FieldProps) {\n return (\n <div className=\"dshAcField\">\n <div className=\"dshAcHead\">\n <label className=\"dshAcLabel\" htmlFor={props.id}>{props.label}</label>\n {props.overridden ? (\n <span className=\"dshAcBadges\">\n <span className=\"dshAcBadge\">{props.t('chrome.overridden')}</span>\n <button type=\"button\" className=\"dshAcReset\" disabled={props.disabled} onClick={props.onReset}>\n {props.t('chrome.reset')}\n </button>\n </span>\n ) : null}\n </div>\n <select\n id={props.id}\n className=\"dshAcSelect\"\n value={props.text}\n disabled={props.disabled}\n onChange={(event) => props.onEdit(event.target.value)}\n >\n <option value=\"\">{props.t('chrome.inherit')}</option>\n <option value=\"true\">{props.t('chrome.on')}</option>\n <option value=\"false\">{props.t('chrome.off')}</option>\n </select>\n <p className=\"dshAcHint\">{props.hint}</p>\n </div>\n );\n}\n\n/** 实时面板: 今日统计 + 已暂停会话。浏览器本地状态, 每 5 秒刷新一次。 */\nfunction LivePanels(props: { t: (key: SettingsCardKey) => string }) {\n const { t } = props;\n const [, refresh] = useState(0);\n useEffect(() => {\n const timer = setInterval(() => refresh((value) => value + 1), 5000);\n return () => clearInterval(timer);\n }, []);\n const stats = readTodayStats();\n const hasStats = stats.sent + stats.skipped + stats.recovered + stats.failed + stats.gaveUp > 0;\n const codes = Object.entries(stats.byCode)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 5);\n const paused = pausedSessions();\n return (\n <>\n <section className=\"dshAcPanel\">\n <div className=\"dshAcPanelHead\">\n <span className=\"dshAcPanelTitle\">{t('stats.title')}</span>\n {hasStats ? (\n <button\n type=\"button\"\n className=\"dshAcReset\"\n onClick={() => {\n resetTodayStats();\n refresh((value) => value + 1);\n }}\n >\n {t('stats.reset')}\n </button>\n ) : null}\n </div>\n {!hasStats ? (\n <p className=\"dshAcHint\">{t('stats.empty')}</p>\n ) : (\n <>\n <dl className=\"dshAcStats\">\n <div><dt>{t('stats.sent')}</dt><dd>{stats.sent}</dd></div>\n <div><dt>{t('stats.recovered')}</dt><dd>{stats.recovered}</dd></div>\n <div><dt>{t('stats.failed')}</dt><dd>{stats.failed}</dd></div>\n <div><dt>{t('stats.skipped')}</dt><dd>{stats.skipped}</dd></div>\n <div><dt>{t('stats.gaveUp')}</dt><dd>{stats.gaveUp}</dd></div>\n </dl>\n {codes.length > 0 ? (\n <div className=\"dshAcCodes\">\n <span className=\"dshAcHint\">{t('stats.byCode')}:</span>\n {codes.map(([code, count]) => (\n <span key={code} className=\"dshAcCode\">\n {code} ×{count}\n </span>\n ))}\n </div>\n ) : null}\n </>\n )}\n </section>\n <section className=\"dshAcPanel\">\n <div className=\"dshAcPanelHead\">\n <span className=\"dshAcPanelTitle\">{t('pause.title')}</span>\n {paused.length > 0 ? (\n <button\n type=\"button\"\n className=\"dshAcReset\"\n onClick={() => {\n for (const item of paused) unpauseSession(item.sessionId);\n refresh((value) => value + 1);\n }}\n >\n {t('pause.clearAll')}\n </button>\n ) : null}\n </div>\n {paused.length === 0 ? (\n <p className=\"dshAcHint\">{t('pause.none')}</p>\n ) : (\n <ul className=\"dshAcPauseList\">\n {paused.map((item) => (\n <li key={item.sessionId}>\n <span className=\"dshAcPauseId\">{item.sessionId.slice(0, 8)}…</span>\n <span className=\"dshAcHint\">\n {Math.max(1, Math.ceil((item.until - Date.now()) / 60000))} {t('pause.minutes')}\n </span>\n <button\n type=\"button\"\n className=\"dshAcReset\"\n onClick={() => {\n unpauseSession(item.sessionId);\n refresh((value) => value + 1);\n }}\n >\n {t('pause.unpause')}\n </button>\n </li>\n ))}\n </ul>\n )}\n </section>\n </>\n );\n}\n\n/**\n * Render the auto-continue card.\n * @param props - locale copy, the card snapshot, and its form actions.\n * @returns the card.\n */\nexport function AutoContinueSettingsCard(props: AutoContinueSettingsCardProps) {\n const { t } = props;\n const state = props.useAutoContinueSettingsCard((snapshot) => snapshot);\n const disabled = !state.writable;\n const shared = { t, disabled };\n return (\n <SettingsCard\n t={t}\n titleKey=\"card.title\"\n descriptionKey=\"card.description\"\n state={state}\n onSave={props.save}\n onDiscard={props.discard}\n >\n <BooleanField\n id=\"auto-continue-paused\"\n label={t('field.paused')}\n hint={t('field.pausedHint')}\n {...shared}\n {...state.paused}\n onEdit={(text) => props.edit('paused', text)}\n onReset={() => props.resetField('paused')}\n />\n <ValueField\n id=\"auto-continue-continue-text\"\n label={t('field.continueText')}\n hint={t('field.continueTextHint')}\n {...shared}\n {...state.continueText}\n onEdit={(text) => props.edit('continueText', text)}\n onReset={() => props.resetField('continueText')}\n />\n <ValueField\n id=\"auto-continue-continue-text-max-tokens\"\n label={t('field.continueTextMaxTokens')}\n hint={t('field.continueTextMaxTokensHint')}\n {...shared}\n {...state.continueTextMaxTokens}\n onEdit={(text) => props.edit('continueTextMaxTokens', text)}\n onReset={() => props.resetField('continueTextMaxTokens')}\n />\n <BooleanField\n id=\"auto-continue-guard-tools\"\n label={t('field.guardTools')}\n hint={t('field.guardToolsHint')}\n {...shared}\n {...state.guardTools}\n onEdit={(text) => props.edit('guardTools', text)}\n onReset={() => props.resetField('guardTools')}\n />\n <ValueField\n id=\"auto-continue-guard-pending-text\"\n label={t('field.guardPendingText')}\n hint={t('field.guardPendingTextHint')}\n {...shared}\n {...state.guardPendingText}\n onEdit={(text) => props.edit('guardPendingText', text)}\n onReset={() => props.resetField('guardPendingText')}\n />\n <ValueField\n id=\"auto-continue-guard-done-text\"\n label={t('field.guardDoneText')}\n hint={t('field.guardDoneTextHint')}\n {...shared}\n {...state.guardDoneText}\n onEdit={(text) => props.edit('guardDoneText', text)}\n onReset={() => props.resetField('guardDoneText')}\n />\n <ValueField\n id=\"auto-continue-grace-ms\"\n label={t('field.graceMs')}\n hint={t('field.graceMsHint')}\n numeric\n {...shared}\n {...state.graceMs}\n onEdit={(text) => props.edit('graceMs', text)}\n onReset={() => props.resetField('graceMs')}\n />\n <ValueField\n id=\"auto-continue-cooldown-ms\"\n label={t('field.cooldownMs')}\n hint={t('field.cooldownMsHint')}\n numeric\n {...shared}\n {...state.cooldownMs}\n onEdit={(text) => props.edit('cooldownMs', text)}\n onReset={() => props.resetField('cooldownMs')}\n />\n <ValueField\n id=\"auto-continue-max-consecutive\"\n label={t('field.maxConsecutive')}\n hint={t('field.maxConsecutiveHint')}\n numeric\n {...shared}\n {...state.maxConsecutive}\n onEdit={(text) => props.edit('maxConsecutive', text)}\n onReset={() => props.resetField('maxConsecutive')}\n />\n <BooleanField\n id=\"auto-continue-scan-on-boot\"\n label={t('field.scanOnBoot')}\n hint={t('field.scanOnBootHint')}\n {...shared}\n {...state.scanOnBoot}\n onEdit={(text) => props.edit('scanOnBoot', text)}\n onReset={() => props.resetField('scanOnBoot')}\n />\n <ValueField\n id=\"auto-continue-scan-limit\"\n label={t('field.scanLimit')}\n hint={t('field.scanLimitHint')}\n numeric\n {...shared}\n {...state.scanLimit}\n onEdit={(text) => props.edit('scanLimit', text)}\n onReset={() => props.resetField('scanLimit')}\n />\n <ValueField\n id=\"auto-continue-fresh-ms\"\n label={t('field.freshMs')}\n hint={t('field.freshMsHint')}\n numeric\n {...shared}\n {...state.freshMs}\n onEdit={(text) => props.edit('freshMs', text)}\n onReset={() => props.resetField('freshMs')}\n />\n <ValueField\n id=\"auto-continue-reconnect-scan-delay\"\n label={t('field.reconnectScanDelayMs')}\n hint={t('field.reconnectScanDelayMsHint')}\n numeric\n {...shared}\n {...state.reconnectScanDelayMs}\n onEdit={(text) => props.edit('reconnectScanDelayMs', text)}\n onReset={() => props.resetField('reconnectScanDelayMs')}\n />\n <ValueField\n id=\"auto-continue-reconnect-backoff\"\n label={t('field.reconnectBackoffMs')}\n hint={t('field.reconnectBackoffMsHint')}\n numeric\n {...shared}\n {...state.reconnectBackoffMs}\n onEdit={(text) => props.edit('reconnectBackoffMs', text)}\n onReset={() => props.resetField('reconnectBackoffMs')}\n />\n <BooleanField\n id=\"auto-continue-verbose\"\n label={t('field.verbose')}\n hint={t('field.verboseHint')}\n {...shared}\n {...state.verbose}\n onEdit={(text) => props.edit('verbose', text)}\n onReset={() => props.resetField('verbose')}\n />\n <BooleanField\n id=\"auto-continue-classify\"\n label={t('field.classify')}\n hint={t('field.classifyHint')}\n {...shared}\n {...state.classify}\n onEdit={(text) => props.edit('classify', text)}\n onReset={() => props.resetField('classify')}\n />\n <ValueField\n id=\"auto-continue-backoff-factor\"\n label={t('field.backoffFactor')}\n hint={t('field.backoffFactorHint')}\n numeric\n {...shared}\n {...state.backoffFactor}\n onEdit={(text) => props.edit('backoffFactor', text)}\n onReset={() => props.resetField('backoffFactor')}\n />\n <ValueField\n id=\"auto-continue-backoff-max\"\n label={t('field.backoffMaxMs')}\n hint={t('field.backoffMaxMsHint')}\n numeric\n {...shared}\n {...state.backoffMaxMs}\n onEdit={(text) => props.edit('backoffMaxMs', text)}\n onReset={() => props.resetField('backoffMaxMs')}\n />\n <BooleanField\n id=\"auto-continue-notify\"\n label={t('field.notify')}\n hint={t('field.notifyHint')}\n {...shared}\n {...state.notify}\n onEdit={(text) => props.edit('notify', text)}\n onReset={() => props.resetField('notify')}\n />\n <LivePanels t={t} />\n </SettingsCard>\n );\n}\n", "/**\n * Staged form model behind the plugin settings card — a self-contained\n * implementation of the plugin-card store pattern used by the DSH plugin\n * configuration section.\n *\n * A card stages what the user types and writes it only when they save. Each\n * settings write is a durable, revision-fenced document mutation, so staging\n * keeps what is on screen exactly what a save would store. A field shows its\n * effective value — the user layer over the composition layer over the schema\n * default — and whether the user layer carries it (presence, not value\n * equality, marks an override).\n */\nimport type { SettingsScope, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client';\n\n/** The write one field's staged text performs when the card is saved. */\nexport type FieldWrite = { kind: 'set'; value: unknown } | { kind: 'clear' };\n\n/** How one field converts between its stored value and its draft text. */\nexport interface CardFieldSpec {\n /** Field name inside the namespace section. */\n field: string;\n /** Render a stored value as draft text; the empty string when the section carries none. */\n format: (value: unknown) => string;\n /**\n * The write this draft text stages, or undefined when the text is not a\n * value this field accepts — which blocks the save rather than discarding it.\n */\n parse: (text: string) => FieldWrite | undefined;\n}\n\n/** One field as the card's control renders it. */\nexport interface CardFieldState {\n /** Draft text the control renders. */\n text: string;\n /** Whether saving would leave a user-layer entry for this field. */\n overridden: boolean;\n /** Whether the draft is not a value this field accepts, which blocks saving. */\n invalid: boolean;\n}\n\n/** Form state every plugin card shares. */\nexport interface CardShell {\n /** False while the namespace is not served to this client; the card renders nothing. */\n available: boolean;\n /** Whether the Host document accepts writes. */\n writable: boolean;\n /** Whether the form holds edits that a save would write. */\n dirty: boolean;\n /** Whether any staged draft is invalid, which blocks the save. */\n invalid: boolean;\n /** Whether a save is crossing the wire. */\n saving: boolean;\n /** Whether the last save did not land as staged; cleared by the next edit or save. */\n failed: boolean;\n}\n\n/** The write actions the card's slot entry injects. */\nexport interface CardActions {\n /** Stage draft text for one field. */\n edit: (field: string, text: string) => void;\n /** Stage a clear, so saving lets the field re-inherit the composition layer. */\n resetField: (field: string) => void;\n /** Write every staged edit, then re-seed from what the Host accepted. */\n save: () => void;\n /** Drop every staged edit. */\n discard: () => void;\n}\n\n/** A whole-number field. An empty draft clears the field; a non-number or out-of-range draft blocks the save. */\nexport function numberField(field: string, min = 0): CardFieldSpec {\n return {\n field,\n format: (value) => (typeof value === 'number' ? String(value) : ''),\n parse: (text) => {\n const trimmed = text.trim();\n if (trimmed === '') return { kind: 'clear' };\n const parsed = Number(trimmed);\n if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed < min) return undefined;\n return { kind: 'set', value: parsed };\n },\n };\n}\n\n/** A free-text field. An empty draft clears the field, so emptying the control and saving is the same gesture as resetting it. */\nexport function textField(field: string): CardFieldSpec {\n return {\n field,\n format: (value) => (typeof value === 'string' ? value : ''),\n parse: (text) => {\n const trimmed = text.trim();\n return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed };\n },\n };\n}\n\n/** A boolean field, edited through true/false draft text; an empty draft inherits. */\nexport function booleanField(field: string): CardFieldSpec {\n return {\n field,\n format: (value) => (typeof value === 'boolean' ? String(value) : ''),\n parse: (text) => {\n const trimmed = text.trim();\n if (trimmed === '') return { kind: 'clear' };\n if (trimmed === 'true') return { kind: 'set', value: true };\n if (trimmed === 'false') return { kind: 'set', value: false };\n return undefined;\n },\n };\n}\n\n/** One field's staged edit. */\ninterface StagedEdit {\n /** Draft text the control renders. */\n text: string;\n /** True when this edit clears the field whatever text it shows. */\n clear: boolean;\n}\n\n/**\n * Stages one card's edits over one settings namespace and writes them on save.\n *\n * The Host is the only authority on whether a value was accepted, so the\n * outcome is read back from the section rather than predicted here. A save\n * that did not land keeps its drafts, so the user can correct them instead of\n * retyping.\n */\nexport class CardForm<T> {\n private readonly specs: Map<string, CardFieldSpec>;\n private readonly staged = new Map<string, StagedEdit>();\n private readonly listeners = new Set<() => void>();\n private saving = false;\n private failed = false;\n\n /**\n * @param scope - the bound settings scope for this card's namespace.\n * @param specs - the section fields this card edits.\n */\n constructor(\n private readonly scope: SettingsScope<T>,\n specs: CardFieldSpec[],\n ) {\n this.specs = new Map(specs.map((spec) => [spec.field, spec]));\n this.scope.subscribe(() => this.publish());\n }\n\n /** Publish a projection of this form, rebuilt whenever the scope or a draft changes. */\n bind<S>(project: () => S, createStore: (init: S) => SnapshotStore<S>): SnapshotStore<S> {\n const store = createStore(project());\n this.listeners.add(() => store.set(project()));\n return store;\n }\n\n /** Read the card-level state: what the Host serves, and what a save would do. */\n shell(): CardShell {\n const snapshot = this.scope.getSnapshot();\n return {\n available: snapshot.status === 'ready',\n writable: snapshot.writable,\n dirty: this.plan().length > 0,\n invalid: this.plan().some((item) => item.run === undefined),\n saving: this.saving,\n failed: this.failed,\n };\n }\n\n /** Read one field's state from the effective section and its staged draft. */\n field(field: string): CardFieldState {\n const spec = this.specOf(field);\n const staged = this.staged.get(field);\n if (staged === undefined) {\n return {\n text: spec.format(this.sectionValue(field)),\n overridden: this.stored(field),\n invalid: false,\n };\n }\n const write = staged.clear ? { kind: 'clear' as const } : spec.parse(staged.text);\n return {\n text: staged.text,\n overridden: write?.kind === 'set',\n invalid: write === undefined,\n };\n }\n\n /** The actions the card's slot registration injects. */\n actions(): CardActions {\n return {\n edit: (field, text) => this.stage(field, { text, clear: false }),\n resetField: (field) => {\n this.stage(field, { text: this.specOf(field).format(this.baseValue(field)), clear: true });\n },\n save: () => void this.save(),\n discard: () => {\n if (this.staged.size === 0 && !this.failed) return;\n this.staged.clear();\n this.failed = false;\n this.publish();\n },\n };\n }\n\n /**\n * Write every staged edit, then re-seed from what the Host accepted.\n * @returns settlement after every write and the read-back.\n */\n async save(): Promise<void> {\n const plan = this.plan();\n const writes = plan.flatMap((item) => (item.run === undefined ? [] : [item.run]));\n if (plan.length === 0 || this.saving || writes.length !== plan.length) return;\n // Snapshot the fields this save writes, so edits staged while it is in\n // flight survive: only the staged keys this save actually wrote are cleared.\n const fields = new Set(plan.map((item) => item.field));\n this.saving = true;\n this.failed = false;\n this.publish();\n let landed = true;\n for (const write of writes) {\n landed = (await write()) && landed;\n }\n if (landed) {\n for (const field of fields) this.staged.delete(field);\n }\n this.saving = false;\n this.failed = !landed;\n this.publish();\n }\n\n /**\n * Every staged edit a save would write. An entry whose draft is not a value\n * its field accepts carries no write: the form is still dirty, and the save\n * refuses rather than dropping the edit. A staged edit that matches the\n * effective section is not a write at all.\n */\n private plan(): { field: string; run: (() => Promise<boolean>) | undefined }[] {\n const plan: { field: string; run: (() => Promise<boolean>) | undefined }[] = [];\n for (const [field, staged] of this.staged) {\n const spec = this.specOf(field);\n if (staged.clear) {\n if (this.stored(field)) plan.push({ field, run: () => this.clear(field) });\n continue;\n }\n if (staged.text === spec.format(this.sectionValue(field))) continue;\n const write = spec.parse(staged.text);\n if (write === undefined) plan.push({ field, run: undefined });\n else if (write.kind === 'clear') plan.push({ field, run: () => this.clear(field) });\n else plan.push({ field, run: () => this.store(field, write.value) });\n }\n return plan;\n }\n\n private async clear(field: string): Promise<boolean> {\n await this.scope.unset(field);\n return !this.stored(field);\n }\n\n private async store(field: string, value: unknown): Promise<boolean> {\n await this.scope.set(field, value);\n return this.userLayer()?.[field] === value;\n }\n\n private stage(field: string, edit: StagedEdit): void {\n this.staged.set(field, edit);\n this.failed = false;\n this.publish();\n }\n\n private specOf(field: string): CardFieldSpec {\n const spec = this.specs.get(field);\n if (spec === undefined) throw new Error(`settings card has no field ${field}`);\n return spec;\n }\n\n private sectionValue(field: string): unknown {\n return (this.scope.getSnapshot().value as Record<string, unknown> | undefined)?.[field];\n }\n\n private baseValue(field: string): unknown {\n return (this.scope.getSnapshot().base as Record<string, unknown> | undefined)?.[field];\n }\n\n private userLayer(): Record<string, unknown> | undefined {\n return this.scope.getSnapshot().user as Record<string, unknown> | undefined;\n }\n\n private stored(field: string): boolean {\n const user = this.userLayer();\n return user !== undefined && Object.prototype.hasOwnProperty.call(user, field);\n }\n\n private publish(): void {\n for (const listener of this.listeners) listener();\n }\n}\n", "/**\n * Styles for the auto-continue settings card, injected at factory\n * materialization so the client module system's style bookkeeping (HMR) owns\n * them. Uses the DSH design tokens (`--dsw-alias-*`) so the card follows the\n * active theme.\n */\n\nconst css = `\n.dshAcCard {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-3);\n border-radius: 12px;\n list-style: none;\n transition: border-color .16s, background .16s;\n}\n.dshAcCard:hover { border-color: var(--dsw-alias-label-dimmed); }\n.dshAcCardOpen {\n background: var(--dsw-alias-bg-layer-2);\n border-color: var(--dsw-alias-label-dimmed);\n}\n.dshAcHeader {\n appearance: none;\n width: 100%;\n font: inherit;\n color: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n border-radius: 12px;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n display: flex;\n}\n.dshAcHeader:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: -2px; }\n.dshAcHeadText { flex-direction: column; flex: 1; gap: 4px; min-width: 0; display: flex; }\n.dshAcName { color: var(--dsw-alias-label-primary); font-size: 15px; font-weight: 600; line-height: 1.4; }\n.dshAcDescription { color: var(--dsw-alias-label-tertiary); font-size: 13px; line-height: 1.5; }\n.dshAcChevron { color: var(--dsw-alias-label-tertiary); flex: none; transition: transform .16s; }\n.dshAcChevronOpen { transform: rotate(180deg); }\n.dshAcBody { border-top: 1px solid var(--dsw-alias-border-l2); margin: 0 16px; padding-bottom: 8px; }\n.dshAcReadOnly { color: var(--dsw-alias-label-tertiary); margin: 12px 0 0; font-size: 12px; line-height: 1.5; }\n.dshAcPending {\n white-space: nowrap;\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-label-secondary);\n border-radius: 999px;\n flex: none;\n padding: 1px 8px;\n font-size: 11px;\n font-weight: 500;\n line-height: 17px;\n}\n.dshAcFooter {\n border-top: 1px solid var(--dsw-alias-border-l2);\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n padding: 12px 0 4px;\n display: flex;\n}\n.dshAcFailed { min-width: 0; color: var(--dsw-alias-label-error); flex: 1; margin: 0; font-size: 12px; line-height: 1.5; }\n.dshAcDiscard, .dshAcSave {\n appearance: none;\n font: inherit;\n cursor: pointer;\n border: 1px solid transparent;\n border-radius: 8px;\n padding: 5px 14px;\n font-size: 13px;\n line-height: 1.5;\n}\n.dshAcDiscard { border-color: var(--dsw-alias-border-l2); color: var(--dsw-alias-label-secondary); background: none; }\n.dshAcDiscard:hover:not(:disabled) { color: var(--dsw-alias-label-primary); border-color: var(--dsw-alias-label-dimmed); }\n.dshAcSave { background: var(--dsw-alias-label-primary); color: var(--dsw-alias-bg-layer-3); }\n.dshAcDiscard:disabled, .dshAcSave:disabled { opacity: .4; cursor: default; }\n.dshAcDiscard:focus-visible, .dshAcSave:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 1px; }\n.dshAcField { flex-direction: column; gap: 6px; padding: 12px 0; display: flex; }\n.dshAcField + .dshAcField { border-top: 1px solid var(--dsw-alias-border-l2); }\n.dshAcHead { align-items: center; gap: 8px; display: flex; }\n.dshAcLabel { min-width: 0; color: var(--dsw-alias-label-primary); flex: 1; font-size: 13px; font-weight: 500; line-height: 1.5; }\n.dshAcBadges { align-items: center; gap: 8px; display: inline-flex; }\n.dshAcBadge {\n white-space: nowrap;\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-label-secondary);\n border-radius: 999px;\n padding: 1px 8px;\n font-size: 11px;\n font-weight: 500;\n line-height: 17px;\n}\n.dshAcReset {\n font: inherit;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n background: none;\n border: none;\n padding: 0;\n font-size: 12px;\n line-height: 1.5;\n}\n.dshAcReset:hover:not(:disabled) { color: var(--dsw-alias-label-primary); }\n.dshAcReset:disabled { cursor: default; }\n.dshAcInput {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-3);\n height: 34px;\n font: inherit;\n color: var(--dsw-alias-label-primary);\n border-radius: 8px;\n padding: 0 12px;\n font-size: 13px;\n line-height: 1.5;\n}\n.dshAcInput:focus-visible { border-color: var(--dsw-alias-brand-primary); outline: none; }\n.dshAcInput:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n.dshAcInputInvalid { border-color: var(--dsw-alias-label-error); }\n.dshAcSelect {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-3);\n height: 34px;\n font: inherit;\n color: var(--dsw-alias-label-primary);\n border-radius: 8px;\n padding: 0 8px;\n font-size: 13px;\n line-height: 1.5;\n}\n.dshAcSelect:focus-visible { border-color: var(--dsw-alias-brand-primary); outline: none; }\n.dshAcSelect:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n.dshAcInvalid { color: var(--dsw-alias-label-error); margin: 0; font-size: 12px; line-height: 1.5; }\n.dshAcHint { color: var(--dsw-alias-label-tertiary); margin: 0; font-size: 12px; line-height: 1.5; }\n.dshAcPanel { border-top: 1px solid var(--dsw-alias-border-l2); flex-direction: column; gap: 8px; padding: 12px 0; display: flex; }\n.dshAcPanelHead { align-items: center; gap: 8px; display: flex; }\n.dshAcPanelTitle { color: var(--dsw-alias-label-primary); flex: 1; font-size: 13px; font-weight: 600; line-height: 1.5; }\n.dshAcStats { gap: 4px 16px; margin: 0; grid-template-columns: repeat(2, minmax(0, 1fr)); display: grid; }\n.dshAcStats > div { justify-content: space-between; gap: 8px; display: flex; }\n.dshAcStats dt { color: var(--dsw-alias-label-secondary); font-size: 12px; line-height: 1.5; }\n.dshAcStats dd { color: var(--dsw-alias-label-primary); margin: 0; font-size: 12px; font-weight: 600; line-height: 1.5; }\n.dshAcCodes { flex-wrap: wrap; align-items: center; gap: 6px; display: flex; }\n.dshAcCode {\n white-space: nowrap;\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-label-secondary);\n border-radius: 999px;\n padding: 1px 8px;\n font-size: 11px;\n font-weight: 500;\n line-height: 17px;\n}\n.dshAcPauseList { flex-direction: column; gap: 4px; margin: 0; padding: 0; list-style: none; display: flex; }\n.dshAcPauseList li { align-items: center; gap: 8px; display: flex; }\n.dshAcPauseId {\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 1.5;\n}\n`;\n\n/** Inject the stylesheet once; a no-op outside a browser environment. */\nexport function injectStyles(): void {\n if (typeof document === 'undefined') return;\n if (document.querySelector('style[data-plugin-css=\"auto-continue/card\"]') !== null) return;\n const tag = document.createElement('style');\n tag.dataset.plugin = 'dsh-client-auto-continue';\n tag.dataset.pluginCss = 'auto-continue/card';\n tag.textContent = css;\n document.head.appendChild(tag);\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * Auto-continue plugin, browser half.\n *\n * - Runs the auto-continue engine over the live mux + host event streams.\n * - Registers the `auto-continue` settings card into the plugin-configuration\n * section (`settings.plugin.item`), editing the same namespace the engine\n * reads — every behavior knob is configurable from the GUI.\n */\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';\nimport type { ConnectionHandle } from '@deepseek-ai/dsh-client-connection/client';\n// Type-only: pulls the locale plugin's Context merge (ctx.locale).\nimport type {} from '@deepseek-ai/dsh-client-locale/client';\n// Type-only: pulls the settings-surface SlotMap merge and ctx.settingsScope.\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client';\n// Type-only: pulls the `settings.plugin.item` SlotMap merge.\nimport type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client';\nimport { AutoContinueRunner, resolveConfig, type AutoContinueSettings } from './engine.ts';\nimport { en, zh, type SettingsCardKey } from './locales.ts';\nimport {\n AutoContinueSettingsCard,\n AutoContinueSettingsCardController,\n} from './settings-card.tsx';\n\n/** 客户端根上下文的 connection 服务(由 dsh-client-connection 挂载)。 */\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n connection: ConnectionHandle;\n }\n}\n\n/** Dictionary namespace owned by this plugin. */\nconst NS = 'auto-continue';\n\n/** Settings namespace the engine reads and the settings card edits. */\nconst SETTINGS_NS = 'auto-continue';\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** auto-continue settings-card copy. */\n 'auto-continue': SettingsCardKey;\n }\n}\n\n/** Services required by this plugin. */\nexport const inject = ['slots', 'locale', 'connection', 'settingsScope'];\n\n// 浏览器侧辅助(设置卡片与模拟测试共用): 暂停控制与统计读取。\nexport {\n fillTemplate,\n pauseSession,\n pausedSessions,\n readTodayStats,\n resetTodayStats,\n sessionPauseUntil,\n unpauseSession,\n} from './engine.ts';\n\n/** 当前 runner(HMR 重载时先销毁旧的再建新的)。 */\nlet current: AutoContinueRunner | null = null;\n\n/**\n * Plugin body: mount the engine and the settings card.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'auto-continue: dictionaries');\n\n // Engine: reads the settings scope live, so GUI changes apply immediately.\n const scope = ctx.settingsScope.bind<AutoContinueSettings>({ namespace: SETTINGS_NS });\n current?.dispose();\n current = new AutoContinueRunner(ctx.connection.api, () => resolveConfig(scope.getSnapshot().value));\n\n // Plugin configuration card: one staged form over the `auto-continue`\n // settings namespace, contributed to the plugin-configuration section\n // (Settings → Plugins). Since DSH 0.1.0-rc.7 `settings.plugin.item` is a\n // keyed slot dispatched by the settings namespace it edits, so the entry\n // registers with `key` (the namespace), like the official cards.\n const controller = new AutoContinueSettingsCardController(scope);\n ctx.slots.inject('settings.plugin.item', () =>\n ctx.slots.register(\n {\n name: 'settings.plugin.item',\n key: SETTINGS_NS,\n locale: NS,\n inject: () => controller.inject(),\n },\n AutoContinueSettingsCard,\n ),\n );\n}\n", "/**\n * Auto-continue engine — browser half core.\n *\n * Watches the two live event streams of the dsh web GUI (mux + host):\n * - turns ended for a non-human reason (`turn/end` reason ∈ error / interrupted / max-tokens)\n * - host-reported agent failures with no turn position (`host/agent-error`)\n * After a grace period it sends a queued prompt (default 「继续」) to that\n * session — exactly equivalent to the user typing it manually.\n *\n * All behavior is driven by the `auto-continue` settings namespace (see the\n * plugin's settings card); every knob below is user-configurable there.\n */\n\nimport type {\n HostFrame,\n IApiClient,\n MuxFrame,\n SessionId,\n SessionSummary,\n} from '@deepseek-ai/dsh-client-connection/client';\nimport type { SessionEvent } from '@deepseek-ai/dsh-session/types';\n\n/** The `auto-continue` settings section (all fields optional on the wire; the host schema carries defaults). */\nexport interface AutoContinueSettings {\n /** Text automatically sent after an interruption. */\n continueText?: string;\n /** Text sent when the output token ceiling is reached (same placeholders as `continueText`). */\n continueTextMaxTokens?: string;\n /** Idempotency guard: inspect the last tool call before resuming and steer the model. */\n guardTools?: boolean;\n /** Guard text appended when the last tool call has no confirmed result (it may have partially executed). */\n guardPendingText?: string;\n /** Guard text appended when the last tool call completed successfully (don't rerun it). */\n guardDoneText?: string;\n /** Grace period after an interruption before auto-sending (ms). */\n graceMs?: number;\n /** Minimum interval between two auto-continues per session (ms). */\n cooldownMs?: number;\n /** Max consecutive auto-continues per session before stopping. */\n maxConsecutive?: number;\n /** Scan recently interrupted sessions on page load / reconnect. */\n scanOnBoot?: boolean;\n /** Max sessions the scan checks (most recently updated). */\n scanLimit?: number;\n /** Scan only considers interruptions inside this window (ms). */\n freshMs?: number;\n /** Delay before scanning after a reconnect (ms). */\n reconnectScanDelayMs?: number;\n /** SSE reconnect backoff (ms). */\n reconnectBackoffMs?: number;\n /** Log `[auto-continue]` lines to the browser console. */\n verbose?: boolean;\n /** Classify failures: auto-continue transient errors only; permanent ones (auth/balance/model) are skipped and notified. */\n classify?: boolean;\n /** Cooldown multiplier per consecutive failure (adaptive backoff). */\n backoffFactor?: number;\n /** Cap on the effective backoff interval (ms). */\n backoffMaxMs?: number;\n /** Show browser notifications for auto-continue events. */\n notify?: boolean;\n /** Globally pause auto-continue: no live or scan send, queued pending sends cancelled. */\n paused?: boolean;\n}\n\n/** Fully resolved configuration (built-in defaults + user overrides). */\nexport type AutoContinueConfig = Required<AutoContinueSettings>;\n\n/** Built-in defaults — must match the host schema defaults in src/index.ts. */\nexport const DEFAULT_CONFIG: AutoContinueConfig = {\n continueText: '继续',\n continueTextMaxTokens: '继续',\n guardTools: true,\n guardPendingText: '(上一步工具「{tool}」可能未完成, 先确认状态再继续, 不要重复执行)',\n guardDoneText: '(上一步工具「{tool}」已完成, 结果: {result}; 不要重复执行, 直接继续)',\n graceMs: 3000,\n cooldownMs: 20000,\n maxConsecutive: 3,\n scanOnBoot: true,\n scanLimit: 8,\n freshMs: 15 * 60 * 1000,\n reconnectScanDelayMs: 5000,\n reconnectBackoffMs: 3000,\n verbose: true,\n classify: true,\n backoffFactor: 2,\n backoffMaxMs: 300000,\n notify: false,\n paused: false,\n};\n\nfunction numberOr(value: unknown, fallback: number): number {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : fallback;\n}\n\nfunction booleanOr(value: unknown, fallback: boolean): boolean {\n return typeof value === 'boolean' ? value : fallback;\n}\n\n/** Resolve a (possibly partial / not-yet-loaded) settings section to a full config. */\nexport function resolveConfig(section: AutoContinueSettings | undefined): AutoContinueConfig {\n const value = section ?? {};\n const text =\n typeof value.continueText === 'string' && value.continueText.trim() !== ''\n ? value.continueText\n : DEFAULT_CONFIG.continueText;\n const maxTokensText =\n typeof value.continueTextMaxTokens === 'string' && value.continueTextMaxTokens.trim() !== ''\n ? value.continueTextMaxTokens\n : DEFAULT_CONFIG.continueTextMaxTokens;\n const guardPendingText =\n typeof value.guardPendingText === 'string' && value.guardPendingText.trim() !== ''\n ? value.guardPendingText\n : DEFAULT_CONFIG.guardPendingText;\n const guardDoneText =\n typeof value.guardDoneText === 'string' && value.guardDoneText.trim() !== ''\n ? value.guardDoneText\n : DEFAULT_CONFIG.guardDoneText;\n return {\n continueText: text,\n continueTextMaxTokens: maxTokensText,\n guardTools: booleanOr(value.guardTools, DEFAULT_CONFIG.guardTools),\n guardPendingText,\n guardDoneText,\n graceMs: numberOr(value.graceMs, DEFAULT_CONFIG.graceMs),\n cooldownMs: numberOr(value.cooldownMs, DEFAULT_CONFIG.cooldownMs),\n maxConsecutive: Math.max(1, numberOr(value.maxConsecutive, DEFAULT_CONFIG.maxConsecutive)),\n scanOnBoot: booleanOr(value.scanOnBoot, DEFAULT_CONFIG.scanOnBoot),\n scanLimit: Math.max(1, numberOr(value.scanLimit, DEFAULT_CONFIG.scanLimit)),\n freshMs: numberOr(value.freshMs, DEFAULT_CONFIG.freshMs),\n reconnectScanDelayMs: numberOr(value.reconnectScanDelayMs, DEFAULT_CONFIG.reconnectScanDelayMs),\n reconnectBackoffMs: numberOr(value.reconnectBackoffMs, DEFAULT_CONFIG.reconnectBackoffMs),\n verbose: booleanOr(value.verbose, DEFAULT_CONFIG.verbose),\n classify: booleanOr(value.classify, DEFAULT_CONFIG.classify),\n backoffFactor: Math.max(1, numberOr(value.backoffFactor, DEFAULT_CONFIG.backoffFactor)),\n backoffMaxMs: numberOr(value.backoffMaxMs, DEFAULT_CONFIG.backoffMaxMs),\n notify: booleanOr(value.notify, DEFAULT_CONFIG.notify),\n paused: booleanOr(value.paused, DEFAULT_CONFIG.paused),\n };\n}\n\n/**\n * 视为「非人为中断」的回合结束原因, 用于启动/重连扫描。\n * - `interrupted` 只由崩溃修复在宿主重载时写入(loop 永不实时发出), 因此仅在扫描路径处理;\n * - 实时事件路径只对 `error` / `max-tokens` 自动续跑;\n * - `aborted`(用户停止)与 `blocked`(策略拒绝)永不自动继续。\n */\ntype NonHumanReason = 'error' | 'interrupted' | 'max-tokens';\n\nfunction isNonHumanReason(kind: string): kind is NonHumanReason {\n return kind === 'error' || kind === 'interrupted' || kind === 'max-tokens';\n}\n\n/** 一次回合失败的机器可读事实(turn/end error 的 LlmFailure 载荷)。 */\nexport interface FailureFacts {\n /** 稳定机器路由码(如 UPSTREAM、RATE_LIMIT_EXCEEDED、INVALID_API_KEY)。 */\n code: string;\n /** 人类可读的失败描述。 */\n message: string;\n /** 供应商 HTTP 状态码(可用时)。 */\n status?: number;\n}\n\n/**\n * 错误分类: 该失败是否值得自动继续。\n * 永久性失败(认证/余额/模型不存在/上下文超限等)重试也不会成功, 应跳过并通知用户;\n * 其余(网络、超时、5xx、429 等)视为临时性失败, 允许自动恢复。\n */\nexport function isTransientFailure(failure: FailureFacts): boolean {\n const haystack = `${failure.code} ${failure.message}`.toLowerCase();\n const status = failure.status;\n if (status !== undefined && (status === 401 || status === 403)) return false;\n const permanent =\n /auth|unauthor|forbidden|credential|api[_-]?key|permission/i.test(haystack) ||\n /insufficient.*(balance|quota)|billing|payment|quota.*exceeded.*(?!retry)/i.test(haystack) ||\n /model.*not[_-]?found|unknown[_-]?model|model[_-]?not[_-]?found|not.*support.*model/i.test(haystack) ||\n /context.*(length|limit|overflow|exceed)|token.*limit|max.*context/i.test(haystack) ||\n /invalid[_-]?request|bad[_-]?request/i.test(haystack);\n return !permanent;\n}\n\n/**\n * host/agent-error 消息分类: 仅明确属于网络/传输类的临时错误才自动继续。\n * 其余(序列化失败、配置/宿主内部错误等)视为永久性——重试无益, 且用户停止导致的\n * 序列化失败(如 Windows 下 abort 的 DOMException reason)绝不能自动续跑。\n */\nexport function isTransientAgentError(message: string): boolean {\n return /network|timeout|timed ?out|econn|etimedout|socket|5\\d\\d|\\b429\\b|upstream|temporar/i.test(message);\n}\n\n/** 通知上的一个操作按钮(action 标识 + 显示文案)。 */\nexport interface NotifyAction {\n /** 稳定动作标识, 点击时经 onAction 回调传出。 */\n action: string;\n /** 按钮显示文案。 */\n title: string;\n}\n\n/** 通知的可选行为: 操作按钮列表与点击回调。 */\nexport interface NotifyOptions {\n actions?: NotifyAction[];\n onAction?: (action: string) => void;\n}\n\n/** 浏览器通知(不可用时静默跳过); 点击通知聚焦窗口, 操作按钮走 onAction。 */\nfunction notify(title: string, body: string, options?: NotifyOptions): void {\n try {\n const N = (globalThis as { Notification?: unknown }).Notification as\n | (new (t: string, o: { body: string; actions?: NotifyAction[] }) => unknown)\n | undefined;\n if (typeof N === 'undefined') return;\n const permission = (N as unknown as { permission?: string }).permission;\n const create = (): void => {\n const instance = new N(title, {\n body,\n ...(options?.actions !== undefined && options.actions.length > 0\n ? { actions: options.actions }\n : {}),\n });\n const target = instance as {\n onclick?: (() => void) | null;\n onaction?: ((event: { action: string }) => void) | null;\n };\n target.onclick = () => {\n try {\n (globalThis as { focus?: () => void }).focus?.();\n } catch {\n /* ignore */\n }\n };\n if (options?.onAction !== undefined) {\n target.onaction = (event) => options.onAction?.(event.action);\n }\n };\n if (permission === 'granted') {\n create();\n } else if (permission === 'default') {\n // 首次使用时请求一次权限, 用户拒绝后不再打扰。\n void (N as unknown as { requestPermission?: () => Promise<string> }).requestPermission?.()\n .then((result) => {\n if (result === 'granted') create();\n })\n .catch(() => {});\n }\n } catch {\n /* 通知失败不影响核心逻辑 */\n }\n}\n\n/** 把毫秒格式化为人类可读的经过时长(如 65s → 1m5s)。 */\nfunction formatElapsed(ms: number | undefined): string {\n if (ms === undefined || !Number.isFinite(ms) || ms < 0) return '';\n if (ms < 1000) return `${Math.round(ms)}ms`;\n const s = Math.round(ms / 1000);\n if (s < 60) return `${s}s`;\n return `${Math.floor(s / 60)}m${s % 60 > 0 ? `${s % 60}s` : ''}`;\n}\n\n/** 模板填充所需的上下文(全部可选, 缺失的占位符填为空串)。 */\nexport interface TemplateContext {\n /** 失败事实(错误码/消息/HTTP 状态), 对应 {code}/{message}/{status}。 */\n facts?: FailureFacts;\n /** 失败前最后一次工具调用的名称, 对应 {tool}。 */\n tool?: string;\n /** 失败回合的编号, 对应 {turn}。 */\n turn?: number;\n /** 连续失败次数(含本次), 对应 {errorCount}。 */\n errorCount?: number;\n /** 会话标题(来自 session.list 投影, 可用时), 对应 {sessionTitle}。 */\n sessionTitle?: string;\n /** 自失败发生以来的毫秒数, 对应 {elapsed}。 */\n elapsedMs?: number;\n /** 上一步工具结果摘要(截断), 对应 {result}(护栏模板用)。 */\n result?: string;\n}\n\n/** 用失败事实与回合信息填充 continueText 模板占位符({code}/{message}/{status}/{tool}/{turn}/{errorCount}/{sessionTitle}/{elapsed}/{result})。 */\nexport function fillTemplate(template: string, ctx: TemplateContext): string {\n return template\n .replace(/\\{code\\}/g, ctx.facts?.code ?? '')\n .replace(/\\{message\\}/g, ctx.facts?.message ?? '')\n .replace(/\\{status\\}/g, ctx.facts?.status !== undefined ? String(ctx.facts.status) : '')\n .replace(/\\{tool\\}/g, ctx.tool ?? '')\n .replace(/\\{turn\\}/g, ctx.turn !== undefined ? String(ctx.turn) : '')\n .replace(/\\{errorCount\\}/g, ctx.errorCount !== undefined ? String(ctx.errorCount) : '')\n .replace(/\\{sessionTitle\\}/g, ctx.sessionTitle ?? '')\n .replace(/\\{elapsed\\}/g, formatElapsed(ctx.elapsedMs))\n .replace(/\\{result\\}/g, ctx.result ?? '');\n}\n\n// ---------- 幂等护栏: 上一步工具调用的执行状态 ----------\n\n/** 工具结果摘要的最大长度(护栏模板 {result} 用)。 */\nconst TOOL_RESULT_CAP = 160;\n\n/** 从任意内容块里递归收集文本(结果为模型可见的工具输出)。 */\nfunction extractText(blocks: unknown, cap: number): string {\n let out = '';\n const walk = (value: unknown): void => {\n if (out.length >= cap) return;\n if (Array.isArray(value)) {\n for (const item of value) walk(item);\n return;\n }\n if (typeof value !== 'object' || value === null) return;\n const record = value as Record<string, unknown>;\n if (record['type'] === 'text' && typeof record['text'] === 'string') {\n out += record['text'];\n return;\n }\n for (const child of Object.values(record)) walk(child);\n };\n walk(blocks);\n return out.slice(0, cap);\n}\n\n/** 上一步工具调用的判定结果: 是否已确认完成, 以及文本摘要。 */\nexport interface ToolResultFacts {\n /** 工具是否成功完成(内部失败或 isError 视为未成功)。 */\n ok: boolean;\n /** 工具输出的文本摘要(截断)。 */\n excerpt: string;\n}\n\n/** 从 tool/result 事件载荷提取成功与否与文本摘要。 */\nfunction toolResultFacts(data: {\n error?: { name?: string; code?: string };\n message?: { content?: Array<{ type?: string; content?: unknown; isError?: boolean }> };\n}): ToolResultFacts {\n const failed = data.error !== undefined || data.message?.content?.[0]?.isError === true;\n return { ok: !failed, excerpt: extractText(data.message?.content?.[0]?.content, TOOL_RESULT_CAP) };\n}\n\n/** 自适应退避: 同一会话连续失败时的有效冷却间隔。 */\nexport function effectiveCooldown(\n consecutive: number,\n base: number,\n factor: number,\n max: number,\n): number {\n // consecutive = 已连续自动继续的次数; 第 1 次后开始按 factor 递增\n const multiplier = Math.pow(factor, consecutive);\n return Math.min(Math.max(base, base * multiplier), Math.max(base, max));\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** 浏览器当前 IANA 时区; 不可用时省略(宿主允许省略)。 */\nfunction clientTimeZone(): string | undefined {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone || undefined;\n } catch {\n return undefined;\n }\n}\n\n/** 跨标签页互斥与冷却记录(仅浏览器本地, 不落盘到宿主)。 */\nconst lockPrefix = 'dsh-auto-continue:';\nconst lockKey = (sessionId: SessionId) => `${lockPrefix}lock:${sessionId}`;\nconst stampKey = (sessionId: SessionId) => `${lockPrefix}last:${sessionId}`;\n\n/** 尝试独占本次发送: 两个标签页同时触发时只有一个成功。 */\nfunction claimSend(sessionId: SessionId): boolean {\n try {\n const token = `${Date.now()}-${Math.random().toString(36).slice(2)}`;\n localStorage.setItem(lockKey(sessionId), token);\n return localStorage.getItem(lockKey(sessionId)) === token;\n } catch {\n return true; // 存储不可用(隐私模式等)时放行\n }\n}\n\nfunction releaseSend(sessionId: SessionId): void {\n try {\n localStorage.removeItem(lockKey(sessionId));\n } catch {\n /* ignore */\n }\n}\n\n/** 读/写「上次自动发送」时间戳(跨标签页冷却)。 */\nfunction readLastSend(sessionId: SessionId): number {\n try {\n return Number(localStorage.getItem(stampKey(sessionId)) ?? 0) || 0;\n } catch {\n return 0;\n }\n}\n\nfunction writeLastSend(sessionId: SessionId, at: number): void {\n try {\n localStorage.setItem(stampKey(sessionId), String(at));\n } catch {\n /* ignore */\n }\n}\n\n// ---------- 会话级暂停(仅浏览器本地, 跨标签页共享) ----------\n\nconst pauseKey = (sessionId: SessionId) => `${lockPrefix}pause:${sessionId}`;\n\n/** 暂停某会话: 到 `until` 之前, 引擎不会为该会话自动继续(通知按钮等调用)。 */\nexport function pauseSession(sessionId: SessionId, ms: number): void {\n try {\n localStorage.setItem(pauseKey(sessionId), String(Date.now() + ms));\n } catch {\n /* ignore */\n }\n}\n\n/** 解除某会话的暂停。 */\nexport function unpauseSession(sessionId: SessionId): void {\n try {\n localStorage.removeItem(pauseKey(sessionId));\n } catch {\n /* ignore */\n }\n}\n\n/** 会话暂停的截止时间戳; 0 表示未暂停。 */\nexport function sessionPauseUntil(sessionId: SessionId): number {\n try {\n return Number(localStorage.getItem(pauseKey(sessionId)) ?? 0) || 0;\n } catch {\n return 0;\n }\n}\n\n/** 当前生效(未过期)的暂停会话列表; 顺带清理过期条目。 */\nexport function pausedSessions(): { sessionId: SessionId; until: number }[] {\n const out: { sessionId: SessionId; until: number }[] = [];\n const now = Date.now();\n try {\n for (let i = 0; i < localStorage.length; i += 1) {\n const key = localStorage.key(i);\n if (key === null || !key.startsWith(`${lockPrefix}pause:`)) continue;\n const sessionId = key.slice(lockPrefix.length + 'pause:'.length) as SessionId;\n const until = Number(localStorage.getItem(key) ?? 0) || 0;\n if (until > now) out.push({ sessionId, until });\n else localStorage.removeItem(key);\n }\n } catch {\n /* ignore */\n }\n return out;\n}\n\n// ---------- 统计(仅浏览器本地; 按本地日期分桶, 最多保留 90 天) ----------\n\n/** 一天的自动继续统计。 */\nexport interface DayStats {\n /** 本地日期 YYYY-MM-DD。 */\n date: string;\n /** 自动发送次数。 */\n sent: number;\n /** 因永久性错误跳过的次数。 */\n skipped: number;\n /** 发送后回合成功完成(恢复成功)的次数。 */\n recovered: number;\n /** 发送后再次失败的次数。 */\n failed: number;\n /** 达到连续上限而停止的次数(按停止事件计)。 */\n gaveUp: number;\n /** 按错误码计数的失败分布。 */\n byCode: Record<string, number>;\n}\n\nconst statsKey = `${lockPrefix}stats`;\nconst STATS_MAX_DAYS = 90;\n\nfunction todayKey(): string {\n const d = new Date();\n const mm = String(d.getMonth() + 1).padStart(2, '0');\n const dd = String(d.getDate()).padStart(2, '0');\n return `${d.getFullYear()}-${mm}-${dd}`;\n}\n\nfunction readStats(): DayStats[] {\n try {\n const raw = localStorage.getItem(statsKey);\n if (raw === null) return [];\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n return parsed.filter(\n (item): item is DayStats =>\n typeof item === 'object' && item !== null && typeof item.date === 'string',\n );\n } catch {\n return [];\n }\n}\n\nfunction writeStats(list: DayStats[]): void {\n try {\n localStorage.setItem(statsKey, JSON.stringify(list));\n } catch {\n /* ignore */\n }\n}\n\n/** 累加今日统计(引擎内部记账)。 */\nfunction bumpStat(delta: {\n sent?: number;\n skipped?: number;\n recovered?: number;\n failed?: number;\n gaveUp?: number;\n code?: string;\n}): void {\n const list = readStats();\n let day = list.find((item) => item.date === todayKey());\n if (day === undefined) {\n day = { date: todayKey(), sent: 0, skipped: 0, recovered: 0, failed: 0, gaveUp: 0, byCode: {} };\n list.unshift(day);\n }\n if (delta.sent !== undefined) day.sent += delta.sent;\n if (delta.skipped !== undefined) day.skipped += delta.skipped;\n if (delta.recovered !== undefined) day.recovered += delta.recovered;\n if (delta.failed !== undefined) day.failed += delta.failed;\n if (delta.gaveUp !== undefined) day.gaveUp += delta.gaveUp;\n if (delta.code !== undefined) day.byCode[delta.code] = (day.byCode[delta.code] ?? 0) + 1;\n writeStats(list.slice(0, STATS_MAX_DAYS));\n}\n\n/** 今日统计(设置卡片展示用)。 */\nexport function readTodayStats(): DayStats {\n const today = todayKey();\n const found = readStats().find((item) => item.date === today);\n return (\n found ?? { date: today, sent: 0, skipped: 0, recovered: 0, failed: 0, gaveUp: 0, byCode: {} }\n );\n}\n\n/** 清零今日统计。 */\nexport function resetTodayStats(): void {\n writeStats(readStats().filter((item) => item.date !== todayKey()));\n}\n\n/** 每会话运行时状态。 */\ninterface SessionState {\n /** 连续自动「继续」次数; 成功回合或用户手动介入后归零。 */\n consecutive: number;\n /** 上次自动「继续」时间戳。 */\n lastAutoAt: number;\n /** 上次自动「继续」尝试(成功或失败)时间戳; 防止失败场景下的快速重试循环。 */\n lastAttemptAt: number;\n /** 我们上次自动发送的文本(用于识别自己的回显)。 */\n lastSentText: string;\n /** 宽限期定时器(进行中的待发送)。 */\n pendingTimer: number | undefined;\n /** 宿主权威 running 位(来自 host/session-status 与回合事件)。 */\n running: boolean | undefined;\n /** 当前排队消息数(来自 session/queue 帧)。 */\n queued: number;\n /** 子代理会话(host/session-added 带 parentSessionId)。 */\n subagent: boolean;\n /** 最近一次回合失败的事实(用于分类与模板填充)。 */\n lastFailure: FailureFacts | undefined;\n /** 最近一次失败的发生时间(模板 {elapsed} 与恢复统计用)。 */\n lastFailureAt: number;\n /** 失败前最后一次工具调用的名称(模板 {tool} 与幂等护栏用)。 */\n lastTool: string | undefined;\n /** 上一步工具调用的结果状态: 'pending' = 已发起未见结果(可能已部分执行)。 */\n lastToolResult: 'pending' | ToolResultFacts | undefined;\n /** 失败回合的编号(模板 {turn})。 */\n lastTurn: number | undefined;\n /** 我们最近一次自动发送的时间戳; 0 = 没有待确认的恢复。 */\n pendingRecoveryAt: number;\n}\n\nconst freshState = (): SessionState => ({\n consecutive: 0,\n lastAutoAt: 0,\n lastAttemptAt: 0,\n lastSentText: '',\n pendingTimer: undefined,\n running: undefined,\n queued: 0,\n subagent: false,\n lastFailure: undefined,\n lastFailureAt: 0,\n lastTool: undefined,\n lastToolResult: undefined,\n lastTurn: undefined,\n pendingRecoveryAt: 0,\n});\n\n/** 自动发送后, 在该窗口内出现的回合结束才计入恢复统计。 */\nconst RECOVERY_WINDOW_MS = 10 * 60 * 1000;\n\n/** 判定一条 user/message 是否是我们自己自动发送的回显。 */\nfunction isOurEcho(state: SessionState, event: SessionEvent): boolean {\n if (event.type !== 'user/message') return false;\n const message = event.data;\n if (message.source.kind !== 'user') return false;\n if (state.lastSentText === '') return false;\n if (Date.now() - state.lastAutoAt > 30000) return false;\n const text = message.content\n .filter((part): part is { type: 'text'; text: string } => part.type === 'text')\n .map((part) => part.text)\n .join('');\n return text === state.lastSentText;\n}\n\n/** SSE 帧外壳: `{ rpcId, payload }`。 */\ntype FrameEnvelope<T> = { payload: T };\n\n/**\n * 事件流泵: 带指数退避的 SSE 重连循环。\n * - 从未收到任何帧(宿主未就绪): 退避重试, 不触发扫描\n * - 曾连上后断开: 重连, 并通过 onReconnect 通知外层(宿主可能崩溃重启过)\n */\nasync function pumpStream<T>(\n open: (signal: AbortSignal) => AsyncIterable<FrameEnvelope<T>>,\n onFrame: (payload: T) => void,\n onReconnect: () => void,\n getBackoff: () => number,\n log: (message: string) => void,\n signal: AbortSignal,\n): Promise<void> {\n let backoff = getBackoff();\n while (!signal.aborted) {\n let connected = false;\n try {\n for await (const envelope of open(signal)) {\n connected = true;\n onFrame(envelope.payload);\n }\n if (signal.aborted) return;\n } catch (error) {\n if (signal.aborted) return;\n log(`stream error: ${error instanceof Error ? error.message : String(error)}`);\n }\n if (!connected) {\n // 从未连上(宿主未就绪): 指数退避重试\n await sleep(backoff);\n backoff = Math.min(backoff * 2, 15000);\n continue;\n }\n // 曾连上后断开 → 重连并触发外层扫描\n backoff = getBackoff();\n onReconnect();\n await sleep(backoff);\n }\n}\n\n/** 插件主体: 一条 mux 流 + 一条 host 流 + 启动/重连扫描。 */\nexport class AutoContinueRunner {\n private readonly states = new Map<SessionId, SessionState>();\n private readonly muxAbort = new AbortController();\n private readonly hostAbort = new AbortController();\n private disposed = false;\n private reconnectScans = 0;\n\n /**\n * @param api - shared wire client (ctx.connection.api).\n * @param getConfig - read the current resolved configuration (settings scope).\n */\n constructor(\n private readonly api: IApiClient,\n private readonly getConfig: () => AutoContinueConfig,\n ) {\n const config = this.getConfig();\n void this.runMux();\n void this.runHost();\n if (config.scanOnBoot) {\n // 启动时连接可能尚未建立, 循环重试直到成功。\n void this.bootScanLoop();\n }\n this.log(\n `已启动(文本=\"${config.continueText}\", 宽限 ${config.graceMs}ms, ` +\n `冷却 ${config.cooldownMs}ms, 最多连续 ${config.maxConsecutive} 次)`,\n );\n }\n\n private log(message: string): void {\n if (this.getConfig().verbose) console.info(`[auto-continue] ${message}`);\n }\n\n dispose(): void {\n this.disposed = true;\n this.muxAbort.abort();\n this.hostAbort.abort();\n for (const state of this.states.values()) {\n if (state.pendingTimer !== undefined) clearTimeout(state.pendingTimer);\n }\n this.states.clear();\n }\n\n private state(sessionId: SessionId): SessionState {\n let state = this.states.get(sessionId);\n if (state === undefined) {\n state = freshState();\n this.states.set(sessionId, state);\n }\n return state;\n }\n\n private runMux(): Promise<void> {\n return pumpStream<MuxFrame>(\n (signal) => this.api.events.mux({}, signal),\n (payload) => this.onMuxFrame(payload),\n () => this.scheduleReconnectScan(),\n () => this.getConfig().reconnectBackoffMs,\n (m) => this.log(m),\n this.muxAbort.signal,\n );\n }\n\n private runHost(): Promise<void> {\n return pumpStream<HostFrame>(\n (signal) => this.api.events.host({}, signal),\n (payload) => this.onHostFrame(payload),\n () => this.scheduleReconnectScan(),\n () => this.getConfig().reconnectBackoffMs,\n (m) => this.log(m),\n this.hostAbort.signal,\n );\n }\n\n // ---------- mux 帧 ----------\n\n private onMuxFrame(frame: MuxFrame): void {\n switch (frame.type) {\n case 'session/event':\n if (frame.event.type === 'tool/call') {\n const name = frame.event.data.name;\n if (typeof name === 'string') {\n const state = this.state(frame.sessionId);\n state.lastTool = name;\n state.lastToolResult = 'pending'; // 已发起, 尚未见结果\n }\n } else if (frame.event.type === 'tool/result') {\n const state = this.state(frame.sessionId);\n if (state.lastToolResult === 'pending') {\n state.lastToolResult = toolResultFacts(frame.event.data);\n }\n }\n this.onSessionEvent(frame.sessionId, frame.event);\n break;\n case 'session/queue':\n this.state(frame.sessionId).queued = frame.items.length;\n if (frame.items.length > 0) this.cancelPending(frame.sessionId, '出现排队消息');\n break;\n case 'stream/error':\n this.log(`mux stream/error: ${frame.error.code} ${frame.error.message}`);\n break;\n default:\n break; // session/subscribed、approval/*、question/*、session/jobs、session/projection 与本插件无关\n }\n }\n\n private onSessionEvent(sessionId: SessionId, event: SessionEvent): void {\n const state = this.state(sessionId);\n switch (event.type) {\n case 'turn/start':\n state.running = true;\n // 新回合开始: 清空上一步工具调用状态, 避免跨回合误用护栏\n state.lastTool = undefined;\n state.lastToolResult = undefined;\n this.cancelPending(sessionId, '宿主自行开启新回合');\n break;\n case 'turn/end': {\n state.running = false;\n this.cancelPending(sessionId, '收到新的 turn/end');\n const reason = event.data.reason;\n if (reason.kind === 'completed') {\n // 成功回合: 恢复健康状态, 并确认上一次自动发送的效果\n state.consecutive = 0;\n state.lastFailure = undefined;\n this.noteRecovery(sessionId, 'completed');\n } else if (reason.kind === 'aborted') {\n // 用户主动停止: 不自动继续, 视为用户介入\n state.consecutive = 0;\n state.pendingRecoveryAt = 0;\n } else if (reason.kind === 'blocked') {\n // 策略拒绝: 不自动继续\n } else if (reason.kind === 'interrupted') {\n // 实时路径的 interrupted 仅来自崩溃修复重载(loop 从不实时发出);\n // 用户手动停止在 DSH 中标记为 aborted, 不走到这里。实时流里出现\n // interrupted 视为异常中断, 不自动继续——宿主崩溃孤儿回合由扫描恢复。\n state.consecutive = 0;\n state.pendingRecoveryAt = 0;\n } else if (reason.kind === 'error') {\n // 记录失败事实(分类与模板填充用), 然后按类型处理\n const error = reason.error;\n state.lastFailure = {\n code: typeof error.code === 'string' ? error.code : 'UNKNOWN',\n message: typeof error.message === 'string' ? error.message : String(error),\n ...(typeof error.status === 'number' ? { status: error.status } : {}),\n };\n state.lastTurn = event.data.turn;\n state.lastFailureAt = Date.now();\n this.noteRecovery(sessionId, 'error');\n this.onTurnFailure(sessionId, 'turn/end:error', state.lastFailure);\n } else if (reason.kind === 'max-tokens') {\n state.lastFailureAt = Date.now();\n this.noteRecovery(sessionId, 'error');\n this.schedule(sessionId, 'turn/end:max-tokens');\n }\n break;\n }\n case 'user/message':\n if (isOurEcho(state, event)) break; // 我们自己的回显\n if (event.data.source.kind === 'user') {\n // 用户手动介入\n state.consecutive = 0;\n this.cancelPending(sessionId, '用户手动发送消息');\n }\n break;\n default:\n break;\n }\n }\n\n // ---------- host 帧 ----------\n\n private onHostFrame(frame: HostFrame): void {\n switch (frame.type) {\n case 'host/session-status':\n this.state(frame.sessionId).running = frame.running;\n if (frame.running) this.cancelPending(frame.sessionId, '宿主报告会话开始运行');\n break;\n case 'host/session-added':\n this.state(frame.sessionId).subagent = frame.parentSessionId !== undefined;\n break;\n case 'host/agent-error':\n if (this.state(frame.sessionId).subagent) break;\n this.log(`host/agent-error(${frame.sessionId}): ${frame.message}`);\n // agent-error 的「仅网络/超时类自动续跑」是无条件安全承诺(与 classify 开关无关):\n // 序列化失败等永久性 agent 错误(包括用户停止的连带 DOMException)绝不能自动续跑,\n // 否则会退回「用户停止被误续跑」的场景(issue #2)。\n if (!isTransientAgentError(frame.message)) {\n // 永久性 agent 错误(序列化失败/配置错误等): 跳过并通知, 避免把用户停止等\n // 场景误判为可恢复中断后自动续跑。\n this.log(`跳过 ${frame.sessionId}: 永久性 agent 错误 — ${frame.message}`);\n bumpStat({ skipped: 1 });\n if (this.getConfig().notify) {\n notify(\n 'dsh-auto-continue: 未自动继续',\n `${frame.sessionId}: 永久性 agent 错误 ${frame.message.slice(0, 120)}`,\n this.notifyOptions(frame.sessionId),\n );\n }\n break;\n }\n this.schedule(frame.sessionId, 'host/agent-error');\n break;\n case 'host/session-removed':\n this.cancelPending(frame.sessionId, '会话已移除');\n this.states.delete(frame.sessionId);\n break;\n default:\n break;\n }\n }\n\n // ---------- 调度 ----------\n\n /** 回合失败入口: 先做错误分类, 永久性失败跳过并通知, 临时性失败走正常调度。 */\n private onTurnFailure(sessionId: SessionId, reason: string, failure: FailureFacts): void {\n const config = this.getConfig();\n if (config.classify && !isTransientFailure(failure)) {\n const summary = `${failure.code}${failure.status !== undefined ? ` (HTTP ${failure.status})` : ''}`;\n this.log(`跳过 ${sessionId}(${reason}): 永久性失败 ${summary} — ${failure.message}`);\n bumpStat({ skipped: 1, code: failure.code });\n if (config.notify) {\n notify(\n 'dsh-auto-continue: 未自动继续',\n `${sessionId}: 永久性错误 ${summary},需要人工处理`,\n this.notifyOptions(sessionId),\n );\n }\n return;\n }\n this.schedule(sessionId, reason);\n }\n\n /** 通知操作按钮与回调(「立即续跑」/「暂停该会话 1 小时」)。 */\n private notifyOptions(sessionId: SessionId): NotifyOptions {\n return {\n actions: [\n { action: 'resume', title: '立即续跑' },\n { action: 'pause1h', title: '暂停该会话 1 小时' },\n ],\n onAction: (action) => this.onNotifyAction(sessionId, action),\n };\n }\n\n private onNotifyAction(sessionId: SessionId, action: string): void {\n if (action === 'resume') {\n this.log(`通知按钮: 立即续跑 ${sessionId}`);\n void this.resumeNow(sessionId);\n } else if (action === 'pause1h') {\n this.log(`通知按钮: 暂停 ${sessionId} 1 小时`);\n pauseSession(sessionId, 60 * 60 * 1000);\n this.cancelPending(sessionId, '通知按钮暂停该会话');\n }\n }\n\n /** 恢复结果记账: 自动发送后窗口内的回合结束, 判定恢复成功或失败。 */\n private noteRecovery(sessionId: SessionId, outcome: 'completed' | 'error'): void {\n const state = this.state(sessionId);\n if (state.pendingRecoveryAt === 0) return;\n if (Date.now() - state.pendingRecoveryAt > RECOVERY_WINDOW_MS) {\n state.pendingRecoveryAt = 0; // 窗口过期, 不再归属这次发送\n return;\n }\n state.pendingRecoveryAt = 0;\n bumpStat(outcome === 'completed' ? { recovered: 1 } : { failed: 1 });\n this.log(`恢复结果(${sessionId}): ${outcome === 'completed' ? '成功' : '失败'}`);\n }\n\n /** 立即为该会话发送一次自动继续(无视冷却与连续上限; 由通知按钮触发)。 */\n async resumeNow(sessionId: SessionId): Promise<void> {\n if (this.disposed) return;\n const state = this.state(sessionId);\n if (state.subagent) return;\n if (state.pendingTimer !== undefined) {\n clearTimeout(state.pendingTimer);\n state.pendingTimer = undefined;\n }\n await this.fire(sessionId, 'manual:notification', true);\n }\n\n /** 本会话当前生效的冷却间隔(自适应退避)。 */\n private cooldownFor(state: SessionState): number {\n const config = this.getConfig();\n return effectiveCooldown(\n state.consecutive,\n config.cooldownMs,\n config.backoffFactor,\n config.backoffMaxMs,\n );\n }\n\n private schedule(sessionId: SessionId, reason: string): void {\n const state = this.state(sessionId);\n const config = this.getConfig();\n if (state.subagent) return; // 子代理会话由父代理处理, 不抢跑\n if (config.paused) {\n this.log(`跳过 ${sessionId}(${reason}): 全局暂停中`);\n return;\n }\n if (Date.now() < sessionPauseUntil(sessionId)) {\n this.log(`跳过 ${sessionId}(${reason}): 会话暂停中`);\n return;\n }\n if (state.pendingTimer !== undefined) return; // 已有待发送\n if (Date.now() - state.lastAttemptAt < this.cooldownFor(state)) return; // 冷却期(含失败尝试, 自适应退避)\n if (state.consecutive >= config.maxConsecutive) {\n this.log(\n `跳过 ${sessionId}(${reason}): 已连续自动继续 ${state.consecutive} 次, 等待用户介入或成功回合`,\n );\n return;\n }\n if (state.queued > 0) return; // 已有排队消息, 宿主会自行唤醒\n const timer = setTimeout(() => {\n if (state.pendingTimer !== timer) return;\n state.pendingTimer = undefined;\n void this.fire(sessionId, reason);\n }, config.graceMs);\n state.pendingTimer = timer;\n const template = reason.includes('max-tokens') ? config.continueTextMaxTokens : config.continueText;\n this.log(\n `检测到非人为中断 ${sessionId}(${reason}), ${config.graceMs}ms 后自动发送「${template}」`,\n );\n }\n\n private cancelPending(sessionId: SessionId, why: string): void {\n const state = this.state(sessionId);\n if (state.pendingTimer === undefined) return;\n clearTimeout(state.pendingTimer);\n state.pendingTimer = undefined;\n this.log(`取消 ${sessionId} 的自动继续(${why})`);\n }\n\n private async fire(sessionId: SessionId, reason: string, force = false): Promise<void> {\n if (this.disposed) return;\n const state = this.state(sessionId);\n const config = this.getConfig();\n // 权威 running 检查: 优先用 host 帧, 未知时回退到 session.list\n if (state.running === undefined) {\n const running = await this.runningViaList(sessionId);\n if (running === undefined || running) {\n this.log(`跳过 ${sessionId}: 无法确认空闲(${running === undefined ? '未知' : '运行中'})`);\n return;\n }\n } else if (state.running) {\n this.log(`跳过 ${sessionId}: 会话仍在运行`);\n return;\n }\n if (state.queued > 0) {\n this.log(`跳过 ${sessionId}: 已有排队消息`);\n return;\n }\n // 跨标签页冷却(自适应退避); 通知按钮的强制续跑不受冷却约束\n if (!force && Date.now() - readLastSend(sessionId) < this.cooldownFor(state)) {\n this.log(`跳过 ${sessionId}: 其他标签页刚发送过`);\n return;\n }\n if (!claimSend(sessionId)) {\n this.log(`跳过 ${sessionId}: 其他标签页正在发送`);\n return;\n }\n // 模板填充: continueText 可含 {code}/{message}/{status}/{tool}/{turn}/{errorCount}/{sessionTitle}/{elapsed} 占位符\n const template = reason.includes('max-tokens') ? config.continueTextMaxTokens : config.continueText;\n let sessionTitle: string | undefined;\n if (template.includes('{sessionTitle}')) {\n sessionTitle = this.titles.get(sessionId);\n if (sessionTitle === undefined) {\n const info = await this.fetchSessionInfo(sessionId);\n sessionTitle = info?.title;\n }\n }\n const text = this.buildContinueText(config, state, template, sessionTitle);\n const zone = clientTimeZone();\n state.lastAttemptAt = Date.now(); // 先记账: 无论成败, 本次尝试都进入冷却\n try {\n const response = await this.api.sessions.prompt({\n sessionId,\n mode: 'queue',\n content: [{ type: 'text', text }],\n ...(zone === undefined ? {} : { clientTimeZone: zone }),\n });\n if (response.result.ok) {\n const now = Date.now();\n state.consecutive += 1;\n state.lastAutoAt = now;\n state.lastSentText = text;\n state.pendingRecoveryAt = now; // 等待窗口内的下一个回合结束来判定恢复结果\n writeLastSend(sessionId, now);\n bumpStat({ sent: 1, ...(state.lastFailure !== undefined ? { code: state.lastFailure.code } : {}) });\n this.log(`已自动发送「${text}」到 ${sessionId}(${reason}), 第 ${state.consecutive} 次连续`);\n if (config.notify) {\n notify(\n 'dsh-auto-continue: 已自动继续',\n `${sessionId}: 已发送「${text}」(第 ${state.consecutive} 次连续)`,\n this.notifyOptions(sessionId),\n );\n }\n if (state.consecutive >= config.maxConsecutive) {\n bumpStat({ gaveUp: 1 });\n this.log(`达到连续上限 ${config.maxConsecutive} 次, 停止自动继续 ${sessionId}`);\n if (config.notify) {\n notify(\n 'dsh-auto-continue: 已停止自动继续',\n `${sessionId}: 连续失败 ${state.consecutive} 次, 需要人工介入`,\n this.notifyOptions(sessionId),\n );\n }\n }\n } else {\n this.log(\n `发送失败 ${sessionId}: ${response.result.error.code} ${response.result.error.message}`,\n );\n }\n } catch (error) {\n this.log(`发送异常 ${sessionId}: ${error instanceof Error ? error.message : String(error)}`);\n } finally {\n releaseSend(sessionId);\n }\n }\n\n /**\n * 组装本次续跑消息: 模板填充 + 幂等护栏。\n * 护栏依据上一步工具调用的执行状态附加指引, 防止重跑副作用操作:\n * - 结果未确认(可能已部分执行)→ 提示先确认状态、不要重复执行\n * - 已确认成功 → 提示已完成、不要重复执行\n * - 已失败 → 不加护栏(重试工具本来就是目的)\n */\n private buildContinueText(\n config: AutoContinueConfig,\n state: SessionState,\n template: string,\n sessionTitle: string | undefined,\n ): string {\n let text = fillTemplate(template, {\n facts: state.lastFailure,\n tool: state.lastTool,\n turn: state.lastTurn,\n errorCount: state.consecutive + 1,\n sessionTitle,\n elapsedMs: state.lastFailureAt > 0 ? Date.now() - state.lastFailureAt : undefined,\n });\n if (!config.guardTools) return text;\n const guard = this.currentGuard(state);\n if (guard.kind === 'pending') {\n text += ` ${fillTemplate(config.guardPendingText, { tool: guard.tool, result: guard.result })}`;\n } else if (guard.kind === 'done') {\n text += ` ${fillTemplate(config.guardDoneText, { tool: guard.tool, result: guard.result })}`;\n }\n return text;\n }\n\n /** 上一步工具调用的护栏状态(实时路径, 由 mux 帧维护)。 */\n private currentGuard(state: SessionState): {\n kind: 'none' | 'pending' | 'done' | 'failed';\n tool?: string;\n result?: string;\n } {\n if (state.lastTool === undefined || state.lastToolResult === undefined) return { kind: 'none' };\n if (state.lastToolResult === 'pending') return { kind: 'pending', tool: state.lastTool };\n if (state.lastToolResult.ok) {\n return { kind: 'done', tool: state.lastTool, result: state.lastToolResult.excerpt };\n }\n return { kind: 'failed', tool: state.lastTool };\n }\n\n /** 会话标题缓存(来自 session.list 投影, {sessionTitle} 占位符用)。 */\n private readonly titles = new Map<SessionId, string>();\n\n /** 查一次 session.list, 顺带缓存该会话的标题。 */\n private async fetchSessionInfo(\n sessionId: SessionId,\n ): Promise<{ running: boolean | undefined; title: string | undefined } | undefined> {\n try {\n const response = await this.api.sessions.list({});\n if (!response.result.ok) return undefined;\n const item = response.result.value.items.find(\n (summary: SessionSummary) => summary.sessionId === sessionId,\n );\n if (item === undefined) return undefined;\n // `title` 投影由 @deepseek-ai/dsh-session-title 声明; 此处用局部断言避免引入额外依赖。\n const title = (item.projections?.values as { title?: string | null } | undefined)?.title;\n if (typeof title === 'string' && title !== '') this.titles.set(sessionId, title);\n return { running: item.running, title: typeof title === 'string' ? title : undefined };\n } catch {\n return undefined;\n }\n }\n\n private async runningViaList(sessionId: SessionId): Promise<boolean | undefined> {\n const info = await this.fetchSessionInfo(sessionId);\n return info?.running;\n }\n\n // ---------- 启动/重连扫描 ----------\n\n private scheduleReconnectScan(): void {\n this.reconnectScans += 1;\n const scan = this.reconnectScans;\n setTimeout(() => {\n if (scan !== this.reconnectScans || this.disposed) return;\n void this.scanLoop(6, this.getConfig().reconnectScanDelayMs);\n }, this.getConfig().reconnectScanDelayMs);\n }\n\n private async bootScanLoop(): Promise<void> {\n await this.scanLoop(Infinity, 3000);\n }\n\n /** 反复尝试扫描, 直到成功(宿主就绪)或达到次数上限。 */\n private async scanLoop(attempts: number, delayMs: number): Promise<void> {\n for (let attempt = 0; attempt < attempts && !this.disposed; attempt += 1) {\n try {\n if (await this.scanInterrupted()) return;\n } catch (error) {\n if (this.disposed) return;\n // 宿主未就绪时每 3s 重试; 只节流记录日志, 避免刷屏。\n if (attempt % 10 === 0) {\n this.log(\n `扫描失败(${attempt + 1}/${attempts === Infinity ? '∞' : attempts}): ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n }\n if (attempt + 1 < attempts) await sleep(delayMs);\n }\n }\n\n /**\n * 扫描最近中断过的会话: 最后回合以非人为原因结束, 且其后没有新回合或用户消息。\n * @returns 是否成功完成一次扫描(宿主就绪)。\n */\n private async scanInterrupted(): Promise<boolean> {\n const config = this.getConfig();\n if (config.paused) return true; // 全局暂停: 不做任何扫描\n const response = await this.api.sessions.list({});\n if (!response.result.ok) return false;\n const items = response.result.value.items;\n for (const summary of items) {\n const title = (summary.projections?.values as { title?: string | null } | undefined)?.title;\n if (typeof title === 'string' && title !== '') this.titles.set(summary.sessionId, title);\n }\n const candidates = items\n .filter((summary) => !summary.running && summary.parentSessionId === undefined)\n .slice(0, config.scanLimit);\n const now = Date.now();\n for (const summary of candidates) {\n if (this.disposed) return true;\n const state = this.state(summary.sessionId);\n if (state.pendingTimer !== undefined) continue;\n if (state.consecutive >= config.maxConsecutive) continue;\n if (now - state.lastAttemptAt < this.cooldownFor(state)) continue;\n if (now < sessionPauseUntil(summary.sessionId)) continue; // 会话暂停中\n let events;\n try {\n const page = await this.api.sessions.history({\n sessionId: summary.sessionId,\n maxMessages: 30,\n });\n if (!page.result.ok) continue;\n events = page.result.value.events;\n } catch {\n continue; // 会话可能刚被移除\n }\n // 从尾部找最后一个 turn/end(在分支内完成收窄)\n let lastEnd: SessionEvent<'turn/end'> | undefined;\n for (let i = events.length - 1; i >= 0; i -= 1) {\n const event = events[i]?.event;\n if (event !== undefined && event.type === 'turn/end') {\n lastEnd = event;\n break;\n }\n }\n if (lastEnd === undefined) continue;\n const reason = lastEnd.data.reason;\n if (!isNonHumanReason(reason.kind)) continue;\n if (lastEnd.time < now - config.freshMs) continue; // 太久远, 不翻旧账\n // 该 turn/end 之后不能有新回合或用户消息(说明已被处理)\n let superseded = false;\n for (const entry of events) {\n const event = entry.event;\n if (event.seq <= lastEnd.seq) continue;\n if (event.type === 'turn/start') superseded = true;\n if (event.type === 'user/message' && event.data.source.kind === 'user') superseded = true;\n if (superseded) break;\n }\n if (superseded) continue;\n // 幂等护栏: 从历史事件里重建上一步工具调用的执行状态\n this.applyGuardFromEvents(state, events, lastEnd.seq);\n this.log(`扫描发现中断 ${summary.sessionId}(turn/end:${reason.kind}), 安排自动继续`);\n this.schedule(summary.sessionId, `scan:turn/end:${reason.kind}`);\n }\n return true;\n }\n\n /** 从历史事件恢复上一步工具调用状态(扫描路径的幂等护栏)。 */\n private applyGuardFromEvents(\n state: SessionState,\n events: { event: SessionEvent }[],\n untilSeq: number,\n ): void {\n state.lastTool = undefined;\n state.lastToolResult = undefined;\n let call: SessionEvent<'tool/call'> | undefined;\n for (const entry of events) {\n const event = entry.event;\n if (event.seq >= untilSeq) continue;\n if (event.type === 'tool/call') call = event;\n }\n if (call === undefined) return;\n state.lastTool = call.data.name;\n state.lastToolResult = 'pending';\n for (const entry of events) {\n const event = entry.event;\n if (event.seq <= call.seq || event.seq >= untilSeq) continue;\n if (event.type === 'tool/result') {\n state.lastToolResult = toolResultFacts(event.data);\n break;\n }\n }\n }\n}\n", "/**\n * `auto-continue` namespace dictionaries: copy for the plugin settings card\n * registered into the `settings.plugin.item` seat of the plugin-configuration\n * section. Includes the card-chrome keys the card component reads.\n */\n\n/** 简体中文词典(键集的事实来源)。 */\nexport const zh = {\n 'card.title': '自动继续',\n 'card.description': '请求因网络等原因(非人为)中断后, 自动发送「继续」续跑。',\n 'field.paused': '暂停自动继续',\n 'field.pausedHint': '全局暂停: 实时与扫描都不会再自动发送, 已排队的待发送也会取消。',\n 'field.continueText': '继续文本',\n 'field.continueTextHint': '中断后自动发送的消息内容。',\n 'field.continueTextMaxTokens': '超限时的继续文本',\n 'field.continueTextMaxTokensHint': '达到输出 token 上限时自动发送的文本, 支持与继续文本相同的占位符。',\n 'field.guardTools': '幂等护栏',\n 'field.guardToolsHint': '续跑前检查上一步工具调用: 结果未确认时提示先确认状态, 已成功时提示不要重复执行, 避免重复 commit/调 API。',\n 'field.guardPendingText': '结果未确认时的护栏文本',\n 'field.guardPendingTextHint': '上一步工具可能已部分执行时附加到继续文本之后, 支持 {tool} 占位符。',\n 'field.guardDoneText': '工具已成功时的护栏文本',\n 'field.guardDoneTextHint': '上一步工具已确认成功时附加到继续文本之后, 支持 {tool} 与 {result}(结果摘要)占位符。',\n 'field.graceMs': '宽限期 (ms)',\n 'field.graceMsHint': '检测到中断后等待的时长; 期间宿主自行恢复则取消。',\n 'field.cooldownMs': '冷却时间 (ms)',\n 'field.cooldownMsHint': '同一会话两次自动「继续」的最小间隔, 失败尝试也计入。',\n 'field.maxConsecutive': '最大连续次数',\n 'field.maxConsecutiveHint': '同一会话连续自动「继续」的上限; 超过后停止, 直到用户手动介入或出现成功回合。',\n 'field.scanOnBoot': '启动/重连扫描',\n 'field.scanOnBootHint': '页面启动或重连时扫描最近中断的会话并自动续跑(如浏览器关闭期间宿主崩溃)。',\n 'field.scanLimit': '扫描会话数',\n 'field.scanLimitHint': '最多检查多少个最近更新的会话(不含运行中与子代理会话)。',\n 'field.freshMs': '扫描时间窗 (ms)',\n 'field.freshMsHint': '扫描只处理该时间窗内的中断。',\n 'field.reconnectScanDelayMs': '重连扫描延迟 (ms)',\n 'field.reconnectScanDelayMsHint': '重连后等待宿主完成恢复再扫描。',\n 'field.reconnectBackoffMs': '重连退避 (ms)',\n 'field.reconnectBackoffMsHint': '事件流断开后的重连间隔。',\n 'field.verbose': '详细日志',\n 'field.verboseHint': '在浏览器控制台输出 [auto-continue] 日志。',\n 'field.classify': '错误分类',\n 'field.classifyHint': '仅自动恢复临时性错误(网络/超时/5xx 等); 认证/余额/模型不存在等永久性错误跳过并通知。',\n 'field.backoffFactor': '退避系数',\n 'field.backoffFactorHint': '连续失败时冷却间隔的倍率(如 2 表示 20s→40s→80s 递增)。',\n 'field.backoffMaxMs': '最大退避间隔 (ms)',\n 'field.backoffMaxMsHint': '自适应退避的上限, 防止等待过久。',\n 'field.notify': '浏览器通知',\n 'field.notifyHint': '自动继续成功/放弃/遇到永久性错误时弹出浏览器通知, 通知带「立即续跑」与「暂停该会话 1 小时」按钮。',\n 'stats.title': '今日统计',\n 'stats.sent': '自动继续',\n 'stats.skipped': '跳过(永久错误)',\n 'stats.recovered': '恢复成功',\n 'stats.failed': '继续后仍失败',\n 'stats.gaveUp': '停止(达上限)',\n 'stats.byCode': '按错误码统计',\n 'stats.empty': '今天还没有自动继续记录。',\n 'stats.reset': '清零',\n 'pause.title': '已暂停会话',\n 'pause.none': '没有暂停中的会话。',\n 'pause.clearAll': '全部解除',\n 'pause.unpause': '解除',\n 'pause.minutes': '分钟',\n 'chrome.collapse': '收起设置',\n 'chrome.expand': '展开设置',\n 'chrome.unsaved': '未保存',\n 'chrome.readOnly': '当前部署的设置只读。',\n 'chrome.saveFailed': '部署未接受这些值, 已保留供你修改。',\n 'chrome.discard': '放弃',\n 'chrome.saving': '保存中…',\n 'chrome.save': '保存',\n 'chrome.overridden': '已覆盖',\n 'chrome.reset': '恢复默认',\n 'chrome.invalidNumber': '请输入数字, 留空则使用默认值。',\n 'chrome.inherit': '继承',\n 'chrome.on': '开',\n 'chrome.off': '关',\n} satisfies Record<string, string>;\n\n/** 本插件的键联合。 */\nexport type SettingsCardKey = keyof typeof zh;\n\n/** English dictionary, checked complete against the zh key set. */\nexport const en: Record<SettingsCardKey, string> = {\n 'card.title': 'Auto continue',\n 'card.description': 'When a request is interrupted by a non-human cause, automatically send 「继续」 to resume.',\n 'field.paused': 'Pause auto-continue',\n 'field.pausedHint': 'Globally pause: no live or scan auto-send fires, and queued pending sends are cancelled.',\n 'field.continueText': 'Continue text',\n 'field.continueTextHint': 'Message automatically sent after an interruption.',\n 'field.continueTextMaxTokens': 'Continue text (max tokens)',\n 'field.continueTextMaxTokensHint': 'Text sent when the output token ceiling is reached; same placeholders as the continue text.',\n 'field.guardTools': 'Idempotency guard',\n 'field.guardToolsHint': 'Before resuming, inspect the last tool call: if its result is unconfirmed, tell the model to check state first; if it succeeded, tell it not to rerun — avoids duplicate commits / API calls.',\n 'field.guardPendingText': 'Guard text (unconfirmed result)',\n 'field.guardPendingTextHint': 'Appended when the last tool may have partially executed; supports the {tool} placeholder.',\n 'field.guardDoneText': 'Guard text (tool succeeded)',\n 'field.guardDoneTextHint': 'Appended when the last tool is confirmed done; supports {tool} and {result} (result excerpt).',\n 'field.graceMs': 'Grace period (ms)',\n 'field.graceMsHint': 'Wait after an interruption; cancelled if the host recovers on its own.',\n 'field.cooldownMs': 'Cooldown (ms)',\n 'field.cooldownMsHint': 'Minimum interval between auto-continues per session; failed attempts count too.',\n 'field.maxConsecutive': 'Max consecutive',\n 'field.maxConsecutiveHint': 'Max consecutive auto-continues per session; stops until a user intervenes or a turn completes.',\n 'field.scanOnBoot': 'Scan on load / reconnect',\n 'field.scanOnBootHint': 'Scan recently interrupted sessions on page load or reconnect (e.g. the host crashed while the browser was closed).',\n 'field.scanLimit': 'Scan limit',\n 'field.scanLimitHint': 'How many most-recently-updated sessions to check (running / subagent sessions excluded).',\n 'field.freshMs': 'Scan window (ms)',\n 'field.freshMsHint': 'Only interruptions inside this window are considered.',\n 'field.reconnectScanDelayMs': 'Reconnect scan delay (ms)',\n 'field.reconnectScanDelayMsHint': 'Wait for the host to finish recovering before scanning after a reconnect.',\n 'field.reconnectBackoffMs': 'Reconnect backoff (ms)',\n 'field.reconnectBackoffMsHint': 'Interval between event-stream reconnect attempts.',\n 'field.verbose': 'Verbose logs',\n 'field.verboseHint': 'Log [auto-continue] lines to the browser console.',\n 'field.classify': 'Classify errors',\n 'field.classifyHint': 'Auto-resume transient failures only (network/timeout/5xx…); auth, balance and model errors are skipped and notified.',\n 'field.backoffFactor': 'Backoff factor',\n 'field.backoffFactorHint': 'Cooldown multiplier per consecutive failure (2 = 20s→40s→80s…).',\n 'field.backoffMaxMs': 'Max backoff (ms)',\n 'field.backoffMaxMsHint': 'Cap on the adaptive backoff interval.',\n 'field.notify': 'Browser notifications',\n 'field.notifyHint': 'Notify when auto-continue fires, gives up, or hits a permanent error; notifications carry \"Resume now\" and \"Pause this session 1h\" buttons.',\n 'stats.title': \"Today's stats\",\n 'stats.sent': 'Auto-continued',\n 'stats.skipped': 'Skipped (permanent)',\n 'stats.recovered': 'Recovered',\n 'stats.failed': 'Failed after',\n 'stats.gaveUp': 'Gave up (cap)',\n 'stats.byCode': 'By error code',\n 'stats.empty': 'No auto-continue activity today.',\n 'stats.reset': 'Reset',\n 'pause.title': 'Paused sessions',\n 'pause.none': 'No sessions paused.',\n 'pause.clearAll': 'Clear all',\n 'pause.unpause': 'Resume',\n 'pause.minutes': 'min',\n 'chrome.collapse': 'Hide settings',\n 'chrome.expand': 'Show settings',\n 'chrome.unsaved': 'Unsaved',\n 'chrome.readOnly': 'This deployment stores settings read-only.',\n 'chrome.saveFailed': 'The deployment did not accept these values; they were left for you to correct.',\n 'chrome.discard': 'Discard',\n 'chrome.saving': 'Saving…',\n 'chrome.save': 'Save',\n 'chrome.overridden': 'Overridden',\n 'chrome.reset': 'Reset to default',\n 'chrome.invalidNumber': 'Enter a number, or leave blank to use the default.',\n 'chrome.inherit': 'Inherit',\n 'chrome.on': 'On',\n 'chrome.off': 'Off',\n};\n", "/**\n * The auto-continue settings card: edits the `auto-continue` namespace fields\n * from the plugin-configuration section (the `settings.plugin.item` seat).\n *\n * Self-contained card chrome (disclosure header, staged fields, save/discard\n * footer) following the plugin-card store pattern of the DSH plugin\n * configuration section; styles live in `styles.ts` and use the DSH design\n * tokens so the card follows the active theme.\n */\nimport { useEffect, useState, type ReactNode } from 'react';\nimport { createSnapshotStore, type SettingsScope, type SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client';\nimport type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';\nimport {\n pausedSessions,\n readTodayStats,\n resetTodayStats,\n unpauseSession,\n type AutoContinueSettings,\n} from './engine.ts';\nimport type { SettingsCardKey } from './locales.ts';\nimport {\n booleanField,\n CardForm,\n numberField,\n textField,\n type CardActions,\n type CardFieldState,\n type CardShell,\n} from './settings-form.ts';\nimport { injectStyles } from './styles.ts';\n\n// Styles must land during factory materialization so the module system's\n// style bookkeeping (HMR) owns them.\ninjectStyles();\n\n/** What the auto-continue card renders. */\nexport interface AutoContinueSettingsCardState extends CardShell {\n paused: CardFieldState;\n continueText: CardFieldState;\n continueTextMaxTokens: CardFieldState;\n guardTools: CardFieldState;\n guardPendingText: CardFieldState;\n guardDoneText: CardFieldState;\n graceMs: CardFieldState;\n cooldownMs: CardFieldState;\n maxConsecutive: CardFieldState;\n scanOnBoot: CardFieldState;\n scanLimit: CardFieldState;\n freshMs: CardFieldState;\n reconnectScanDelayMs: CardFieldState;\n reconnectBackoffMs: CardFieldState;\n verbose: CardFieldState;\n classify: CardFieldState;\n backoffFactor: CardFieldState;\n backoffMaxMs: CardFieldState;\n notify: CardFieldState;\n}\n\n/** The registration-side face the card's slot entry injects. */\nexport interface AutoContinueSettingsCardFace extends CardActions {\n hooks: {\n /** Card snapshot bound by the renderer as useAutoContinueSettingsCard. */\n autoContinueSettingsCard: SnapshotStore<AutoContinueSettingsCardState>;\n };\n}\n\n/** Bridges the `auto-continue` scope onto the card's staged form. */\nexport class AutoContinueSettingsCardController {\n private readonly form: CardForm<AutoContinueSettings>;\n private readonly store: SnapshotStore<AutoContinueSettingsCardState>;\n\n /**\n * @param scope - the bound settings scope for the `auto-continue` namespace.\n */\n constructor(scope: SettingsScope<AutoContinueSettings>) {\n this.form = new CardForm(scope, [\n booleanField('paused'),\n textField('continueText'),\n textField('continueTextMaxTokens'),\n booleanField('guardTools'),\n textField('guardPendingText'),\n textField('guardDoneText'),\n numberField('graceMs', 0),\n numberField('cooldownMs', 0),\n numberField('maxConsecutive', 1),\n booleanField('scanOnBoot'),\n numberField('scanLimit', 1),\n numberField('freshMs', 0),\n numberField('reconnectScanDelayMs', 0),\n numberField('reconnectBackoffMs', 0),\n booleanField('verbose'),\n booleanField('classify'),\n numberField('backoffFactor', 1),\n numberField('backoffMaxMs', 0),\n booleanField('notify'),\n ]);\n this.store = this.form.bind(() => this.projection(), createSnapshotStore);\n }\n\n private projection(): AutoContinueSettingsCardState {\n return {\n ...this.form.shell(),\n paused: this.form.field('paused'),\n continueText: this.form.field('continueText'),\n continueTextMaxTokens: this.form.field('continueTextMaxTokens'),\n guardTools: this.form.field('guardTools'),\n guardPendingText: this.form.field('guardPendingText'),\n guardDoneText: this.form.field('guardDoneText'),\n graceMs: this.form.field('graceMs'),\n cooldownMs: this.form.field('cooldownMs'),\n maxConsecutive: this.form.field('maxConsecutive'),\n scanOnBoot: this.form.field('scanOnBoot'),\n scanLimit: this.form.field('scanLimit'),\n freshMs: this.form.field('freshMs'),\n reconnectScanDelayMs: this.form.field('reconnectScanDelayMs'),\n reconnectBackoffMs: this.form.field('reconnectBackoffMs'),\n verbose: this.form.field('verbose'),\n classify: this.form.field('classify'),\n backoffFactor: this.form.field('backoffFactor'),\n backoffMaxMs: this.form.field('backoffMaxMs'),\n notify: this.form.field('notify'),\n };\n }\n\n /**\n * Build the face the card's slot registration injects.\n * @returns the card's snapshot and its form actions.\n */\n inject(): AutoContinueSettingsCardFace {\n return { hooks: { autoContinueSettingsCard: this.store }, ...this.form.actions() };\n }\n}\n\n/** Props the renderer binds for the auto-continue plugin-configuration card. */\nexport type AutoContinueSettingsCardProps =\n PropsRuntime<'settings.plugin.item'> & PropsLocale<'auto-continue'> & InjectFace<AutoContinueSettingsCardFace>;\n\n/** Card chrome: a disclosure header naming the plugin and what its settings govern, the controls, and the save that writes them. */\nfunction SettingsCard(props: {\n t: (key: SettingsCardKey) => string;\n titleKey: SettingsCardKey;\n descriptionKey: SettingsCardKey;\n state: CardShell;\n onSave: () => void;\n onDiscard: () => void;\n children: ReactNode;\n}) {\n const [open, setOpen] = useState(false);\n const { state } = props;\n if (!state.available) return null;\n const title = props.t(props.titleKey);\n const blocked = !state.dirty || state.invalid || state.saving;\n return (\n <li className={open ? 'dshAcCard dshAcCardOpen' : 'dshAcCard'}>\n <button\n type=\"button\"\n className=\"dshAcHeader\"\n aria-expanded={open}\n aria-label={`${props.t(open ? 'chrome.collapse' : 'chrome.expand')}: ${title}`}\n title={props.t(props.descriptionKey)}\n onClick={() => setOpen(!open)}\n >\n <span className=\"dshAcHeadText\">\n <span className=\"dshAcName\">{title}</span>\n <span className=\"dshAcDescription\">{props.t(props.descriptionKey)}</span>\n </span>\n {state.dirty ? (\n <span className=\"dshAcPending\" title={props.t('chrome.unsaved')}>\n {props.t('chrome.unsaved')}\n </span>\n ) : null}\n <span className={open ? 'dshAcChevron dshAcChevronOpen' : 'dshAcChevron'}>▾</span>\n </button>\n {open ? (\n <div className=\"dshAcBody\">\n {!state.writable ? (\n <p className=\"dshAcReadOnly\" role=\"status\">{props.t('chrome.readOnly')}</p>\n ) : null}\n {props.children}\n <div className=\"dshAcFooter\">\n {state.failed ? (\n <p className=\"dshAcFailed\" role=\"status\">{props.t('chrome.saveFailed')}</p>\n ) : null}\n <button\n type=\"button\"\n className=\"dshAcDiscard\"\n disabled={!state.dirty || state.saving}\n onClick={props.onDiscard}\n >\n {props.t('chrome.discard')}\n </button>\n <button type=\"button\" className=\"dshAcSave\" disabled={blocked} onClick={props.onSave}>\n {props.t(!state.saving ? 'chrome.save' : 'chrome.saving')}\n </button>\n </div>\n </div>\n ) : null}\n </li>\n );\n}\n\n/** Props every field control needs regardless of its value type. */\ninterface FieldProps {\n id: string;\n label: string;\n hint: string;\n text: string;\n overridden: boolean;\n invalid: boolean;\n disabled: boolean;\n t: (key: SettingsCardKey) => string;\n onEdit: (text: string) => void;\n onReset: () => void;\n}\n\n/** A staged value field; `numeric` only hints the keypad, which drafts a field accepts is decided by its spec. */\nfunction ValueField(props: FieldProps & { numeric?: boolean; placeholder?: string }) {\n return (\n <div className=\"dshAcField\">\n <div className=\"dshAcHead\">\n <label className=\"dshAcLabel\" htmlFor={props.id}>{props.label}</label>\n {props.overridden ? (\n <span className=\"dshAcBadges\">\n <span className=\"dshAcBadge\">{props.t('chrome.overridden')}</span>\n <button type=\"button\" className=\"dshAcReset\" disabled={props.disabled} onClick={props.onReset}>\n {props.t('chrome.reset')}\n </button>\n </span>\n ) : null}\n </div>\n <input\n id={props.id}\n className={props.invalid ? 'dshAcInput dshAcInputInvalid' : 'dshAcInput'}\n type=\"text\"\n inputMode={props.numeric === true ? 'numeric' : undefined}\n aria-invalid={props.invalid || undefined}\n value={props.text}\n placeholder={props.placeholder ?? ''}\n disabled={props.disabled}\n onChange={(event) => props.onEdit(event.target.value)}\n />\n <p className={props.invalid ? 'dshAcInvalid' : 'dshAcHint'}>\n {props.invalid ? props.t('chrome.invalidNumber') : props.hint}\n </p>\n </div>\n );\n}\n\n/** A staged boolean field: inherit / on / off. */\nfunction BooleanField(props: FieldProps) {\n return (\n <div className=\"dshAcField\">\n <div className=\"dshAcHead\">\n <label className=\"dshAcLabel\" htmlFor={props.id}>{props.label}</label>\n {props.overridden ? (\n <span className=\"dshAcBadges\">\n <span className=\"dshAcBadge\">{props.t('chrome.overridden')}</span>\n <button type=\"button\" className=\"dshAcReset\" disabled={props.disabled} onClick={props.onReset}>\n {props.t('chrome.reset')}\n </button>\n </span>\n ) : null}\n </div>\n <select\n id={props.id}\n className=\"dshAcSelect\"\n value={props.text}\n disabled={props.disabled}\n onChange={(event) => props.onEdit(event.target.value)}\n >\n <option value=\"\">{props.t('chrome.inherit')}</option>\n <option value=\"true\">{props.t('chrome.on')}</option>\n <option value=\"false\">{props.t('chrome.off')}</option>\n </select>\n <p className=\"dshAcHint\">{props.hint}</p>\n </div>\n );\n}\n\n/** 实时面板: 今日统计 + 已暂停会话。浏览器本地状态, 每 5 秒刷新一次。 */\nfunction LivePanels(props: { t: (key: SettingsCardKey) => string }) {\n const { t } = props;\n const [, refresh] = useState(0);\n useEffect(() => {\n const timer = setInterval(() => refresh((value) => value + 1), 5000);\n return () => clearInterval(timer);\n }, []);\n const stats = readTodayStats();\n const hasStats = stats.sent + stats.skipped + stats.recovered + stats.failed + stats.gaveUp > 0;\n const codes = Object.entries(stats.byCode)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 5);\n const paused = pausedSessions();\n return (\n <>\n <section className=\"dshAcPanel\">\n <div className=\"dshAcPanelHead\">\n <span className=\"dshAcPanelTitle\">{t('stats.title')}</span>\n {hasStats ? (\n <button\n type=\"button\"\n className=\"dshAcReset\"\n onClick={() => {\n resetTodayStats();\n refresh((value) => value + 1);\n }}\n >\n {t('stats.reset')}\n </button>\n ) : null}\n </div>\n {!hasStats ? (\n <p className=\"dshAcHint\">{t('stats.empty')}</p>\n ) : (\n <>\n <dl className=\"dshAcStats\">\n <div><dt>{t('stats.sent')}</dt><dd>{stats.sent}</dd></div>\n <div><dt>{t('stats.recovered')}</dt><dd>{stats.recovered}</dd></div>\n <div><dt>{t('stats.failed')}</dt><dd>{stats.failed}</dd></div>\n <div><dt>{t('stats.skipped')}</dt><dd>{stats.skipped}</dd></div>\n <div><dt>{t('stats.gaveUp')}</dt><dd>{stats.gaveUp}</dd></div>\n </dl>\n {codes.length > 0 ? (\n <div className=\"dshAcCodes\">\n <span className=\"dshAcHint\">{t('stats.byCode')}:</span>\n {codes.map(([code, count]) => (\n <span key={code} className=\"dshAcCode\">\n {code} ×{count}\n </span>\n ))}\n </div>\n ) : null}\n </>\n )}\n </section>\n <section className=\"dshAcPanel\">\n <div className=\"dshAcPanelHead\">\n <span className=\"dshAcPanelTitle\">{t('pause.title')}</span>\n {paused.length > 0 ? (\n <button\n type=\"button\"\n className=\"dshAcReset\"\n onClick={() => {\n for (const item of paused) unpauseSession(item.sessionId);\n refresh((value) => value + 1);\n }}\n >\n {t('pause.clearAll')}\n </button>\n ) : null}\n </div>\n {paused.length === 0 ? (\n <p className=\"dshAcHint\">{t('pause.none')}</p>\n ) : (\n <ul className=\"dshAcPauseList\">\n {paused.map((item) => (\n <li key={item.sessionId}>\n <span className=\"dshAcPauseId\">{item.sessionId.slice(0, 8)}…</span>\n <span className=\"dshAcHint\">\n {Math.max(1, Math.ceil((item.until - Date.now()) / 60000))} {t('pause.minutes')}\n </span>\n <button\n type=\"button\"\n className=\"dshAcReset\"\n onClick={() => {\n unpauseSession(item.sessionId);\n refresh((value) => value + 1);\n }}\n >\n {t('pause.unpause')}\n </button>\n </li>\n ))}\n </ul>\n )}\n </section>\n </>\n );\n}\n\n/**\n * Render the auto-continue card.\n * @param props - locale copy, the card snapshot, and its form actions.\n * @returns the card.\n */\nexport function AutoContinueSettingsCard(props: AutoContinueSettingsCardProps) {\n const { t } = props;\n const state = props.useAutoContinueSettingsCard((snapshot) => snapshot);\n const disabled = !state.writable;\n const shared = { t, disabled };\n return (\n <SettingsCard\n t={t}\n titleKey=\"card.title\"\n descriptionKey=\"card.description\"\n state={state}\n onSave={props.save}\n onDiscard={props.discard}\n >\n <BooleanField\n id=\"auto-continue-paused\"\n label={t('field.paused')}\n hint={t('field.pausedHint')}\n {...shared}\n {...state.paused}\n onEdit={(text) => props.edit('paused', text)}\n onReset={() => props.resetField('paused')}\n />\n <ValueField\n id=\"auto-continue-continue-text\"\n label={t('field.continueText')}\n hint={t('field.continueTextHint')}\n {...shared}\n {...state.continueText}\n onEdit={(text) => props.edit('continueText', text)}\n onReset={() => props.resetField('continueText')}\n />\n <ValueField\n id=\"auto-continue-continue-text-max-tokens\"\n label={t('field.continueTextMaxTokens')}\n hint={t('field.continueTextMaxTokensHint')}\n {...shared}\n {...state.continueTextMaxTokens}\n onEdit={(text) => props.edit('continueTextMaxTokens', text)}\n onReset={() => props.resetField('continueTextMaxTokens')}\n />\n <BooleanField\n id=\"auto-continue-guard-tools\"\n label={t('field.guardTools')}\n hint={t('field.guardToolsHint')}\n {...shared}\n {...state.guardTools}\n onEdit={(text) => props.edit('guardTools', text)}\n onReset={() => props.resetField('guardTools')}\n />\n <ValueField\n id=\"auto-continue-guard-pending-text\"\n label={t('field.guardPendingText')}\n hint={t('field.guardPendingTextHint')}\n {...shared}\n {...state.guardPendingText}\n onEdit={(text) => props.edit('guardPendingText', text)}\n onReset={() => props.resetField('guardPendingText')}\n />\n <ValueField\n id=\"auto-continue-guard-done-text\"\n label={t('field.guardDoneText')}\n hint={t('field.guardDoneTextHint')}\n {...shared}\n {...state.guardDoneText}\n onEdit={(text) => props.edit('guardDoneText', text)}\n onReset={() => props.resetField('guardDoneText')}\n />\n <ValueField\n id=\"auto-continue-grace-ms\"\n label={t('field.graceMs')}\n hint={t('field.graceMsHint')}\n numeric\n {...shared}\n {...state.graceMs}\n onEdit={(text) => props.edit('graceMs', text)}\n onReset={() => props.resetField('graceMs')}\n />\n <ValueField\n id=\"auto-continue-cooldown-ms\"\n label={t('field.cooldownMs')}\n hint={t('field.cooldownMsHint')}\n numeric\n {...shared}\n {...state.cooldownMs}\n onEdit={(text) => props.edit('cooldownMs', text)}\n onReset={() => props.resetField('cooldownMs')}\n />\n <ValueField\n id=\"auto-continue-max-consecutive\"\n label={t('field.maxConsecutive')}\n hint={t('field.maxConsecutiveHint')}\n numeric\n {...shared}\n {...state.maxConsecutive}\n onEdit={(text) => props.edit('maxConsecutive', text)}\n onReset={() => props.resetField('maxConsecutive')}\n />\n <BooleanField\n id=\"auto-continue-scan-on-boot\"\n label={t('field.scanOnBoot')}\n hint={t('field.scanOnBootHint')}\n {...shared}\n {...state.scanOnBoot}\n onEdit={(text) => props.edit('scanOnBoot', text)}\n onReset={() => props.resetField('scanOnBoot')}\n />\n <ValueField\n id=\"auto-continue-scan-limit\"\n label={t('field.scanLimit')}\n hint={t('field.scanLimitHint')}\n numeric\n {...shared}\n {...state.scanLimit}\n onEdit={(text) => props.edit('scanLimit', text)}\n onReset={() => props.resetField('scanLimit')}\n />\n <ValueField\n id=\"auto-continue-fresh-ms\"\n label={t('field.freshMs')}\n hint={t('field.freshMsHint')}\n numeric\n {...shared}\n {...state.freshMs}\n onEdit={(text) => props.edit('freshMs', text)}\n onReset={() => props.resetField('freshMs')}\n />\n <ValueField\n id=\"auto-continue-reconnect-scan-delay\"\n label={t('field.reconnectScanDelayMs')}\n hint={t('field.reconnectScanDelayMsHint')}\n numeric\n {...shared}\n {...state.reconnectScanDelayMs}\n onEdit={(text) => props.edit('reconnectScanDelayMs', text)}\n onReset={() => props.resetField('reconnectScanDelayMs')}\n />\n <ValueField\n id=\"auto-continue-reconnect-backoff\"\n label={t('field.reconnectBackoffMs')}\n hint={t('field.reconnectBackoffMsHint')}\n numeric\n {...shared}\n {...state.reconnectBackoffMs}\n onEdit={(text) => props.edit('reconnectBackoffMs', text)}\n onReset={() => props.resetField('reconnectBackoffMs')}\n />\n <BooleanField\n id=\"auto-continue-verbose\"\n label={t('field.verbose')}\n hint={t('field.verboseHint')}\n {...shared}\n {...state.verbose}\n onEdit={(text) => props.edit('verbose', text)}\n onReset={() => props.resetField('verbose')}\n />\n <BooleanField\n id=\"auto-continue-classify\"\n label={t('field.classify')}\n hint={t('field.classifyHint')}\n {...shared}\n {...state.classify}\n onEdit={(text) => props.edit('classify', text)}\n onReset={() => props.resetField('classify')}\n />\n <ValueField\n id=\"auto-continue-backoff-factor\"\n label={t('field.backoffFactor')}\n hint={t('field.backoffFactorHint')}\n numeric\n {...shared}\n {...state.backoffFactor}\n onEdit={(text) => props.edit('backoffFactor', text)}\n onReset={() => props.resetField('backoffFactor')}\n />\n <ValueField\n id=\"auto-continue-backoff-max\"\n label={t('field.backoffMaxMs')}\n hint={t('field.backoffMaxMsHint')}\n numeric\n {...shared}\n {...state.backoffMaxMs}\n onEdit={(text) => props.edit('backoffMaxMs', text)}\n onReset={() => props.resetField('backoffMaxMs')}\n />\n <BooleanField\n id=\"auto-continue-notify\"\n label={t('field.notify')}\n hint={t('field.notifyHint')}\n {...shared}\n {...state.notify}\n onEdit={(text) => props.edit('notify', text)}\n onReset={() => props.resetField('notify')}\n />\n <LivePanels t={t} />\n </SettingsCard>\n );\n}\n", "/**\n * Staged form model behind the plugin settings card — a self-contained\n * implementation of the plugin-card store pattern used by the DSH plugin\n * configuration section.\n *\n * A card stages what the user types and writes it only when they save. Each\n * settings write is a durable, revision-fenced document mutation, so staging\n * keeps what is on screen exactly what a save would store. A field shows its\n * effective value — the user layer over the composition layer over the schema\n * default — and whether the user layer carries it (presence, not value\n * equality, marks an override).\n */\nimport type { SettingsScope, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client';\n\n/** The write one field's staged text performs when the card is saved. */\nexport type FieldWrite = { kind: 'set'; value: unknown } | { kind: 'clear' };\n\n/** How one field converts between its stored value and its draft text. */\nexport interface CardFieldSpec {\n /** Field name inside the namespace section. */\n field: string;\n /** Render a stored value as draft text; the empty string when the section carries none. */\n format: (value: unknown) => string;\n /**\n * The write this draft text stages, or undefined when the text is not a\n * value this field accepts — which blocks the save rather than discarding it.\n */\n parse: (text: string) => FieldWrite | undefined;\n}\n\n/** One field as the card's control renders it. */\nexport interface CardFieldState {\n /** Draft text the control renders. */\n text: string;\n /** Whether saving would leave a user-layer entry for this field. */\n overridden: boolean;\n /** Whether the draft is not a value this field accepts, which blocks saving. */\n invalid: boolean;\n}\n\n/** Form state every plugin card shares. */\nexport interface CardShell {\n /** False while the namespace is not served to this client; the card renders nothing. */\n available: boolean;\n /** Whether the Host document accepts writes. */\n writable: boolean;\n /** Whether the form holds edits that a save would write. */\n dirty: boolean;\n /** Whether any staged draft is invalid, which blocks the save. */\n invalid: boolean;\n /** Whether a save is crossing the wire. */\n saving: boolean;\n /** Whether the last save did not land as staged; cleared by the next edit or save. */\n failed: boolean;\n}\n\n/** The write actions the card's slot entry injects. */\nexport interface CardActions {\n /** Stage draft text for one field. */\n edit: (field: string, text: string) => void;\n /** Stage a clear, so saving lets the field re-inherit the composition layer. */\n resetField: (field: string) => void;\n /** Write every staged edit, then re-seed from what the Host accepted. */\n save: () => void;\n /** Drop every staged edit. */\n discard: () => void;\n}\n\n/** A whole-number field. An empty draft clears the field; a non-number or out-of-range draft blocks the save. */\nexport function numberField(field: string, min = 0): CardFieldSpec {\n return {\n field,\n format: (value) => (typeof value === 'number' ? String(value) : ''),\n parse: (text) => {\n const trimmed = text.trim();\n if (trimmed === '') return { kind: 'clear' };\n const parsed = Number(trimmed);\n if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed < min) return undefined;\n return { kind: 'set', value: parsed };\n },\n };\n}\n\n/** A free-text field. An empty draft clears the field, so emptying the control and saving is the same gesture as resetting it. */\nexport function textField(field: string): CardFieldSpec {\n return {\n field,\n format: (value) => (typeof value === 'string' ? value : ''),\n parse: (text) => {\n const trimmed = text.trim();\n return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: trimmed };\n },\n };\n}\n\n/** A boolean field, edited through true/false draft text; an empty draft inherits. */\nexport function booleanField(field: string): CardFieldSpec {\n return {\n field,\n format: (value) => (typeof value === 'boolean' ? String(value) : ''),\n parse: (text) => {\n const trimmed = text.trim();\n if (trimmed === '') return { kind: 'clear' };\n if (trimmed === 'true') return { kind: 'set', value: true };\n if (trimmed === 'false') return { kind: 'set', value: false };\n return undefined;\n },\n };\n}\n\n/** One field's staged edit. */\ninterface StagedEdit {\n /** Draft text the control renders. */\n text: string;\n /** True when this edit clears the field whatever text it shows. */\n clear: boolean;\n}\n\n/**\n * Stages one card's edits over one settings namespace and writes them on save.\n *\n * The Host is the only authority on whether a value was accepted, so the\n * outcome is read back from the section rather than predicted here. A save\n * that did not land keeps its drafts, so the user can correct them instead of\n * retyping.\n */\nexport class CardForm<T> {\n private readonly specs: Map<string, CardFieldSpec>;\n private readonly staged = new Map<string, StagedEdit>();\n private readonly listeners = new Set<() => void>();\n private saving = false;\n private failed = false;\n\n /**\n * @param scope - the bound settings scope for this card's namespace.\n * @param specs - the section fields this card edits.\n */\n constructor(\n private readonly scope: SettingsScope<T>,\n specs: CardFieldSpec[],\n ) {\n this.specs = new Map(specs.map((spec) => [spec.field, spec]));\n this.scope.subscribe(() => this.publish());\n }\n\n /** Publish a projection of this form, rebuilt whenever the scope or a draft changes. */\n bind<S>(project: () => S, createStore: (init: S) => SnapshotStore<S>): SnapshotStore<S> {\n const store = createStore(project());\n this.listeners.add(() => store.set(project()));\n return store;\n }\n\n /** Read the card-level state: what the Host serves, and what a save would do. */\n shell(): CardShell {\n const snapshot = this.scope.getSnapshot();\n return {\n available: snapshot.status === 'ready',\n writable: snapshot.writable,\n dirty: this.plan().length > 0,\n invalid: this.plan().some((item) => item.run === undefined),\n saving: this.saving,\n failed: this.failed,\n };\n }\n\n /** Read one field's state from the effective section and its staged draft. */\n field(field: string): CardFieldState {\n const spec = this.specOf(field);\n const staged = this.staged.get(field);\n if (staged === undefined) {\n return {\n text: spec.format(this.sectionValue(field)),\n overridden: this.stored(field),\n invalid: false,\n };\n }\n const write = staged.clear ? { kind: 'clear' as const } : spec.parse(staged.text);\n return {\n text: staged.text,\n overridden: write?.kind === 'set',\n invalid: write === undefined,\n };\n }\n\n /** The actions the card's slot registration injects. */\n actions(): CardActions {\n return {\n edit: (field, text) => this.stage(field, { text, clear: false }),\n resetField: (field) => {\n this.stage(field, { text: this.specOf(field).format(this.baseValue(field)), clear: true });\n },\n save: () => void this.save(),\n discard: () => {\n if (this.staged.size === 0 && !this.failed) return;\n this.staged.clear();\n this.failed = false;\n this.publish();\n },\n };\n }\n\n /**\n * Write every staged edit, then re-seed from what the Host accepted.\n * @returns settlement after every write and the read-back.\n */\n async save(): Promise<void> {\n const plan = this.plan();\n const writes = plan.flatMap((item) => (item.run === undefined ? [] : [item.run]));\n if (plan.length === 0 || this.saving || writes.length !== plan.length) return;\n // Snapshot the fields this save writes, so edits staged while it is in\n // flight survive: only the staged keys this save actually wrote are cleared.\n const fields = new Set(plan.map((item) => item.field));\n this.saving = true;\n this.failed = false;\n this.publish();\n let landed = true;\n for (const write of writes) {\n landed = (await write()) && landed;\n }\n if (landed) {\n for (const field of fields) this.staged.delete(field);\n }\n this.saving = false;\n this.failed = !landed;\n this.publish();\n }\n\n /**\n * Every staged edit a save would write. An entry whose draft is not a value\n * its field accepts carries no write: the form is still dirty, and the save\n * refuses rather than dropping the edit. A staged edit that matches the\n * effective section is not a write at all.\n */\n private plan(): { field: string; run: (() => Promise<boolean>) | undefined }[] {\n const plan: { field: string; run: (() => Promise<boolean>) | undefined }[] = [];\n for (const [field, staged] of this.staged) {\n const spec = this.specOf(field);\n if (staged.clear) {\n if (this.stored(field)) plan.push({ field, run: () => this.clear(field) });\n continue;\n }\n if (staged.text === spec.format(this.sectionValue(field))) continue;\n const write = spec.parse(staged.text);\n if (write === undefined) plan.push({ field, run: undefined });\n else if (write.kind === 'clear') plan.push({ field, run: () => this.clear(field) });\n else plan.push({ field, run: () => this.store(field, write.value) });\n }\n return plan;\n }\n\n private async clear(field: string): Promise<boolean> {\n await this.scope.unset(field);\n return !this.stored(field);\n }\n\n private async store(field: string, value: unknown): Promise<boolean> {\n await this.scope.set(field, value);\n return this.userLayer()?.[field] === value;\n }\n\n private stage(field: string, edit: StagedEdit): void {\n this.staged.set(field, edit);\n this.failed = false;\n this.publish();\n }\n\n private specOf(field: string): CardFieldSpec {\n const spec = this.specs.get(field);\n if (spec === undefined) throw new Error(`settings card has no field ${field}`);\n return spec;\n }\n\n private sectionValue(field: string): unknown {\n return (this.scope.getSnapshot().value as Record<string, unknown> | undefined)?.[field];\n }\n\n private baseValue(field: string): unknown {\n return (this.scope.getSnapshot().base as Record<string, unknown> | undefined)?.[field];\n }\n\n private userLayer(): Record<string, unknown> | undefined {\n return this.scope.getSnapshot().user as Record<string, unknown> | undefined;\n }\n\n private stored(field: string): boolean {\n const user = this.userLayer();\n return user !== undefined && Object.prototype.hasOwnProperty.call(user, field);\n }\n\n private publish(): void {\n for (const listener of this.listeners) listener();\n }\n}\n", "/**\n * Styles for the auto-continue settings card, injected at factory\n * materialization so the client module system's style bookkeeping (HMR) owns\n * them. Uses the DSH design tokens (`--dsw-alias-*`) so the card follows the\n * active theme.\n */\n\nconst css = `\n.dshAcCard {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-3);\n border-radius: 12px;\n list-style: none;\n transition: border-color .16s, background .16s;\n}\n.dshAcCard:hover { border-color: var(--dsw-alias-label-dimmed); }\n.dshAcCardOpen {\n background: var(--dsw-alias-bg-layer-2);\n border-color: var(--dsw-alias-label-dimmed);\n}\n.dshAcHeader {\n appearance: none;\n width: 100%;\n font: inherit;\n color: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n border-radius: 12px;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n display: flex;\n}\n.dshAcHeader:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: -2px; }\n.dshAcHeadText { flex-direction: column; flex: 1; gap: 4px; min-width: 0; display: flex; }\n.dshAcName { color: var(--dsw-alias-label-primary); font-size: 15px; font-weight: 600; line-height: 1.4; }\n.dshAcDescription { color: var(--dsw-alias-label-tertiary); font-size: 13px; line-height: 1.5; }\n.dshAcChevron { color: var(--dsw-alias-label-tertiary); flex: none; transition: transform .16s; }\n.dshAcChevronOpen { transform: rotate(180deg); }\n.dshAcBody { border-top: 1px solid var(--dsw-alias-border-l2); margin: 0 16px; padding-bottom: 8px; }\n.dshAcReadOnly { color: var(--dsw-alias-label-tertiary); margin: 12px 0 0; font-size: 12px; line-height: 1.5; }\n.dshAcPending {\n white-space: nowrap;\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-label-secondary);\n border-radius: 999px;\n flex: none;\n padding: 1px 8px;\n font-size: 11px;\n font-weight: 500;\n line-height: 17px;\n}\n.dshAcFooter {\n border-top: 1px solid var(--dsw-alias-border-l2);\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n padding: 12px 0 4px;\n display: flex;\n}\n.dshAcFailed { min-width: 0; color: var(--dsw-alias-label-error); flex: 1; margin: 0; font-size: 12px; line-height: 1.5; }\n.dshAcDiscard, .dshAcSave {\n appearance: none;\n font: inherit;\n cursor: pointer;\n border: 1px solid transparent;\n border-radius: 8px;\n padding: 5px 14px;\n font-size: 13px;\n line-height: 1.5;\n}\n.dshAcDiscard { border-color: var(--dsw-alias-border-l2); color: var(--dsw-alias-label-secondary); background: none; }\n.dshAcDiscard:hover:not(:disabled) { color: var(--dsw-alias-label-primary); border-color: var(--dsw-alias-label-dimmed); }\n.dshAcSave { background: var(--dsw-alias-label-primary); color: var(--dsw-alias-bg-layer-3); }\n.dshAcDiscard:disabled, .dshAcSave:disabled { opacity: .4; cursor: default; }\n.dshAcDiscard:focus-visible, .dshAcSave:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 1px; }\n.dshAcField { flex-direction: column; gap: 6px; padding: 12px 0; display: flex; }\n.dshAcField + .dshAcField { border-top: 1px solid var(--dsw-alias-border-l2); }\n.dshAcHead { align-items: center; gap: 8px; display: flex; }\n.dshAcLabel { min-width: 0; color: var(--dsw-alias-label-primary); flex: 1; font-size: 13px; font-weight: 500; line-height: 1.5; }\n.dshAcBadges { align-items: center; gap: 8px; display: inline-flex; }\n.dshAcBadge {\n white-space: nowrap;\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-label-secondary);\n border-radius: 999px;\n padding: 1px 8px;\n font-size: 11px;\n font-weight: 500;\n line-height: 17px;\n}\n.dshAcReset {\n font: inherit;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n background: none;\n border: none;\n padding: 0;\n font-size: 12px;\n line-height: 1.5;\n}\n.dshAcReset:hover:not(:disabled) { color: var(--dsw-alias-label-primary); }\n.dshAcReset:disabled { cursor: default; }\n.dshAcInput {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-3);\n height: 34px;\n font: inherit;\n color: var(--dsw-alias-label-primary);\n border-radius: 8px;\n padding: 0 12px;\n font-size: 13px;\n line-height: 1.5;\n}\n.dshAcInput:focus-visible { border-color: var(--dsw-alias-brand-primary); outline: none; }\n.dshAcInput:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n.dshAcInputInvalid { border-color: var(--dsw-alias-label-error); }\n.dshAcSelect {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-3);\n height: 34px;\n font: inherit;\n color: var(--dsw-alias-label-primary);\n border-radius: 8px;\n padding: 0 8px;\n font-size: 13px;\n line-height: 1.5;\n}\n.dshAcSelect:focus-visible { border-color: var(--dsw-alias-brand-primary); outline: none; }\n.dshAcSelect:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }\n.dshAcInvalid { color: var(--dsw-alias-label-error); margin: 0; font-size: 12px; line-height: 1.5; }\n.dshAcHint { color: var(--dsw-alias-label-tertiary); margin: 0; font-size: 12px; line-height: 1.5; }\n.dshAcPanel { border-top: 1px solid var(--dsw-alias-border-l2); flex-direction: column; gap: 8px; padding: 12px 0; display: flex; }\n.dshAcPanelHead { align-items: center; gap: 8px; display: flex; }\n.dshAcPanelTitle { color: var(--dsw-alias-label-primary); flex: 1; font-size: 13px; font-weight: 600; line-height: 1.5; }\n.dshAcStats { gap: 4px 16px; margin: 0; grid-template-columns: repeat(2, minmax(0, 1fr)); display: grid; }\n.dshAcStats > div { justify-content: space-between; gap: 8px; display: flex; }\n.dshAcStats dt { color: var(--dsw-alias-label-secondary); font-size: 12px; line-height: 1.5; }\n.dshAcStats dd { color: var(--dsw-alias-label-primary); margin: 0; font-size: 12px; font-weight: 600; line-height: 1.5; }\n.dshAcCodes { flex-wrap: wrap; align-items: center; gap: 6px; display: flex; }\n.dshAcCode {\n white-space: nowrap;\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-label-secondary);\n border-radius: 999px;\n padding: 1px 8px;\n font-size: 11px;\n font-weight: 500;\n line-height: 17px;\n}\n.dshAcPauseList { flex-direction: column; gap: 4px; margin: 0; padding: 0; list-style: none; display: flex; }\n.dshAcPauseList li { align-items: center; gap: 8px; display: flex; }\n.dshAcPauseId {\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 1.5;\n}\n`;\n\n/** Inject the stylesheet once; a no-op outside a browser environment. */\nexport function injectStyles(): void {\n if (typeof document === 'undefined') return;\n if (document.querySelector('style[data-plugin-css=\"auto-continue/card\"]') !== null) return;\n const tag = document.createElement('style');\n tag.dataset.plugin = 'dsh-client-auto-continue';\n tag.dataset.pluginCss = 'auto-continue/card';\n tag.textContent = css;\n document.head.appendChild(tag);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-client-auto-continue",
|
|
3
3
|
"description": "DSH Web UI plugin: automatically sends \"继续\" (continue) when a request is interrupted by network errors or other non-human causes",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/types/index.d.ts",
|
|
@@ -68,20 +68,20 @@
|
|
|
68
68
|
"typescript": "~5.8.0",
|
|
69
69
|
"@types/react": "~18.3.1",
|
|
70
70
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
71
|
-
"@deepseek-ai/dsh-client-connection": "^0.1.0-rc.
|
|
72
|
-
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.
|
|
73
|
-
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.
|
|
74
|
-
"@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.
|
|
75
|
-
"@deepseek-ai/dsh-client-ui-settings-plugins": "^0.1.0-rc.
|
|
76
|
-
"@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.
|
|
77
|
-
"@deepseek-ai/dsh-session": "^0.1.0-rc.
|
|
78
|
-
"@deepseek-ai/dsh-settings": "^0.1.0-rc.
|
|
71
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.0-rc.7",
|
|
72
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.7",
|
|
73
|
+
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.7",
|
|
74
|
+
"@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.7",
|
|
75
|
+
"@deepseek-ai/dsh-client-ui-settings-plugins": "^0.1.0-rc.7",
|
|
76
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.7",
|
|
77
|
+
"@deepseek-ai/dsh-session": "^0.1.0-rc.7",
|
|
78
|
+
"@deepseek-ai/dsh-settings": "^0.1.0-rc.7",
|
|
79
79
|
"@deepseek-ai/schemastery": "^3.18.1"
|
|
80
80
|
},
|
|
81
81
|
"license": "MIT",
|
|
82
82
|
"peerDependencies": {
|
|
83
83
|
"react": "^18.2.0",
|
|
84
|
-
"@deepseek-ai/dsh-settings": "^0.1.0-rc.
|
|
84
|
+
"@deepseek-ai/dsh-settings": "^0.1.0-rc.7",
|
|
85
85
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
86
86
|
"@deepseek-ai/cordis": "^4.0.1"
|
|
87
87
|
},
|
package/scripts/patch-expose.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Vendor patch for a known DSH limitation (0.1.0-rc.6):
|
|
3
|
+
* Vendor patch for a known DSH limitation (0.1.0-rc.6 and earlier):
|
|
4
4
|
*
|
|
5
5
|
* The web settings surface only exposes namespaces listed in the hardcoded
|
|
6
6
|
* `WEB_SETTINGS_NAMESPACES` / `PRODUCT_SETTINGS_NAMESPACES` allowlists inside
|
|
@@ -10,11 +10,13 @@
|
|
|
10
10
|
* proxy's own comment calls moving exposure into `settings.register()` "deferred
|
|
11
11
|
* work").
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
13
|
+
* Since DSH 0.1.0-rc.7 upstream made exposure REGISTRY-DRIVEN, so this script
|
|
14
|
+
* is a no-op there (it detects the missing function and reports accordingly).
|
|
15
|
+
* On rc.6 and earlier it patches `exposedNamespaces()` to also expose every
|
|
16
|
+
* namespace currently registered with the settings provider. The patch
|
|
17
|
+
* contains NO plugin-specific string, so the settings of ANY plugin that
|
|
18
|
+
* registers a namespace (and mounts its own settings section) appear
|
|
19
|
+
* automatically — this plugin included.
|
|
18
20
|
*
|
|
19
21
|
* It is applied to every reachable dsh installation: the profile-linked copy
|
|
20
22
|
* (pnpm store / npx cache), a global `npm i -g @deepseek-ai/dsh` install under
|
|
@@ -100,7 +102,10 @@ for (const packageJson of candidates) {
|
|
|
100
102
|
if (!source.includes(GENERIC_MARKER)) {
|
|
101
103
|
const fnStart = source.indexOf('\tfunction exposedNamespaces() {');
|
|
102
104
|
if (fnStart === -1) {
|
|
103
|
-
|
|
105
|
+
// DSH ≥ 0.1.0-rc.7 已把设置暴露改为注册表驱动, 没有这个函数也不需要补丁。
|
|
106
|
+
console.log(
|
|
107
|
+
`[patch-expose] ${bundlePath}: DSH ≥ 0.1.0-rc.7 已原生支持 registry-driven 设置暴露, 无需补丁 — skipped.`,
|
|
108
|
+
);
|
|
104
109
|
continue;
|
|
105
110
|
}
|
|
106
111
|
const fnEnd = source.indexOf('\t}', fnStart);
|
package/src/client/engine.ts
CHANGED
|
@@ -828,7 +828,10 @@ export class AutoContinueRunner {
|
|
|
828
828
|
case 'host/agent-error':
|
|
829
829
|
if (this.state(frame.sessionId).subagent) break;
|
|
830
830
|
this.log(`host/agent-error(${frame.sessionId}): ${frame.message}`);
|
|
831
|
-
|
|
831
|
+
// agent-error 的「仅网络/超时类自动续跑」是无条件安全承诺(与 classify 开关无关):
|
|
832
|
+
// 序列化失败等永久性 agent 错误(包括用户停止的连带 DOMException)绝不能自动续跑,
|
|
833
|
+
// 否则会退回「用户停止被误续跑」的场景(issue #2)。
|
|
834
|
+
if (!isTransientAgentError(frame.message)) {
|
|
832
835
|
// 永久性 agent 错误(序列化失败/配置错误等): 跳过并通知, 避免把用户停止等
|
|
833
836
|
// 场景误判为可恢复中断后自动续跑。
|
|
834
837
|
this.log(`跳过 ${frame.sessionId}: 永久性 agent 错误 — ${frame.message}`);
|
package/src/client/index.ts
CHANGED
|
@@ -72,16 +72,15 @@ export function apply(ctx: ClientContext): void {
|
|
|
72
72
|
|
|
73
73
|
// Plugin configuration card: one staged form over the `auto-continue`
|
|
74
74
|
// settings namespace, contributed to the plugin-configuration section
|
|
75
|
-
// (Settings → Plugins).
|
|
76
|
-
// slot
|
|
77
|
-
//
|
|
75
|
+
// (Settings → Plugins). Since DSH 0.1.0-rc.7 `settings.plugin.item` is a
|
|
76
|
+
// keyed slot dispatched by the settings namespace it edits, so the entry
|
|
77
|
+
// registers with `key` (the namespace), like the official cards.
|
|
78
78
|
const controller = new AutoContinueSettingsCardController(scope);
|
|
79
79
|
ctx.slots.inject('settings.plugin.item', () =>
|
|
80
80
|
ctx.slots.register(
|
|
81
81
|
{
|
|
82
82
|
name: 'settings.plugin.item',
|
|
83
|
-
|
|
84
|
-
order: 90,
|
|
83
|
+
key: SETTINGS_NS,
|
|
85
84
|
locale: NS,
|
|
86
85
|
inject: () => controller.inject(),
|
|
87
86
|
},
|
package/src/client/locales.ts
CHANGED
|
Binary file
|