stitchkit 0.105.1 → 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 +45 -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-5c26631f.js → index-4q9jvqg7.js} +222 -52
- package/dist/{index-y7k2cdgv.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 +86 -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 +64 -15
- 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 +104 -18
- package/llms.txt +5 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,51 @@ 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
|
+
|
|
48
|
+
## [0.105.2] - 2026-10-06
|
|
49
|
+
|
|
50
|
+
### Added
|
|
51
|
+
|
|
52
|
+
- `stitchkit/process` — `runNativeCommand` takes `onLeaderStarted({ pid })`, called once right
|
|
53
|
+
after the leader exists (a throw stops the command with that error), and `drainTimeoutMs`,
|
|
54
|
+
which bounds how long the output pipes may stay open after the leader exited: a holder that
|
|
55
|
+
left the group with `setsid` otherwise keeps the command waiting until `timeoutMs` or the
|
|
56
|
+
signal, and with the bound it ends with `COMMAND_CLEANUP`.
|
|
57
|
+
|
|
58
|
+
### Documentation
|
|
59
|
+
|
|
60
|
+
- `stitchkit/process` — the native IO guide no longer says that `cleanupTimeoutMs` bounds the drain
|
|
61
|
+
after the leader exited; it bounds the wait after a stop, and `drainTimeoutMs` bounds the drain.
|
|
62
|
+
|
|
18
63
|
## [0.105.1] - 2026-10-06
|
|
19
64
|
|
|
20
65
|
### 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([]),
|
|
@@ -51,12 +67,12 @@ var NativeCommandOptionsSchema = z.strictObject({
|
|
|
51
67
|
maxStdinBytes: z.number().int().positive().default(1024 * 1024),
|
|
52
68
|
onOutput: z.custom((v) => typeof v === "function").optional(),
|
|
53
69
|
onLeaderSettled: z.custom((v) => typeof v === "function").optional(),
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
descendants: z.enum(["terminate-after-leader", "leave"]).
|
|
70
|
+
onLeaderStarted: z.custom((v) => typeof v === "function").optional(),
|
|
71
|
+
drainTimeoutMs: z.number().int().positive().max(MAX_TIMER_MS).optional(),
|
|
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(),
|
|
60
76
|
cleanupTimeoutMs: z.number().int().positive().max(30000).default(COMMAND_CLEANUP_TIMEOUT_MS)
|
|
61
77
|
}, {
|
|
62
78
|
error: (issue) => issue.code === "unrecognized_keys" ? unknownOptionMessage(issue.keys) : undefined
|
|
@@ -80,7 +96,38 @@ var NativeCommandOptionsSchema = z.strictObject({
|
|
|
80
96
|
input: ctx.value,
|
|
81
97
|
message: "stdin exceeds maxStdinBytes"
|
|
82
98
|
});
|
|
83
|
-
|
|
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
|
+
}));
|
|
84
131
|
var NativeCommandResultSchema = z.object({
|
|
85
132
|
exitCode: z.number().int().nullable(),
|
|
86
133
|
signal: z.string().nullable(),
|
|
@@ -214,6 +261,37 @@ async function stopCommandLeader(stop) {
|
|
|
214
261
|
}
|
|
215
262
|
return await signalUntilSettled(pid, "SIGKILL", deadline) || signalled;
|
|
216
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
|
+
}
|
|
217
295
|
function commandCleanupError(cause) {
|
|
218
296
|
return new NativeCommandError2("COMMAND_CLEANUP", "Command cleanup did not complete", {
|
|
219
297
|
cause
|
|
@@ -241,8 +319,25 @@ async function cleanupNativeCommand(input) {
|
|
|
241
319
|
const released = signalled.then(awaitRelease, () => {
|
|
242
320
|
return;
|
|
243
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
|
+
};
|
|
244
339
|
const cleanup = await Promise.allSettled([
|
|
245
|
-
input.settle(input.event
|
|
340
|
+
input.event ? input.settle(input.event) : stopped().then(input.settle),
|
|
246
341
|
destroyed,
|
|
247
342
|
signalled,
|
|
248
343
|
released
|
|
@@ -316,6 +411,50 @@ function spawnOwnedCommand(input) {
|
|
|
316
411
|
groups.add(child);
|
|
317
412
|
return child;
|
|
318
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
|
+
}
|
|
319
458
|
function ownsCommandGroup(child) {
|
|
320
459
|
return groups.has(child);
|
|
321
460
|
}
|
|
@@ -517,15 +656,21 @@ function launchNativeCommand({
|
|
|
517
656
|
}) {
|
|
518
657
|
let native;
|
|
519
658
|
const launch = driver?.launch;
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
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;
|
|
529
674
|
if (!child)
|
|
530
675
|
throw new Error("Native command launcher did not supply a process");
|
|
531
676
|
const transport = createCommandTransport(child);
|
|
@@ -609,6 +754,44 @@ function createLeaderSettlement(options, signal) {
|
|
|
609
754
|
};
|
|
610
755
|
}
|
|
611
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
|
+
|
|
612
795
|
// src/process/start-failure.ts
|
|
613
796
|
async function failedCommandStart(cause, cleanup) {
|
|
614
797
|
const error = new NativeCommandError2("COMMAND_UNAVAILABLE", "Command could not start", {
|
|
@@ -629,6 +812,13 @@ function signalCommandChild(child, input) {
|
|
|
629
812
|
};
|
|
630
813
|
return input.policy.target === "leader" ? stopCommandLeader({ ...stop, leader: child, leaderExit: input.leaderExit }) : stopCommandGroup(stop);
|
|
631
814
|
}
|
|
815
|
+
if (input.callerGroup)
|
|
816
|
+
return stopLeaderAlone({
|
|
817
|
+
leader: child,
|
|
818
|
+
policy: input.policy,
|
|
819
|
+
leaderExit: input.leaderExit,
|
|
820
|
+
force: input.force
|
|
821
|
+
});
|
|
632
822
|
return Promise.resolve().then(() => {
|
|
633
823
|
if (child.exitCode !== null || child.signalCode !== null)
|
|
634
824
|
return false;
|
|
@@ -696,7 +886,8 @@ function startNativeCommand(input, onSpawn, driver) {
|
|
|
696
886
|
if (!acquired)
|
|
697
887
|
return Promise.resolve(false);
|
|
698
888
|
return signalCommandChild(acquired.child, {
|
|
699
|
-
group: driver?.group !== false,
|
|
889
|
+
group: driver?.group !== false && options.group === "own",
|
|
890
|
+
callerGroup: options.group === "caller",
|
|
700
891
|
policy: options.stop,
|
|
701
892
|
leaderExit: acquired.leader,
|
|
702
893
|
cleanupTimeoutMs,
|
|
@@ -744,41 +935,18 @@ function startNativeCommand(input, onSpawn, driver) {
|
|
|
744
935
|
})).then(completion.resolve, completion.reject);
|
|
745
936
|
return owner;
|
|
746
937
|
}
|
|
747
|
-
const
|
|
748
|
-
const stderr =
|
|
749
|
-
|
|
750
|
-
const { stdout: output, stderr: errorOutput, leader, closed } = launched;
|
|
751
|
-
const cancelCloseDeadline = createLeaderCloseDeadline(leader, driver?.closeTimeoutMs, controller);
|
|
752
|
-
const drain = async (stream, channel, captured) => {
|
|
753
|
-
for await (const chunk of stream) {
|
|
754
|
-
if (controller.signal.aborted)
|
|
755
|
-
continue;
|
|
756
|
-
if (!(chunk instanceof Uint8Array))
|
|
757
|
-
throw new TypeError("Expected binary command output");
|
|
758
|
-
total += chunk.byteLength;
|
|
759
|
-
if (options.maxOutputBytes !== undefined && total > options.maxOutputBytes)
|
|
760
|
-
throw new NativeCommandError2("COMMAND_LIMIT", "Command output budget exceeded", {
|
|
761
|
-
reason: "output-budget"
|
|
762
|
-
});
|
|
763
|
-
if (options.capture)
|
|
764
|
-
captured.push(Uint8Array.from(chunk));
|
|
765
|
-
if (options.onOutput)
|
|
766
|
-
try {
|
|
767
|
-
await raceAbort(Promise.resolve().then(() => {
|
|
768
|
-
controller.signal.throwIfAborted();
|
|
769
|
-
return options.onOutput?.(chunk, channel, controller.signal);
|
|
770
|
-
}), controller.signal);
|
|
771
|
-
} catch (error) {
|
|
772
|
-
if (!controller.signal.aborted || error !== controller.signal.reason)
|
|
773
|
-
throw error;
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
};
|
|
938
|
+
const output = createOutputDrain(options, controller.signal);
|
|
939
|
+
const { stdout, stderr, leader, closed } = launched;
|
|
940
|
+
const cancelCloseDeadline = createLeaderCloseDeadline(leader, driver?.closeTimeoutMs ?? options.drainTimeoutMs, controller);
|
|
777
941
|
let descendantsStopped = false;
|
|
778
942
|
const settleLeader = async (event) => {
|
|
943
|
+
if (controller.signal.aborted)
|
|
944
|
+
return;
|
|
779
945
|
await settle(event);
|
|
780
946
|
if (controller.signal.aborted)
|
|
781
947
|
return;
|
|
948
|
+
if (options.group === "caller")
|
|
949
|
+
return;
|
|
782
950
|
if (options.descendants !== "terminate-after-leader" || event.kind !== "exit")
|
|
783
951
|
return;
|
|
784
952
|
try {
|
|
@@ -790,9 +958,12 @@ function startNativeCommand(input, onSpawn, driver) {
|
|
|
790
958
|
const run = (async () => {
|
|
791
959
|
try {
|
|
792
960
|
launched.start();
|
|
961
|
+
const pid = acquired?.child.pid;
|
|
962
|
+
if (pid !== undefined)
|
|
963
|
+
options.onLeaderStarted?.({ pid });
|
|
793
964
|
const drains = Promise.all([
|
|
794
|
-
drain(
|
|
795
|
-
drain(
|
|
965
|
+
output.drain(stdout, "stdout"),
|
|
966
|
+
output.drain(stderr, "stderr")
|
|
796
967
|
]);
|
|
797
968
|
await raceAbort(Promise.all([drains, leader.then(settleLeader)]), controller.signal);
|
|
798
969
|
const status = await raceAbort(closed, controller.signal);
|
|
@@ -801,8 +972,7 @@ function startNativeCommand(input, onSpawn, driver) {
|
|
|
801
972
|
return {
|
|
802
973
|
...status,
|
|
803
974
|
descendantsStopped,
|
|
804
|
-
|
|
805
|
-
stderr: Buffer.concat(stderr)
|
|
975
|
+
...output.captured()
|
|
806
976
|
};
|
|
807
977
|
} catch (error) {
|
|
808
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"}
|