dsh-client-auto-continue 0.7.5 → 0.8.0

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 CHANGED
@@ -31,7 +31,7 @@
31
31
 
32
32
  ## What It Does
33
33
 
34
- For [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (`dsh web`): whenever a request in the web GUI gets interrupted by a **non-human cause**, the plugin simulates the user typing **「继续」** and sends it, so the agent keeps working without manual intervention. The message enters the session log exactly like a manual prompt — the model sees it, and the interrupted work resumes.
34
+ For [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (`dsh web`): whenever a request in the web GUI gets interrupted by a **non-human cause**, the plugin simulates the user typing **「继续」** and sends it, so the agent keeps working without manual intervention. The message enters the session log exactly like a manual prompt — the model sees it, and the interrupted work resumes. Since 0.8.0 the engine runs **inside the host process** (single instance), so it keeps watching even with every browser tab closed, and multiple open tabs can never double-send.
35
35
 
36
36
  ![demo](docs/demo.svg)
37
37
 
@@ -62,15 +62,11 @@ It watches the live event streams and reacts to:
62
62
 
63
63
  ## How It Works
64
64
 
65
- The plugin opens two extra SSE streams in the browser`events.mux` (session events) and `events.host` (host events). The host supports multiple consumers, so this never interferes with the built-in runtime. On an interruption it waits a **grace period** (default 3 s) — if the host starts a new turn by itself (`turn/start`), the auto-continue is cancelled — then calls `sessions.prompt` in `queue` mode with the configured text.
65
+ The host-side engine subscribes to the session event firehose inside the dsh host process exactly one engine, regardless of how many tabs are open (the duplicate-send class of bugs cannot exist by construction). On an interruption it waits a **grace period** (default 3 s) — if the host starts a new turn by itself (`turn/start`), the auto-continue is cancelled — then sends the configured text through the agent registry (`agent.followup`, the same queue the Send button uses).
66
66
 
67
- On page load / reconnect it also scans the most recently updated sessions: a session whose last turn ended with a non-human reason **within the scan window** (default 15 minutes), with no later `turn/start` or user message, gets resumed automatically too (e.g. the host crashed while the browser was closed). Before every send the plugin also asks the host one authoritative question — is the latest session event already this exact message? If the same text is still queued (the last event is that `user/message`), it skips; once the message has been processed (the last event is a turn end or anything else), a fresh send is allowed, so legitimate consecutive resumes are never blocked.
67
+ On host boot it also scans the live sessions: a session whose last turn ended with a non-human reason **within the scan window** (default 15 minutes), with no later `turn/start` or user message, gets resumed automatically too (e.g. the host crashed while the browser was closed the agent-loop resumes the session and the engine picks it up).
68
68
 
69
- With the page open in several tabs, a cross-tab atomic send lock (Web Locks API with a mutex-stamp fallback), a shared per-session cooldown stamp, and a shared send counter that hard-caps consecutive sends at `maxConsecutive` guarantee exactly one tab sends no duplicated 「继续」, even when several tabs watch the same session.
70
-
71
- All knobs live in the plugin's settings card — see [Configuration](#configuration).
72
-
73
- ---
69
+ The browser half is a thin shell: the settings card, plus a status bridge that shows notifications (with Resume now / Pause this session 1h buttons, routed back to the host engine) and feeds the card's stats / paused-sessions panels.
74
70
 
75
71
  ## Quick Start
76
72
 
@@ -214,8 +210,8 @@ auto-continue:
214
210
  | Scan on load / reconnect | `on` | Scan recently interrupted sessions on load / reconnect |
215
211
  | Scan limit | `8` | Max sessions scanned (running / subagent sessions excluded) |
216
212
  | Scan window (ms) | `900000` | Scan only considers interruptions inside this window |
217
- | Reconnect scan delay (ms) | `5000` | Delay before scanning after a reconnect |
218
- | Reconnect backoff (ms) | `3000` | SSE reconnect backoff |
213
+ | Reconnect scan delay (ms) | `5000` | Legacy unused since the engine moved into the host (kept for config compatibility) |
214
+ | Reconnect backoff (ms) | `3000` | Legacy unused since the engine moved into the host (kept for config compatibility) |
219
215
  | Verbose logs | `on` | `[auto-continue]` console logs |
220
216
  | Classify errors | `on` | Auto-resume transient failures only; auth / balance / model errors are skipped and notified |
221
217
  | Backoff factor | `2` | Cooldown multiplier per consecutive failure (2 = 20s → 40s → 80s…) |
@@ -232,7 +228,7 @@ The plugin is browser-only and touches **no files, credentials, or network beyon
232
228
 
233
229
  - It opens the same two read-only event streams the web UI already uses (no extra server, no third-party endpoints)
234
230
  - 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)
235
- - Browser storage is limited to small `localStorage` keys: cross-tab send locks and counts (a hard cap that stops duplicate sends even with several tabs open), per-session pauses, and the daily stats counters
231
+ - No browser storage at all: the single host-side engine keeps its cooldowns, send caps, pauses and stats in process memory
236
232
  - Browser notifications are opt-in (`notify` setting) and permission is requested on first use only
237
233
 
238
234
  ---
@@ -243,7 +239,7 @@ The plugin is browser-only and touches **no files, credentials, or network beyon
243
239
  npm run typecheck # tsc --noEmit
244
240
  npm run build # lib/client.js + lib/index.js + lib/types
245
241
  npm run watch # rebuild on change; host HMR hot-reloads without a page refresh
246
- npm run test # node tests/simulate.mjs — 43 behavioral scenarios
242
+ npm run test # node tests/simulate-host.mjs — 15 host-side behavioral scenarios
247
243
  ```
248
244
 
249
245
  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.
package/README.zh.md CHANGED
@@ -31,7 +31,7 @@
31
31
 
32
32
  ## 它做什么
33
33
 
34
- 适用于 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(`dsh web`): 当 webui 里的请求因为**非人为因素**中断时, 插件模拟用户输入 **「继续」** 并自动发送, 让 Agent 继续干活, 无需手动干预。消息与手动输入完全等价——进入会话日志、对模型可见, 中断的任务随即恢复。
34
+ 适用于 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(`dsh web`): 当 webui 里的请求因为**非人为因素**中断时, 插件模拟用户输入 **「继续」** 并自动发送, 让 Agent 继续干活, 无需手动干预。消息与手动输入完全等价——进入会话日志、对模型可见, 中断的任务随即恢复。自 0.8.0 起引擎跑在**宿主进程内**(单实例): 浏览器标签全关掉也在值守, 多标签页同时打开也不可能重复发送。
35
35
 
36
36
  ![demo](docs/demo-zh.svg)
37
37
 
@@ -62,15 +62,11 @@
62
62
 
63
63
  ## 工作原理
64
64
 
65
- 插件在浏览器里额外打开两条 SSE 流——`events.mux`(会话事件)与 `events.host`(宿主事件)。宿主支持多消费者, 与内置运行时互不干扰。检测到中断后先等待一个**宽限期**(默认 3 秒)——若宿主自行开启了新回合(`turn/start`), 自动继续即取消——然后以 `queue` 模式调用 `sessions.prompt` 发送配置的文本。
65
+ 宿主侧引擎在 dsh 宿主进程内订阅会话事件 firehose——**全局只有一个引擎**, 无论开多少个标签页(重复发送这类 bug 从构造上不可能存在)。检测到中断后先等待一个**宽限期**(默认 3 秒)——若宿主自行开启了新回合(`turn/start`), 自动继续即取消——然后经 agent 注册表(`agent.followup`, 与「发送」按钮同一个排队通道)发送配置的文本。
66
66
 
67
- 页面启动 / 重连时, 插件还会扫描最近更新的会话: 若某个会话的最后一个回合在**扫描时间窗**(默认 15 分钟)内以非人为原因结束, 且之后没有新的 `turn/start` 或用户消息, 也会被自动续跑(例如浏览器关闭期间宿主崩溃的情况)。每次发送前插件还会问宿主一个权威问题——会话的**最后一条事件**是否正是这条消息: 若相同文本还在排队(最后一条就是那条 `user/message`)则跳过; 一旦该消息已被处理(最后一条是回合结束或其他事件)就允许再发, 因此合法的连续续跑不会被误挡。
67
+ 宿主启动时还会扫描存活会话: 最后一个回合在**扫描时间窗**(默认 15 分钟)内以非人为原因结束、且其后没有新回合或用户消息的会话, 会被自动续跑(例如浏览器关闭期间宿主崩溃——agent-loop 恢复会话后引擎接着接手)
68
68
 
69
- 多个标签页同时打开时, 通过跨标签页原子发送锁(Web Locks API, 旧环境回退互斥戳)+ 共享的每会话冷却记录 + `maxConsecutive` 为硬上限的共享发送计数, 保证**只有一个标签页发送**——即使多个标签页盯着同一会话, 也不会重复出现两条「继续」。
70
-
71
- 所有参数都在插件的设置卡片中调整——见 [配置](#配置)。
72
-
73
- ---
69
+ 浏览器半侧是瘦壳: 设置卡片 + 一条状态桥(展示通知, 带「立即续跑 / 暂停该会话 1 小时」按钮并把动作回传给宿主引擎; 驱动卡片里的统计与暂停面板)。
74
70
 
75
71
  ## 快速开始
76
72
 
@@ -214,8 +210,8 @@ auto-continue:
214
210
  | 启动/重连扫描 | 开 | 页面启动 / 重连时扫描最近中断的会话 |
215
211
  | 扫描会话数 | `8` | 扫描最多检查的会话数(不含运行中 / 子代理会话) |
216
212
  | 扫描时间窗 (ms) | `900000` | 扫描只处理该时间窗内的中断 |
217
- | 重连扫描延迟 (ms) | `5000` | 重连后等待宿主恢复再扫描 |
218
- | 重连退避 (ms) | `3000` | SSE 流断开后的重连间隔 |
213
+ | 重连扫描延迟 (ms) | `5000` | 遗留字段 — 引擎迁入宿主后不再使用(仅为配置兼容保留) |
214
+ | 重连退避 (ms) | `3000` | 遗留字段 引擎迁入宿主后不再使用(仅为配置兼容保留) |
219
215
  | 详细日志 | 开 | 控制台输出 `[auto-continue]` 日志 |
220
216
  | 错误分类 | 开 | 仅自动恢复临时性错误; 认证 / 余额 / 模型等永久性错误跳过并通知 |
221
217
  | 退避系数 | `2` | 连续失败时冷却间隔的倍率(2 = 20s → 40s → 80s…) |
@@ -232,7 +228,7 @@ auto-continue:
232
228
 
233
229
  - 只复用 webui 本身就在用的两条只读事件流(无额外服务、无第三方端点)
234
230
  - 引擎**唯一会自动执行的写入**是 `sessions.prompt`——与点「发送」按钮完全相同的调用, 内容为你配置的文本(设置卡片里保存配置会通过常规设置 API 写入 `~/.dsh/settings.yaml` 的 `auto-continue` 段落, 与任何其他设置一样)
235
- - 浏览器存储仅限于少量 `localStorage` 键: 跨标签页发送锁与发送计数(多标签页同时打开时也绝不重复刷屏的硬上限)、会话级暂停、每日统计计数
231
+ - 不使用任何浏览器存储: 宿主侧单实例引擎的冷却、发送上限、暂停与统计全部保存在进程内存里
236
232
  - 浏览器通知是可选开启的(`notify` 设置), 仅在首次使用时请求一次权限
237
233
 
238
234
  ---
@@ -243,7 +239,7 @@ auto-continue:
243
239
  npm run typecheck # tsc --noEmit
244
240
  npm run build # lib/client.js + lib/index.js + lib/types
245
241
  npm run watch # 监听变更自动重建; 宿主 HMR 免刷新热重载
246
- npm run test # node tests/simulate.mjs — 43 个行为场景
242
+ npm run test # node tests/simulate-host.mjs — 15 个 host 侧行为场景
247
243
  ```
248
244
 
249
245
  `npm run watch` 运行时, profile 的 client-hmr 行每 500ms 轮询 `lib/client.js` 并在浏览器中热重载插件——改代码无需重启服务。