@claudexor/core 3.0.4 → 3.1.1
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/answer-assembly.d.ts +17 -1
- package/dist/answer-assembly.d.ts.map +1 -1
- package/dist/answer-assembly.js +36 -10
- package/dist/answer-assembly.js.map +1 -1
- package/dist/effort.d.ts +54 -12
- package/dist/effort.d.ts.map +1 -1
- package/dist/effort.js +60 -39
- package/dist/effort.js.map +1 -1
- package/dist/env-scope.d.ts +1 -1
- package/dist/env-scope.d.ts.map +1 -1
- package/dist/env-scope.js +2 -2
- package/dist/env-scope.js.map +1 -1
- package/dist/errors.d.ts +11 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +11 -0
- package/dist/errors.js.map +1 -1
- package/dist/inactivity.d.ts +7 -14
- package/dist/inactivity.d.ts.map +1 -1
- package/dist/inactivity.js +97 -10
- package/dist/inactivity.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/native/claudexor-process-identity +0 -0
- package/dist/proc.d.ts +53 -0
- package/dist/proc.d.ts.map +1 -1
- package/dist/proc.js +150 -42
- package/dist/proc.js.map +1 -1
- package/dist/process-identity.d.ts.map +1 -1
- package/dist/process-identity.js +17 -7
- package/dist/process-identity.js.map +1 -1
- package/dist/process-tree.d.ts +116 -0
- package/dist/process-tree.d.ts.map +1 -0
- package/dist/process-tree.js +258 -0
- package/dist/process-tree.js.map +1 -0
- package/dist/runloop.d.ts +5 -0
- package/dist/runloop.d.ts.map +1 -1
- package/dist/runloop.js +41 -0
- package/dist/runloop.js.map +1 -1
- package/dist/runtime-env.d.ts +57 -3
- package/dist/runtime-env.d.ts.map +1 -1
- package/dist/runtime-env.js +187 -10
- package/dist/runtime-env.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-tree.d.ts","sourceRoot":"","sources":["../src/process-tree.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whole-tree termination (QA-027). `spawnProcess` puts the direct harness child
|
|
3
|
+
* in its OWN process group so a cancel/timeout can signal the group. But a
|
|
4
|
+
* vendor tool can `setsid` into a NEW process group and, once its parent CLI
|
|
5
|
+
* exits, reparent to pid 1 — so signalling only the direct group leaks that
|
|
6
|
+
* escaped group (it kept a `/bin/sleep 60` orphan alive ~40s after a terminal
|
|
7
|
+
* `cancelled`). Group kill of one PGID is NOT a process-tree boundary.
|
|
8
|
+
*
|
|
9
|
+
* This module snapshots the live process tree WHILE it is still intact
|
|
10
|
+
* (descendants still chained by ppid to the root), captures an identity-proven
|
|
11
|
+
* {@link ProcessGroupHandle} for every distinct descendant process group, then
|
|
12
|
+
* reaps them all with the EXISTING recorded-orphan machinery — the same
|
|
13
|
+
* `ProcessGroupService` (identity-verified `signal` + `probeEmpty`) the daemon
|
|
14
|
+
* crash-GC reaper uses. No new raw killer: a recycled/stale pgid is never
|
|
15
|
+
* signalled, and terminal is reported only after every owned group is proven
|
|
16
|
+
* empty (fail-closed to `unconfirmed`, never a silent success).
|
|
17
|
+
*/
|
|
18
|
+
import { spawnSync } from "node:child_process";
|
|
19
|
+
import { defaultProcessGroupService, } from "./process-group.js";
|
|
20
|
+
import { compareProcessIdentity, defaultProcessIdentityService, } from "./process-identity.js";
|
|
21
|
+
/**
|
|
22
|
+
* Read the live process table via `ps` (POSIX, present on both darwin and
|
|
23
|
+
* linux). C locale, bounded time/buffer, no shell. Any failure yields [] — the
|
|
24
|
+
* caller then falls back to the direct-group signal it already sends, and a
|
|
25
|
+
* genuinely alive-but-invisible group surfaces as `unconfirmed`.
|
|
26
|
+
*/
|
|
27
|
+
export function readProcessTable(run = (cmd, args) => {
|
|
28
|
+
const r = spawnSync(cmd, args, {
|
|
29
|
+
encoding: "utf8",
|
|
30
|
+
timeout: 1_500,
|
|
31
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
32
|
+
env: { PATH: "/usr/bin:/bin", LANG: "C", LC_ALL: "C" },
|
|
33
|
+
});
|
|
34
|
+
return { status: r.status, stdout: r.stdout ?? "" };
|
|
35
|
+
}) {
|
|
36
|
+
let out;
|
|
37
|
+
try {
|
|
38
|
+
out = run("ps", ["-A", "-o", "pid=,ppid=,pgid="]);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
if (out.status !== 0 || !out.stdout)
|
|
44
|
+
return [];
|
|
45
|
+
const nodes = [];
|
|
46
|
+
for (const line of out.stdout.split("\n")) {
|
|
47
|
+
const parts = line.trim().split(/\s+/);
|
|
48
|
+
if (parts.length !== 3)
|
|
49
|
+
continue;
|
|
50
|
+
const pid = Number(parts[0]);
|
|
51
|
+
const ppid = Number(parts[1]);
|
|
52
|
+
const pgid = Number(parts[2]);
|
|
53
|
+
if (!Number.isSafeInteger(pid) ||
|
|
54
|
+
!Number.isSafeInteger(ppid) ||
|
|
55
|
+
!Number.isSafeInteger(pgid) ||
|
|
56
|
+
pid <= 0) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
nodes.push({ pid, ppid, pgid });
|
|
60
|
+
}
|
|
61
|
+
return nodes;
|
|
62
|
+
}
|
|
63
|
+
export const defaultProcessTreeReader = {
|
|
64
|
+
snapshot: () => readProcessTable(),
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Distinct process-group ids of `rootPid` and every transitive descendant, per
|
|
68
|
+
* a tree snapshot. BFS over ppid so a grandchild that escaped into its own
|
|
69
|
+
* pgid is still discovered — as long as the snapshot was taken before its
|
|
70
|
+
* parent chain was torn down.
|
|
71
|
+
*/
|
|
72
|
+
export function descendantProcessGroupIds(rootPid, nodes) {
|
|
73
|
+
const childrenByPpid = new Map();
|
|
74
|
+
const self = new Map();
|
|
75
|
+
for (const node of nodes) {
|
|
76
|
+
self.set(node.pid, node);
|
|
77
|
+
const bucket = childrenByPpid.get(node.ppid);
|
|
78
|
+
if (bucket)
|
|
79
|
+
bucket.push(node);
|
|
80
|
+
else
|
|
81
|
+
childrenByPpid.set(node.ppid, [node]);
|
|
82
|
+
}
|
|
83
|
+
const pgids = new Set();
|
|
84
|
+
const seen = new Set();
|
|
85
|
+
const queue = [rootPid];
|
|
86
|
+
const rootNode = self.get(rootPid);
|
|
87
|
+
if (rootNode)
|
|
88
|
+
pgids.add(rootNode.pgid);
|
|
89
|
+
while (queue.length > 0) {
|
|
90
|
+
const pid = queue.shift();
|
|
91
|
+
if (seen.has(pid))
|
|
92
|
+
continue;
|
|
93
|
+
seen.add(pid);
|
|
94
|
+
for (const child of childrenByPpid.get(pid) ?? []) {
|
|
95
|
+
if (child.pid === pid)
|
|
96
|
+
continue; // pid 1 is its own ppid on some tables
|
|
97
|
+
pgids.add(child.pgid);
|
|
98
|
+
queue.push(child.pid);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return [...pgids];
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Identity-proven handles for every process group in `rootPid`'s tree. A pgid
|
|
105
|
+
* whose leader is gone/recycled/unreadable lands in `unresolved` — we never
|
|
106
|
+
* signal an unproven group.
|
|
107
|
+
*/
|
|
108
|
+
export function captureProcessTreeGroups(rootPid, deps = {}) {
|
|
109
|
+
const tree = deps.tree ?? defaultProcessTreeReader;
|
|
110
|
+
const groups = deps.groups ?? defaultProcessGroupService;
|
|
111
|
+
const probeGroupAlive = deps.probeGroupAlive ?? defaultProbeGroupAlive;
|
|
112
|
+
const handles = [];
|
|
113
|
+
const unresolved = [];
|
|
114
|
+
for (const pgid of descendantProcessGroupIds(rootPid, tree.snapshot())) {
|
|
115
|
+
const capture = groups.captureLeader(pgid);
|
|
116
|
+
if (capture.status === "known")
|
|
117
|
+
handles.push(capture.handle);
|
|
118
|
+
else if (capture.status === "unknown")
|
|
119
|
+
unresolved.push({ pgid, reason: capture.reason });
|
|
120
|
+
else {
|
|
121
|
+
// `missing` = the group LEADER exited between the ps snapshot and this
|
|
122
|
+
// capture. That does NOT prove the group empty: a non-leader member can
|
|
123
|
+
// still be alive under the leaderless pgid (round-2 #3). A raw signal-0
|
|
124
|
+
// group probe is the honest liveness check — if the group is still alive we
|
|
125
|
+
// record it as unresolved (we can never signal it without a proven leader,
|
|
126
|
+
// but reapProcessTree must NOT report `confirmed` while it survives). ESRCH
|
|
127
|
+
// (truly gone) is the only outcome that lets the pgid drop silently.
|
|
128
|
+
if (probeGroupAlive(pgid)) {
|
|
129
|
+
unresolved.push({ pgid, reason: "leader_exited_group_alive" });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return { handles, unresolved };
|
|
134
|
+
}
|
|
135
|
+
function defaultProbeGroupAlive(pgid) {
|
|
136
|
+
try {
|
|
137
|
+
process.kill(-pgid, 0);
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
return error?.code !== "ESRCH";
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Reap `rootPid`'s whole process tree and PROVE it dead. Cooperative signal ->
|
|
146
|
+
* bounded grace -> SIGKILL, re-scanning for groups that fork/re-group during
|
|
147
|
+
* the race (fixed point) until every group probes empty or the deadline lapses.
|
|
148
|
+
*
|
|
149
|
+
* The initial capture runs synchronously (before the first await) so callers
|
|
150
|
+
* that invoke this the instant a cancel fires snapshot the tree while its ppid
|
|
151
|
+
* chain is still intact.
|
|
152
|
+
*/
|
|
153
|
+
export async function reapProcessTree(opts) {
|
|
154
|
+
const groups = opts.groups ?? defaultProcessGroupService;
|
|
155
|
+
const tree = opts.tree ?? defaultProcessTreeReader;
|
|
156
|
+
const identity = opts.identity ?? defaultProcessIdentityService;
|
|
157
|
+
const sleep = opts.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
158
|
+
const now = opts.now ?? Date.now;
|
|
159
|
+
const coop = opts.cooperativeSignal ?? "SIGTERM";
|
|
160
|
+
const graceMs = opts.graceMs ?? 1_000;
|
|
161
|
+
const deadlineMs = opts.deadlineMs ?? graceMs + 4_000;
|
|
162
|
+
const probeIntervalMs = Math.max(1, opts.probeIntervalMs ?? 100);
|
|
163
|
+
const probeGroupAlive = opts.probeGroupAlive ?? defaultProbeGroupAlive;
|
|
164
|
+
const start = now();
|
|
165
|
+
const handles = new Map();
|
|
166
|
+
const unresolved = new Map();
|
|
167
|
+
// Drop identity-unverified pgids that have actually exited (raw ESRCH probe).
|
|
168
|
+
const pruneDeadUnresolved = () => {
|
|
169
|
+
for (const pgid of [...unresolved.keys()]) {
|
|
170
|
+
if (!handles.has(pgid) && !probeGroupAlive(pgid))
|
|
171
|
+
unresolved.delete(pgid);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
// Is the numeric rootPid still the SAME process we were asked to reap? Only a
|
|
175
|
+
// proven `different`/`missing` blocks further descendant discovery (the PID was
|
|
176
|
+
// reused or the root vanished); `same` and an unreadable `unknown` keep
|
|
177
|
+
// discovering (best-effort — we can never prove reuse from an unreadable read,
|
|
178
|
+
// and refusing on `unknown` would leak escaped descendants on hosts without a
|
|
179
|
+
// usable identity source). With no `rootIdentity` supplied this is always true.
|
|
180
|
+
const rootStillReapable = () => {
|
|
181
|
+
if (!opts.rootIdentity)
|
|
182
|
+
return true;
|
|
183
|
+
const comparison = compareProcessIdentity(opts.rootIdentity, identity.read(opts.rootPid));
|
|
184
|
+
return comparison !== "different" && comparison !== "missing";
|
|
185
|
+
};
|
|
186
|
+
const capture = () => {
|
|
187
|
+
// Once the root is gone/reused, stop enumerating NEW descendants from its
|
|
188
|
+
// (possibly recycled) PID; keep probing the groups captured while it was valid.
|
|
189
|
+
if (!rootStillReapable())
|
|
190
|
+
return;
|
|
191
|
+
const snap = captureProcessTreeGroups(opts.rootPid, { tree, groups, probeGroupAlive });
|
|
192
|
+
for (const handle of snap.handles) {
|
|
193
|
+
if (!handles.has(handle.pgid)) {
|
|
194
|
+
handles.set(handle.pgid, handle);
|
|
195
|
+
opts.onCapture?.(handle);
|
|
196
|
+
}
|
|
197
|
+
unresolved.delete(handle.pgid);
|
|
198
|
+
}
|
|
199
|
+
for (const item of snap.unresolved) {
|
|
200
|
+
if (!handles.has(item.pgid))
|
|
201
|
+
unresolved.set(item.pgid, item.reason);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
// Snapshot WHILE the tree is alive, then seed any externally captured groups.
|
|
205
|
+
capture();
|
|
206
|
+
for (const handle of opts.seedHandles ?? []) {
|
|
207
|
+
if (!handles.has(handle.pgid)) {
|
|
208
|
+
handles.set(handle.pgid, handle);
|
|
209
|
+
opts.onCapture?.(handle);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const done = () => {
|
|
213
|
+
// Re-probe every captured group so a group we signalled but never re-probed
|
|
214
|
+
// is not falsely reported alive.
|
|
215
|
+
for (const [pgid, handle] of [...handles]) {
|
|
216
|
+
if (groups.probeEmpty(handle).status === "empty")
|
|
217
|
+
handles.delete(pgid);
|
|
218
|
+
}
|
|
219
|
+
pruneDeadUnresolved();
|
|
220
|
+
if (handles.size === 0 && unresolved.size === 0) {
|
|
221
|
+
return { state: "confirmed", pgids: [] };
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
state: "unconfirmed",
|
|
225
|
+
survivors: [...handles.keys()],
|
|
226
|
+
unresolved: [...unresolved].map(([pgid, reason]) => ({ pgid, reason })),
|
|
227
|
+
};
|
|
228
|
+
};
|
|
229
|
+
pruneDeadUnresolved();
|
|
230
|
+
if (handles.size === 0 && unresolved.size === 0)
|
|
231
|
+
return { state: "confirmed", pgids: [] };
|
|
232
|
+
// Cooperative signal to every proven group.
|
|
233
|
+
for (const handle of handles.values())
|
|
234
|
+
groups.signal(handle, coop);
|
|
235
|
+
for (;;) {
|
|
236
|
+
// Drop groups proven empty; only ESRCH proves a group gone.
|
|
237
|
+
for (const [pgid, handle] of [...handles]) {
|
|
238
|
+
if (groups.probeEmpty(handle).status === "empty")
|
|
239
|
+
handles.delete(pgid);
|
|
240
|
+
}
|
|
241
|
+
// Fixed point: catch a descendant that forked/re-grouped during the race.
|
|
242
|
+
capture();
|
|
243
|
+
pruneDeadUnresolved();
|
|
244
|
+
if (handles.size === 0 && unresolved.size === 0)
|
|
245
|
+
return { state: "confirmed", pgids: [] };
|
|
246
|
+
const elapsed = now() - start;
|
|
247
|
+
if (elapsed >= deadlineMs)
|
|
248
|
+
return done();
|
|
249
|
+
// Past the grace window every surviving/newly-captured group gets SIGKILL,
|
|
250
|
+
// each round (a group that fork/re-grouped after escalation still dies).
|
|
251
|
+
if (elapsed >= graceMs) {
|
|
252
|
+
for (const handle of handles.values())
|
|
253
|
+
groups.signal(handle, "SIGKILL");
|
|
254
|
+
}
|
|
255
|
+
await sleep(probeIntervalMs);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=process-tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-tree.js","sourceRoot":"","sources":["../src/process-tree.ts"],"names":[],"mappings":"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"}
|
package/dist/runloop.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { HarnessEvent, HarnessRunSpec } from "@claudexor/schema";
|
|
2
2
|
import { type ChildStdin } from "./proc.js";
|
|
3
|
+
import type { ProcessTreeTerminationOutcome, ReapProcessTreeOptions } from "./process-tree.js";
|
|
3
4
|
export declare function abortSignalFromSpec(spec: HarnessRunSpec): AbortSignal | undefined;
|
|
4
5
|
export interface CliRunLoopOptions {
|
|
5
6
|
bin: string;
|
|
@@ -30,6 +31,10 @@ export interface CliRunLoopOptions {
|
|
|
30
31
|
handle: (obj: unknown, io: ChildStdin) => AsyncGenerator<HarnessEvent>;
|
|
31
32
|
closeStdinOn?: (obj: unknown) => boolean;
|
|
32
33
|
};
|
|
34
|
+
/** Injection seam for the whole-tree death proof (deterministic tests of the
|
|
35
|
+
* termination_unconfirmed terminal fact). Forwarded to spawnProcess; production
|
|
36
|
+
* callers never set this. */
|
|
37
|
+
reap?: (opts: ReapProcessTreeOptions) => Promise<ProcessTreeTerminationOutcome>;
|
|
33
38
|
}
|
|
34
39
|
export declare function runCliHarness(opts: CliRunLoopOptions): AsyncGenerator<HarnessEvent>;
|
|
35
40
|
//# sourceMappingURL=runloop.d.ts.map
|
package/dist/runloop.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runloop.d.ts","sourceRoot":"","sources":["../src/runloop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"runloop.d.ts","sourceRoot":"","sources":["../src/runloop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,KAAK,EAAE,6BAA6B,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAwB/F,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,cAAc,GAAG,WAAW,GAAG,SAAS,CAOjF;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,cAAc,CAAC;IACrB;;;;OAIG;IACH,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,YAAY,EAAE,GAAG,IAAI,CAAC;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAChD,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAClC;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE;QACR,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;QACnC,MAAM,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,KAAK,cAAc,CAAC,YAAY,CAAC,CAAC;QACvE,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;KAC1C,CAAC;IACF;;iCAE6B;IAC7B,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,sBAAsB,KAAK,OAAO,CAAC,6BAA6B,CAAC,CAAC;CACjF;AAED,wBAAuB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,cAAc,CAAC,YAAY,CAAC,CAkK1F"}
|
package/dist/runloop.js
CHANGED
|
@@ -37,8 +37,12 @@ export async function* runCliHarness(opts) {
|
|
|
37
37
|
let droppedUnparsedLines = 0;
|
|
38
38
|
let droppedUnrecognizedEvents = 0;
|
|
39
39
|
let sawError = false;
|
|
40
|
+
let spawnFailed = false;
|
|
40
41
|
let exitCode = null;
|
|
41
42
|
let exitSignal = null;
|
|
43
|
+
// QA-027: a cancellation whose whole-tree death proof could not confirm death
|
|
44
|
+
// (a proven-alive survivor group or an unreadable-identity group). Never silent.
|
|
45
|
+
let terminationUnconfirmed = null;
|
|
42
46
|
const abortSignal = abortSignalFromSpec(spec);
|
|
43
47
|
const stderrTail = () => redact(stderrRing.join("\n")).slice(-STDERR_DETAIL_MAX).trim();
|
|
44
48
|
// Box the stdin handle: it is assigned inside the onSpawn callback, which
|
|
@@ -50,6 +54,7 @@ export async function* runCliHarness(opts) {
|
|
|
50
54
|
env: opts.env,
|
|
51
55
|
inheritEnv: spec.env_inheritance,
|
|
52
56
|
abortSignal,
|
|
57
|
+
...(opts.reap ? { reap: opts.reap } : {}),
|
|
53
58
|
...(opts.session
|
|
54
59
|
? {
|
|
55
60
|
keepStdinOpen: true,
|
|
@@ -72,6 +77,13 @@ export async function* runCliHarness(opts) {
|
|
|
72
77
|
exitSignal = ev.signal;
|
|
73
78
|
continue;
|
|
74
79
|
}
|
|
80
|
+
if (ev.type === "termination_unconfirmed") {
|
|
81
|
+
// Death could not be proven — a fail-closed terminal fact (QA-027). Mark
|
|
82
|
+
// the attempt non-clean so it can never launder as a clean success.
|
|
83
|
+
terminationUnconfirmed = { survivors: ev.survivors, unresolved: ev.unresolved };
|
|
84
|
+
sawError = true;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
75
87
|
let obj;
|
|
76
88
|
try {
|
|
77
89
|
obj = JSON.parse(ev.line);
|
|
@@ -108,6 +120,7 @@ export async function* runCliHarness(opts) {
|
|
|
108
120
|
}
|
|
109
121
|
catch (err) {
|
|
110
122
|
sawError = true;
|
|
123
|
+
spawnFailed = true;
|
|
111
124
|
yield {
|
|
112
125
|
type: "error",
|
|
113
126
|
session_id: spec.session_id,
|
|
@@ -120,6 +133,19 @@ export async function* runCliHarness(opts) {
|
|
|
120
133
|
session.io = null;
|
|
121
134
|
}
|
|
122
135
|
const aborted = abortSignal?.aborted === true;
|
|
136
|
+
// QA-027 fail-closed: an unconfirmed death is disclosed as its own typed terminal
|
|
137
|
+
// fact EVEN on an aborted run (a default cancellation that could not prove death
|
|
138
|
+
// is exactly the silent-survivor case) — emitted regardless of `aborted`.
|
|
139
|
+
if (terminationUnconfirmed) {
|
|
140
|
+
yield {
|
|
141
|
+
type: "error",
|
|
142
|
+
session_id: spec.session_id,
|
|
143
|
+
ts: ts(),
|
|
144
|
+
error: `${label} cancellation could not confirm process death: ${terminationUnconfirmed.survivors.length} surviving group(s)${terminationUnconfirmed.unresolved.length
|
|
145
|
+
? `, ${terminationUnconfirmed.unresolved.length} group(s) with unreadable identity`
|
|
146
|
+
: ""}`,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
123
149
|
if (!sawError && !aborted && exitCode !== null && exitCode !== 0) {
|
|
124
150
|
const tail = stderrTail();
|
|
125
151
|
yield {
|
|
@@ -146,6 +172,21 @@ export async function* runCliHarness(opts) {
|
|
|
146
172
|
payload["aborted"] = true;
|
|
147
173
|
if (exitCode !== null)
|
|
148
174
|
payload["exit_code"] = exitCode;
|
|
175
|
+
// Typed unconfirmed-death terminal fact (QA-027): the run cannot read as a clean
|
|
176
|
+
// cancel/success while a proven survivor lives — the disclosure rides the
|
|
177
|
+
// terminal completed event (and the error above), never a silent drop.
|
|
178
|
+
if (terminationUnconfirmed) {
|
|
179
|
+
payload["termination_unconfirmed"] = {
|
|
180
|
+
survivors: terminationUnconfirmed.survivors,
|
|
181
|
+
unresolved: terminationUnconfirmed.unresolved,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
// Typed crash evidence (GH #31): a non-aborted signal kill or spawn failure is
|
|
185
|
+
// a process crash the orchestrator classifies without parsing prose.
|
|
186
|
+
if (!aborted && exitSignal)
|
|
187
|
+
payload["exit_signal"] = exitSignal;
|
|
188
|
+
if (spawnFailed)
|
|
189
|
+
payload["spawn_failed"] = true;
|
|
149
190
|
yield {
|
|
150
191
|
type: "completed",
|
|
151
192
|
session_id: spec.session_id,
|
package/dist/runloop.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runloop.js","sourceRoot":"","sources":["../src/runloop.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAmB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"runloop.js","sourceRoot":"","sources":["../src/runloop.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime-env.d.ts
CHANGED
|
@@ -1,18 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The directory of the Node binary Claudexor ITSELF is running on, when that
|
|
3
|
+
* binary is safe to expose to a harness's inner login shell. In production this
|
|
4
|
+
* is the notarized app-bundled runtime
|
|
5
|
+
* (`.../Claudexor.app/Contents/Resources`); a CLI/dev daemon runs on the
|
|
6
|
+
* managed `~/.claudexor/node/bin/node`. Putting this dir FIRST on the harness
|
|
7
|
+
* PATH is the QA-022 fix: a vendor tool's inner `/bin/bash -lc` grandchild
|
|
8
|
+
* re-sources login profiles (`path_helper`, `brew shellenv`) and would
|
|
9
|
+
* otherwise resolve an ad-hoc Homebrew Node that macOS's code-signing monitor
|
|
10
|
+
* SIGKILLs (`Killed: 9`). Anchoring the SAME Node the daemon already proved
|
|
11
|
+
* runnable — by executing on it — lets the grandchild resolve a working Node
|
|
12
|
+
* even after the login shell reshuffles PATH.
|
|
13
|
+
*
|
|
14
|
+
* Guarded so the prepend can never make things worse:
|
|
15
|
+
* - the path must be absolute and a spawnable regular file (the running
|
|
16
|
+
* process is itself proof the bytes launch — "self-contained/valid");
|
|
17
|
+
* - it must NOT itself be an at-risk Homebrew Node — prepending a killable
|
|
18
|
+
* Node's dir would poison the very shell we are trying to protect;
|
|
19
|
+
* - the REAL binary's dir (symlinks followed) is what we anchor — a symlinked
|
|
20
|
+
* launcher must not put the WRONG dir first on the harness PATH;
|
|
21
|
+
* - that dir must NOT be group/world-writable — prepending a dir any non-owner
|
|
22
|
+
* can write to lets a local attacker drop a malicious `node`/`bash` that then
|
|
23
|
+
* SHADOWS the system tools for every harness child.
|
|
24
|
+
* Returns null when any guard fails; the guessed `preferred` entries still apply.
|
|
25
|
+
*/
|
|
26
|
+
export declare function managedRunnerNodeDir(execPath?: string, platform?: NodeJS.Platform): string | null;
|
|
1
27
|
/**
|
|
2
28
|
* Single producer for the PATH every local harness discovery/run surface should
|
|
3
29
|
* use. Surfaces may still inherit other env vars, but binary resolution must not
|
|
4
30
|
* depend on whether the daemon was launched from a GUI app, login shell, or CLI.
|
|
31
|
+
* Existing inherited entries are never dropped (only de-duplicated); the only
|
|
32
|
+
* additions are the trusted `preferred` prefixes.
|
|
5
33
|
*/
|
|
6
|
-
export declare function normalizedHarnessPath(source?: NodeJS.ProcessEnv): string;
|
|
7
|
-
export declare function harnessRuntimeEnv(source?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
34
|
+
export declare function normalizedHarnessPath(source?: NodeJS.ProcessEnv, execPath?: string, platform?: NodeJS.Platform): string;
|
|
35
|
+
export declare function harnessRuntimeEnv(source?: NodeJS.ProcessEnv, execPath?: string, platform?: NodeJS.Platform): NodeJS.ProcessEnv;
|
|
8
36
|
/**
|
|
9
37
|
* Resolve which binary a harness child will ACTUALLY execute, using the same
|
|
10
38
|
* normalized PATH the spawn layer composes. Doctor discloses this path so a
|
|
11
39
|
* stale pinned shim (e.g. `~/.claudexor/node/bin/codex` shadowing a newer
|
|
12
40
|
* install) is visible instead of silently answering for the wrong version.
|
|
13
41
|
* Returns null when the binary is not on the harness PATH.
|
|
42
|
+
*
|
|
43
|
+
* `execPath`/`platform` are forwarded to `normalizedHarnessPath` (same defaults,
|
|
44
|
+
* so production behavior is unchanged). Forwarding them is what lets a test
|
|
45
|
+
* fully control the resolution PATH: without it the resolver always anchors the
|
|
46
|
+
* REAL `process.execPath` dir (e.g. `~/.claudexor/node/bin`) first, and any
|
|
47
|
+
* `claude`/`codex` living beside the running Node shadows an injected fixture —
|
|
48
|
+
* the machine-specific parity failure this seam closes.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveHarnessBinary(bin: string, source?: NodeJS.ProcessEnv, execPath?: string, platform?: NodeJS.Platform): string | null;
|
|
51
|
+
/**
|
|
52
|
+
* Advisory explaining WHY a harness binary failed to resolve when the
|
|
53
|
+
* filesystem still holds evidence of an install. The live incident this
|
|
54
|
+
* guards: Homebrew's codex cask stayed registered (Caskroom dir present,
|
|
55
|
+
* version pinned) while its payload and bin link had vanished, so every
|
|
56
|
+
* surface dead-ended at "not found on PATH"/ENOENT with no path to repair.
|
|
57
|
+
* Two evidence classes, checked in order:
|
|
58
|
+
*
|
|
59
|
+
* 1. an entry named like the binary exists on the harness PATH (or at the
|
|
60
|
+
* configured absolute override) but is not spawnable — dangling symlink,
|
|
61
|
+
* exec bit stripped, or a directory shadowing the name;
|
|
62
|
+
* 2. nothing is on PATH at all, but a Homebrew Caskroom/Cellar dir still
|
|
63
|
+
* lists the binary as installed.
|
|
64
|
+
*
|
|
65
|
+
* Diagnostic only (doctor/discover append it); never gates a run and never
|
|
66
|
+
* executes a package manager. Returns null when the binary resolves or when
|
|
67
|
+
* there is nothing better to say than "not installed".
|
|
14
68
|
*/
|
|
15
|
-
export declare function
|
|
69
|
+
export declare function brokenInstallAdvisory(bin: string, source?: NodeJS.ProcessEnv, brewPrefixes?: readonly string[]): string | null;
|
|
16
70
|
/**
|
|
17
71
|
* Advisory when the Node binary running Claudexor is one macOS's code-signing
|
|
18
72
|
* monitor is known to SIGKILL (Homebrew's adhoc-signed node). The daemon spawns
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-env.d.ts","sourceRoot":"","sources":["../src/runtime-env.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime-env.d.ts","sourceRoot":"","sources":["../src/runtime-env.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,GAAE,MAAyB,EACnC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,MAAM,GAAG,IAAI,CAef;AAYD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,GAAE,MAAM,CAAC,UAAwB,EACvC,QAAQ,GAAE,MAAyB,EACnC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,MAAM,CAyBR;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,GAAE,MAAM,CAAC,UAAwB,EACvC,QAAQ,GAAE,MAAyB,EACnC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,MAAM,CAAC,UAAU,CAEnB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,MAAM,CAAC,UAAwB,EACvC,QAAQ,GAAE,MAAyB,EACnC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,MAAM,GAAG,IAAI,CAcf;AAwBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,MAAM,CAAC,UAAwB,EACvC,YAAY,GAAE,SAAS,MAAM,EAAsB,GAClD,MAAM,GAAG,IAAI,CA4Cf;AA4CD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,GAAE,MAAyB,EACnC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,MAAM,GAAG,IAAI,CAQf"}
|