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.
Files changed (35) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/agent-runtime/coding-shell-process.d.ts.map +1 -1
  3. package/dist/agent-runtime/store-conformance-lifecycle.d.ts +10 -10
  4. package/dist/agent-runtime/store-conformance-support.d.ts +5 -5
  5. package/dist/entrypoints/agent-runtime/coding-tools.js +2 -2
  6. package/dist/entrypoints/agent-runtime/sandbox.js +2 -2
  7. package/dist/entrypoints/process.js +1 -1
  8. package/dist/{index-3s86a7kf.js → index-4q9jvqg7.js} +216 -51
  9. package/dist/{index-sevbwsnn.js → index-9bskshe3.js} +2 -4
  10. package/dist/process/cleanup.d.ts.map +1 -1
  11. package/dist/process/command-owner.d.ts.map +1 -1
  12. package/dist/process/contract.d.ts +80 -7
  13. package/dist/process/contract.d.ts.map +1 -1
  14. package/dist/process/group.d.ts +12 -0
  15. package/dist/process/group.d.ts.map +1 -1
  16. package/dist/process/launch.d.ts +5 -0
  17. package/dist/process/launch.d.ts.map +1 -1
  18. package/dist/process/output-drain.d.ts +14 -0
  19. package/dist/process/output-drain.d.ts.map +1 -0
  20. package/dist/process/owned-child.d.ts +9 -0
  21. package/dist/process/owned-child.d.ts.map +1 -1
  22. package/dist/process/terminate.d.ts +2 -0
  23. package/dist/process/terminate.d.ts.map +1 -1
  24. package/dist/process/transport.d.ts +5 -0
  25. package/dist/process/transport.d.ts.map +1 -1
  26. package/llms/process.txt +62 -17
  27. package/llms/stitchkit.txt +3 -3
  28. package/llms/{upgrading-0.37.0-0.50.0.txt → upgrading-0.37.0-0.53.0.txt} +25 -3
  29. package/llms/{upgrading-0.53.0-0.67.0.txt → upgrading-0.55.0-0.68.0.txt} +53 -25
  30. package/llms/{upgrading-0.68.0-0.94.0.txt → upgrading-0.69.0-0.95.0.txt} +45 -53
  31. package/llms/{upgrading-0.95.0-0.105.0.txt → upgrading-0.96.0-0.106.0.txt} +40 -45
  32. package/llms/upgrading.txt +4 -4
  33. package/llms-full.txt +102 -20
  34. package/llms.txt +5 -5
  35. 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;;;;;;;;;;;;;;;GA4JA"}
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-sevbwsnn.js";
10
+ } from "../../index-9bskshe3.js";
11
11
  import"../../index-v5ee8ath.js";
12
12
  import"../../index-j4zh647a.js";
13
- import"../../index-3s86a7kf.js";
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-sevbwsnn.js";
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-3s86a7kf.js";
22
+ } from "../../index-4q9jvqg7.js";
23
23
  import"../../index-gxm9rc97.js";
24
24
  import {
25
25
  MAX_TIMER_MS
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  NativeCommandError2,
9
9
  startNativeCommand
10
- } from "../index-3s86a7kf.js";
10
+ } from "../index-4q9jvqg7.js";
11
11
  // src/process/command.ts
12
12
  function runNativeCommand(input) {
13
13
  return startNativeCommand(input).result;
@@ -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
- stop: NativeCommandStopPolicySchema.default({
57
- target: "group",
58
- signal: "SIGTERM",
59
- graceMs: 100
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 ?? { kind: "error", cause: input.error }),
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
- if (!launch)
523
- native = spawnOwnedCommand({
524
- executable: options.executable,
525
- args: options.args,
526
- cwd: options.cwd,
527
- env: options.envPolicy === "ambient" ? { ...process.env, ...options.env } : options.env ?? {},
528
- group: driver?.group ?? true
529
- });
530
- const child = launch ? launch() : native;
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 stdout = [];
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(output, "stdout", stdout),
800
- drain(errorOutput, "stderr", stderr)
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
- stdout: Buffer.concat(stdout),
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-3s86a7kf.js";
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 !== "exit")
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,CA8BhB"}
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;AAMlB,wFAAwF;AACxF,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,oBAAoB,EAC3B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,8BAA8B,KAAK,IAAI,EACzD,MAAM,CAAC,EAAE,yBAAyB;;;;;;;;;;EAiMnC"}
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"}