@zhushanwen/subagent-core 0.7.0 → 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/dist/{chunk-VURUAGMM.js → chunk-OL5BK4VN.js} +237 -40
- package/dist/{engine-discovery-scan-ocpM8FmI.d.cts → engine-discovery-scan-BXLA8y-z.d.cts} +17 -1
- package/dist/{engine-discovery-scan-ocpM8FmI.d.ts → engine-discovery-scan-BXLA8y-z.d.ts} +17 -1
- package/dist/execution/engine/engine-discovery-scan.cjs +150 -40
- package/dist/execution/engine/engine-discovery-scan.d.cts +1 -1
- package/dist/execution/engine/engine-discovery-scan.d.ts +1 -1
- package/dist/execution/engine/engine-discovery-scan.js +1 -1
- package/dist/index.cjs +278 -225
- package/dist/index.d.cts +24 -4
- package/dist/index.d.ts +24 -4
- package/dist/index.js +188 -304
- package/dist.bundle/index.cjs +279 -226
- package/package.json +5 -5
- package/src/__tests__/record-store-last-line.test.ts +12 -0
- package/src/core/logger.ts +1 -1
- package/src/execution/__tests__/inflight-production-wiring.test.ts +223 -0
- package/src/execution/__tests__/nested-visibility.test.ts +13 -1
- package/src/execution/engine/__tests__/conformance/registry-fork-filter.test.ts +55 -53
- package/src/execution/engine/__tests__/inflight-snapshot.test.ts +180 -0
- package/src/execution/engine/client/engine-client.ts +30 -1
- package/src/execution/engine/host/host-bridge.ts +7 -0
- package/src/execution/engine/host/spawned-children.ts +1 -1
- package/src/execution/engine/inflight-snapshot.ts +92 -0
- package/src/execution/engine/port.ts +18 -0
- package/src/execution/path-encoding.ts +6 -0
- package/src/execution/subagent-service.ts +25 -0
- package/src/execution/worktree-registry.ts +11 -7
- package/src/index.ts +11 -1
package/dist/index.js
CHANGED
|
@@ -12,31 +12,46 @@ import {
|
|
|
12
12
|
CONSERVATIVE_CAPABILITIES,
|
|
13
13
|
DEFAULT_DATA_ROOT,
|
|
14
14
|
DEFAULT_ENGINE_ID,
|
|
15
|
+
DEFAULT_IDLE_TIMEOUT_MS,
|
|
15
16
|
EngineClient,
|
|
16
17
|
EngineError,
|
|
17
18
|
EngineNotFoundError,
|
|
19
|
+
MAX_TIMER_DELAY_MS,
|
|
18
20
|
RemoteEngine,
|
|
21
|
+
armIdleTimer,
|
|
22
|
+
assertSafeTimerDelay,
|
|
19
23
|
assertTaskShapeSupported,
|
|
20
24
|
configureCore,
|
|
25
|
+
disarmIdleTimer,
|
|
21
26
|
discoverAndRegisterEngines,
|
|
22
27
|
ensureEngineDiscovered,
|
|
23
28
|
getEngine,
|
|
24
29
|
getEngineDataDir,
|
|
25
30
|
getHostServices,
|
|
31
|
+
getInFlightSnapshot,
|
|
26
32
|
getLogger,
|
|
27
33
|
hasEngine,
|
|
34
|
+
hasIdleTimer,
|
|
35
|
+
hasLiveProcessHandle,
|
|
28
36
|
inspectEnginePackage,
|
|
37
|
+
isIdle,
|
|
38
|
+
isResumable,
|
|
39
|
+
killAllSpawnedChildren,
|
|
40
|
+
killRecordChildWithEscalation,
|
|
29
41
|
listEngines,
|
|
30
42
|
listEnginesByDisplayName,
|
|
31
43
|
loadedDiscoveryIds,
|
|
32
44
|
normalizeEngineId,
|
|
45
|
+
notifyInFlightChanged,
|
|
33
46
|
parseCapabilities,
|
|
34
47
|
parseEnvPrefixes,
|
|
35
48
|
parseModelCatalog,
|
|
36
49
|
registerEngineDescriptor,
|
|
50
|
+
registerSpawnedChildForRecord,
|
|
37
51
|
resolveManifestBin,
|
|
38
|
-
setHostUiRequestEndpoint
|
|
39
|
-
|
|
52
|
+
setHostUiRequestEndpoint,
|
|
53
|
+
setInFlightListener
|
|
54
|
+
} from "./chunk-OL5BK4VN.js";
|
|
40
55
|
|
|
41
56
|
// src/core/notify-ports.ts
|
|
42
57
|
var NOTIFY_PORTS_SLOT_KEY = /* @__PURE__ */ Symbol.for("@zhushanwen/subagent-core.notify-ports");
|
|
@@ -434,72 +449,6 @@ function syncEnginesFile(agentDir) {
|
|
|
434
449
|
}
|
|
435
450
|
}
|
|
436
451
|
|
|
437
|
-
// src/execution/engine/host/spawned-children.ts
|
|
438
|
-
var CoreSpawnedChildrenMirror = class {
|
|
439
|
-
entries = /* @__PURE__ */ new Map();
|
|
440
|
-
/** 落项 / 覆盖(同 recordId 重 spawn = 覆盖旧句柄,与引擎侧 Map 同语义)。 */
|
|
441
|
-
register(recordId, child) {
|
|
442
|
-
this.entries.set(recordId, {
|
|
443
|
-
pid: child.pid,
|
|
444
|
-
killed: child.killed,
|
|
445
|
-
updatedAt: Date.now()
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
/** 单项置死(杀链入口:killRecordChildWithEscalation 途经)。 */
|
|
449
|
-
markKilled(recordId) {
|
|
450
|
-
const entry = this.entries.get(recordId);
|
|
451
|
-
if (entry !== void 0) {
|
|
452
|
-
entry.killed = true;
|
|
453
|
-
entry.updatedAt = Date.now();
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
/** 整体置死 + 清空(失效语义 2+3:引擎 exit / 重建 / dispose / killAll)。 */
|
|
457
|
-
killAll() {
|
|
458
|
-
this.entries.clear();
|
|
459
|
-
}
|
|
460
|
-
getChildByRecord(recordId) {
|
|
461
|
-
return this.entries.get(recordId);
|
|
462
|
-
}
|
|
463
|
-
/** 句柄存活谓词(镜像面;判据与引擎侧 `!child.killed` 同构)。 */
|
|
464
|
-
hasLiveProcessHandle(recordId) {
|
|
465
|
-
const entry = this.entries.get(recordId);
|
|
466
|
-
return entry !== void 0 && !entry.killed;
|
|
467
|
-
}
|
|
468
|
-
/** 快照(诊断/测试)。 */
|
|
469
|
-
snapshot() {
|
|
470
|
-
return [...this.entries.entries()].map(([recordId, entry]) => ({ recordId, ...entry }));
|
|
471
|
-
}
|
|
472
|
-
/** 测试隔离专用(生产禁用——进程级全局状态)。 */
|
|
473
|
-
clear() {
|
|
474
|
-
this.entries.clear();
|
|
475
|
-
}
|
|
476
|
-
};
|
|
477
|
-
var MIRROR_SLOT_KEY = /* @__PURE__ */ Symbol.for(
|
|
478
|
-
"@zhushanwen/pi-subagent-workflow.coreSpawnedChildrenMirror"
|
|
479
|
-
);
|
|
480
|
-
function coreMirrorSlot() {
|
|
481
|
-
let slot = Reflect.get(globalThis, MIRROR_SLOT_KEY);
|
|
482
|
-
if (!slot) {
|
|
483
|
-
slot = new CoreSpawnedChildrenMirror();
|
|
484
|
-
Reflect.set(globalThis, MIRROR_SLOT_KEY, slot);
|
|
485
|
-
}
|
|
486
|
-
return slot;
|
|
487
|
-
}
|
|
488
|
-
function registerSpawnedChildForRecord(recordId, child) {
|
|
489
|
-
coreMirrorSlot().register(recordId, { pid: child.pid, killed: child.killed });
|
|
490
|
-
}
|
|
491
|
-
function killRecordChildWithEscalation(recordId, _source) {
|
|
492
|
-
coreMirrorSlot().markKilled(recordId);
|
|
493
|
-
}
|
|
494
|
-
function killAllSpawnedChildren(_signal = "SIGTERM") {
|
|
495
|
-
const before = coreMirrorSlot().snapshot().length;
|
|
496
|
-
coreMirrorSlot().killAll();
|
|
497
|
-
return before;
|
|
498
|
-
}
|
|
499
|
-
function hasLiveProcessHandleCore(recordId) {
|
|
500
|
-
return coreMirrorSlot().hasLiveProcessHandle(recordId);
|
|
501
|
-
}
|
|
502
|
-
|
|
503
452
|
// src/execution/engine/d8-compat.ts
|
|
504
453
|
import * as fs2 from "fs";
|
|
505
454
|
import * as path3 from "path";
|
|
@@ -1576,21 +1525,6 @@ var DirtyWorktreeError = class extends Error {
|
|
|
1576
1525
|
// src/execution/subagent-service.ts
|
|
1577
1526
|
import { AsyncLocalStorage } from "async_hooks";
|
|
1578
1527
|
|
|
1579
|
-
// src/shared/timer-delay.ts
|
|
1580
|
-
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
1581
|
-
function assertSafeTimerDelay(ms, source) {
|
|
1582
|
-
if (!Number.isFinite(ms)) {
|
|
1583
|
-
throw new Error(
|
|
1584
|
-
`[subagent-workflow] ${source} = ${ms} is not a finite number (NaN/\xB1Infinity). Non-finite delays collapse to 1ms in Node setTimeout and fire immediately. Recovery: fix the upstream computation that produced this value (e.g. guard division/parse results before passing them in) and retry.`
|
|
1585
|
-
);
|
|
1586
|
-
}
|
|
1587
|
-
if (ms > MAX_TIMER_DELAY_MS) {
|
|
1588
|
-
throw new Error(
|
|
1589
|
-
`[subagent-workflow] ${source} = ${ms} exceeds the Node setTimeout limit (${MAX_TIMER_DELAY_MS} ms = 2^31-1); larger delays silently collapse to 1ms and fire immediately. Recovery: clamp the value to <= ${MAX_TIMER_DELAY_MS} (e.g. omit the option for "unlimited" semantics, or clamp explicitly) and retry.`
|
|
1590
|
-
);
|
|
1591
|
-
}
|
|
1592
|
-
}
|
|
1593
|
-
|
|
1594
1528
|
// src/execution/agent-result-mapper.ts
|
|
1595
1529
|
var TOOL_ARGS_JSON_MAX_CHARS = 500;
|
|
1596
1530
|
function mapToWorkflowAgentResult(r) {
|
|
@@ -1893,56 +1827,6 @@ function sanitizeEngineRouting(value) {
|
|
|
1893
1827
|
return typeof strict === "boolean" ? { strict } : void 0;
|
|
1894
1828
|
}
|
|
1895
1829
|
|
|
1896
|
-
// src/execution/lifecycle-manager.ts
|
|
1897
|
-
var logger8 = getLogger("subagents");
|
|
1898
|
-
var MS_PER_SECOND3 = 1e3;
|
|
1899
|
-
var SECONDS_PER_MINUTE2 = 60;
|
|
1900
|
-
var IDLE_TIMEOUT_MINUTES = 5;
|
|
1901
|
-
var DEFAULT_IDLE_TIMEOUT_MS = IDLE_TIMEOUT_MINUTES * SECONDS_PER_MINUTE2 * MS_PER_SECOND3;
|
|
1902
|
-
function getEnvIdleTimeoutMs() {
|
|
1903
|
-
const raw = process.env.XYZ_SUBAGENT_IDLE_TIMEOUT_MS;
|
|
1904
|
-
if (!raw) return void 0;
|
|
1905
|
-
const parsed = Number(raw);
|
|
1906
|
-
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
1907
|
-
logger8.warn(
|
|
1908
|
-
`[lifecycle-manager] XYZ_SUBAGENT_IDLE_TIMEOUT_MS="${raw}" is invalid (expected a positive millisecond number) \u2014 falling back to DEFAULT_IDLE_TIMEOUT_MS (${DEFAULT_IDLE_TIMEOUT_MS}ms); set a plain ms value (e.g. 1800000) to override`
|
|
1909
|
-
);
|
|
1910
|
-
return void 0;
|
|
1911
|
-
}
|
|
1912
|
-
return parsed;
|
|
1913
|
-
}
|
|
1914
|
-
var idleTimers = /* @__PURE__ */ new Map();
|
|
1915
|
-
function armIdleTimer(recordId, onTimeout, timeoutMs) {
|
|
1916
|
-
if (timeoutMs !== void 0 && timeoutMs <= 0) {
|
|
1917
|
-
disarmIdleTimer(recordId);
|
|
1918
|
-
return;
|
|
1919
|
-
}
|
|
1920
|
-
const resolved = timeoutMs ?? getEnvIdleTimeoutMs() ?? DEFAULT_IDLE_TIMEOUT_MS;
|
|
1921
|
-
assertSafeTimerDelay(resolved, "idleTimeoutMs");
|
|
1922
|
-
disarmIdleTimer(recordId);
|
|
1923
|
-
const timer = setTimeout(() => {
|
|
1924
|
-
if (idleTimers.get(recordId)?.timer === timer) {
|
|
1925
|
-
idleTimers.delete(recordId);
|
|
1926
|
-
}
|
|
1927
|
-
onTimeout();
|
|
1928
|
-
}, resolved);
|
|
1929
|
-
timer.unref?.();
|
|
1930
|
-
idleTimers.set(recordId, { timer, timeoutMs: resolved });
|
|
1931
|
-
}
|
|
1932
|
-
function disarmIdleTimer(recordId) {
|
|
1933
|
-
const entry = idleTimers.get(recordId);
|
|
1934
|
-
if (!entry) {
|
|
1935
|
-
return;
|
|
1936
|
-
}
|
|
1937
|
-
clearTimeout(entry.timer);
|
|
1938
|
-
idleTimers.delete(recordId);
|
|
1939
|
-
}
|
|
1940
|
-
function hasIdleTimer(recordId) {
|
|
1941
|
-
return idleTimers.has(recordId);
|
|
1942
|
-
}
|
|
1943
|
-
var ACTIVATE_LOCK_TIMEOUT_SECONDS = 30;
|
|
1944
|
-
var ACTIVATE_LOCK_TIMEOUT_MS = ACTIVATE_LOCK_TIMEOUT_SECONDS * MS_PER_SECOND3;
|
|
1945
|
-
|
|
1946
1830
|
// src/execution/concurrency-pool.ts
|
|
1947
1831
|
var DefaultConcurrencyPool = class {
|
|
1948
1832
|
_active = 0;
|
|
@@ -2521,7 +2405,7 @@ function readCancelledTombstone(sessionFile) {
|
|
|
2521
2405
|
}
|
|
2522
2406
|
|
|
2523
2407
|
// src/execution/finalize-record.ts
|
|
2524
|
-
var
|
|
2408
|
+
var logger8 = getLogger("subagents");
|
|
2525
2409
|
function findSessionFileByRecordIdentity(sessionDir, recordId) {
|
|
2526
2410
|
let names;
|
|
2527
2411
|
try {
|
|
@@ -2542,7 +2426,7 @@ function resolveMissingSessionFile(deps, record) {
|
|
|
2542
2426
|
const resolved = findSessionFileByRecordIdentity(deps.sessionDir, record.id);
|
|
2543
2427
|
if (resolved) {
|
|
2544
2428
|
record.sessionFile = resolved;
|
|
2545
|
-
|
|
2429
|
+
logger8.warn(
|
|
2546
2430
|
`[subagent] finalizeRecord: sessionFile was missing, resolved via sessionDir identity lookup: ${resolved}`
|
|
2547
2431
|
);
|
|
2548
2432
|
}
|
|
@@ -2614,7 +2498,7 @@ async function writeManifestBestEffort(deps, record) {
|
|
|
2614
2498
|
});
|
|
2615
2499
|
} catch (err) {
|
|
2616
2500
|
const msg = err instanceof Error ? err.message : String(err);
|
|
2617
|
-
|
|
2501
|
+
logger8.error(`[subagent] manifest \u5199\u5165\u5931\u8D25 (record=${record.id}): ${msg}`);
|
|
2618
2502
|
deps.pi?.appendEntry?.("subagent:manifest-write-failed", {
|
|
2619
2503
|
id: record.id,
|
|
2620
2504
|
error: msg
|
|
@@ -2946,7 +2830,7 @@ function safeEngineDefault(engine) {
|
|
|
2946
2830
|
import * as fs10 from "fs";
|
|
2947
2831
|
import * as fsPromises2 from "fs/promises";
|
|
2948
2832
|
import * as path7 from "path";
|
|
2949
|
-
var
|
|
2833
|
+
var logger9 = getLogger("subagents");
|
|
2950
2834
|
var MANIFEST_INDENT_SPACES = 2;
|
|
2951
2835
|
function statStamp(p) {
|
|
2952
2836
|
try {
|
|
@@ -3099,13 +2983,13 @@ var ManifestStore = class {
|
|
|
3099
2983
|
}
|
|
3100
2984
|
} catch (fileErr) {
|
|
3101
2985
|
failed++;
|
|
3102
|
-
|
|
2986
|
+
logger9.warn(`[subagents] recoverTmpFiles: failed to recover ${tmpFile}, skipping (leftovers retry on next startup)`, {
|
|
3103
2987
|
detail: fileErr instanceof Error ? fileErr.message : String(fileErr)
|
|
3104
2988
|
});
|
|
3105
2989
|
}
|
|
3106
2990
|
}
|
|
3107
2991
|
if (failed > 0) {
|
|
3108
|
-
|
|
2992
|
+
logger9.warn(
|
|
3109
2993
|
`[subagents] recoverTmpFiles: ${failed} of ${tmpFiles.length} tmp file(s) could not be recovered`
|
|
3110
2994
|
);
|
|
3111
2995
|
}
|
|
@@ -3166,22 +3050,11 @@ function displayAgentName(ref) {
|
|
|
3166
3050
|
return base.endsWith(AGENT_REF_EXT) ? base.slice(0, -AGENT_REF_EXT.length) : base;
|
|
3167
3051
|
}
|
|
3168
3052
|
|
|
3169
|
-
// src/execution/lifecycle-predicates.ts
|
|
3170
|
-
function hasLiveProcessHandle(recordId) {
|
|
3171
|
-
return hasLiveProcessHandleCore(recordId);
|
|
3172
|
-
}
|
|
3173
|
-
function isIdle(record) {
|
|
3174
|
-
return hasIdleTimer(record.id);
|
|
3175
|
-
}
|
|
3176
|
-
function isResumable(record) {
|
|
3177
|
-
return record.status === "running" && !hasLiveProcessHandle(record.id);
|
|
3178
|
-
}
|
|
3179
|
-
|
|
3180
3053
|
// src/execution/notifier.ts
|
|
3181
3054
|
import { createHash } from "crypto";
|
|
3182
3055
|
|
|
3183
3056
|
// src/execution/notify-ledger.ts
|
|
3184
|
-
var
|
|
3057
|
+
var logger10 = getLogger("subagents");
|
|
3185
3058
|
var NOTIFY_LEDGER_CUSTOM_TYPE = "subagent-bg-notify-ledger";
|
|
3186
3059
|
var NOTIFY_ACK_CUSTOM_TYPE = "subagent-bg-notify-ack";
|
|
3187
3060
|
var NOTIFY_ABANDONED_CUSTOM_TYPE = "subagent-bg-notify-abandoned";
|
|
@@ -3407,7 +3280,7 @@ function createNotifyLedger(host, options) {
|
|
|
3407
3280
|
host.appendLedgerEntry(NOTIFY_ABANDONED_CUSTOM_TYPE, { v: 1, notifyId: item.notifyId });
|
|
3408
3281
|
items.delete(item.notifyId);
|
|
3409
3282
|
abandonedIds.add(item.notifyId);
|
|
3410
|
-
|
|
3283
|
+
logger10.warn(
|
|
3411
3284
|
`Subagent "${itemLabel(item)}" notification abandoned - no receipt after ${NOTIFY_REDELIVERY_MAX_ATTEMPTS} delivery attempts; verify manually via subagents action:"list"`,
|
|
3412
3285
|
{ notifyId: item.notifyId, attempts: item.attempts }
|
|
3413
3286
|
);
|
|
@@ -3458,7 +3331,7 @@ function createNotifyLedger(host, options) {
|
|
|
3458
3331
|
api.checkReceipts();
|
|
3459
3332
|
}
|
|
3460
3333
|
function emitBucketLog(bucket, total, extra) {
|
|
3461
|
-
|
|
3334
|
+
logger10.warn(`notify delivery bucket [${bucket}]`, { total, ...extra });
|
|
3462
3335
|
}
|
|
3463
3336
|
if (options?.registerSettledListener !== false) {
|
|
3464
3337
|
host.onAgentSettled(() => {
|
|
@@ -3918,7 +3791,7 @@ function toSubagentRecordEntry(record) {
|
|
|
3918
3791
|
// src/execution/sessions-index.ts
|
|
3919
3792
|
import * as fs11 from "fs";
|
|
3920
3793
|
import * as path8 from "path";
|
|
3921
|
-
var
|
|
3794
|
+
var logger11 = getLogger("subagents");
|
|
3922
3795
|
var INDEX_FILENAME = "sessions-index.json";
|
|
3923
3796
|
var INDEX_VERSION = 1;
|
|
3924
3797
|
var INDEX_WRITE_MIN_INTERVAL_MS = 6e4;
|
|
@@ -3961,7 +3834,7 @@ function readIndexFile(indexPath, encDir) {
|
|
|
3961
3834
|
} catch (err) {
|
|
3962
3835
|
const code = errorCodeOf(err);
|
|
3963
3836
|
if (code !== "ENOENT") {
|
|
3964
|
-
|
|
3837
|
+
logger11.debug("[subagents] sessions-index read failed, fallback to empty", {
|
|
3965
3838
|
detail: { dir: encDir, code }
|
|
3966
3839
|
});
|
|
3967
3840
|
}
|
|
@@ -3972,7 +3845,7 @@ function parseIndexJson(raw, indexPath) {
|
|
|
3972
3845
|
try {
|
|
3973
3846
|
return JSON.parse(raw);
|
|
3974
3847
|
} catch (err) {
|
|
3975
|
-
|
|
3848
|
+
logger11.debug("[subagents] sessions-index corrupted JSON, fallback to empty", {
|
|
3976
3849
|
detail: { path: indexPath, error: err instanceof Error ? err.message : String(err) }
|
|
3977
3850
|
});
|
|
3978
3851
|
return null;
|
|
@@ -3983,14 +3856,14 @@ function isIndexTopHeader(v) {
|
|
|
3983
3856
|
}
|
|
3984
3857
|
function readTopLevel(parsed, indexPath) {
|
|
3985
3858
|
if (typeof parsed !== "object" || parsed === null) {
|
|
3986
|
-
|
|
3859
|
+
logger11.debug("[subagents] sessions-index invalid top-level shape, fallback to empty", {
|
|
3987
3860
|
detail: { path: indexPath }
|
|
3988
3861
|
});
|
|
3989
3862
|
return null;
|
|
3990
3863
|
}
|
|
3991
3864
|
const top = parsed;
|
|
3992
3865
|
if (!isIndexTopHeader(top)) {
|
|
3993
|
-
|
|
3866
|
+
logger11.debug("[subagents] sessions-index invalid header fields, fallback to empty", {
|
|
3994
3867
|
detail: { path: indexPath }
|
|
3995
3868
|
});
|
|
3996
3869
|
return null;
|
|
@@ -4018,7 +3891,7 @@ function loadIndex(encDir) {
|
|
|
4018
3891
|
return { entries: /* @__PURE__ */ new Map(), higherVersion: true };
|
|
4019
3892
|
}
|
|
4020
3893
|
if (top.version < INDEX_VERSION) {
|
|
4021
|
-
|
|
3894
|
+
logger11.debug("[subagents] sessions-index stale version, discarded", {
|
|
4022
3895
|
detail: { path: indexPath, version: top.version, expected: INDEX_VERSION }
|
|
4023
3896
|
});
|
|
4024
3897
|
return empty;
|
|
@@ -4036,7 +3909,7 @@ async function saveIndex(encDir, data) {
|
|
|
4036
3909
|
}
|
|
4037
3910
|
|
|
4038
3911
|
// src/execution/record-store.ts
|
|
4039
|
-
var
|
|
3912
|
+
var logger12 = getLogger("subagents");
|
|
4040
3913
|
var STATUS_PRIORITY = {
|
|
4041
3914
|
running: 0,
|
|
4042
3915
|
closed: 3
|
|
@@ -4102,7 +3975,7 @@ function collectLastRecordEntries(content) {
|
|
|
4102
3975
|
try {
|
|
4103
3976
|
entry = asSubagentRecordEntry(JSON.parse(line));
|
|
4104
3977
|
} catch (err) {
|
|
4105
|
-
|
|
3978
|
+
logger12.debug("[subagents] entry-only orphan scan: skip unparsable line", {
|
|
4106
3979
|
reason: err instanceof Error ? err.message : String(err)
|
|
4107
3980
|
});
|
|
4108
3981
|
}
|
|
@@ -4366,7 +4239,7 @@ var RecordStore = class _RecordStore {
|
|
|
4366
4239
|
if (rootSessionFilter !== void 0 && manifest.rootSessionId !== rootSessionFilter) continue;
|
|
4367
4240
|
const rec = _RecordStore.manifestToSubagent(manifest);
|
|
4368
4241
|
if (!rec) {
|
|
4369
|
-
|
|
4242
|
+
logger12.warn("[subagents] skip manifest with invalid status", {
|
|
4370
4243
|
detail: { id: manifest.id, status: manifest.status }
|
|
4371
4244
|
});
|
|
4372
4245
|
this.pi?.appendEntry?.("subagent:manifest-invalid-status", {
|
|
@@ -4765,7 +4638,7 @@ var RecordStore = class _RecordStore {
|
|
|
4765
4638
|
this.lastIndexWriteAt = Date.now();
|
|
4766
4639
|
}).catch((err) => {
|
|
4767
4640
|
this.indexDirty = true;
|
|
4768
|
-
|
|
4641
|
+
logger12.warn("[subagents] sessions-index write failed", {
|
|
4769
4642
|
detail: { dir: encDir, error: err instanceof Error ? err.message : String(err) }
|
|
4770
4643
|
});
|
|
4771
4644
|
});
|
|
@@ -5093,12 +4966,12 @@ function bufferedMemberFallbackRecord(m, rootSessionId) {
|
|
|
5093
4966
|
var MAX_FORK_DEPTH = 10;
|
|
5094
4967
|
|
|
5095
4968
|
// src/execution/settled-watchdog.ts
|
|
5096
|
-
var
|
|
5097
|
-
var
|
|
5098
|
-
var
|
|
4969
|
+
var logger13 = getLogger("subagents");
|
|
4970
|
+
var MS_PER_SECOND3 = 1e3;
|
|
4971
|
+
var SECONDS_PER_MINUTE2 = 60;
|
|
5099
4972
|
var MID_ROUND_MINUTES = 30;
|
|
5100
4973
|
var SETTLED_WATCHDOG_TIMEOUT_MS = 6e5;
|
|
5101
|
-
var SETTLED_MID_ROUND_NO_PROGRESS_MS = MID_ROUND_MINUTES *
|
|
4974
|
+
var SETTLED_MID_ROUND_NO_PROGRESS_MS = MID_ROUND_MINUTES * SECONDS_PER_MINUTE2 * MS_PER_SECOND3;
|
|
5102
4975
|
var SETTLED_WATCHDOG_ENV = "XYZ_SUBAGENT_SETTLED_WATCHDOG_MS";
|
|
5103
4976
|
var armedEntries = /* @__PURE__ */ new Map();
|
|
5104
4977
|
var envCache;
|
|
@@ -5109,13 +4982,13 @@ function resolveSettledWatchdogEnv() {
|
|
|
5109
4982
|
if (raw === void 0 || raw.trim() === "") return envCache;
|
|
5110
4983
|
const parsed = Number(raw);
|
|
5111
4984
|
if (!Number.isFinite(parsed)) {
|
|
5112
|
-
|
|
4985
|
+
logger13.warn(
|
|
5113
4986
|
`[settled-watchdog] ${SETTLED_WATCHDOG_ENV}="${raw}" is invalid (expected a millisecond number) \u2014 falling back to default settled phase limit (${SETTLED_WATCHDOG_TIMEOUT_MS}ms); set a plain ms value (e.g. 60000) to override, or 0 to disable both phases`
|
|
5114
4987
|
);
|
|
5115
4988
|
return envCache;
|
|
5116
4989
|
}
|
|
5117
4990
|
if (parsed <= 0) {
|
|
5118
|
-
|
|
4991
|
+
logger13.warn(
|
|
5119
4992
|
`[settled-watchdog] ${SETTLED_WATCHDOG_ENV}=${parsed} disables BOTH watchdog phases (mid-round no-progress + settled phase limit). Consequence: a wedged chatMode round (no agent_end, or agent_settled never arriving) has NO independent recovery timer \u2014 the process leaks until the host exits (the "three-no-window" shape). Recovery: unset the env or set a positive ms value.`
|
|
5120
4993
|
);
|
|
5121
4994
|
envCache.disabled = true;
|
|
@@ -5142,7 +5015,7 @@ function armMidRoundNoProgress(recordId, handlers) {
|
|
|
5142
5015
|
assertSafeTimerDelay(SETTLED_MID_ROUND_NO_PROGRESS_MS, "settled watchdog (mid-round)");
|
|
5143
5016
|
const timer = setTimeout(() => {
|
|
5144
5017
|
armedEntries.delete(recordId);
|
|
5145
|
-
|
|
5018
|
+
logger13.debug(
|
|
5146
5019
|
`[settled-watchdog] mid-round fired for ${recordId} after ${SETTLED_MID_ROUND_NO_PROGRESS_MS}ms without a valid protocol event`
|
|
5147
5020
|
);
|
|
5148
5021
|
handlers.onMidTimeout({ phase: "mid-round", waitedMs: SETTLED_MID_ROUND_NO_PROGRESS_MS });
|
|
@@ -5162,7 +5035,7 @@ function armSettledWatchdog(recordId, onTimeout) {
|
|
|
5162
5035
|
assertSafeTimerDelay(windowMs, "settled watchdog");
|
|
5163
5036
|
const timer = setTimeout(() => {
|
|
5164
5037
|
armedEntries.delete(recordId);
|
|
5165
|
-
|
|
5038
|
+
logger13.debug(
|
|
5166
5039
|
`[settled-watchdog] settled phase fired for ${recordId} after ${windowMs}ms without agent_settled`
|
|
5167
5040
|
);
|
|
5168
5041
|
onTimeout({ phase: "settled", waitedMs: windowMs });
|
|
@@ -5185,7 +5058,7 @@ function refreshMidRoundNoProgress(recordId) {
|
|
|
5185
5058
|
const onMidTimeout = entry.onMidTimeout;
|
|
5186
5059
|
const timer = setTimeout(() => {
|
|
5187
5060
|
armedEntries.delete(recordId);
|
|
5188
|
-
|
|
5061
|
+
logger13.debug(
|
|
5189
5062
|
`[settled-watchdog] mid-round fired for ${recordId} after ${SETTLED_MID_ROUND_NO_PROGRESS_MS}ms without a valid protocol event`
|
|
5190
5063
|
);
|
|
5191
5064
|
onMidTimeout?.({ phase: "mid-round", waitedMs: SETTLED_MID_ROUND_NO_PROGRESS_MS });
|
|
@@ -5209,7 +5082,7 @@ function disarmRoundFromProtocol(recordId) {
|
|
|
5209
5082
|
// src/execution/engine/common/pool-manager.ts
|
|
5210
5083
|
import * as fsSync from "fs";
|
|
5211
5084
|
import { join as join11 } from "path";
|
|
5212
|
-
var
|
|
5085
|
+
var logger14 = getLogger("subagents");
|
|
5213
5086
|
var POOL_CLEANUP_FAILED_MARKER = ".pool-cleanup-failed";
|
|
5214
5087
|
var REFS_JSON_FILENAME = "refs.json";
|
|
5215
5088
|
var REFS_VERSION = 1;
|
|
@@ -5225,7 +5098,7 @@ function readPoolRefs(poolDir, fs19) {
|
|
|
5225
5098
|
try {
|
|
5226
5099
|
parsed = JSON.parse(fs19.readFileSync(refsPath));
|
|
5227
5100
|
} catch (err) {
|
|
5228
|
-
|
|
5101
|
+
logger14.warn(
|
|
5229
5102
|
`[pool-manager] refs.json unparsable for ${poolDir}, starting from empty refs: ${toErrorMessage(err)}`
|
|
5230
5103
|
);
|
|
5231
5104
|
return emptyRefs();
|
|
@@ -5233,7 +5106,7 @@ function readPoolRefs(poolDir, fs19) {
|
|
|
5233
5106
|
if (typeof parsed !== "object" || parsed === null) return emptyRefs();
|
|
5234
5107
|
const obj = parsed;
|
|
5235
5108
|
if (obj.v !== REFS_VERSION || typeof obj.refs !== "object" || obj.refs === null) {
|
|
5236
|
-
|
|
5109
|
+
logger14.warn(`[pool-manager] refs.json unexpected shape for ${poolDir}, starting from empty refs`);
|
|
5237
5110
|
return emptyRefs();
|
|
5238
5111
|
}
|
|
5239
5112
|
const refs = {};
|
|
@@ -5267,7 +5140,7 @@ function releasePoolRef(dataDir, engineId, poolKey, taskId, fs19 = nodeFs) {
|
|
|
5267
5140
|
removeJournalFile(dataDir, engineId, poolKey, taskId, fs19);
|
|
5268
5141
|
const file = readPoolRefs(poolDir, fs19);
|
|
5269
5142
|
if (file.refs[taskId] === void 0) {
|
|
5270
|
-
|
|
5143
|
+
logger14.debug(`[pool-manager] release without live ref, skip pool deletion: ${poolDir} (${taskId})`);
|
|
5271
5144
|
return;
|
|
5272
5145
|
}
|
|
5273
5146
|
delete file.refs[taskId];
|
|
@@ -5360,7 +5233,7 @@ function removeOrphanJournals(poolDir, file, entries, ttlMs, fs19, now) {
|
|
|
5360
5233
|
changed = true;
|
|
5361
5234
|
}
|
|
5362
5235
|
} catch (err) {
|
|
5363
|
-
|
|
5236
|
+
logger14.debug(
|
|
5364
5237
|
`[pool-manager] ttl cleanup stat failed for ${journalPath}: ${toErrorMessage(err)}`
|
|
5365
5238
|
);
|
|
5366
5239
|
}
|
|
@@ -5375,7 +5248,7 @@ function unlinkBestEffort(path15, fs19) {
|
|
|
5375
5248
|
try {
|
|
5376
5249
|
fs19.rmSync(path15, { force: true, recursive: true });
|
|
5377
5250
|
} catch (err) {
|
|
5378
|
-
|
|
5251
|
+
logger14.debug(`[pool-manager] ttl cleanup failed for ${path15}: ${toErrorMessage(err)}`);
|
|
5379
5252
|
}
|
|
5380
5253
|
}
|
|
5381
5254
|
function isJournalFile(name) {
|
|
@@ -5416,14 +5289,14 @@ function deletePoolNativeState(poolDir, fs19) {
|
|
|
5416
5289
|
function markCleanupFailed(poolDir, failures, fs19) {
|
|
5417
5290
|
const marker = join11(poolDir, POOL_CLEANUP_FAILED_MARKER);
|
|
5418
5291
|
const payload = JSON.stringify({ ts: Date.now(), failures });
|
|
5419
|
-
|
|
5292
|
+
logger14.warn(
|
|
5420
5293
|
`[pool-manager] pool cleanup failed for ${poolDir} (${failures.length} item(s)); marker written to ${marker} \u2014 re-run cleanup after fixing the underlying error`
|
|
5421
5294
|
);
|
|
5422
5295
|
try {
|
|
5423
5296
|
fs19.writeFileSync(marker, `${payload}
|
|
5424
5297
|
`);
|
|
5425
5298
|
} catch (err) {
|
|
5426
|
-
|
|
5299
|
+
logger14.warn(
|
|
5427
5300
|
`[pool-manager] failed to write cleanup-failed marker ${marker}: ${toErrorMessage(err)}`
|
|
5428
5301
|
);
|
|
5429
5302
|
}
|
|
@@ -5441,7 +5314,7 @@ var nodeFs = {
|
|
|
5441
5314
|
};
|
|
5442
5315
|
|
|
5443
5316
|
// src/execution/idle-gc.ts
|
|
5444
|
-
var
|
|
5317
|
+
var logger15 = getLogger("subagents");
|
|
5445
5318
|
var GC_INTERVAL_MS = 60 * 60 * 1e3;
|
|
5446
5319
|
var IDLE_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
5447
5320
|
var MS_PER_DAY = 24 * 60 * 60 * 1e3;
|
|
@@ -5453,7 +5326,7 @@ function startIdleGc(store, workflowRuns) {
|
|
|
5453
5326
|
const anchorMs = record.idleSince ?? record.startedAt;
|
|
5454
5327
|
const age = now - anchorMs;
|
|
5455
5328
|
if (age > IDLE_TTL_MS) {
|
|
5456
|
-
|
|
5329
|
+
logger15.warn(
|
|
5457
5330
|
`[subagents] GC: archiving idle record ${record.id} (idle for ${Math.round(age / MS_PER_DAY)}d)`
|
|
5458
5331
|
);
|
|
5459
5332
|
try {
|
|
@@ -5476,7 +5349,7 @@ async function gcWorkflowRuns(workflowRuns, now) {
|
|
|
5476
5349
|
try {
|
|
5477
5350
|
runs = await workflowRuns.loadAll();
|
|
5478
5351
|
} catch (err) {
|
|
5479
|
-
|
|
5352
|
+
logger15.debug(`[subagents] GC: workflow run store loadAll failed (skipped this cycle): ${err instanceof Error ? err.message : String(err)}`);
|
|
5480
5353
|
return;
|
|
5481
5354
|
}
|
|
5482
5355
|
for (const run of runs) {
|
|
@@ -5485,7 +5358,7 @@ async function gcWorkflowRuns(workflowRuns, now) {
|
|
|
5485
5358
|
if (!Number.isFinite(startedMs)) continue;
|
|
5486
5359
|
const age = now - startedMs;
|
|
5487
5360
|
if (age <= IDLE_TTL_MS) continue;
|
|
5488
|
-
|
|
5361
|
+
logger15.warn(
|
|
5489
5362
|
`[subagents] GC: terminating stale running workflow run ${run.runId} (started ${Math.round(age / MS_PER_DAY)}d ago)`
|
|
5490
5363
|
);
|
|
5491
5364
|
try {
|
|
@@ -6015,7 +5888,7 @@ function fromRunSnapshot(snap) {
|
|
|
6015
5888
|
}
|
|
6016
5889
|
|
|
6017
5890
|
// src/orchestration/file-run-store.ts
|
|
6018
|
-
var
|
|
5891
|
+
var logger16 = getLogger("file-run-store");
|
|
6019
5892
|
var STATE_DIR_NAME = "workflow-state";
|
|
6020
5893
|
var STATE_FILE_GLOB = /^wf-.*\.jsonl$/;
|
|
6021
5894
|
var DEFAULT_STATE_MAX_RUNS = 50;
|
|
@@ -6161,7 +6034,7 @@ var FileRunStore = class {
|
|
|
6161
6034
|
content = await readFile2(absPath, "utf8");
|
|
6162
6035
|
} catch (err) {
|
|
6163
6036
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6164
|
-
|
|
6037
|
+
logger16.warn(`[file-run-store] skip unreadable state file ${display}: ${msg}`);
|
|
6165
6038
|
return void 0;
|
|
6166
6039
|
}
|
|
6167
6040
|
const lines = content.split("\n");
|
|
@@ -6171,7 +6044,7 @@ var FileRunStore = class {
|
|
|
6171
6044
|
const run = this.parseLine(line, display, i);
|
|
6172
6045
|
if (run) return run;
|
|
6173
6046
|
}
|
|
6174
|
-
|
|
6047
|
+
logger16.warn(`[file-run-store] no valid snapshot line in ${display} (empty or all corrupted)`);
|
|
6175
6048
|
return void 0;
|
|
6176
6049
|
}
|
|
6177
6050
|
/**
|
|
@@ -6193,7 +6066,7 @@ var FileRunStore = class {
|
|
|
6193
6066
|
parsed = JSON.parse(line);
|
|
6194
6067
|
} catch (err) {
|
|
6195
6068
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6196
|
-
|
|
6069
|
+
logger16.warn(`[file-run-store] skip corrupted line ${display}:${lineNo}: ${msg}`);
|
|
6197
6070
|
return void 0;
|
|
6198
6071
|
}
|
|
6199
6072
|
if (parsed !== null && typeof parsed === "object") {
|
|
@@ -6201,7 +6074,7 @@ var FileRunStore = class {
|
|
|
6201
6074
|
if (rec.v === void 0) {
|
|
6202
6075
|
rec.v = SNAPSHOT_VERSION;
|
|
6203
6076
|
} else if (rec.v !== SNAPSHOT_VERSION) {
|
|
6204
|
-
|
|
6077
|
+
logger16.warn(
|
|
6205
6078
|
`[file-run-store] skip snapshot with unsupported version ${display}:${lineNo}: v=${JSON.stringify(rec.v)} (this build only reads v=${JSON.stringify(SNAPSHOT_VERSION)}; the run line is skipped). To recover: upgrade @zhushanwen/subagent-core, or migrate/delete this state file if its runs are no longer needed`
|
|
6206
6079
|
);
|
|
6207
6080
|
return void 0;
|
|
@@ -6209,7 +6082,7 @@ var FileRunStore = class {
|
|
|
6209
6082
|
}
|
|
6210
6083
|
const run = fromRunSnapshot(parsed);
|
|
6211
6084
|
if (run === void 0) {
|
|
6212
|
-
|
|
6085
|
+
logger16.warn(`[file-run-store] skip malformed snapshot ${display}:${lineNo} (shape validation failed)`);
|
|
6213
6086
|
return void 0;
|
|
6214
6087
|
}
|
|
6215
6088
|
return run;
|
|
@@ -6249,8 +6122,8 @@ var FileRunStore = class {
|
|
|
6249
6122
|
}
|
|
6250
6123
|
}
|
|
6251
6124
|
await pruneStateFilesBeyondCap(this.stateDir(), cap, {
|
|
6252
|
-
warn: (msg) =>
|
|
6253
|
-
debug: (msg) =>
|
|
6125
|
+
warn: (msg) => logger16.warn(`[file-run-store] ${msg}`),
|
|
6126
|
+
debug: (msg) => logger16.debug(`[file-run-store] ${msg}`),
|
|
6254
6127
|
toMsg: (err) => err instanceof Error ? err.message : String(err)
|
|
6255
6128
|
});
|
|
6256
6129
|
}
|
|
@@ -6312,7 +6185,7 @@ function classifyReplacement(subject, candidates, windowMs, now) {
|
|
|
6312
6185
|
|
|
6313
6186
|
// src/execution/round-supervisor/reconcile-sweep.ts
|
|
6314
6187
|
import * as fs13 from "fs";
|
|
6315
|
-
var
|
|
6188
|
+
var logger17 = getLogger("subagents");
|
|
6316
6189
|
function runReconcileSweep(deps) {
|
|
6317
6190
|
const result = {
|
|
6318
6191
|
reconciled: [],
|
|
@@ -6325,7 +6198,7 @@ function runReconcileSweep(deps) {
|
|
|
6325
6198
|
sweepSingleRegister(deps, entry, result);
|
|
6326
6199
|
}
|
|
6327
6200
|
if (result.reconciled.length > 0) {
|
|
6328
|
-
|
|
6201
|
+
logger17.warn(
|
|
6329
6202
|
`[subagents] reconcile sweep re-emitted ${result.reconciled.length} unregister(s) for terminal/missing records: ${result.reconciled.join(",")}`
|
|
6330
6203
|
);
|
|
6331
6204
|
}
|
|
@@ -6353,7 +6226,7 @@ function reemitUnregister(deps, id, state, result) {
|
|
|
6353
6226
|
try {
|
|
6354
6227
|
deps.appendEntry?.("pending:unregister", { id, reason, status: reason });
|
|
6355
6228
|
} catch (err) {
|
|
6356
|
-
|
|
6229
|
+
logger17.warn(
|
|
6357
6230
|
`[subagents] reconcile sweep appendEntry failed for ${id} (retry on next sweep): ${err instanceof Error ? err.message : String(err)}`
|
|
6358
6231
|
);
|
|
6359
6232
|
return;
|
|
@@ -6361,7 +6234,7 @@ function reemitUnregister(deps, id, state, result) {
|
|
|
6361
6234
|
try {
|
|
6362
6235
|
deps.emit?.("pending:unregister", { id, reason });
|
|
6363
6236
|
} catch (err) {
|
|
6364
|
-
|
|
6237
|
+
logger17.debug(
|
|
6365
6238
|
`[subagents] reconcile sweep best-effort emit failed (harmless) for ${id}: ${err instanceof Error ? err.message : String(err)}`
|
|
6366
6239
|
);
|
|
6367
6240
|
}
|
|
@@ -6406,7 +6279,7 @@ function collectActiveRegisterEntries(sessionFile) {
|
|
|
6406
6279
|
}
|
|
6407
6280
|
|
|
6408
6281
|
// src/execution/round-supervisor/supervisor.ts
|
|
6409
|
-
var
|
|
6282
|
+
var logger18 = getLogger("subagents");
|
|
6410
6283
|
var MS_PER_HOUR = 36e5;
|
|
6411
6284
|
var WATCHDOG_DEFAULT_HOURS = 2;
|
|
6412
6285
|
var ROUND_SUPERVISOR_WATCHDOG_DEFAULT_MS = WATCHDOG_DEFAULT_HOURS * MS_PER_HOUR;
|
|
@@ -6419,13 +6292,13 @@ function resolveWatchdogEnv() {
|
|
|
6419
6292
|
if (raw === void 0 || raw.trim() === "") return watchdogEnvCache;
|
|
6420
6293
|
const parsed = Number(raw);
|
|
6421
6294
|
if (!Number.isFinite(parsed)) {
|
|
6422
|
-
|
|
6295
|
+
logger18.warn(
|
|
6423
6296
|
`[round-supervisor] ${ROUND_SUPERVISOR_WATCHDOG_ENV}="${raw}" is invalid \u2014 falling back to default decision watchdog window (${ROUND_SUPERVISOR_WATCHDOG_DEFAULT_MS}ms)`
|
|
6424
6297
|
);
|
|
6425
6298
|
return watchdogEnvCache;
|
|
6426
6299
|
}
|
|
6427
6300
|
if (parsed <= 0) {
|
|
6428
|
-
|
|
6301
|
+
logger18.warn(
|
|
6429
6302
|
`[round-supervisor] ${ROUND_SUPERVISOR_WATCHDOG_ENV}=${parsed} disables the give-up path: a dead background task stays resumable and registered forever (goal guard keeps deferring). Recovery: unset the env or set a positive millisecond value.`
|
|
6430
6303
|
);
|
|
6431
6304
|
watchdogEnvCache.disabled = true;
|
|
@@ -6501,7 +6374,7 @@ var RoundSupervisor = class {
|
|
|
6501
6374
|
this.evaluate(view.id);
|
|
6502
6375
|
}
|
|
6503
6376
|
if (readopted.length > 0) {
|
|
6504
|
-
|
|
6377
|
+
logger18.warn(
|
|
6505
6378
|
`[round-supervisor] boot partition: readopted ${readopted.length} idle-resumable record(s): ${readopted.join(",")}`
|
|
6506
6379
|
);
|
|
6507
6380
|
}
|
|
@@ -6569,7 +6442,7 @@ var RoundSupervisor = class {
|
|
|
6569
6442
|
this.deps.now()
|
|
6570
6443
|
);
|
|
6571
6444
|
if (verdict.kind === "high-confidence") {
|
|
6572
|
-
|
|
6445
|
+
logger18.warn(
|
|
6573
6446
|
`[round-supervisor] record ${view.id} superseded by ${verdict.replacementId} (same root/agent/slug within watchdog window) \u2014 withdrawing guidance, giving up original`
|
|
6574
6447
|
);
|
|
6575
6448
|
this.release(recordId);
|
|
@@ -6596,7 +6469,7 @@ var RoundSupervisor = class {
|
|
|
6596
6469
|
this.supervised.delete(recordId);
|
|
6597
6470
|
const view = this.deps.getRecordView(recordId);
|
|
6598
6471
|
if (view === void 0 || view.status !== "running") return;
|
|
6599
|
-
|
|
6472
|
+
logger18.warn(
|
|
6600
6473
|
`[round-supervisor] decision watchdog expired for ${recordId} after ${windowMs}ms (guidance unanswered, no convergence) \u2014 giving up (failed + unregister + termination notice)`
|
|
6601
6474
|
);
|
|
6602
6475
|
this.deps.giveUp(recordId, "watchdog-expired", {});
|
|
@@ -6877,7 +6750,7 @@ function createBackgroundStream(recordId, sink, mode, env) {
|
|
|
6877
6750
|
}
|
|
6878
6751
|
|
|
6879
6752
|
// src/execution/ui-request-observability.ts
|
|
6880
|
-
var
|
|
6753
|
+
var logger19 = getLogger("subagents");
|
|
6881
6754
|
var GLOBAL_OBSERVABILITY_KEY = /* @__PURE__ */ Symbol.for("pi-subagent-workflow.ui-observability");
|
|
6882
6755
|
function registerGlobalObservability(obs) {
|
|
6883
6756
|
globalThis[GLOBAL_OBSERVABILITY_KEY] = obs;
|
|
@@ -6905,7 +6778,7 @@ var UiRequestObservability = class {
|
|
|
6905
6778
|
this.warnedMissingHandlerSessions.clear();
|
|
6906
6779
|
}
|
|
6907
6780
|
this.warnedMissingHandlerSessions.add(sessionId);
|
|
6908
|
-
|
|
6781
|
+
logger19.warn(`[subagents] uiRequestHandler missing (session=${sessionId}, mode=${this.sessionMode})`);
|
|
6909
6782
|
}
|
|
6910
6783
|
};
|
|
6911
6784
|
|
|
@@ -6920,7 +6793,7 @@ import * as path11 from "path";
|
|
|
6920
6793
|
import * as fs14 from "fs";
|
|
6921
6794
|
import * as path10 from "path";
|
|
6922
6795
|
import lockfile from "proper-lockfile";
|
|
6923
|
-
var
|
|
6796
|
+
var logger20 = getLogger("subagents");
|
|
6924
6797
|
var SPAWN_GRACE_MS = 6e4;
|
|
6925
6798
|
var JSON_INDENT2 = 2;
|
|
6926
6799
|
var LOCK_STALE_MS = 3e4;
|
|
@@ -7003,7 +6876,7 @@ var WorktreeRegistry = class {
|
|
|
7003
6876
|
run();
|
|
7004
6877
|
});
|
|
7005
6878
|
} catch (lockErr) {
|
|
7006
|
-
|
|
6879
|
+
logger20.warn("[worktree] registry lock unavailable, degraded to lock-free RMW", {
|
|
7007
6880
|
...context ?? {},
|
|
7008
6881
|
err: lockErr instanceof Error ? lockErr.message : String(lockErr)
|
|
7009
6882
|
});
|
|
@@ -7016,9 +6889,11 @@ var WorktreeRegistry = class {
|
|
|
7016
6889
|
}
|
|
7017
6890
|
/**
|
|
7018
6891
|
* proper-lockfile 直用的跨进程锁(取代已删除的共享 file-lock 包装,抽包去依赖)。
|
|
7019
|
-
*
|
|
7020
|
-
*
|
|
7021
|
-
*
|
|
6892
|
+
* 锁协议对齐现存三方同协议实现——runtime 侧 packages/runtime/src/utils/file-lock.ts
|
|
6893
|
+
* 的 withFileLockAsync(范本 pi FileAuthStorageBackend,参数对齐 proper-lockfile
|
|
6894
|
+
* 内部 retry 库)与 extension 侧 @zhushanwen/pi-file-lock:
|
|
6895
|
+
* - lockfile 路径 = <目标文件>.lock(proper-lockfile 默认,与 runtime 侧/
|
|
6896
|
+
* extension 侧同一路径才互斥)
|
|
7022
6897
|
* - realpath:false —— 目标文件不存在也可锁(realpath 默认 true 时 ENOENT)
|
|
7023
6898
|
* - stale 30s:持锁进程崩溃后锁可被夺取
|
|
7024
6899
|
* - async retries 指数退避:10 次 / factor 2 / 100ms~10s / randomize,耗尽抛
|
|
@@ -7052,7 +6927,7 @@ var WorktreeRegistry = class {
|
|
|
7052
6927
|
try {
|
|
7053
6928
|
await release();
|
|
7054
6929
|
} catch (unlockErr) {
|
|
7055
|
-
|
|
6930
|
+
logger20.debug("unlock failed after compromise (ignorable)", {
|
|
7056
6931
|
detail: { err: unlockErr instanceof Error ? unlockErr.message : String(unlockErr) }
|
|
7057
6932
|
});
|
|
7058
6933
|
}
|
|
@@ -7087,7 +6962,7 @@ var WorktreeRegistry = class {
|
|
|
7087
6962
|
writeAtomicFileSync(this.filePath, JSON.stringify({ entries }, null, JSON_INDENT2));
|
|
7088
6963
|
} catch (err) {
|
|
7089
6964
|
bestEffort(err, "worktree registry save");
|
|
7090
|
-
|
|
6965
|
+
logger20.warn(
|
|
7091
6966
|
"[worktree] registry save failed; pid may stay 0 and be reaped by orphan reaper",
|
|
7092
6967
|
{ ...context ?? {}, err: err instanceof Error ? err.message : String(err) }
|
|
7093
6968
|
);
|
|
@@ -7096,7 +6971,7 @@ var WorktreeRegistry = class {
|
|
|
7096
6971
|
};
|
|
7097
6972
|
|
|
7098
6973
|
// src/execution/worktree-manager.ts
|
|
7099
|
-
var
|
|
6974
|
+
var logger21 = getLogger("subagents");
|
|
7100
6975
|
var SAFE_ID_RE = /^[\w-]+$/;
|
|
7101
6976
|
var GIT_TIMEOUT_MS = 3e4;
|
|
7102
6977
|
var WORKTREE_TMP_ROOT = "pi-subagents";
|
|
@@ -7355,7 +7230,7 @@ ${statusText}`
|
|
|
7355
7230
|
const branchGone = !branches.has(entry.branch);
|
|
7356
7231
|
const checkoutGone = !fs15.existsSync(entry.checkout);
|
|
7357
7232
|
if (branchGone && checkoutGone) {
|
|
7358
|
-
|
|
7233
|
+
logger21.warn("[worktree] reconcile: registry entry has no physical worktree/branch, removing entry", {
|
|
7359
7234
|
branch: entry.branch,
|
|
7360
7235
|
repo: entry.repo,
|
|
7361
7236
|
pid: entry.pid
|
|
@@ -7399,7 +7274,7 @@ ${statusText}`
|
|
|
7399
7274
|
}
|
|
7400
7275
|
if (alivePids.length === 1 && list.length === 1) {
|
|
7401
7276
|
const pt = list[0];
|
|
7402
|
-
|
|
7277
|
+
logger21.warn("[worktree] reconcile: unregistered physical worktree with one alive pid, re-registering (self-heal)", {
|
|
7403
7278
|
branch: pt.branch,
|
|
7404
7279
|
checkout: pt.checkout,
|
|
7405
7280
|
repo: pt.repo,
|
|
@@ -7422,7 +7297,7 @@ ${statusText}`
|
|
|
7422
7297
|
if (cycles < RECONCILE_SKIP_ESCALATION_CYCLES) continue;
|
|
7423
7298
|
escalated++;
|
|
7424
7299
|
const repoHint = pt.repo ?? "<main-repo>";
|
|
7425
|
-
|
|
7300
|
+
logger21.warn(
|
|
7426
7301
|
`[worktree] reconcile: unregistered physical worktree skipped for ${cycles} consecutive cycles (alive-pid mapping still ambiguous) \u2014 manual cleanup may be needed. Inspect: git -C ${repoHint} worktree list. If no live process owns it: git -C ${repoHint} worktree remove --force ${pt.checkout} && git -C ${repoHint} branch -D ${pt.branch}. Ownerless checkout (repo unknown, delete the directory directly): rm -rf ${pt.checkout}`,
|
|
7427
7302
|
{
|
|
7428
7303
|
branch: pt.branch,
|
|
@@ -7433,7 +7308,7 @@ ${statusText}`
|
|
|
7433
7308
|
);
|
|
7434
7309
|
}
|
|
7435
7310
|
if (escalated < list.length) {
|
|
7436
|
-
|
|
7311
|
+
logger21.warn("[worktree] reconcile: unregistered physical worktrees present but alive-pid mapping ambiguous, skipping this cycle", {
|
|
7437
7312
|
enc,
|
|
7438
7313
|
orphans: list.length - escalated,
|
|
7439
7314
|
alivePids: alivePids.length
|
|
@@ -7446,7 +7321,7 @@ ${statusText}`
|
|
|
7446
7321
|
for (const pt of list) {
|
|
7447
7322
|
const age = Date.now() - pt.mtimeMs;
|
|
7448
7323
|
if (age <= SPAWN_GRACE_MS) continue;
|
|
7449
|
-
|
|
7324
|
+
logger21.warn("[worktree] reconcile: unregistered physical worktree with no alive pid, cleaning up", {
|
|
7450
7325
|
branch: pt.branch,
|
|
7451
7326
|
checkout: pt.checkout,
|
|
7452
7327
|
repo: pt.repo,
|
|
@@ -7574,7 +7449,7 @@ ${statusText}`
|
|
|
7574
7449
|
if (entry.pid === 0) {
|
|
7575
7450
|
const expired = now - entry.createdAt > SPAWN_GRACE_MS;
|
|
7576
7451
|
if (expired) {
|
|
7577
|
-
|
|
7452
|
+
logger21.warn(
|
|
7578
7453
|
"[worktree] orphan reaper: pid=0 entry exceeded SPAWN_GRACE_MS, treating as orphan",
|
|
7579
7454
|
{ branch: entry.branch, checkout: entry.checkout, createdAt: entry.createdAt, now }
|
|
7580
7455
|
);
|
|
@@ -7658,11 +7533,11 @@ ${statusText}`
|
|
|
7658
7533
|
};
|
|
7659
7534
|
|
|
7660
7535
|
// src/execution/subagent-service.ts
|
|
7661
|
-
var
|
|
7536
|
+
var logger22 = getLogger("subagents");
|
|
7662
7537
|
var disposedUiRequestStub = () => Promise.resolve({ cancelled: true });
|
|
7663
7538
|
var PRIORITY_BACKGROUND = 1e3;
|
|
7664
|
-
var
|
|
7665
|
-
var
|
|
7539
|
+
var MS_PER_SECOND4 = 1e3;
|
|
7540
|
+
var SECONDS_PER_MINUTE3 = 60;
|
|
7666
7541
|
var NOTIFY_BLOCKED_CLOSED_REASONS = /* @__PURE__ */ new Set(["parent-new", "parent-fork"]);
|
|
7667
7542
|
function notifyGateAllowsDelivery(closedReason) {
|
|
7668
7543
|
if (closedReason === void 0) return true;
|
|
@@ -7945,7 +7820,7 @@ var SubagentService = class {
|
|
|
7945
7820
|
this.execNesting.setBaseline({ recordId: envSelfRecord, depth: nestingDepth });
|
|
7946
7821
|
this.execNesting.enterWith({ recordId: envSelfRecord, depth: nestingDepth });
|
|
7947
7822
|
if (process.env.XYZ_AGENT_DEBUG) {
|
|
7948
|
-
|
|
7823
|
+
logger22.debug(
|
|
7949
7824
|
`[subagents] execNesting initialized: recordId=${envSelfRecord} depth=${nestingDepth} rootSessionId=${envRoot ?? sessionId}`
|
|
7950
7825
|
);
|
|
7951
7826
|
}
|
|
@@ -7969,7 +7844,7 @@ var SubagentService = class {
|
|
|
7969
7844
|
if (!isChildProcess) {
|
|
7970
7845
|
this.recoverOrphanRecords();
|
|
7971
7846
|
} else if (process.env.XYZ_AGENT_DEBUG) {
|
|
7972
|
-
|
|
7847
|
+
logger22.debug("[subagents] child process detected (PI_SUBAGENT_SELF_RECORD_ID set), skipping orphan recovery scan");
|
|
7973
7848
|
}
|
|
7974
7849
|
}
|
|
7975
7850
|
/** 孤儿终态恢复委托(RecordStore.recoverOrphanRecords 的唯一调用入口,维持 store
|
|
@@ -7983,14 +7858,14 @@ var SubagentService = class {
|
|
|
7983
7858
|
try {
|
|
7984
7859
|
this.store.recoverOrphanRecords(this.sessionRootId ?? void 0, this.mainSessionFile);
|
|
7985
7860
|
} catch (err) {
|
|
7986
|
-
|
|
7861
|
+
logger22.warn("[subagents] orphan recovery failed", {
|
|
7987
7862
|
reason: toErrorMessage(err)
|
|
7988
7863
|
});
|
|
7989
7864
|
}
|
|
7990
7865
|
try {
|
|
7991
7866
|
this.store.recoverEntryOnlyOrphans(this.mainSessionFile, this.sessionRootId ?? void 0);
|
|
7992
7867
|
} catch (err) {
|
|
7993
|
-
|
|
7868
|
+
logger22.warn("[subagents] entry-only orphan recovery failed", {
|
|
7994
7869
|
reason: toErrorMessage(err)
|
|
7995
7870
|
});
|
|
7996
7871
|
}
|
|
@@ -8058,6 +7933,7 @@ var SubagentService = class {
|
|
|
8058
7933
|
this.notifyHost.emitPendingUnregister(record.id, "closed");
|
|
8059
7934
|
count++;
|
|
8060
7935
|
}
|
|
7936
|
+
notifyInFlightChanged();
|
|
8061
7937
|
return count;
|
|
8062
7938
|
}
|
|
8063
7939
|
/** SP-4: /fork 新 session 时清理旧 record。
|
|
@@ -8118,7 +7994,7 @@ var SubagentService = class {
|
|
|
8118
7994
|
if (!full) continue;
|
|
8119
7995
|
this.appendBatchFinalizedEntry(full);
|
|
8120
7996
|
void this.writeBatchMemberManifest(full).catch((err) => {
|
|
8121
|
-
|
|
7997
|
+
logger22.debug(
|
|
8122
7998
|
`[subagents] batch-finalized manifest write failed (record=${full.id})`,
|
|
8123
7999
|
{ reason: err instanceof Error ? err.message : String(err) }
|
|
8124
8000
|
);
|
|
@@ -8173,7 +8049,7 @@ var SubagentService = class {
|
|
|
8173
8049
|
for (let i = 0; i < results.length; i++) {
|
|
8174
8050
|
const result = results[i];
|
|
8175
8051
|
if (result.status === "rejected") {
|
|
8176
|
-
|
|
8052
|
+
logger22.warn(
|
|
8177
8053
|
`[subagents] batch-finalized manifest write failed (record=${recs[i].id}, manifest=${this.recordsDir}/${recs[i].id}.json)`,
|
|
8178
8054
|
{ reason: result.reason instanceof Error ? result.reason.message : String(result.reason) }
|
|
8179
8055
|
);
|
|
@@ -8195,7 +8071,7 @@ var SubagentService = class {
|
|
|
8195
8071
|
this.notifyHost.notify(member);
|
|
8196
8072
|
}
|
|
8197
8073
|
this.markMembersBatchFinalized(members.map((m) => m.id));
|
|
8198
|
-
|
|
8074
|
+
logger22.warn(
|
|
8199
8075
|
`[subagents] E9 dispose: converted ${members.length} buffered sync member(s) to async notify`,
|
|
8200
8076
|
{ ids: members.map((m) => m.id) }
|
|
8201
8077
|
);
|
|
@@ -8237,7 +8113,7 @@ var SubagentService = class {
|
|
|
8237
8113
|
this.armSettledRescan();
|
|
8238
8114
|
}
|
|
8239
8115
|
} catch (err) {
|
|
8240
|
-
|
|
8116
|
+
logger22.warn("[subagents] sync collect batch recovery failed", {
|
|
8241
8117
|
reason: err instanceof Error ? err.message : String(err)
|
|
8242
8118
|
});
|
|
8243
8119
|
}
|
|
@@ -8257,7 +8133,7 @@ var SubagentService = class {
|
|
|
8257
8133
|
if (candidates.length === 0) return { outcome: "idle", waitingIds: [] };
|
|
8258
8134
|
const running = candidates.filter((r) => r.resumable !== true && r.status !== "closed");
|
|
8259
8135
|
if (running.length > 0) {
|
|
8260
|
-
|
|
8136
|
+
logger22.debug(
|
|
8261
8137
|
`[subagents] E1 sync batch recovery: ${running.length} member(s) still running, wait for natural completion`,
|
|
8262
8138
|
{ ids: running.map((r) => r.id) }
|
|
8263
8139
|
);
|
|
@@ -8269,7 +8145,7 @@ var SubagentService = class {
|
|
|
8269
8145
|
for (const rec of candidates) {
|
|
8270
8146
|
this.appendBatchFinalizedEntry(rec);
|
|
8271
8147
|
}
|
|
8272
|
-
|
|
8148
|
+
logger22.warn(
|
|
8273
8149
|
`[subagents] E1 sync batch recovery: re-notified ${members.length} member(s) (ledger accepted=${accepted})`,
|
|
8274
8150
|
{ ids: members.map((m) => m.id) }
|
|
8275
8151
|
);
|
|
@@ -8299,7 +8175,7 @@ var SubagentService = class {
|
|
|
8299
8175
|
if (outcome === "waiting" && state.scans < SETTLED_RESCAN_LIMIT) return;
|
|
8300
8176
|
state.disposed = true;
|
|
8301
8177
|
if (outcome === "waiting") {
|
|
8302
|
-
|
|
8178
|
+
logger22.warn(
|
|
8303
8179
|
`[subagents] E1 settled rescan: reached limit (${SETTLED_RESCAN_LIMIT}) with member(s) still running, disposed until next session_start`,
|
|
8304
8180
|
{ ids: waitingIds }
|
|
8305
8181
|
);
|
|
@@ -8356,7 +8232,7 @@ var SubagentService = class {
|
|
|
8356
8232
|
record: item.record
|
|
8357
8233
|
});
|
|
8358
8234
|
}
|
|
8359
|
-
|
|
8235
|
+
logger22.warn(
|
|
8360
8236
|
`[subagents] shutdown flush blocked by busy main agent: ${pending.length} pending notification(s) persisted to ledger for replay on next session_start`,
|
|
8361
8237
|
{ count: pending.length }
|
|
8362
8238
|
);
|
|
@@ -8485,6 +8361,7 @@ var SubagentService = class {
|
|
|
8485
8361
|
);
|
|
8486
8362
|
}
|
|
8487
8363
|
disarmIdleTimer(record.id);
|
|
8364
|
+
notifyInFlightChanged();
|
|
8488
8365
|
const engine = this.resolveChatEnginePort();
|
|
8489
8366
|
if (!this.chatRoundRoutes.has(record.id)) {
|
|
8490
8367
|
this.chatRoundRoutes.set(
|
|
@@ -8613,11 +8490,12 @@ var SubagentService = class {
|
|
|
8613
8490
|
* fire-and-forget 且 catch 归 bestEffort——错误逃出回调 = uncaughtException 崩宿主。
|
|
8614
8491
|
*/
|
|
8615
8492
|
onHotPathSettledWatchdogTimeout(record, fire) {
|
|
8616
|
-
const windowDesc = fire.phase === "mid-round" ? `no valid protocol event for ${fire.waitedMs /
|
|
8617
|
-
|
|
8493
|
+
const windowDesc = fire.phase === "mid-round" ? `no valid protocol event for ${fire.waitedMs / MS_PER_SECOND4 / SECONDS_PER_MINUTE3} min after prompt (mid-round no-progress)` : `no agent_settled within ${fire.waitedMs / MS_PER_SECOND4}s after agent_end (settled phase)`;
|
|
8494
|
+
logger22.warn(
|
|
8618
8495
|
`[subagents] settled watchdog (${fire.phase}) fired for ${record.id}: ${windowDesc}, terminating (LC-1 wedge recovery)`
|
|
8619
8496
|
);
|
|
8620
8497
|
killRecordChildWithEscalation(record.id, "settled watchdog (hot path)");
|
|
8498
|
+
notifyInFlightChanged();
|
|
8621
8499
|
this.terminateChatSession(record, "cancel", "settled watchdog (hot path)");
|
|
8622
8500
|
const failedResult = {
|
|
8623
8501
|
text: "",
|
|
@@ -8730,6 +8608,7 @@ var SubagentService = class {
|
|
|
8730
8608
|
*/
|
|
8731
8609
|
async closeChatIdle(record) {
|
|
8732
8610
|
disarmIdleTimer(record.id);
|
|
8611
|
+
notifyInFlightChanged();
|
|
8733
8612
|
disarmSettledWatchdog(record.id);
|
|
8734
8613
|
disarmRoundFromProtocol(record.id);
|
|
8735
8614
|
killRecordChildWithEscalation(record.id, "closeChatIdle");
|
|
@@ -8778,6 +8657,7 @@ var SubagentService = class {
|
|
|
8778
8657
|
*/
|
|
8779
8658
|
async closeAfterRoundSettled(record) {
|
|
8780
8659
|
disarmIdleTimer(record.id);
|
|
8660
|
+
notifyInFlightChanged();
|
|
8781
8661
|
disarmSettledWatchdog(record.id);
|
|
8782
8662
|
disarmRoundFromProtocol(record.id);
|
|
8783
8663
|
killRecordChildWithEscalation(record.id, "closeAfterRoundSettled");
|
|
@@ -9406,7 +9286,7 @@ var SubagentService = class {
|
|
|
9406
9286
|
await this.finalizeFailed(record, err);
|
|
9407
9287
|
}
|
|
9408
9288
|
if (err instanceof Error) {
|
|
9409
|
-
|
|
9289
|
+
logger22.debug(`[subagent] chat round run error (record=${record.id}): ${err.message}`);
|
|
9410
9290
|
}
|
|
9411
9291
|
} finally {
|
|
9412
9292
|
this.pool.release();
|
|
@@ -9460,13 +9340,14 @@ var SubagentService = class {
|
|
|
9460
9340
|
bestEffort(err, "armIdleTimer (chat idle phase)", "error");
|
|
9461
9341
|
try {
|
|
9462
9342
|
armIdleTimer(record.id, onTimeout, DEFAULT_IDLE_TIMEOUT_MS);
|
|
9463
|
-
|
|
9343
|
+
logger22.warn(
|
|
9464
9344
|
`[subagents] idleTimeoutMs invalid for ${record.id}, fell back to DEFAULT_IDLE_TIMEOUT_MS (${DEFAULT_IDLE_TIMEOUT_MS}ms) \u2014 idle GC and round notification gate stay active`
|
|
9465
9345
|
);
|
|
9466
9346
|
} catch (fallbackErr) {
|
|
9467
9347
|
bestEffort(fallbackErr, "armIdleTimer fallback (chat idle phase)", "error");
|
|
9468
9348
|
}
|
|
9469
9349
|
}
|
|
9350
|
+
notifyInFlightChanged();
|
|
9470
9351
|
}
|
|
9471
9352
|
/** [W3] idle 帧锚点回填(冷续锚点 = 引擎侧会话滚动/compaction 后的最新定位)。 */
|
|
9472
9353
|
backfillChatAnchor(record, anchor) {
|
|
@@ -9542,7 +9423,7 @@ var SubagentService = class {
|
|
|
9542
9423
|
const handle = this.chatHandleFor(record);
|
|
9543
9424
|
const result = kind === "cancel" ? await engine.interact(handle, { kind: "cancel" }) : await engine.interact(handle, { kind: "close", payload: { force: true } });
|
|
9544
9425
|
if (!result.ok) {
|
|
9545
|
-
|
|
9426
|
+
logger22.debug(
|
|
9546
9427
|
`[subagents] terminateChatSession (${kind}, ${source}) rejected for ${record.id}: ${result.message}`
|
|
9547
9428
|
);
|
|
9548
9429
|
}
|
|
@@ -9613,6 +9494,7 @@ var SubagentService = class {
|
|
|
9613
9494
|
record.controller?.abort();
|
|
9614
9495
|
killRecordChildWithEscalation(record.id, "cancelBackground");
|
|
9615
9496
|
disarmIdleTimer(record.id);
|
|
9497
|
+
notifyInFlightChanged();
|
|
9616
9498
|
disarmSettledWatchdog(record.id);
|
|
9617
9499
|
disarmRoundFromProtocol(record.id);
|
|
9618
9500
|
this.unregisterChatRoundRoute(record.id);
|
|
@@ -9790,7 +9672,7 @@ import * as fsSync2 from "fs";
|
|
|
9790
9672
|
import { access, readdir as readdir2, readFile as readFile3, realpath, stat as stat2 } from "fs/promises";
|
|
9791
9673
|
import { homedir as homedir3 } from "os";
|
|
9792
9674
|
import { delimiter, join as join16, resolve as resolve3 } from "path";
|
|
9793
|
-
var
|
|
9675
|
+
var logger23 = getLogger("subagents");
|
|
9794
9676
|
var shadowWarnDedup = /* @__PURE__ */ new Set();
|
|
9795
9677
|
var MAX_SHADOW_WARN_DEDUP = 1024;
|
|
9796
9678
|
var MACHINE_SOURCES = /* @__PURE__ */ new Set([
|
|
@@ -10113,7 +9995,7 @@ async function discoverResources(config) {
|
|
|
10113
9995
|
const msg = `[resource-discovery] duplicate ${config.kind} "${key}" from ${r.source} shadows ${existing.source}`;
|
|
10114
9996
|
const data = { shadowed: existing.path, kept: r.path };
|
|
10115
9997
|
if (isMachineSource(existing.source) || isMachineSource(r.source)) {
|
|
10116
|
-
|
|
9998
|
+
logger23.debug(msg, data);
|
|
10117
9999
|
} else {
|
|
10118
10000
|
const dedupKey = `${config.kind}|${key}|${existing.path}|${r.path}`;
|
|
10119
10001
|
if (!shadowWarnDedup.has(dedupKey)) {
|
|
@@ -10121,7 +10003,7 @@ async function discoverResources(config) {
|
|
|
10121
10003
|
shadowWarnDedup.clear();
|
|
10122
10004
|
}
|
|
10123
10005
|
shadowWarnDedup.add(dedupKey);
|
|
10124
|
-
|
|
10006
|
+
logger23.warn(msg, data);
|
|
10125
10007
|
}
|
|
10126
10008
|
}
|
|
10127
10009
|
}
|
|
@@ -10762,7 +10644,7 @@ function lintScript(source) {
|
|
|
10762
10644
|
}
|
|
10763
10645
|
|
|
10764
10646
|
// src/execution/agent-registry.ts
|
|
10765
|
-
var
|
|
10647
|
+
var logger24 = getLogger("subagents");
|
|
10766
10648
|
var FM_DELIM = "---";
|
|
10767
10649
|
function parseAgentWithMeta(filePath, content) {
|
|
10768
10650
|
const name = path12.basename(filePath, ".md");
|
|
@@ -10795,7 +10677,7 @@ function resolveLegacyRoutingFallbacks(agentMeta, yamlBlock, filePath) {
|
|
|
10795
10677
|
const modelFallback = extractYamlField(yamlBlock, "model");
|
|
10796
10678
|
const toolsFallback = parseCommaListFallback(extractYamlField(yamlBlock, "tools"));
|
|
10797
10679
|
if (!agentMeta && /^model:|^tools:/m.test(yamlBlock)) {
|
|
10798
|
-
|
|
10680
|
+
logger24.warn(
|
|
10799
10681
|
`[agent-registry] ${filePath}: agent frontmatter \u7F3A name/description\uFF08IF1 \u5FC5\u586B\uFF09\uFF0Cmodel/tools \u7ECF legacy fallback \u751F\u6548\uFF08\u76F4\u63A5\u8DEF\u5F84\u4E0D\u4E22\u914D\u7F6E\uFF09\uFF0C\u4F46\u7ED3\u6784\u5316\u8DEF\u7531\u4E0D\u53EF\u89C1\u2014\u2014\u8BF7\u8865\u5145 description`
|
|
10800
10682
|
);
|
|
10801
10683
|
}
|
|
@@ -10971,7 +10853,7 @@ var AgentRegistry = class {
|
|
|
10971
10853
|
const { config, meta } = parseAgentWithMeta(filePath, file.content);
|
|
10972
10854
|
const lintFindings = meta ? lintAgentMeta(meta) : [];
|
|
10973
10855
|
for (const finding of lintFindings) {
|
|
10974
|
-
|
|
10856
|
+
logger24.warn(`[agent-registry] ${filePath}: ${finding.message}`);
|
|
10975
10857
|
}
|
|
10976
10858
|
this.fileCache.set(filePath, { mtimeMs: file.mtimeMs, config, meta });
|
|
10977
10859
|
return config;
|
|
@@ -11194,21 +11076,21 @@ import {
|
|
|
11194
11076
|
} from "@zhushanwen/subagent-engine-sdk";
|
|
11195
11077
|
|
|
11196
11078
|
// src/execution/channel-registry-access.ts
|
|
11197
|
-
var
|
|
11079
|
+
var logger25 = getLogger("subagents");
|
|
11198
11080
|
var CHANNEL_HANDSHAKE_KEY = /* @__PURE__ */ Symbol.for("@zhushanwen/pi-subagents.channelHandshake");
|
|
11199
11081
|
var HANDSHAKE_VERSION = 1;
|
|
11200
11082
|
function readHandshakeSlot() {
|
|
11201
11083
|
const slot = Reflect.get(globalThis, CHANNEL_HANDSHAKE_KEY);
|
|
11202
11084
|
if (slot === void 0) return void 0;
|
|
11203
11085
|
if (typeof slot !== "object" || slot === null) {
|
|
11204
|
-
|
|
11086
|
+
logger25.warn(
|
|
11205
11087
|
"[pi-subagent-workflow] channel handshake slot is not an object; discarding and recreating."
|
|
11206
11088
|
);
|
|
11207
11089
|
return void 0;
|
|
11208
11090
|
}
|
|
11209
11091
|
const version = slot.version;
|
|
11210
11092
|
if (version !== HANDSHAKE_VERSION) {
|
|
11211
|
-
|
|
11093
|
+
logger25.warn(
|
|
11212
11094
|
`[pi-subagent-workflow] channel handshake version mismatch (got ${String(
|
|
11213
11095
|
version
|
|
11214
11096
|
)}, expected ${HANDSHAKE_VERSION}); discarding and recreating.`
|
|
@@ -11217,7 +11099,7 @@ function readHandshakeSlot() {
|
|
|
11217
11099
|
}
|
|
11218
11100
|
const candidate = slot;
|
|
11219
11101
|
if (!Array.isArray(candidate.pending)) {
|
|
11220
|
-
|
|
11102
|
+
logger25.warn(
|
|
11221
11103
|
"[pi-subagent-workflow] channel handshake pending is not an array; discarding and recreating."
|
|
11222
11104
|
);
|
|
11223
11105
|
return void 0;
|
|
@@ -11259,11 +11141,11 @@ function isDialogMethod(method) {
|
|
|
11259
11141
|
}
|
|
11260
11142
|
|
|
11261
11143
|
// src/execution/dialog-queue.ts
|
|
11262
|
-
var
|
|
11263
|
-
var
|
|
11264
|
-
var
|
|
11144
|
+
var logger26 = getLogger("subagents");
|
|
11145
|
+
var SECONDS_PER_MINUTE4 = 60;
|
|
11146
|
+
var MS_PER_SECOND5 = 1e3;
|
|
11265
11147
|
var DEFAULT_DIALOG_TIMEOUT_MINUTES = 30;
|
|
11266
|
-
var DEFAULT_DIALOG_TIMEOUT_MS = DEFAULT_DIALOG_TIMEOUT_MINUTES *
|
|
11148
|
+
var DEFAULT_DIALOG_TIMEOUT_MS = DEFAULT_DIALOG_TIMEOUT_MINUTES * SECONDS_PER_MINUTE4 * MS_PER_SECOND5;
|
|
11267
11149
|
function resolveDialogTimeoutMs(timeout) {
|
|
11268
11150
|
const resolved = isValidDialogTimeout(timeout) ? timeout : DEFAULT_DIALOG_TIMEOUT_MS;
|
|
11269
11151
|
return Math.min(resolved, MAX_TIMER_DELAY_MS);
|
|
@@ -11396,7 +11278,7 @@ var DialogGlobalQueue = class {
|
|
|
11396
11278
|
const timeoutMs = resolveDialogTimeoutMs(item.req.timeout);
|
|
11397
11279
|
const timer = setTimeout(() => {
|
|
11398
11280
|
if (item.settled) return;
|
|
11399
|
-
|
|
11281
|
+
logger26.warn(dialogTimeoutLogMessage(item.req, timeoutMs));
|
|
11400
11282
|
this.settleItem(item, { cancelled: true });
|
|
11401
11283
|
}, timeoutMs);
|
|
11402
11284
|
item.timeoutTimer = timer;
|
|
@@ -11456,9 +11338,9 @@ import * as path13 from "path";
|
|
|
11456
11338
|
var TTL_DAYS = 30;
|
|
11457
11339
|
var HOURS_PER_DAY = 24;
|
|
11458
11340
|
var MINUTES_PER_HOUR = 60;
|
|
11459
|
-
var
|
|
11460
|
-
var
|
|
11461
|
-
var TTL_MS = TTL_DAYS * HOURS_PER_DAY * MINUTES_PER_HOUR *
|
|
11341
|
+
var SECONDS_PER_MINUTE5 = 60;
|
|
11342
|
+
var MS_PER_SECOND6 = 1e3;
|
|
11343
|
+
var TTL_MS = TTL_DAYS * HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE5 * MS_PER_SECOND6;
|
|
11462
11344
|
var CLEANUP_PROBABILITY_DIVISOR = 20;
|
|
11463
11345
|
var CLEANUP_PROBABILITY = 1 / CLEANUP_PROBABILITY_DIVISOR;
|
|
11464
11346
|
var SUBAGENTS_DIR = "subagents";
|
|
@@ -11544,7 +11426,7 @@ function walkAndClean(dir, now, allowManifestJson = false) {
|
|
|
11544
11426
|
}
|
|
11545
11427
|
|
|
11546
11428
|
// src/execution/ui-request-handler-factory.ts
|
|
11547
|
-
var
|
|
11429
|
+
var logger27 = getLogger("subagents");
|
|
11548
11430
|
function createUiRequestHandlerForMode(ctx, registry, dialogQueue) {
|
|
11549
11431
|
const hostMode = resolveHostMode(ctx.mode);
|
|
11550
11432
|
if (hostMode === "headless") return void 0;
|
|
@@ -11573,7 +11455,7 @@ function createRealHandler(ctx, _hostMode, registry) {
|
|
|
11573
11455
|
}
|
|
11574
11456
|
function coerceUiResponse(raw, reqId) {
|
|
11575
11457
|
if (typeof raw !== "object" || raw === null) {
|
|
11576
|
-
|
|
11458
|
+
logger27.warn("[subagents] channel handler returned non-object, coercing to cancelled", { detail: { reqId } });
|
|
11577
11459
|
return { cancelled: true };
|
|
11578
11460
|
}
|
|
11579
11461
|
const obj = raw;
|
|
@@ -11581,7 +11463,7 @@ function coerceUiResponse(raw, reqId) {
|
|
|
11581
11463
|
if (typeof obj.confirmed === "boolean") return { confirmed: obj.confirmed };
|
|
11582
11464
|
if (obj.cancelled === true) return { cancelled: true };
|
|
11583
11465
|
if (obj.ack === true) return { ack: true };
|
|
11584
|
-
|
|
11466
|
+
logger27.warn("[subagents] channel handler returned unrecognized shape, coercing to cancelled", { detail: { reqId } });
|
|
11585
11467
|
return { cancelled: true };
|
|
11586
11468
|
}
|
|
11587
11469
|
function sdkTimeoutArg(req) {
|
|
@@ -11604,7 +11486,7 @@ async function forwardEditor(req, ui) {
|
|
|
11604
11486
|
const text = await ui.editor(req.title ?? "", req.prefill);
|
|
11605
11487
|
return text === void 0 ? { cancelled: true } : { value: text };
|
|
11606
11488
|
} catch (err) {
|
|
11607
|
-
|
|
11489
|
+
logger27.warn(
|
|
11608
11490
|
"[subagents] ctx.ui.editor unavailable/threw, returning cancelled",
|
|
11609
11491
|
{ detail: { id: req.id, error: err instanceof Error ? err.message : String(err) } }
|
|
11610
11492
|
);
|
|
@@ -11650,7 +11532,7 @@ var DIALOG_METHOD_FORWARDERS = {
|
|
|
11650
11532
|
async function defaultDialogForward(req, ctx) {
|
|
11651
11533
|
const forwarder = DIALOG_METHOD_FORWARDERS[req.method];
|
|
11652
11534
|
if (!forwarder) {
|
|
11653
|
-
|
|
11535
|
+
logger27.warn(
|
|
11654
11536
|
"[subagents] defaultDialogForward: unknown method",
|
|
11655
11537
|
{ detail: { method: req.method, id: req.id } }
|
|
11656
11538
|
);
|
|
@@ -12147,7 +12029,7 @@ function hasApiKey(entry) {
|
|
|
12147
12029
|
import { execFile as execFile2 } from "child_process";
|
|
12148
12030
|
import { buildOutboundChildEnv as buildOutboundChildEnv2 } from "@zhushanwen/subagent-engine-sdk";
|
|
12149
12031
|
import * as fs17 from "fs";
|
|
12150
|
-
var
|
|
12032
|
+
var logger28 = getLogger("subagents");
|
|
12151
12033
|
var GIT_TIMEOUT_MS2 = 3e4;
|
|
12152
12034
|
var GitRunError2 = class extends Error {
|
|
12153
12035
|
exitCode;
|
|
@@ -12214,7 +12096,7 @@ async function collectWorktreePatch(opts) {
|
|
|
12214
12096
|
const commit = anchor.baseCommit.trim();
|
|
12215
12097
|
if (commit.length === 0) {
|
|
12216
12098
|
patchIncomplete = true;
|
|
12217
|
-
|
|
12099
|
+
logger28.warn(
|
|
12218
12100
|
"[worktree-git-ops] patch baseline anchor commit is empty, degrading to bare diff (uncommitted changes only); patch marked incomplete",
|
|
12219
12101
|
{ worktreePath }
|
|
12220
12102
|
);
|
|
@@ -12226,7 +12108,7 @@ async function collectWorktreePatch(opts) {
|
|
|
12226
12108
|
const commit = fs17.readFileSync(anchor.path, "utf-8").trim();
|
|
12227
12109
|
if (commit.length === 0) {
|
|
12228
12110
|
patchIncomplete = true;
|
|
12229
|
-
|
|
12111
|
+
logger28.warn(
|
|
12230
12112
|
"[worktree-git-ops] patch baseline anchor file is empty or blank, degrading to bare diff (uncommitted changes only); patch marked incomplete",
|
|
12231
12113
|
{ worktreePath, anchorFile: anchor.path }
|
|
12232
12114
|
);
|
|
@@ -12235,7 +12117,7 @@ async function collectWorktreePatch(opts) {
|
|
|
12235
12117
|
}
|
|
12236
12118
|
} catch (err) {
|
|
12237
12119
|
patchIncomplete = true;
|
|
12238
|
-
|
|
12120
|
+
logger28.warn(
|
|
12239
12121
|
"[worktree-git-ops] patch baseline anchor file missing or unreadable, degrading to bare diff (uncommitted changes only); patch marked incomplete",
|
|
12240
12122
|
{
|
|
12241
12123
|
worktreePath,
|
|
@@ -12251,7 +12133,7 @@ async function collectWorktreePatch(opts) {
|
|
|
12251
12133
|
} catch (err) {
|
|
12252
12134
|
addFailed = true;
|
|
12253
12135
|
patchIncomplete = true;
|
|
12254
|
-
|
|
12136
|
+
logger28.warn(
|
|
12255
12137
|
"[worktree-git-ops] git add -A failed, continuing with bare diff (tracked uncommitted changes only); patch marked incomplete",
|
|
12256
12138
|
{
|
|
12257
12139
|
worktreePath,
|
|
@@ -12269,7 +12151,7 @@ async function collectWorktreePatch(opts) {
|
|
|
12269
12151
|
});
|
|
12270
12152
|
} catch (err) {
|
|
12271
12153
|
patchIncomplete = true;
|
|
12272
|
-
|
|
12154
|
+
logger28.warn(
|
|
12273
12155
|
"[worktree-git-ops] patch baseline anchor rejected by git (corrupted?), degrading to bare diff (uncommitted changes only); patch marked incomplete",
|
|
12274
12156
|
{
|
|
12275
12157
|
worktreePath,
|
|
@@ -12329,7 +12211,7 @@ async function cleanupWorktree(opts) {
|
|
|
12329
12211
|
try {
|
|
12330
12212
|
await opts.onRemoved();
|
|
12331
12213
|
} catch (err) {
|
|
12332
|
-
|
|
12214
|
+
logger28.warn("[worktree-git-ops] cleanup onRemoved host hook failed (worktree/branch already cleaned)", {
|
|
12333
12215
|
branch: opts.branch,
|
|
12334
12216
|
detail: err instanceof Error ? err.message : String(err)
|
|
12335
12217
|
});
|
|
@@ -12457,7 +12339,7 @@ function formatModelList(models, opts) {
|
|
|
12457
12339
|
}
|
|
12458
12340
|
|
|
12459
12341
|
// src/execution/agents-assembly.ts
|
|
12460
|
-
var
|
|
12342
|
+
var logger29 = getLogger("agents-assembly");
|
|
12461
12343
|
async function discoverAgents(workspaceRoot, hostRoots) {
|
|
12462
12344
|
const resources = await discoverResources({
|
|
12463
12345
|
kind: "agents",
|
|
@@ -12469,7 +12351,7 @@ async function discoverAgents(workspaceRoot, hostRoots) {
|
|
|
12469
12351
|
if (!resource.available) continue;
|
|
12470
12352
|
const content = getCachedFileContent(resource.path);
|
|
12471
12353
|
if (content === null) {
|
|
12472
|
-
|
|
12354
|
+
logger29.error(`[agents-assembly] skip unreadable agent file ${resource.path}`);
|
|
12473
12355
|
continue;
|
|
12474
12356
|
}
|
|
12475
12357
|
const profile = parseAgentProfile(content, resource.path);
|
|
@@ -12482,7 +12364,7 @@ async function discoverAgents(workspaceRoot, hostRoots) {
|
|
|
12482
12364
|
path: resource.path
|
|
12483
12365
|
});
|
|
12484
12366
|
} else if (content.trimStart().startsWith("---")) {
|
|
12485
|
-
|
|
12367
|
+
logger29.warn(
|
|
12486
12368
|
`[agents-assembly] ${resource.path}: agent frontmatter \u89E3\u6790\u5931\u8D25\uFF08IF1 \u6821\u9A8C\u4E0D\u901A\u8FC7\uFF09\u2014\u2014agent \u672A\u8FDB\u6E05\u5355`
|
|
12487
12369
|
);
|
|
12488
12370
|
}
|
|
@@ -12846,7 +12728,7 @@ var RunRuntime = class {
|
|
|
12846
12728
|
};
|
|
12847
12729
|
|
|
12848
12730
|
// src/orchestration/worker-message-pump.ts
|
|
12849
|
-
var
|
|
12731
|
+
var logger30 = getLogger("subagents");
|
|
12850
12732
|
var MAX_WORKER_RETRIES = 3;
|
|
12851
12733
|
var RETRY_BACKOFF_BASE_MS = 1e3;
|
|
12852
12734
|
var EXPONENTIAL_BACKOFF_BASE = 2;
|
|
@@ -12869,7 +12751,7 @@ async function saveRunBestEffort(run, deps, context) {
|
|
|
12869
12751
|
await deps.store.save(run);
|
|
12870
12752
|
} catch (err) {
|
|
12871
12753
|
const m = toErrorMessage(err);
|
|
12872
|
-
|
|
12754
|
+
logger30.error(
|
|
12873
12755
|
`[workflow] store.save failed (${context}, runId=${run.runId}): ${m}. Continuing state-machine finalization (in-memory state already terminal).`
|
|
12874
12756
|
);
|
|
12875
12757
|
}
|
|
@@ -12900,14 +12782,14 @@ async function finalizeRun(run, deps, doneReason, options) {
|
|
|
12900
12782
|
});
|
|
12901
12783
|
} catch (err) {
|
|
12902
12784
|
const m = toErrorMessage(err);
|
|
12903
|
-
|
|
12785
|
+
logger30.error(`[workflow] pending:unregister emit failed (${options.context}): ${m}`);
|
|
12904
12786
|
}
|
|
12905
12787
|
if (options.notifyDone !== false) {
|
|
12906
12788
|
try {
|
|
12907
12789
|
deps.onRunDone?.(run);
|
|
12908
12790
|
} catch (err) {
|
|
12909
12791
|
const m = toErrorMessage(err);
|
|
12910
|
-
|
|
12792
|
+
logger30.error(`[workflow] onRunDone failed (${options.context}): ${m}`);
|
|
12911
12793
|
}
|
|
12912
12794
|
}
|
|
12913
12795
|
return true;
|
|
@@ -12927,7 +12809,7 @@ function resolveRebuildFailureInjectionThreshold() {
|
|
|
12927
12809
|
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
12928
12810
|
if (!rebuildFailureHookWarned) {
|
|
12929
12811
|
rebuildFailureHookWarned = true;
|
|
12930
|
-
|
|
12812
|
+
logger30.warn(
|
|
12931
12813
|
`[workflow] ${REBUILD_FAILURE_INJECT_ENV}="${raw}" is not a positive integer \u2014 test hook INACTIVE, no rebuild failure will be injected`
|
|
12932
12814
|
);
|
|
12933
12815
|
}
|
|
@@ -12935,7 +12817,7 @@ function resolveRebuildFailureInjectionThreshold() {
|
|
|
12935
12817
|
}
|
|
12936
12818
|
if (!rebuildFailureHookWarned) {
|
|
12937
12819
|
rebuildFailureHookWarned = true;
|
|
12938
|
-
|
|
12820
|
+
logger30.warn(
|
|
12939
12821
|
`[workflow] ${REBUILD_FAILURE_INJECT_ENV}=${raw} ACTIVE \u2014 rebuildRuntime invocations #${parsed} and later will throw (S-D test hook; NEVER set in production)`
|
|
12940
12822
|
);
|
|
12941
12823
|
}
|
|
@@ -13057,7 +12939,7 @@ async function handleWorkerMessage(run, raw, deps, handlers) {
|
|
|
13057
12939
|
handleWorkerLog(run, msg, deps);
|
|
13058
12940
|
return;
|
|
13059
12941
|
default:
|
|
13060
|
-
|
|
12942
|
+
logger30.warn(
|
|
13061
12943
|
`[workflow] unknown worker message type dropped (runId=${run.runId}): ${JSON.stringify(msg.type)}`
|
|
13062
12944
|
);
|
|
13063
12945
|
deps.log?.("warn", "workflow:worker-message-pump", "unknown worker message type", {
|
|
@@ -13084,7 +12966,7 @@ function isMalformedAgentCallMsg(msg) {
|
|
|
13084
12966
|
}
|
|
13085
12967
|
function dispatchAgentCall(run, msg, deps) {
|
|
13086
12968
|
if (isMalformedAgentCallMsg(msg)) {
|
|
13087
|
-
|
|
12969
|
+
logger30.error(`[workflow] malformed agent-call message: callId=${JSON.stringify(msg.callId)}, opts=${JSON.stringify(msg.opts)?.slice(0, MALFORMED_MSG_LOG_PREVIEW_CHARS)}`);
|
|
13088
12970
|
return;
|
|
13089
12971
|
}
|
|
13090
12972
|
const cached = run.state.calls.get(msg.callId);
|
|
@@ -13135,7 +13017,7 @@ function dispatchAgentCall(run, msg, deps) {
|
|
|
13135
13017
|
});
|
|
13136
13018
|
postAgentResult(run, msg.callId, errorResult2, false);
|
|
13137
13019
|
deps.store.save(run).catch((e) => {
|
|
13138
|
-
|
|
13020
|
+
logger30.error(`[workflow] store.save failed (resolveAgentOpts): ${toErrorMessage(e)}`);
|
|
13139
13021
|
});
|
|
13140
13022
|
return;
|
|
13141
13023
|
}
|
|
@@ -13170,7 +13052,7 @@ function dispatchAgentCall(run, msg, deps) {
|
|
|
13170
13052
|
postBudgetUpdate(run);
|
|
13171
13053
|
deps.store.save(run).catch((e) => {
|
|
13172
13054
|
const m = toErrorMessage(e);
|
|
13173
|
-
|
|
13055
|
+
logger30.error(`[workflow] store.save failed (agent call ${msg.callId}): ${m}`);
|
|
13174
13056
|
});
|
|
13175
13057
|
if (run.state.budget.isExceeded()) {
|
|
13176
13058
|
run.state.error = run.state.error ?? "Budget exceeded";
|
|
@@ -13180,7 +13062,7 @@ function dispatchAgentCall(run, msg, deps) {
|
|
|
13180
13062
|
}).catch((err) => {
|
|
13181
13063
|
if (err instanceof Error && err.name === "AbortError") return;
|
|
13182
13064
|
const message = toErrorMessage(err);
|
|
13183
|
-
|
|
13065
|
+
logger30.error(`[workflow] agent call ${msg.callId} failed: ${message}`);
|
|
13184
13066
|
node.live = void 0;
|
|
13185
13067
|
if (isOrphanedCall(run, msg.callId, call)) {
|
|
13186
13068
|
deps.log?.("debug", "workflow:worker-message-pump", "orphan agent call failure dropped", { runId: run.runId, callId: msg.callId });
|
|
@@ -13199,7 +13081,7 @@ function dispatchAgentCall(run, msg, deps) {
|
|
|
13199
13081
|
postAgentResult(run, msg.callId, errorResult2, false);
|
|
13200
13082
|
postBudgetUpdate(run);
|
|
13201
13083
|
deps.store.save(run).catch((e) => {
|
|
13202
|
-
|
|
13084
|
+
logger30.error(`[workflow] store.save failed (catch fallback): ${toErrorMessage(e)}`);
|
|
13203
13085
|
});
|
|
13204
13086
|
});
|
|
13205
13087
|
}
|
|
@@ -13208,7 +13090,7 @@ function makeSerializeFailedResult(prefix, errMsg) {
|
|
|
13208
13090
|
}
|
|
13209
13091
|
function dispatchWorkflowCall(run, msg, deps) {
|
|
13210
13092
|
if (typeof msg.callId !== "number" || !Number.isFinite(msg.callId) || typeof msg.name !== "string" || typeof msg.args !== "object" || msg.args === null) {
|
|
13211
|
-
|
|
13093
|
+
logger30.error(`[workflow] malformed workflow-call message: callId=${JSON.stringify(msg.callId)}, name=${JSON.stringify(msg.name)}`);
|
|
13212
13094
|
return;
|
|
13213
13095
|
}
|
|
13214
13096
|
const postResult = (result) => {
|
|
@@ -13221,7 +13103,7 @@ function dispatchWorkflowCall(run, msg, deps) {
|
|
|
13221
13103
|
});
|
|
13222
13104
|
} catch (err) {
|
|
13223
13105
|
const errMsg = toErrorMessage(err);
|
|
13224
|
-
|
|
13106
|
+
logger30.error(`[workflow] postResult (workflow-call callId=${msg.callId}) failed: ${errMsg}. Sending error fallback.`);
|
|
13225
13107
|
try {
|
|
13226
13108
|
run.runtime?.worker.postMessage({
|
|
13227
13109
|
type: "workflow-result",
|
|
@@ -13229,7 +13111,7 @@ function dispatchWorkflowCall(run, msg, deps) {
|
|
|
13229
13111
|
result: makeSerializeFailedResult("Workflow result serialization failed", errMsg)
|
|
13230
13112
|
});
|
|
13231
13113
|
} catch {
|
|
13232
|
-
|
|
13114
|
+
logger30.error(`[workflow] postResult fallback also failed (callId=${msg.callId}): worker pending will hang until timeout`);
|
|
13233
13115
|
}
|
|
13234
13116
|
}
|
|
13235
13117
|
};
|
|
@@ -13252,7 +13134,7 @@ function postAgentResult(run, callId, result, cached) {
|
|
|
13252
13134
|
run.runtime?.worker.postMessage({ type: "agent-result", callId, result, cached });
|
|
13253
13135
|
} catch (err) {
|
|
13254
13136
|
const msg = toErrorMessage(err);
|
|
13255
|
-
|
|
13137
|
+
logger30.error(`[workflow] postAgentResult failed (callId=${callId}): ${msg}. Result likely contains non-cloneable value.`);
|
|
13256
13138
|
try {
|
|
13257
13139
|
run.runtime?.worker.postMessage({
|
|
13258
13140
|
type: "agent-result",
|
|
@@ -13262,7 +13144,7 @@ function postAgentResult(run, callId, result, cached) {
|
|
|
13262
13144
|
cached: false
|
|
13263
13145
|
});
|
|
13264
13146
|
} catch {
|
|
13265
|
-
|
|
13147
|
+
logger30.error(`[workflow] postAgentResult fallback also failed (callId=${callId}): worker pending will hang until timeout`);
|
|
13266
13148
|
}
|
|
13267
13149
|
}
|
|
13268
13150
|
}
|
|
@@ -13277,7 +13159,7 @@ function postBudgetUpdate(run) {
|
|
|
13277
13159
|
});
|
|
13278
13160
|
} catch (err) {
|
|
13279
13161
|
const msg = toErrorMessage(err);
|
|
13280
|
-
|
|
13162
|
+
logger30.error(`[workflow] postBudgetUpdate failed: ${msg}. Budget sync to worker skipped (non-critical).`);
|
|
13281
13163
|
}
|
|
13282
13164
|
}
|
|
13283
13165
|
async function handleReturn(run, msg, deps) {
|
|
@@ -13363,7 +13245,7 @@ async function handleRebuildStartFailure(run, err, deps, handlers) {
|
|
|
13363
13245
|
const message = toErrorMessage(err);
|
|
13364
13246
|
const count = (run.meta.workerErrorCount ?? 0) + 1;
|
|
13365
13247
|
run.meta.workerErrorCount = count;
|
|
13366
|
-
|
|
13248
|
+
logger30.error(
|
|
13367
13249
|
`[workflow] rebuildRuntime failed (runId=${run.runId}, attempt ${count}/${MAX_WORKER_RETRIES}): ${message}`
|
|
13368
13250
|
);
|
|
13369
13251
|
if (count <= MAX_WORKER_RETRIES) {
|
|
@@ -13376,7 +13258,7 @@ async function handleRebuildStartFailure(run, err, deps, handlers) {
|
|
|
13376
13258
|
}
|
|
13377
13259
|
|
|
13378
13260
|
// src/orchestration/lifecycle.ts
|
|
13379
|
-
var
|
|
13261
|
+
var logger31 = getLogger("subagents");
|
|
13380
13262
|
var RUNID_RADIX = 36;
|
|
13381
13263
|
var RUNID_SLICE_START = 2;
|
|
13382
13264
|
var RUNID_SLICE_END = 8;
|
|
@@ -13396,7 +13278,7 @@ function broadcastAbortToWorker(run, reason) {
|
|
|
13396
13278
|
run.runtime?.worker.postMessage({ type: "abort", reason });
|
|
13397
13279
|
} catch (err) {
|
|
13398
13280
|
const msg = toErrorMessage(err);
|
|
13399
|
-
|
|
13281
|
+
logger31.debug(
|
|
13400
13282
|
`[workflow] abort broadcast to worker failed (runId=${run.runId}, worker likely already exited): ${msg}`
|
|
13401
13283
|
);
|
|
13402
13284
|
}
|
|
@@ -13428,7 +13310,7 @@ function scheduleTimeBudget(runId, deps, budgetTimeMs) {
|
|
|
13428
13310
|
void abortRun(runId, deps, "Time budget exceeded", "time_limited").catch(
|
|
13429
13311
|
(err) => {
|
|
13430
13312
|
const msg = toErrorMessage(err);
|
|
13431
|
-
|
|
13313
|
+
logger31.error(`[workflow] time budget abort failed: ${msg}`);
|
|
13432
13314
|
}
|
|
13433
13315
|
);
|
|
13434
13316
|
}, budgetTimeMs);
|
|
@@ -13479,7 +13361,7 @@ function registerSignalAbortListener(run, runId, deps, signal) {
|
|
|
13479
13361
|
disposeSignalAbortListener(run);
|
|
13480
13362
|
void abortRun(runId, deps, "External signal aborted").catch((err) => {
|
|
13481
13363
|
const msg = toErrorMessage(err);
|
|
13482
|
-
|
|
13364
|
+
logger31.error(`[workflow] abortRun on signal failed: ${msg}`);
|
|
13483
13365
|
});
|
|
13484
13366
|
};
|
|
13485
13367
|
signal.addEventListener("abort", onAbort);
|
|
@@ -13546,7 +13428,7 @@ async function terminateRunningRuns(deps, reason) {
|
|
|
13546
13428
|
deps.log?.("debug", "workflow:lifecycle", "run terminated", { runId: run.runId, reason: run.state.reason });
|
|
13547
13429
|
} catch (err) {
|
|
13548
13430
|
const msg = toErrorMessage(err);
|
|
13549
|
-
|
|
13431
|
+
logger31.error(
|
|
13550
13432
|
`[workflow] terminateRunningRuns failed for run ${run.runId}: ${msg} (reason: ${reason})`
|
|
13551
13433
|
);
|
|
13552
13434
|
}
|
|
@@ -13576,7 +13458,7 @@ async function recoverCrashedRuns(store, runs, reason, hooks) {
|
|
|
13576
13458
|
hooks?.onRunRecovered?.({ id: run.runId, reason: "failed" });
|
|
13577
13459
|
} catch (err) {
|
|
13578
13460
|
const msg = toErrorMessage(err);
|
|
13579
|
-
|
|
13461
|
+
logger31.warn(
|
|
13580
13462
|
`[workflow] recoverCrashedRuns onRunRecovered hook failed for run ${run.runId} (recovery continues): ${msg}`
|
|
13581
13463
|
);
|
|
13582
13464
|
}
|
|
@@ -13584,7 +13466,7 @@ async function recoverCrashedRuns(store, runs, reason, hooks) {
|
|
|
13584
13466
|
await store.save(run);
|
|
13585
13467
|
} catch (err) {
|
|
13586
13468
|
const msg = toErrorMessage(err);
|
|
13587
|
-
|
|
13469
|
+
logger31.error(
|
|
13588
13470
|
`[workflow] recoverCrashedRuns store.save failed for run ${run.runId}: ${msg} (reason: ${reason})`
|
|
13589
13471
|
);
|
|
13590
13472
|
}
|
|
@@ -13593,7 +13475,7 @@ async function recoverCrashedRuns(store, runs, reason, hooks) {
|
|
|
13593
13475
|
}
|
|
13594
13476
|
const evicted = evictDoneRunsBeyondCap(runs, MAX_RETAINED_DONE_RUNS);
|
|
13595
13477
|
if (evicted > 0) {
|
|
13596
|
-
|
|
13478
|
+
logger31.debug(
|
|
13597
13479
|
`[workflow] recoverCrashedRuns evicted ${evicted} done runs beyond cap (keep=${MAX_RETAINED_DONE_RUNS})`
|
|
13598
13480
|
);
|
|
13599
13481
|
}
|
|
@@ -13854,7 +13736,7 @@ var WorkflowScript = class {
|
|
|
13854
13736
|
|
|
13855
13737
|
// src/orchestration/config-loader.ts
|
|
13856
13738
|
import { resolve as resolve5 } from "path";
|
|
13857
|
-
var
|
|
13739
|
+
var logger32 = getLogger("config-loader");
|
|
13858
13740
|
var cache2 = /* @__PURE__ */ new Map();
|
|
13859
13741
|
function getCacheBucket(workspaceRoot) {
|
|
13860
13742
|
let bucket = cache2.get(workspaceRoot);
|
|
@@ -13891,11 +13773,11 @@ async function toCachedMeta(filePath, source) {
|
|
|
13891
13773
|
if (meta && meta.kind === "workflow") {
|
|
13892
13774
|
return { ...meta, path: filePath, available: true, source: wfSource };
|
|
13893
13775
|
}
|
|
13894
|
-
|
|
13776
|
+
logger32.warn(
|
|
13895
13777
|
`[config-loader] ${filePath}: \u672A\u89E3\u6790\u5230 @pi-meta \u5143\u6570\u636E\uFF08\u65E7 const meta \u683C\u5F0F\u9700\u8FC1\u79FB\uFF09\u2192 available=false`
|
|
13896
13778
|
);
|
|
13897
13779
|
} catch (err) {
|
|
13898
|
-
|
|
13780
|
+
logger32.debug(`[config-loader] skip unreadable workflow file ${filePath}`, {
|
|
13899
13781
|
reason: err instanceof Error ? err.message : String(err)
|
|
13900
13782
|
});
|
|
13901
13783
|
}
|
|
@@ -14738,7 +14620,7 @@ function isScriptRunning(runs, name) {
|
|
|
14738
14620
|
}
|
|
14739
14621
|
|
|
14740
14622
|
// src/orchestration/args-meta.ts
|
|
14741
|
-
var
|
|
14623
|
+
var logger33 = getLogger("args-meta");
|
|
14742
14624
|
var EMPTY_RESERVED_KEYS = /* @__PURE__ */ new Set();
|
|
14743
14625
|
function collectExactKeys(props, reserved) {
|
|
14744
14626
|
const exact = /* @__PURE__ */ new Set();
|
|
@@ -14757,7 +14639,7 @@ function compilePatterns(pp, reserved) {
|
|
|
14757
14639
|
if ([...reserved].some((tk) => re.test(tk))) continue;
|
|
14758
14640
|
patterns.push(re);
|
|
14759
14641
|
} catch (err) {
|
|
14760
|
-
|
|
14642
|
+
logger33.warn(`[args-meta] patternProperties \u975E\u6CD5\u6B63\u5219\u8DF3\u8FC7: ${p}`, {
|
|
14761
14643
|
reason: err instanceof Error ? err.message : String(err)
|
|
14762
14644
|
});
|
|
14763
14645
|
}
|
|
@@ -14899,7 +14781,7 @@ function boundedPrettySerialize(value, budget) {
|
|
|
14899
14781
|
}
|
|
14900
14782
|
|
|
14901
14783
|
// src/index.ts
|
|
14902
|
-
var CORE_PACKAGE_VERSION = "0.
|
|
14784
|
+
var CORE_PACKAGE_VERSION = "0.8.0";
|
|
14903
14785
|
export {
|
|
14904
14786
|
AGENT_REF_EXT,
|
|
14905
14787
|
AgentCall,
|
|
@@ -14996,6 +14878,7 @@ export {
|
|
|
14996
14878
|
getCachedFileContent,
|
|
14997
14879
|
getCachedParsed,
|
|
14998
14880
|
getHostServices,
|
|
14881
|
+
getInFlightSnapshot,
|
|
14999
14882
|
getLogger,
|
|
15000
14883
|
getModelConfigService,
|
|
15001
14884
|
getOrCreateChannelRegistry,
|
|
@@ -15053,6 +14936,7 @@ export {
|
|
|
15053
14936
|
saveWorkflow,
|
|
15054
14937
|
scheduleTimeBudget,
|
|
15055
14938
|
setEngineDiscoveryRescanOptions,
|
|
14939
|
+
setInFlightListener,
|
|
15056
14940
|
setModelConfigService,
|
|
15057
14941
|
setSubagentService,
|
|
15058
14942
|
sortByCodepoint,
|