stitchkit 0.105.2 → 0.106.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/CHANGELOG.md +30 -0
- package/dist/agent-runtime/coding-shell-process.d.ts.map +1 -1
- package/dist/agent-runtime/store-conformance-lifecycle.d.ts +10 -10
- package/dist/agent-runtime/store-conformance-support.d.ts +5 -5
- package/dist/entrypoints/agent-runtime/coding-tools.js +2 -2
- package/dist/entrypoints/agent-runtime/sandbox.js +2 -2
- package/dist/entrypoints/process.js +1 -1
- package/dist/{index-3s86a7kf.js → index-4q9jvqg7.js} +216 -51
- package/dist/{index-sevbwsnn.js → index-9bskshe3.js} +2 -4
- package/dist/process/cleanup.d.ts.map +1 -1
- package/dist/process/command-owner.d.ts.map +1 -1
- package/dist/process/contract.d.ts +80 -7
- package/dist/process/contract.d.ts.map +1 -1
- package/dist/process/group.d.ts +12 -0
- package/dist/process/group.d.ts.map +1 -1
- package/dist/process/launch.d.ts +5 -0
- package/dist/process/launch.d.ts.map +1 -1
- package/dist/process/output-drain.d.ts +14 -0
- package/dist/process/output-drain.d.ts.map +1 -0
- package/dist/process/owned-child.d.ts +9 -0
- package/dist/process/owned-child.d.ts.map +1 -1
- package/dist/process/terminate.d.ts +2 -0
- package/dist/process/terminate.d.ts.map +1 -1
- package/dist/process/transport.d.ts +5 -0
- package/dist/process/transport.d.ts.map +1 -1
- package/llms/process.txt +62 -17
- package/llms/stitchkit.txt +3 -3
- package/llms/{upgrading-0.37.0-0.50.0.txt → upgrading-0.37.0-0.53.0.txt} +25 -3
- package/llms/{upgrading-0.53.0-0.67.0.txt → upgrading-0.55.0-0.68.0.txt} +53 -25
- package/llms/{upgrading-0.68.0-0.94.0.txt → upgrading-0.69.0-0.95.0.txt} +45 -53
- package/llms/{upgrading-0.95.0-0.105.0.txt → upgrading-0.96.0-0.106.0.txt} +40 -45
- package/llms/upgrading.txt +4 -4
- package/llms-full.txt +102 -20
- package/llms.txt +5 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,36 @@ additive**; the first breaking change landed in 0.10.0. Grep the file for
|
|
|
15
15
|
|
|
16
16
|
## [Unreleased]
|
|
17
17
|
|
|
18
|
+
## [0.106.0] - 2026-10-06
|
|
19
|
+
|
|
20
|
+
### ⚠️ Breaking changes
|
|
21
|
+
|
|
22
|
+
**Who must act:** code passed to `runNativeCommand`'s `onLeaderSettled` that treats
|
|
23
|
+
`kind: 'error'` as "the command was stopped" (a caller abort, `timeoutMs`, an exceeded output budget
|
|
24
|
+
or a failing sink).
|
|
25
|
+
|
|
26
|
+
- `stitchkit/process` — **a stopped leader settles as `'stopped'`, with its exit.**
|
|
27
|
+
`NativeCommandSettlement` gains `{ kind: 'stopped', cause, exitCode, signal }`: a stopped command
|
|
28
|
+
waits for the stop signals and the leader's exit, then settles with the stop's `cause` and the
|
|
29
|
+
exit code and signal the kernel reported (`SIGTERM`, or `SIGKILL` once the grace ended), which
|
|
30
|
+
were lost before. `'error'` now means only that no exit of the leader was observed (it could not
|
|
31
|
+
start, or its exit did not arrive within `cleanupTimeoutMs`); `'exit'` is unchanged. The hook
|
|
32
|
+
still runs once, after the stop sequence instead of beside it.
|
|
33
|
+
`// before: onLeaderSettled: (e) => { if (e.kind === 'error') stopped(e.cause) }` →
|
|
34
|
+
`// after: onLeaderSettled: (e) => { if (e.kind === 'stopped') stopped(e.cause, e.signal) }`
|
|
35
|
+
**Who must act:** code that handles a stop in `kind === 'error'`. See
|
|
36
|
+
[migration](docs/guide/upgrading.md#a-stopped-leader-settles-as-stopped). → ADR 0248
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- `stitchkit/process` — `runNativeCommand` takes `stdio: 'inherit'`: the command gets the caller's
|
|
41
|
+
stdin, stdout and stderr, so a terminal stays a terminal (colour, prompts, `isatty`); `capture`,
|
|
42
|
+
`onOutput`, `stdin`, `maxOutputBytes` and `drainTimeoutMs` are refused by name with it.
|
|
43
|
+
- `stitchkit/process` — `runNativeCommand` takes `group: 'caller'`: the command joins the caller's
|
|
44
|
+
process group, so a Ctrl-C at the terminal reaches it; only its leader is stopped (default stop
|
|
45
|
+
`{ target: 'leader', signal: 'SIGTERM', graceMs: 100 }`), and `descendants` and a group stop are
|
|
46
|
+
refused, since its group is the caller's. → ADR 0248
|
|
47
|
+
|
|
18
48
|
## [0.105.2] - 2026-10-06
|
|
19
49
|
|
|
20
50
|
### Added
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coding-shell-process.d.ts","sourceRoot":"","sources":["../../src/agent-runtime/coding-shell-process.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,qBAAqB,EAAqB,MAAM,wBAAwB,CAAC;AAEvF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAuCrD,wBAAsB,cAAc,CAAC,KAAK,EAAE;IAC1C,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAC;IAC/C,aAAa,CAAC,EAAE,UAAU,CAAC,WAAW,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/E,KAAK,CAAC,EAAE,MAAM,UAAU,CAAC,WAAW,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;CACrE;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"coding-shell-process.d.ts","sourceRoot":"","sources":["../../src/agent-runtime/coding-shell-process.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,qBAAqB,EAAqB,MAAM,wBAAwB,CAAC;AAEvF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAuCrD,wBAAsB,cAAc,CAAC,KAAK,EAAE;IAC1C,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAC;IAC/C,aAAa,CAAC,EAAE,UAAU,CAAC,WAAW,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/E,KAAK,CAAC,EAAE,MAAM,UAAU,CAAC,WAAW,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;CACrE;;;;;;;;;;;;;;;GA2JA"}
|
|
@@ -133,11 +133,6 @@ export declare function fencingPhase(store: AgentRuntimeStore, conversationId: s
|
|
|
133
133
|
parts: ({
|
|
134
134
|
type: "text";
|
|
135
135
|
text: string;
|
|
136
|
-
} | {
|
|
137
|
-
type: "file";
|
|
138
|
-
mediaType: string;
|
|
139
|
-
reference: string;
|
|
140
|
-
filename?: string | undefined;
|
|
141
136
|
} | {
|
|
142
137
|
type: "reasoning";
|
|
143
138
|
text: string;
|
|
@@ -146,6 +141,11 @@ export declare function fencingPhase(store: AgentRuntimeStore, conversationId: s
|
|
|
146
141
|
provider: string;
|
|
147
142
|
data: Record<string, import("zod").JSONType>;
|
|
148
143
|
} | undefined;
|
|
144
|
+
} | {
|
|
145
|
+
type: "file";
|
|
146
|
+
mediaType: string;
|
|
147
|
+
reference: string;
|
|
148
|
+
filename?: string | undefined;
|
|
149
149
|
} | {
|
|
150
150
|
type: "source";
|
|
151
151
|
sourceId: string;
|
|
@@ -313,11 +313,6 @@ export declare function fencingPhase(store: AgentRuntimeStore, conversationId: s
|
|
|
313
313
|
parts: ({
|
|
314
314
|
type: "text";
|
|
315
315
|
text: string;
|
|
316
|
-
} | {
|
|
317
|
-
type: "file";
|
|
318
|
-
mediaType: string;
|
|
319
|
-
reference: string;
|
|
320
|
-
filename?: string | undefined;
|
|
321
316
|
} | {
|
|
322
317
|
type: "reasoning";
|
|
323
318
|
text: string;
|
|
@@ -326,6 +321,11 @@ export declare function fencingPhase(store: AgentRuntimeStore, conversationId: s
|
|
|
326
321
|
provider: string;
|
|
327
322
|
data: Record<string, import("zod").JSONType>;
|
|
328
323
|
} | undefined;
|
|
324
|
+
} | {
|
|
325
|
+
type: "file";
|
|
326
|
+
mediaType: string;
|
|
327
|
+
reference: string;
|
|
328
|
+
filename?: string | undefined;
|
|
329
329
|
} | {
|
|
330
330
|
type: "source";
|
|
331
331
|
sourceId: string;
|
|
@@ -8,6 +8,11 @@ export declare function userMessage(conversationId: string, id: string): {
|
|
|
8
8
|
parts: ({
|
|
9
9
|
type: "text";
|
|
10
10
|
text: string;
|
|
11
|
+
} | {
|
|
12
|
+
type: "file";
|
|
13
|
+
mediaType: string;
|
|
14
|
+
reference: string;
|
|
15
|
+
filename?: string | undefined;
|
|
11
16
|
} | {
|
|
12
17
|
type: "reasoning";
|
|
13
18
|
text: string;
|
|
@@ -16,11 +21,6 @@ export declare function userMessage(conversationId: string, id: string): {
|
|
|
16
21
|
provider: string;
|
|
17
22
|
data: Record<string, import("zod").JSONType>;
|
|
18
23
|
} | undefined;
|
|
19
|
-
} | {
|
|
20
|
-
type: "file";
|
|
21
|
-
mediaType: string;
|
|
22
|
-
reference: string;
|
|
23
|
-
filename?: string | undefined;
|
|
24
24
|
} | {
|
|
25
25
|
type: "source";
|
|
26
26
|
sourceId: string;
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
AgentCodingToolAuthorizationSchema2,
|
|
8
8
|
AgentCodingToolPathAuthorizationSchema2,
|
|
9
9
|
createAgentCodingTools2
|
|
10
|
-
} from "../../index-
|
|
10
|
+
} from "../../index-9bskshe3.js";
|
|
11
11
|
import"../../index-v5ee8ath.js";
|
|
12
12
|
import"../../index-j4zh647a.js";
|
|
13
|
-
import"../../index-
|
|
13
|
+
import"../../index-4q9jvqg7.js";
|
|
14
14
|
import"../../index-8ks9b85e.js";
|
|
15
15
|
import"../../index-gxm9rc97.js";
|
|
16
16
|
import"../../index-yvfk3y36.js";
|
|
@@ -9,7 +9,7 @@ import"../../index-r393tnfp.js";
|
|
|
9
9
|
import"../../index-rpzewktb.js";
|
|
10
10
|
import {
|
|
11
11
|
createAgentCodingTools2
|
|
12
|
-
} from "../../index-
|
|
12
|
+
} from "../../index-9bskshe3.js";
|
|
13
13
|
import"../../index-v5ee8ath.js";
|
|
14
14
|
import"../../index-j4zh647a.js";
|
|
15
15
|
import {
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
nativeCommandOwner,
|
|
20
20
|
terminateOwnedGroup,
|
|
21
21
|
startNativeCommand
|
|
22
|
-
} from "../../index-
|
|
22
|
+
} from "../../index-4q9jvqg7.js";
|
|
23
23
|
import"../../index-gxm9rc97.js";
|
|
24
24
|
import {
|
|
25
25
|
MAX_TIMER_MS
|
|
@@ -17,6 +17,12 @@ var NativeCommandSettlementSchema = z.discriminatedUnion("kind", [
|
|
|
17
17
|
exitCode: z.number().int().nullable(),
|
|
18
18
|
signal: z.string().nullable()
|
|
19
19
|
}),
|
|
20
|
+
z.object({
|
|
21
|
+
kind: z.literal("stopped"),
|
|
22
|
+
cause: z.unknown(),
|
|
23
|
+
exitCode: z.number().int().nullable(),
|
|
24
|
+
signal: z.string().nullable()
|
|
25
|
+
}),
|
|
20
26
|
z.object({ kind: z.literal("error"), cause: z.unknown() })
|
|
21
27
|
]);
|
|
22
28
|
var COMMAND_CLEANUP_TIMEOUT_MS = 2000;
|
|
@@ -37,6 +43,16 @@ function unknownOptionMessage(keys) {
|
|
|
37
43
|
return replacement === undefined ? `Unknown runNativeCommand option ${name}` : `Unknown runNativeCommand option ${name}; use ${replacement}`;
|
|
38
44
|
}).join("; ");
|
|
39
45
|
}
|
|
46
|
+
var DEFAULT_GROUP_STOP = {
|
|
47
|
+
target: "group",
|
|
48
|
+
signal: "SIGTERM",
|
|
49
|
+
graceMs: 100
|
|
50
|
+
};
|
|
51
|
+
var DEFAULT_LEADER_STOP = {
|
|
52
|
+
target: "leader",
|
|
53
|
+
signal: "SIGTERM",
|
|
54
|
+
graceMs: 100
|
|
55
|
+
};
|
|
40
56
|
var NativeCommandOptionsSchema = z.strictObject({
|
|
41
57
|
executable: z.string().min(1),
|
|
42
58
|
args: z.array(z.string()).default([]),
|
|
@@ -53,12 +69,10 @@ var NativeCommandOptionsSchema = z.strictObject({
|
|
|
53
69
|
onLeaderSettled: z.custom((v) => typeof v === "function").optional(),
|
|
54
70
|
onLeaderStarted: z.custom((v) => typeof v === "function").optional(),
|
|
55
71
|
drainTimeoutMs: z.number().int().positive().max(MAX_TIMER_MS).optional(),
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}),
|
|
61
|
-
descendants: z.enum(["terminate-after-leader", "leave"]).default("terminate-after-leader"),
|
|
72
|
+
group: z.enum(["own", "caller"]).default("own"),
|
|
73
|
+
stdio: z.enum(["pipe", "inherit"]).default("pipe"),
|
|
74
|
+
stop: NativeCommandStopPolicySchema.optional(),
|
|
75
|
+
descendants: z.enum(["terminate-after-leader", "leave"]).optional(),
|
|
62
76
|
cleanupTimeoutMs: z.number().int().positive().max(30000).default(COMMAND_CLEANUP_TIMEOUT_MS)
|
|
63
77
|
}, {
|
|
64
78
|
error: (issue) => issue.code === "unrecognized_keys" ? unknownOptionMessage(issue.keys) : undefined
|
|
@@ -82,7 +96,38 @@ var NativeCommandOptionsSchema = z.strictObject({
|
|
|
82
96
|
input: ctx.value,
|
|
83
97
|
message: "stdin exceeds maxStdinBytes"
|
|
84
98
|
});
|
|
85
|
-
|
|
99
|
+
if (input.group === "caller" && input.stop?.target === "group")
|
|
100
|
+
ctx.issues.push({
|
|
101
|
+
code: "custom",
|
|
102
|
+
input: ctx.value,
|
|
103
|
+
message: "group: 'caller' stops only the leader; use stop.target 'leader'"
|
|
104
|
+
});
|
|
105
|
+
if (input.group === "caller" && input.descendants !== undefined)
|
|
106
|
+
ctx.issues.push({
|
|
107
|
+
code: "custom",
|
|
108
|
+
input: ctx.value,
|
|
109
|
+
message: "group: 'caller' has no group of its own, so descendants does not apply"
|
|
110
|
+
});
|
|
111
|
+
if (input.stdio === "inherit") {
|
|
112
|
+
const piped = [
|
|
113
|
+
input.capture && "capture",
|
|
114
|
+
input.onOutput && "onOutput",
|
|
115
|
+
input.stdin && "stdin",
|
|
116
|
+
input.maxOutputBytes !== undefined && "maxOutputBytes",
|
|
117
|
+
input.drainTimeoutMs !== undefined && "drainTimeoutMs"
|
|
118
|
+
].filter((name) => typeof name === "string");
|
|
119
|
+
for (const name of piped)
|
|
120
|
+
ctx.issues.push({
|
|
121
|
+
code: "custom",
|
|
122
|
+
input: ctx.value,
|
|
123
|
+
message: `stdio: 'inherit' leaves no pipe for ${name}`
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}).transform((input) => ({
|
|
127
|
+
...input,
|
|
128
|
+
stop: input.stop ?? (input.group === "caller" ? DEFAULT_LEADER_STOP : DEFAULT_GROUP_STOP),
|
|
129
|
+
descendants: input.descendants ?? "terminate-after-leader"
|
|
130
|
+
}));
|
|
86
131
|
var NativeCommandResultSchema = z.object({
|
|
87
132
|
exitCode: z.number().int().nullable(),
|
|
88
133
|
signal: z.string().nullable(),
|
|
@@ -216,6 +261,37 @@ async function stopCommandLeader(stop) {
|
|
|
216
261
|
}
|
|
217
262
|
return await signalUntilSettled(pid, "SIGKILL", deadline) || signalled;
|
|
218
263
|
}
|
|
264
|
+
async function stopLeaderAlone(stop) {
|
|
265
|
+
const { leader, policy } = stop;
|
|
266
|
+
const running = () => leader.exitCode === null && leader.signalCode === null;
|
|
267
|
+
const send = (signal) => {
|
|
268
|
+
if (leader.pid === undefined || !running())
|
|
269
|
+
return false;
|
|
270
|
+
try {
|
|
271
|
+
process.kill(leader.pid, signal);
|
|
272
|
+
return true;
|
|
273
|
+
} catch (error) {
|
|
274
|
+
if (isErrno(error, "ESRCH"))
|
|
275
|
+
return false;
|
|
276
|
+
throw error;
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
if (stop.force || policy.killOn?.aborted)
|
|
280
|
+
return send("SIGKILL");
|
|
281
|
+
const signalled = send(policy.signal);
|
|
282
|
+
if (signalled) {
|
|
283
|
+
const grace = new AbortController;
|
|
284
|
+
const end = () => grace.abort();
|
|
285
|
+
policy.killOn?.addEventListener("abort", end, { once: true });
|
|
286
|
+
stop.leaderExit.then(end, end);
|
|
287
|
+
await sleep(policy.graceMs, grace.signal).catch(() => {
|
|
288
|
+
return;
|
|
289
|
+
});
|
|
290
|
+
policy.killOn?.removeEventListener("abort", end);
|
|
291
|
+
grace.abort();
|
|
292
|
+
}
|
|
293
|
+
return send("SIGKILL") || signalled;
|
|
294
|
+
}
|
|
219
295
|
function commandCleanupError(cause) {
|
|
220
296
|
return new NativeCommandError2("COMMAND_CLEANUP", "Command cleanup did not complete", {
|
|
221
297
|
cause
|
|
@@ -243,8 +319,25 @@ async function cleanupNativeCommand(input) {
|
|
|
243
319
|
const released = signalled.then(awaitRelease, () => {
|
|
244
320
|
return;
|
|
245
321
|
});
|
|
322
|
+
const stopped = async () => {
|
|
323
|
+
const failed = { kind: "error", cause: input.error };
|
|
324
|
+
if (!input.transport)
|
|
325
|
+
return failed;
|
|
326
|
+
await signalled.catch(() => {
|
|
327
|
+
return;
|
|
328
|
+
});
|
|
329
|
+
const leader = await waitForCommandClose(input.transport.leader, input.timeoutMs).catch(() => {
|
|
330
|
+
return;
|
|
331
|
+
});
|
|
332
|
+
return leader?.kind === "exit" ? {
|
|
333
|
+
kind: "stopped",
|
|
334
|
+
cause: input.error,
|
|
335
|
+
exitCode: leader.exitCode,
|
|
336
|
+
signal: leader.signal
|
|
337
|
+
} : failed;
|
|
338
|
+
};
|
|
246
339
|
const cleanup = await Promise.allSettled([
|
|
247
|
-
input.settle(input.event
|
|
340
|
+
input.event ? input.settle(input.event) : stopped().then(input.settle),
|
|
248
341
|
destroyed,
|
|
249
342
|
signalled,
|
|
250
343
|
released
|
|
@@ -318,6 +411,50 @@ function spawnOwnedCommand(input) {
|
|
|
318
411
|
groups.add(child);
|
|
319
412
|
return child;
|
|
320
413
|
}
|
|
414
|
+
var INHERITED_OUTPUT = {
|
|
415
|
+
destroyed: true,
|
|
416
|
+
on: () => {
|
|
417
|
+
return;
|
|
418
|
+
},
|
|
419
|
+
destroy: () => {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
class InheritedChild {
|
|
425
|
+
child;
|
|
426
|
+
stdout = INHERITED_OUTPUT;
|
|
427
|
+
stderr = INHERITED_OUTPUT;
|
|
428
|
+
constructor(child) {
|
|
429
|
+
this.child = child;
|
|
430
|
+
}
|
|
431
|
+
get pid() {
|
|
432
|
+
return this.child.pid;
|
|
433
|
+
}
|
|
434
|
+
get exitCode() {
|
|
435
|
+
return this.child.exitCode;
|
|
436
|
+
}
|
|
437
|
+
get signalCode() {
|
|
438
|
+
return this.child.signalCode;
|
|
439
|
+
}
|
|
440
|
+
kill(signal) {
|
|
441
|
+
return this.child.kill(signal);
|
|
442
|
+
}
|
|
443
|
+
on(event, listener) {
|
|
444
|
+
return this.child.on(event, listener);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
function spawnInheritedCommand(input) {
|
|
448
|
+
const child = new InheritedChild(spawn(input.executable, [...input.args], {
|
|
449
|
+
cwd: input.cwd,
|
|
450
|
+
env: input.env,
|
|
451
|
+
detached: input.group,
|
|
452
|
+
stdio: "inherit"
|
|
453
|
+
}));
|
|
454
|
+
if (input.group)
|
|
455
|
+
groups.add(child);
|
|
456
|
+
return child;
|
|
457
|
+
}
|
|
321
458
|
function ownsCommandGroup(child) {
|
|
322
459
|
return groups.has(child);
|
|
323
460
|
}
|
|
@@ -519,15 +656,21 @@ function launchNativeCommand({
|
|
|
519
656
|
}) {
|
|
520
657
|
let native;
|
|
521
658
|
const launch = driver?.launch;
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
659
|
+
const spawnInput = {
|
|
660
|
+
executable: options.executable,
|
|
661
|
+
args: options.args,
|
|
662
|
+
cwd: options.cwd,
|
|
663
|
+
env: options.envPolicy === "ambient" ? { ...process.env, ...options.env } : options.env ?? {},
|
|
664
|
+
group: options.group === "own" && (driver?.group ?? true)
|
|
665
|
+
};
|
|
666
|
+
let inherited;
|
|
667
|
+
if (!launch) {
|
|
668
|
+
if (options.stdio === "inherit")
|
|
669
|
+
inherited = spawnInheritedCommand(spawnInput);
|
|
670
|
+
else
|
|
671
|
+
native = spawnOwnedCommand(spawnInput);
|
|
672
|
+
}
|
|
673
|
+
const child = launch ? launch() : native ?? inherited;
|
|
531
674
|
if (!child)
|
|
532
675
|
throw new Error("Native command launcher did not supply a process");
|
|
533
676
|
const transport = createCommandTransport(child);
|
|
@@ -611,6 +754,44 @@ function createLeaderSettlement(options, signal) {
|
|
|
611
754
|
};
|
|
612
755
|
}
|
|
613
756
|
|
|
757
|
+
// src/process/output-drain.ts
|
|
758
|
+
function createOutputDrain(options, signal) {
|
|
759
|
+
const captured = { stdout: [], stderr: [] };
|
|
760
|
+
let total = 0;
|
|
761
|
+
const drain = async (stream, channel) => {
|
|
762
|
+
for await (const chunk of stream) {
|
|
763
|
+
if (signal.aborted)
|
|
764
|
+
continue;
|
|
765
|
+
if (!(chunk instanceof Uint8Array))
|
|
766
|
+
throw new TypeError("Expected binary command output");
|
|
767
|
+
total += chunk.byteLength;
|
|
768
|
+
if (options.maxOutputBytes !== undefined && total > options.maxOutputBytes)
|
|
769
|
+
throw new NativeCommandError2("COMMAND_LIMIT", "Command output budget exceeded", {
|
|
770
|
+
reason: "output-budget"
|
|
771
|
+
});
|
|
772
|
+
if (options.capture)
|
|
773
|
+
captured[channel].push(Uint8Array.from(chunk));
|
|
774
|
+
if (options.onOutput)
|
|
775
|
+
try {
|
|
776
|
+
await raceAbort(Promise.resolve().then(() => {
|
|
777
|
+
signal.throwIfAborted();
|
|
778
|
+
return options.onOutput?.(chunk, channel, signal);
|
|
779
|
+
}), signal);
|
|
780
|
+
} catch (error) {
|
|
781
|
+
if (!signal.aborted || error !== signal.reason)
|
|
782
|
+
throw error;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
};
|
|
786
|
+
return {
|
|
787
|
+
drain,
|
|
788
|
+
captured: () => ({
|
|
789
|
+
stdout: Buffer.concat(captured.stdout),
|
|
790
|
+
stderr: Buffer.concat(captured.stderr)
|
|
791
|
+
})
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
|
|
614
795
|
// src/process/start-failure.ts
|
|
615
796
|
async function failedCommandStart(cause, cleanup) {
|
|
616
797
|
const error = new NativeCommandError2("COMMAND_UNAVAILABLE", "Command could not start", {
|
|
@@ -631,6 +812,13 @@ function signalCommandChild(child, input) {
|
|
|
631
812
|
};
|
|
632
813
|
return input.policy.target === "leader" ? stopCommandLeader({ ...stop, leader: child, leaderExit: input.leaderExit }) : stopCommandGroup(stop);
|
|
633
814
|
}
|
|
815
|
+
if (input.callerGroup)
|
|
816
|
+
return stopLeaderAlone({
|
|
817
|
+
leader: child,
|
|
818
|
+
policy: input.policy,
|
|
819
|
+
leaderExit: input.leaderExit,
|
|
820
|
+
force: input.force
|
|
821
|
+
});
|
|
634
822
|
return Promise.resolve().then(() => {
|
|
635
823
|
if (child.exitCode !== null || child.signalCode !== null)
|
|
636
824
|
return false;
|
|
@@ -698,7 +886,8 @@ function startNativeCommand(input, onSpawn, driver) {
|
|
|
698
886
|
if (!acquired)
|
|
699
887
|
return Promise.resolve(false);
|
|
700
888
|
return signalCommandChild(acquired.child, {
|
|
701
|
-
group: driver?.group !== false,
|
|
889
|
+
group: driver?.group !== false && options.group === "own",
|
|
890
|
+
callerGroup: options.group === "caller",
|
|
702
891
|
policy: options.stop,
|
|
703
892
|
leaderExit: acquired.leader,
|
|
704
893
|
cleanupTimeoutMs,
|
|
@@ -746,41 +935,18 @@ function startNativeCommand(input, onSpawn, driver) {
|
|
|
746
935
|
})).then(completion.resolve, completion.reject);
|
|
747
936
|
return owner;
|
|
748
937
|
}
|
|
749
|
-
const
|
|
750
|
-
const stderr =
|
|
751
|
-
let total = 0;
|
|
752
|
-
const { stdout: output, stderr: errorOutput, leader, closed } = launched;
|
|
938
|
+
const output = createOutputDrain(options, controller.signal);
|
|
939
|
+
const { stdout, stderr, leader, closed } = launched;
|
|
753
940
|
const cancelCloseDeadline = createLeaderCloseDeadline(leader, driver?.closeTimeoutMs ?? options.drainTimeoutMs, controller);
|
|
754
|
-
const drain = async (stream, channel, captured) => {
|
|
755
|
-
for await (const chunk of stream) {
|
|
756
|
-
if (controller.signal.aborted)
|
|
757
|
-
continue;
|
|
758
|
-
if (!(chunk instanceof Uint8Array))
|
|
759
|
-
throw new TypeError("Expected binary command output");
|
|
760
|
-
total += chunk.byteLength;
|
|
761
|
-
if (options.maxOutputBytes !== undefined && total > options.maxOutputBytes)
|
|
762
|
-
throw new NativeCommandError2("COMMAND_LIMIT", "Command output budget exceeded", {
|
|
763
|
-
reason: "output-budget"
|
|
764
|
-
});
|
|
765
|
-
if (options.capture)
|
|
766
|
-
captured.push(Uint8Array.from(chunk));
|
|
767
|
-
if (options.onOutput)
|
|
768
|
-
try {
|
|
769
|
-
await raceAbort(Promise.resolve().then(() => {
|
|
770
|
-
controller.signal.throwIfAborted();
|
|
771
|
-
return options.onOutput?.(chunk, channel, controller.signal);
|
|
772
|
-
}), controller.signal);
|
|
773
|
-
} catch (error) {
|
|
774
|
-
if (!controller.signal.aborted || error !== controller.signal.reason)
|
|
775
|
-
throw error;
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
};
|
|
779
941
|
let descendantsStopped = false;
|
|
780
942
|
const settleLeader = async (event) => {
|
|
943
|
+
if (controller.signal.aborted)
|
|
944
|
+
return;
|
|
781
945
|
await settle(event);
|
|
782
946
|
if (controller.signal.aborted)
|
|
783
947
|
return;
|
|
948
|
+
if (options.group === "caller")
|
|
949
|
+
return;
|
|
784
950
|
if (options.descendants !== "terminate-after-leader" || event.kind !== "exit")
|
|
785
951
|
return;
|
|
786
952
|
try {
|
|
@@ -796,8 +962,8 @@ function startNativeCommand(input, onSpawn, driver) {
|
|
|
796
962
|
if (pid !== undefined)
|
|
797
963
|
options.onLeaderStarted?.({ pid });
|
|
798
964
|
const drains = Promise.all([
|
|
799
|
-
drain(
|
|
800
|
-
drain(
|
|
965
|
+
output.drain(stdout, "stdout"),
|
|
966
|
+
output.drain(stderr, "stderr")
|
|
801
967
|
]);
|
|
802
968
|
await raceAbort(Promise.all([drains, leader.then(settleLeader)]), controller.signal);
|
|
803
969
|
const status = await raceAbort(closed, controller.signal);
|
|
@@ -806,8 +972,7 @@ function startNativeCommand(input, onSpawn, driver) {
|
|
|
806
972
|
return {
|
|
807
973
|
...status,
|
|
808
974
|
descendantsStopped,
|
|
809
|
-
|
|
810
|
-
stderr: Buffer.concat(stderr)
|
|
975
|
+
...output.captured()
|
|
811
976
|
};
|
|
812
977
|
} catch (error) {
|
|
813
978
|
controller.abort(error);
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
NativeCommandError2,
|
|
13
13
|
CommandStopped,
|
|
14
14
|
startNativeCommand
|
|
15
|
-
} from "./index-
|
|
15
|
+
} from "./index-4q9jvqg7.js";
|
|
16
16
|
import {
|
|
17
17
|
probeAgentProcessSandboxOutcome,
|
|
18
18
|
missingSandboxRestrictions2,
|
|
@@ -1073,7 +1073,7 @@ async function runCodingShell(input) {
|
|
|
1073
1073
|
descendants: "terminate-after-leader",
|
|
1074
1074
|
onOutput: (bytes, channel) => retain(channel === "stdout" ? stdout : stderr, channel === "stdout" ? artifactStdout : artifactStderr, bytes),
|
|
1075
1075
|
onLeaderSettled: (event) => {
|
|
1076
|
-
if (event.kind
|
|
1076
|
+
if (event.kind === "error")
|
|
1077
1077
|
return;
|
|
1078
1078
|
exitCode = event.exitCode;
|
|
1079
1079
|
signal = event.signal;
|
|
@@ -1109,8 +1109,6 @@ async function runCodingShell(input) {
|
|
|
1109
1109
|
outcome = "cancelled";
|
|
1110
1110
|
else
|
|
1111
1111
|
throw error;
|
|
1112
|
-
exitCode = child?.exitCode ?? exitCode;
|
|
1113
|
-
signal = child?.signalCode ?? signal;
|
|
1114
1112
|
}
|
|
1115
1113
|
const hasArtifact = input.artifacts && artifactBytes > input.maxOutputBytes;
|
|
1116
1114
|
const completeStdout = Buffer.concat(artifactStdout);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../src/process/cleanup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE;IAChD,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,MAAM,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,KAAK,CAAC,EAAE,uBAAuB,CAAC;IAChC,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../src/process/cleanup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE;IAChD,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,MAAM,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,KAAK,CAAC,EAAE,uBAAuB,CAAC;IAChC,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgDhB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-owner.d.ts","sourceRoot":"","sources":["../../src/process/command-owner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AAIzE,OAAO,EAEL,KAAK,oBAAoB,EAI1B,MAAM,YAAY,CAAC;AAEpB,OAAO,EAEL,KAAK,yBAAyB,EAG/B,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"command-owner.d.ts","sourceRoot":"","sources":["../../src/process/command-owner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AAIzE,OAAO,EAEL,KAAK,oBAAoB,EAI1B,MAAM,YAAY,CAAC;AAEpB,OAAO,EAEL,KAAK,yBAAyB,EAG/B,MAAM,UAAU,CAAC;AAOlB,wFAAwF;AACxF,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,oBAAoB,EAC3B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,8BAA8B,KAAK,IAAI,EACzD,MAAM,CAAC,EAAE,yBAAyB;;;;;;;;;;EAkKnC"}
|