@zhushanwen/subagent-core 0.2.0 → 0.4.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 +45 -2
- package/agents/analyst.md +60 -0
- package/agents/coder.md +69 -0
- package/agents/debugger.md +66 -0
- package/agents/doc-reviewer.md +49 -0
- package/agents/explorer.md +63 -0
- package/agents/general-purpose.md +32 -0
- package/agents/orchestrator.md +61 -0
- package/agents/planner.md +53 -0
- package/agents/researcher.md +67 -0
- package/agents/reviewer.md +73 -0
- package/dist/chunk-4KN4TTG7.js +240 -0
- package/dist/chunk-APZY4IME.js +27 -0
- package/dist/chunk-X7SZ5HLQ.js +66 -0
- package/dist/execution/engine/engines/zcode/constants.cjs +65 -0
- package/dist/execution/engine/engines/zcode/constants.d.cts +93 -1
- package/dist/execution/engine/engines/zcode/constants.d.ts +93 -1
- package/dist/execution/engine/engines/zcode/constants.js +43 -1
- package/dist/execution/engine/engines/zcode/reader.d.cts +1 -1
- package/dist/execution/engine/engines/zcode/reader.d.ts +1 -1
- package/dist/execution/engine/engines/zcode/reader.js +4 -234
- package/dist/execution/engine/paths.js +7 -19
- package/dist/index.cjs +14709 -100
- package/dist/index.d.cts +4053 -200
- package/dist/index.d.ts +4053 -200
- package/dist/index.js +14358 -102
- package/dist/{types-BxyAidGf.d.cts → types-DpUO16pj.d.cts} +464 -1
- package/dist/{types-BxyAidGf.d.ts → types-DpUO16pj.d.ts} +464 -1
- package/package.json +6 -3
- package/src/__tests__/review-fix-loop-script.test.ts +90 -2
- package/src/__tests__/review-fix-loop-utils.test.ts +21 -0
- package/src/__tests__/smoke.test.ts +9 -2
- package/src/execution/__tests__/agent-profile.test.ts +232 -0
- package/src/execution/__tests__/agents-assembly.test.ts +219 -0
- package/src/execution/__tests__/chat-engine-routing.test.ts +71 -0
- package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +1 -0
- package/src/execution/__tests__/create-concurrency-pool.test.ts +194 -0
- package/src/execution/__tests__/delivery-methods.test.ts +2 -0
- package/src/execution/__tests__/descendant-sweep.test.ts +269 -0
- package/src/execution/__tests__/dialog-queue.test.ts +199 -1
- package/src/execution/__tests__/epipe-fallback.test.ts +2 -0
- package/src/execution/__tests__/execution-runtime-face.test.ts +272 -0
- package/src/execution/__tests__/finalize-record.test.ts +106 -0
- package/src/execution/__tests__/gc-timer.test.ts +2 -0
- package/src/execution/__tests__/get-record-for-action-restart.test.ts +2 -0
- package/src/execution/__tests__/get-state-handshake.test.ts +127 -0
- package/src/execution/__tests__/keep-alive-no-progress.test.ts +378 -0
- package/src/execution/__tests__/kill-all-escalation.test.ts +196 -0
- package/src/execution/__tests__/lifecycle-manager-idle-timer-identity.test.ts +117 -0
- package/src/execution/__tests__/lifecycle-manager.test.ts +39 -0
- package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +99 -0
- package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +113 -0
- package/src/execution/__tests__/notify-ledger.test.ts +294 -0
- package/src/execution/__tests__/record-store-orphan-revive.test.ts +159 -0
- package/src/execution/__tests__/record-store.test.ts +83 -0
- package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +4 -0
- package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +1 -0
- package/src/execution/__tests__/run-spawn-edges.test.ts +407 -17
- package/src/execution/__tests__/run-spawn-integration.test.ts +1 -1
- package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +12 -4
- package/src/execution/__tests__/service-kill-escalation.test.ts +89 -0
- package/src/execution/__tests__/session-pending.test.ts +228 -0
- package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +110 -0
- package/src/execution/__tests__/session-runner-close-prune.test.ts +181 -0
- package/src/execution/__tests__/session-runner-epipe.test.ts +1 -0
- package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +226 -0
- package/src/execution/__tests__/settled-watchdog.test.ts +289 -0
- package/src/execution/__tests__/spawned-children.test.ts +153 -10
- package/src/execution/__tests__/subagent-actions-core.test.ts +997 -0
- package/src/execution/__tests__/subagent-service-message-close.test.ts +71 -10
- package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +174 -0
- package/src/execution/__tests__/subagent-service-notify-gate.test.ts +266 -0
- package/src/execution/__tests__/subagent-service-parent-guard.test.ts +3 -0
- package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +316 -0
- package/src/execution/__tests__/timeout-integration.test.ts +7 -7
- package/src/execution/__tests__/ui-request-handler-factory.test.ts +95 -1
- package/src/execution/__tests__/ui-request-queue.test.ts +25 -0
- package/src/execution/__tests__/worktree-git-ops.test.ts +571 -0
- package/src/execution/__tests__/worktree-reconcile-aging.test.ts +204 -0
- package/src/execution/agent-registry.ts +225 -1
- package/src/execution/agents-assembly.ts +88 -0
- package/src/execution/concurrency-pool.ts +71 -9
- package/src/execution/dialog-queue.ts +101 -3
- package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +49 -2
- package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +87 -1
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +26 -0
- package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +83 -1
- package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +131 -0
- package/src/execution/engine/__tests__/registry.test.ts +90 -1
- package/src/execution/engine/engine-discovery.ts +12 -16
- package/src/execution/engine/engines/pi/task-spec-mapper.ts +3 -3
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +274 -0
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +36 -0
- package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +472 -0
- package/src/execution/engine/engines/zcode/__tests__/preparer-appserver.test.ts +387 -0
- package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +780 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +815 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +462 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +119 -1
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +136 -6
- package/src/execution/engine/engines/zcode/appserver-home.ts +442 -0
- package/src/execution/engine/engines/zcode/appserver-probe.ts +141 -0
- package/src/execution/engine/engines/zcode/connection.ts +585 -0
- package/src/execution/engine/engines/zcode/constants.ts +129 -0
- package/src/execution/engine/engines/zcode/golden-sample.ts +54 -8
- package/src/execution/engine/engines/zcode/preparer.ts +25 -22
- package/src/execution/engine/engines/zcode/session-channel.ts +656 -0
- package/src/execution/engine/engines/zcode/zcode-engine.ts +909 -41
- package/src/execution/engine/host-task-spec.ts +3 -3
- package/src/execution/engine/port.ts +41 -1
- package/src/execution/engine/registry.ts +53 -0
- package/src/execution/finalize-record.ts +63 -5
- package/src/execution/get-state-handshake.ts +85 -10
- package/src/execution/lifecycle-manager.ts +27 -3
- package/src/execution/manifest-store.ts +53 -62
- package/src/execution/notifier.ts +10 -10
- package/src/execution/notify-ledger.ts +117 -16
- package/src/execution/record-entry.ts +8 -2
- package/src/execution/record-store.ts +29 -15
- package/src/execution/session-pending.ts +213 -62
- package/src/execution/session-runner.ts +974 -128
- package/src/execution/sessions-index.ts +10 -55
- package/src/execution/settled-watchdog.ts +99 -0
- package/src/execution/subagent-actions-core.ts +686 -0
- package/src/execution/subagent-service.ts +396 -49
- package/src/execution/ui-request-handler-factory.ts +27 -4
- package/src/execution/worktree-git-ops.ts +397 -0
- package/src/execution/worktree-manager.ts +72 -10
- package/src/execution/worktree-registry.ts +6 -12
- package/src/index.ts +413 -6
- package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +42 -3
- package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +2 -4
- package/src/orchestration/__tests__/args-meta.test.ts +358 -0
- package/src/orchestration/__tests__/error-recovery-handlers.test.ts +1 -8
- package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +312 -0
- package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +382 -0
- package/src/orchestration/__tests__/file-run-store-prune.test.ts +168 -0
- package/src/orchestration/__tests__/file-run-store-throttle.test.ts +168 -0
- package/src/orchestration/__tests__/file-run-store.test.ts +389 -0
- package/src/orchestration/__tests__/helpers/flush-microtasks.ts +13 -0
- package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +34 -0
- package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +357 -0
- package/src/orchestration/__tests__/lifecycle-recover-crashed.test.ts +289 -0
- package/src/orchestration/__tests__/lifecycle.test.ts +77 -0
- package/src/orchestration/__tests__/run-snapshot.test.ts +353 -0
- package/src/orchestration/__tests__/script-generate.test.ts +314 -0
- package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +275 -0
- package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +78 -1
- package/src/orchestration/__tests__/workflow-files.test.ts +186 -0
- package/src/orchestration/__tests__/workflow-run-summary.test.ts +119 -0
- package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +124 -0
- package/src/orchestration/agent-opts-resolver.ts +7 -7
- package/src/orchestration/args-meta.ts +198 -0
- package/src/orchestration/error-recovery.ts +416 -146
- package/src/orchestration/execute-agent-call.ts +9 -9
- package/src/orchestration/file-run-store.ts +327 -0
- package/src/orchestration/launcher.ts +35 -26
- package/src/orchestration/lifecycle.ts +355 -79
- package/src/orchestration/models/agent-call.ts +7 -7
- package/src/orchestration/models/budget.ts +5 -5
- package/src/orchestration/models/run-runtime.ts +13 -13
- package/src/orchestration/models/trace.ts +8 -8
- package/src/orchestration/models/workflow-run.ts +27 -27
- package/src/orchestration/models/workflow-script.ts +4 -4
- package/src/orchestration/run-snapshot.ts +266 -0
- package/src/orchestration/script-generate.ts +154 -0
- package/src/orchestration/script-lint.ts +33 -33
- package/src/orchestration/worker-handle.ts +10 -10
- package/src/orchestration/worker-host.ts +10 -10
- package/src/orchestration/worker-script-builder.ts +401 -346
- package/src/orchestration/workflow-files.ts +37 -11
- package/src/orchestration/workflow-run-summary.ts +69 -0
- package/src/orchestration/workflow-script-registry-impl.ts +31 -9
- package/src/shared/__tests__/agent-ref.test.ts +209 -2
- package/src/shared/__tests__/atomic-write.test.ts +267 -0
- package/src/shared/__tests__/bounded-serialize.test.ts +236 -0
- package/src/shared/__tests__/injection-render.test.ts +518 -0
- package/src/shared/__tests__/resource-discovery-host-roots.test.ts +474 -0
- package/src/shared/__tests__/resource-discovery.test.ts +3 -2
- package/src/shared/agent-ref.ts +143 -2
- package/src/shared/atomic-write.ts +320 -0
- package/src/shared/bounded-serialize.ts +154 -0
- package/src/shared/injection-render.ts +279 -0
- package/src/shared/meta-parser.ts +41 -1
- package/src/shared/resource-discovery.ts +104 -37
- package/src/shared/resource-meta.ts +14 -0
- package/src/shared/xml-injection.ts +9 -9
- package/workflows/README.md +9 -9
- package/workflows/chain.js +4 -2
- package/workflows/map-reduce.js +5 -3
- package/workflows/parallel.js +5 -3
- package/workflows/review-fix-loop-utils.cjs +14 -3
- package/workflows/review-fix-loop.js +18 -7
- package/workflows/scatter-gather.js +4 -2
- package/dist/chunk-3VOERJPJ.js +0 -22
|
@@ -21,12 +21,11 @@
|
|
|
21
21
|
// 无状态纯函数模块:不依赖 RecordStore 任何内部状态。
|
|
22
22
|
|
|
23
23
|
import * as fs from "node:fs";
|
|
24
|
-
import * as fsPromises from "node:fs/promises";
|
|
25
24
|
import * as path from "node:path";
|
|
26
25
|
|
|
27
26
|
import { getLogger } from "../core/logger.ts";
|
|
27
|
+
import { writeAtomicFile } from "../shared/atomic-write.ts";
|
|
28
28
|
|
|
29
|
-
import { bestEffort } from "./best-effort.ts";
|
|
30
29
|
import type { ExecutionMode } from "./types.ts";
|
|
31
30
|
|
|
32
31
|
const logger = getLogger("subagents");
|
|
@@ -44,13 +43,6 @@ export const INDEX_VERSION = 1;
|
|
|
44
43
|
/** 两次成功落盘的最小墙钟间隔(节流:overlay 打开期间的高频扫描不放大磁盘写)。 */
|
|
45
44
|
export const INDEX_WRITE_MIN_INTERVAL_MS = 60_000;
|
|
46
45
|
|
|
47
|
-
/** tmp 文件单调计数:同一进程内并发的 saveIndex 各用独立 tmp。节流基准只在写成功后
|
|
48
|
-
* 推进——W1 在途时新一轮过窗扫描可再 dispatch W2,共用同一 tmp 会交错(W2 truncate
|
|
49
|
-
* 落在 W1 write 与 rename 之间 → 半成品被 rename / rename 后失败 → 假失败日志)。
|
|
50
|
-
* pid+seq 双后缀保证 tmp 唯一:交错 rename 的终态必为某次完整快照(last-writer-wins,
|
|
51
|
-
* 与跨进程 pid 隔离同语义;陈旧快照胜出时下轮戳不匹配自愈)。 */
|
|
52
|
-
let tmpSeq = 0;
|
|
53
|
-
|
|
54
46
|
// ============================================================
|
|
55
47
|
// 类型(DM1 磁盘顶层 + DM2 条目)
|
|
56
48
|
// ============================================================
|
|
@@ -245,60 +237,23 @@ export function loadIndex(encDir: string): LoadedSessionsIndex {
|
|
|
245
237
|
// ============================================================
|
|
246
238
|
|
|
247
239
|
/**
|
|
248
|
-
* 原子写索引(tmp
|
|
249
|
-
* ManifestStore.writeManifest
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
240
|
+
* 原子写索引(shared/atomic-write 统一原语,U6b 迁移:tmp → fsync → rename →
|
|
241
|
+
* fsync 目录)。原逐行实现(逐环复刻 ManifestStore.writeManifest 的生产模式)
|
|
242
|
+
* 与 writeAtomicFile 逐环等值;tmp 带 pid+单调序号双后缀防撞的语义由原语的
|
|
243
|
+
* atomicTmpPathFor 接管(pid 防两进程共用同一 tmp,seq+rand 防同进程并发
|
|
244
|
+
* saveIndex 共用同一 tmp)。rename 原子性保证读侧看到旧版或完整新版,绝无半成品。
|
|
245
|
+
* ensureDir:false——旧实现无 mkdir(目录由 sessionsDir 布局保证),缺目录维持
|
|
246
|
+
* fail-fast 上抛(调用方 .catch 兜底),不静默重建。
|
|
253
247
|
*
|
|
254
248
|
* 失败向上抛——RecordStore 的 flushIndexAfterScan 以 fire-and-forget .catch 消费
|
|
255
|
-
|
|
249
|
+
*(写失败不影响任何扫描结果,恢复 dirty 待下轮过窗重试)。
|
|
256
250
|
*/
|
|
257
251
|
export async function saveIndex(encDir: string, data: SessionsIndexData): Promise<void> {
|
|
258
252
|
const filePath = path.join(encDir, INDEX_FILENAME);
|
|
259
|
-
const tmpPath = `${filePath}.tmp.${process.pid}.${++tmpSeq}`;
|
|
260
253
|
const file: SessionsIndexFile = {
|
|
261
254
|
version: INDEX_VERSION,
|
|
262
255
|
pid: process.pid,
|
|
263
256
|
entries: Object.fromEntries(data.entries),
|
|
264
257
|
};
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
let renamed = false;
|
|
268
|
-
try {
|
|
269
|
-
// 1. 写 tmp → fsync 文件
|
|
270
|
-
const fh = await fsPromises.open(tmpPath, "w");
|
|
271
|
-
try {
|
|
272
|
-
await fh.writeFile(content, "utf-8");
|
|
273
|
-
await fh.sync();
|
|
274
|
-
} finally {
|
|
275
|
-
await fh.close();
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// 2. rename tmp → final(放在 try 内:失败时 catch 清理 tmp)
|
|
279
|
-
await fsPromises.rename(tmpPath, filePath);
|
|
280
|
-
renamed = true;
|
|
281
|
-
|
|
282
|
-
// 3. fsync 目录(best-effort:POSIX 不要求,失败不否定已成功的 rename)
|
|
283
|
-
try {
|
|
284
|
-
const dirFh = await fsPromises.open(encDir, "r");
|
|
285
|
-
try {
|
|
286
|
-
await dirFh.sync();
|
|
287
|
-
} finally {
|
|
288
|
-
await dirFh.close();
|
|
289
|
-
}
|
|
290
|
-
} catch (dirSyncErr) {
|
|
291
|
-
bestEffort(dirSyncErr, "fsync dir (saveIndex)");
|
|
292
|
-
}
|
|
293
|
-
} catch (err) {
|
|
294
|
-
// rename 未成功 → 清理残留 tmp(best-effort,不掩盖原错误)
|
|
295
|
-
if (!renamed) {
|
|
296
|
-
try {
|
|
297
|
-
await fsPromises.unlink(tmpPath);
|
|
298
|
-
} catch (cleanupErr) {
|
|
299
|
-
bestEffort(cleanupErr, "unlink tmp (saveIndex)");
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
throw err;
|
|
303
|
-
}
|
|
258
|
+
await writeAtomicFile(filePath, JSON.stringify(file), { ensureDir: false });
|
|
304
259
|
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// src/execution/settled-watchdog.ts
|
|
2
|
+
//
|
|
3
|
+
// [T2-③ / LC-1] chatMode settled 等待固定硬上限(回收层「上界族」共享原语)。
|
|
4
|
+
//
|
|
5
|
+
// 设计:docs/design/subagent-core-unbounded-wait-audit.md §7.2 T2-③ / §4.1 LC-1。
|
|
6
|
+
// chatMode 任意一轮等待 agent_settled 的窗口挂固定硬上限(默认 10 分钟)——settled
|
|
7
|
+
// 永不到达(事件行丢失 / 子进程 wedged)时本 timer 是唯一独立回收通道:现状
|
|
8
|
+
// 「settled 不 arm 则 idle timer 不挂、runSpawn 已在首轮返回、spawn watchdog 默认关」
|
|
9
|
+
// 的三无窗口由此收敛(LC-1 同族变体)。
|
|
10
|
+
//
|
|
11
|
+
// 固定上界(非事件刷新语义):该窗口的正常语义是 post-run 收尾(compact 检查等,
|
|
12
|
+
// 秒级完成),窗口内的任何输出都不能证明 settled 终将到达——「刷新」会让「wedged
|
|
13
|
+
// 但仍有周期性输出」的进程无限续命(LC-9 已证 stdout 可有调试行)。固定上界
|
|
14
|
+
// by construction 覆盖静默与非静默两种 wedged 形态。多轮会话中每轮窗口独立计时
|
|
15
|
+
//(重复 arm = 以新窗口覆盖旧计时,对齐 lifecycle-manager.armIdleTimer 的刷新语义)。
|
|
16
|
+
//
|
|
17
|
+
// 双挂载点共用同一原语——同一常量 + 同一挂载/清除 helper,仅两个调用点(设计
|
|
18
|
+
// T2-③ 明示架构,两处各写一套恰是被否的「散布姿势」微缩复发):
|
|
19
|
+
// - 首轮:session-runner.ts runSpawn(prompt 发出后挂;settled 到达 / close /
|
|
20
|
+
// resolveRun 任一发生即清)
|
|
21
|
+
// - 后续轮次热路径:subagent-service.ts deliverMessage(发出新一轮 prompt 后挂,
|
|
22
|
+
// u-t2b 接线)
|
|
23
|
+
//
|
|
24
|
+
// 与 lifecycle-manager 的 idle timer 互补:idle timer 管 settled 已到达后的空闲
|
|
25
|
+
// 回收,本上界管 settled 永不到达的 wedged——两条正交通道不互相替代。
|
|
26
|
+
//
|
|
27
|
+
// 实现形态对齐 armIdleTimer(recordId → timer 的模块级记账):重复 arm 先清旧
|
|
28
|
+
// timer、到期回调先自删条目再执行——挂载/清除责任内聚在原语,调用方不管理句柄
|
|
29
|
+
// 覆盖(防「忘清旧窗」散布错误)。
|
|
30
|
+
|
|
31
|
+
import { getLogger } from "../core/logger.ts";
|
|
32
|
+
import { assertSafeTimerDelay } from "../shared/timer-delay.ts";
|
|
33
|
+
|
|
34
|
+
const logger = getLogger("subagents");
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* settled 等待固定硬上限(10 分钟)。
|
|
38
|
+
*
|
|
39
|
+
* [P-T2c 定案] 真实 pi 会话 agent_end→agent_settled 间隔 6 轮全部 <2ms(两事件行
|
|
40
|
+
* 同 chunk 到达);30 万 tokens 上下文显式 compaction 耗时 40.1s——10min 上限余量
|
|
41
|
+
* 4 个数量级以上(probe/p-t2c-report.md)。维持设计默认值,仅此一处定义。
|
|
42
|
+
*/
|
|
43
|
+
export const SETTLED_WATCHDOG_TIMEOUT_MS = 600_000;
|
|
44
|
+
|
|
45
|
+
/** recordId → armed settled watchdog timer。仅在等待窗口内 armed(挂载/清除成对)。 */
|
|
46
|
+
const armedTimers = new Map<string, NodeJS.Timeout>();
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 挂载(或按新窗口重挂)某 record 的 settled 等待硬上限。
|
|
50
|
+
*
|
|
51
|
+
* - 重复 arm(同 recordId)先 clearTimeout 旧 timer——每轮窗口独立计时,不叠加。
|
|
52
|
+
* - 到期回调先从 Map 移除自身再执行 onTimeout(onTimeout 内重新 arm 不会被误删)。
|
|
53
|
+
* - timer unref:不阻止主进程退出(回收兜底不阻塞 shutdown,对齐 idle timer /
|
|
54
|
+
* spawn watchdog 的 unref 语义)。
|
|
55
|
+
* - 到期行为由调用方注入 onTimeout(kill 进程 + 该轮失败终态化)——本模块不持有
|
|
56
|
+
* ChildProcess / record,与 lifecycle-manager 同构(副作用能力由调用方注入,
|
|
57
|
+
* 本模块只管 timer 生命周期,可独立编译 + 单测)。
|
|
58
|
+
*/
|
|
59
|
+
export function armSettledWatchdog(recordId: string, onTimeout: () => void): void {
|
|
60
|
+
// 常量恒在安全域内;入口统一校验防未来值改可配置时静默引入 1ms 溢出语义反转。
|
|
61
|
+
assertSafeTimerDelay(SETTLED_WATCHDOG_TIMEOUT_MS, "settled watchdog");
|
|
62
|
+
// 重挂 = 新窗口:先清旧 timer,防同一 record 叠加多个 armed timer。
|
|
63
|
+
disarmSettledWatchdog(recordId);
|
|
64
|
+
const timer = setTimeout(() => {
|
|
65
|
+
armedTimers.delete(recordId);
|
|
66
|
+
logger.debug(`[settled-watchdog] fired for ${recordId} after ${SETTLED_WATCHDOG_TIMEOUT_MS}ms without agent_settled`);
|
|
67
|
+
onTimeout();
|
|
68
|
+
}, SETTLED_WATCHDOG_TIMEOUT_MS);
|
|
69
|
+
timer.unref();
|
|
70
|
+
armedTimers.set(recordId, timer);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 清除某 record 的 settled 等待硬上限(settled 到达 / close / resolveRun 任一发生
|
|
75
|
+
* 即清)。不存在 armed timer 时 no-op。
|
|
76
|
+
*/
|
|
77
|
+
export function disarmSettledWatchdog(recordId: string): void {
|
|
78
|
+
const timer = armedTimers.get(recordId);
|
|
79
|
+
if (!timer) return;
|
|
80
|
+
clearTimeout(timer);
|
|
81
|
+
armedTimers.delete(recordId);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 查询某 record 是否有 armed settled watchdog(测试/接入期断言用)。
|
|
86
|
+
*/
|
|
87
|
+
export function hasSettledWatchdog(recordId: string): boolean {
|
|
88
|
+
return armedTimers.has(recordId);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 清空全部 armed timer(测试隔离用,beforeEach 调;命名对齐 _resetLifecycleState 先例)。
|
|
93
|
+
*/
|
|
94
|
+
export function _resetSettledWatchdogsForTest(): void {
|
|
95
|
+
for (const timer of armedTimers.values()) {
|
|
96
|
+
clearTimeout(timer);
|
|
97
|
+
}
|
|
98
|
+
armedTimers.clear();
|
|
99
|
+
}
|