stitchkit 0.103.10 → 0.103.12

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 (60) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/agent-runtime/coding-shell-process.d.ts.map +1 -1
  3. package/dist/agent-runtime/sandbox-process-owner.d.ts +1 -1
  4. package/dist/agent-runtime/sandbox-process-owner.d.ts.map +1 -1
  5. package/dist/agent-runtime/store-conformance-lifecycle.d.ts +10 -10
  6. package/dist/durability/json.d.ts.map +1 -1
  7. package/dist/entrypoints/agent-runtime/coding-tools.js +2 -1
  8. package/dist/entrypoints/agent-runtime/harness.js +2 -2
  9. package/dist/entrypoints/agent-runtime/sandbox.js +37 -19
  10. package/dist/entrypoints/agent-runtime.js +2 -2
  11. package/dist/entrypoints/application/diagnostic-journal.js +2 -2
  12. package/dist/entrypoints/files.js +8 -2
  13. package/dist/entrypoints/primitives.js +4 -3
  14. package/dist/entrypoints/process.js +1 -1
  15. package/dist/entrypoints/tools.js +1 -1
  16. package/dist/{index-ary5s7k0.js → index-69nvze1q.js} +1 -2
  17. package/dist/{index-a4ajxwmb.js → index-806d5phm.js} +114 -131
  18. package/dist/index-f330qqyg.js +653 -0
  19. package/dist/index-fm1c1a08.js +138 -0
  20. package/dist/index-xvdd2rbb.js +265 -0
  21. package/dist/{index-9jb61j5a.js → index-zp4jpkp0.js} +1 -1
  22. package/dist/internal/exclusive-lock-read.d.ts +20 -0
  23. package/dist/internal/exclusive-lock-read.d.ts.map +1 -0
  24. package/dist/internal/exclusive-lock.d.ts +2 -1
  25. package/dist/internal/exclusive-lock.d.ts.map +1 -1
  26. package/dist/internal/json-data.d.ts +8 -2
  27. package/dist/internal/json-data.d.ts.map +1 -1
  28. package/dist/internal/json-string-size.d.ts +3 -0
  29. package/dist/internal/json-string-size.d.ts.map +1 -0
  30. package/dist/internal/with-exclusive-lock.d.ts.map +1 -1
  31. package/dist/primitives/canonical-json.d.ts.map +1 -1
  32. package/dist/process/cleanup.d.ts +12 -0
  33. package/dist/process/cleanup.d.ts.map +1 -0
  34. package/dist/process/command-lifetime.d.ts +19 -0
  35. package/dist/process/command-lifetime.d.ts.map +1 -0
  36. package/dist/process/command-owner.d.ts +4 -2
  37. package/dist/process/command-owner.d.ts.map +1 -1
  38. package/dist/process/contract.d.ts +12 -1
  39. package/dist/process/contract.d.ts.map +1 -1
  40. package/dist/process/group.d.ts +6 -1
  41. package/dist/process/group.d.ts.map +1 -1
  42. package/dist/process/launch.d.ts +74 -0
  43. package/dist/process/launch.d.ts.map +1 -0
  44. package/dist/process/leader-settlement.d.ts +2 -0
  45. package/dist/process/leader-settlement.d.ts.map +1 -1
  46. package/dist/process/owned-child.d.ts +10 -0
  47. package/dist/process/owned-child.d.ts.map +1 -0
  48. package/dist/process/start-failure.d.ts +4 -0
  49. package/dist/process/start-failure.d.ts.map +1 -0
  50. package/dist/process/transport.d.ts +30 -0
  51. package/dist/process/transport.d.ts.map +1 -0
  52. package/llms/agent-runtime-sandbox.txt +9 -1
  53. package/llms/agent-runtime.txt +7 -1
  54. package/llms/process.txt +70 -7
  55. package/llms-full.txt +86 -9
  56. package/llms.txt +3 -3
  57. package/package.json +2 -2
  58. package/dist/index-6m6a9ty4.js +0 -285
  59. package/dist/index-c1jmtxa0.js +0 -74
  60. package/dist/index-ga597cvy.js +0 -184
@@ -0,0 +1,653 @@
1
+ import {
2
+ raceAbort
3
+ } from "./index-mbnnw3f2.js";
4
+
5
+ // src/process/contract.ts
6
+ import { z } from "zod";
7
+ var NativeCommandSettlementSchema = z.discriminatedUnion("kind", [
8
+ z.object({
9
+ kind: z.literal("exit"),
10
+ exitCode: z.number().int().nullable(),
11
+ signal: z.string().nullable()
12
+ }),
13
+ z.object({ kind: z.literal("error"), cause: z.unknown() })
14
+ ]);
15
+ var NativeCommandOptionsSchema = z.strictObject({
16
+ executable: z.string().min(1),
17
+ args: z.array(z.string()).default([]),
18
+ cwd: z.string().optional(),
19
+ env: z.record(z.string(), z.string()).optional(),
20
+ envPolicy: z.enum(["declared-only", "ambient"]).default("declared-only"),
21
+ signal: z.custom((v) => v instanceof AbortSignal).optional(),
22
+ timeoutMs: z.number().int().positive().max(2147483647).optional(),
23
+ maxOutputBytes: z.number().int().positive().optional(),
24
+ capture: z.boolean().default(false),
25
+ stdin: z.custom((v) => v instanceof Uint8Array).optional(),
26
+ maxStdinBytes: z.number().int().positive().default(1024 * 1024),
27
+ onOutput: z.custom((v) => typeof v === "function").optional(),
28
+ onLeaderSettled: z.custom((v) => typeof v === "function").optional(),
29
+ killGraceMs: z.number().int().nonnegative().max(1e4).default(100),
30
+ cleanupTimeoutMs: z.number().int().positive().max(30000).default(2000)
31
+ }).superRefine((input, ctx) => {
32
+ if (!input.signal && input.timeoutMs === undefined)
33
+ ctx.addIssue({ code: "custom", message: "Declare a caller signal or a finite timeout" });
34
+ if (input.capture && input.maxOutputBytes === undefined)
35
+ ctx.addIssue({
36
+ code: "custom",
37
+ message: "Capture requires a finite combined output budget"
38
+ });
39
+ if (input.stdin && input.stdin.byteLength > input.maxStdinBytes)
40
+ ctx.addIssue({ code: "custom", message: "stdin exceeds maxStdinBytes" });
41
+ });
42
+ var NativeCommandResultSchema = z.object({
43
+ exitCode: z.number().int().nullable(),
44
+ signal: z.string().nullable(),
45
+ stdout: z.instanceof(Uint8Array),
46
+ stderr: z.instanceof(Uint8Array)
47
+ });
48
+ var NativeCommandLimitReasonSchema = z.enum(["deadline", "output-budget"]);
49
+
50
+ class NativeCommandError2 extends Error {
51
+ code;
52
+ reason;
53
+ constructor(code, message, options) {
54
+ super(message, options);
55
+ this.code = code;
56
+ if (options?.reason !== undefined && code !== "COMMAND_LIMIT")
57
+ throw new TypeError("Only COMMAND_LIMIT accepts a limit reason");
58
+ this.reason = options?.reason === undefined ? undefined : NativeCommandLimitReasonSchema.parse(options.reason);
59
+ this.name = "NativeCommandError";
60
+ }
61
+ }
62
+
63
+ // src/process/group.ts
64
+ function createCommandDeadline(timeoutMs, reason) {
65
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0)
66
+ throw new RangeError("Command deadline must be a positive safe integer");
67
+ const controller = new AbortController;
68
+ const deadline = performance.now() + timeoutMs;
69
+ let timer;
70
+ const schedule = () => {
71
+ const remaining = deadline - performance.now();
72
+ if (remaining <= 0)
73
+ controller.abort(reason);
74
+ else
75
+ timer = setTimeout(schedule, Math.min(remaining, 2147483647));
76
+ };
77
+ schedule();
78
+ return {
79
+ signal: controller.signal,
80
+ cancel() {
81
+ if (timer !== undefined)
82
+ clearTimeout(timer);
83
+ }
84
+ };
85
+ }
86
+ function deniedOnDarwin(error) {
87
+ return process.platform === "darwin" && error instanceof Error && "code" in error && error.code === "EPERM";
88
+ }
89
+ function signalGroup(pid, signal) {
90
+ if (pid === undefined)
91
+ return;
92
+ try {
93
+ process.kill(-pid, signal);
94
+ } catch (error) {
95
+ if (!(error instanceof Error && ("code" in error) && error.code === "ESRCH"))
96
+ throw error;
97
+ }
98
+ }
99
+ function exists(pid) {
100
+ if (pid === undefined)
101
+ return false;
102
+ try {
103
+ process.kill(-pid, 0);
104
+ return true;
105
+ } catch (error) {
106
+ if (error instanceof Error && "code" in error && error.code === "ESRCH")
107
+ return false;
108
+ if (deniedOnDarwin(error))
109
+ return true;
110
+ throw error;
111
+ }
112
+ }
113
+ async function signalUntilSettled(pid, signal, deadline) {
114
+ for (;; ) {
115
+ try {
116
+ signalGroup(pid, signal);
117
+ return;
118
+ } catch (error) {
119
+ if (!deniedOnDarwin(error) || performance.now() >= deadline)
120
+ throw error;
121
+ await new Promise((resolve) => setTimeout(resolve, Math.min(10, deadline - performance.now())));
122
+ }
123
+ }
124
+ }
125
+ async function stopCommandGroup(pid, graceMs, cleanupTimeoutMs = 2000, force = false) {
126
+ const deadline = performance.now() + graceMs + cleanupTimeoutMs;
127
+ if (force) {
128
+ await signalUntilSettled(pid, "SIGKILL", deadline);
129
+ return;
130
+ }
131
+ await signalUntilSettled(pid, "SIGTERM", deadline);
132
+ const until = performance.now() + graceMs;
133
+ while (performance.now() < until && exists(pid))
134
+ await new Promise((resolve) => setTimeout(resolve, Math.min(10, until - performance.now())));
135
+ await signalUntilSettled(pid, "SIGKILL", deadline);
136
+ }
137
+ function commandCleanupError(cause) {
138
+ return new NativeCommandError2("COMMAND_CLEANUP", "Command cleanup did not complete", {
139
+ cause
140
+ });
141
+ }
142
+ function waitForCommandClose(closed, timeoutMs) {
143
+ const deadline = createCommandDeadline(timeoutMs, new DOMException("Command settlement timed out", "TimeoutError"));
144
+ return raceAbort(closed, deadline.signal).finally(() => deadline.cancel());
145
+ }
146
+
147
+ // src/process/cleanup.ts
148
+ async function cleanupNativeCommand(input) {
149
+ const cleanup = await Promise.allSettled([
150
+ input.settle(input.event ?? { kind: "error", cause: input.error }),
151
+ Promise.resolve().then(() => input.transport?.destroy()),
152
+ Promise.resolve().then(input.signal).then(async () => {
153
+ if (!input.transport)
154
+ return;
155
+ try {
156
+ await waitForCommandClose(input.transport.released, input.timeoutMs);
157
+ } catch (cause) {
158
+ throw new Error(`Command handles remained open: ${[...input.transport.pendingHandles].join(", ")}`, { cause });
159
+ }
160
+ })
161
+ ]);
162
+ const failures = cleanup.flatMap((item) => item.status === "rejected" && item.reason !== input.error ? [item.reason] : []);
163
+ if (failures.length)
164
+ throw commandCleanupError(new AggregateError([input.error, ...failures], "Command failed and cleanup failed"));
165
+ }
166
+
167
+ // src/process/command-lifetime.ts
168
+ function createCommandLifetime(input) {
169
+ const acceptSettlement = (error) => {
170
+ if (error instanceof NativeCommandError2 && error.code === "COMMAND_CLEANUP")
171
+ throw error;
172
+ };
173
+ return {
174
+ result: input.result,
175
+ async terminate() {
176
+ let refused = false;
177
+ let refusal;
178
+ if (!input.finished()) {
179
+ try {
180
+ await input.signal();
181
+ } catch (error) {
182
+ refused = true;
183
+ refusal = error;
184
+ input.controller.abort(error);
185
+ }
186
+ try {
187
+ await waitForCommandClose(input.result, input.cleanupTimeoutMs);
188
+ } catch (error) {
189
+ if (!input.finished())
190
+ input.controller.abort(error);
191
+ }
192
+ }
193
+ await input.result.then(() => {
194
+ return;
195
+ }, acceptSettlement);
196
+ if (refused)
197
+ throw commandCleanupError(refusal);
198
+ },
199
+ async stop() {
200
+ if (!input.finished())
201
+ input.controller.abort(new DOMException("Command stopped", "AbortError"));
202
+ await input.result.then(() => {
203
+ return;
204
+ }, acceptSettlement);
205
+ }
206
+ };
207
+ }
208
+
209
+ // src/process/launch.ts
210
+ import { Readable as Readable2 } from "node:stream";
211
+
212
+ // src/process/owned-child.ts
213
+ import { spawn } from "node:child_process";
214
+ var groups = new WeakSet;
215
+ function spawnOwnedCommand(input) {
216
+ const child = spawn(input.executable, [...input.args], {
217
+ cwd: input.cwd,
218
+ env: input.env,
219
+ detached: input.group,
220
+ stdio: ["pipe", "pipe", "pipe"]
221
+ });
222
+ if (input.group)
223
+ groups.add(child);
224
+ return child;
225
+ }
226
+ function ownsCommandGroup(child) {
227
+ return groups.has(child);
228
+ }
229
+
230
+ // src/process/transport.ts
231
+ import { Readable, Writable } from "node:stream";
232
+ function createCommandTransport(child) {
233
+ const leader = Promise.withResolvers();
234
+ const closed = Promise.withResolvers();
235
+ const released = Promise.withResolvers();
236
+ const pendingHandles = new Set(["leader", "launcher", "stdout", "stderr"]);
237
+ const destructors = new Map;
238
+ let stdout;
239
+ let stderr;
240
+ let stdin;
241
+ let isClosed = false;
242
+ const release = (name) => {
243
+ pendingHandles.delete(name);
244
+ if (pendingHandles.size === 0)
245
+ released.resolve();
246
+ };
247
+ const settled = (event) => {
248
+ leader.resolve(event);
249
+ release("leader");
250
+ };
251
+ const pipe = (name, source) => {
252
+ if (isClosed || source.closed)
253
+ release(name);
254
+ else
255
+ source.once("close", () => release(name));
256
+ };
257
+ return {
258
+ child,
259
+ leader: leader.promise,
260
+ closed: closed.promise,
261
+ released: released.promise,
262
+ pendingHandles,
263
+ get stdin() {
264
+ return stdin;
265
+ },
266
+ observe(onFailure) {
267
+ child.on("close", (exitCode, signal) => {
268
+ isClosed = true;
269
+ closed.resolve({ exitCode, signal });
270
+ settled({ kind: "exit", exitCode, signal });
271
+ pendingHandles.clear();
272
+ released.resolve();
273
+ });
274
+ child.on("error", (cause) => {
275
+ settled({ kind: "error", cause });
276
+ onFailure(cause);
277
+ });
278
+ child.on("exit", (exitCode, signal) => settled({ kind: "exit", exitCode, signal }));
279
+ if (child.exitCode !== null || child.signalCode !== null)
280
+ settled({ kind: "exit", exitCode: child.exitCode, signal: child.signalCode });
281
+ },
282
+ capture() {
283
+ stdout = child.stdout;
284
+ destructors.set("stdout", () => stdout?.destroy());
285
+ stderr = child.stderr;
286
+ destructors.set("stderr", () => stderr?.destroy());
287
+ const input = "stdin" in child ? child.stdin : undefined;
288
+ if (input instanceof Writable) {
289
+ stdin = input;
290
+ pendingHandles.add("stdin");
291
+ destructors.set("stdin", () => input.destroy());
292
+ pipe("stdin", input);
293
+ }
294
+ if (stdout instanceof Readable)
295
+ pipe("stdout", stdout);
296
+ if (stderr instanceof Readable)
297
+ pipe("stderr", stderr);
298
+ if (stdout instanceof Readable && stderr instanceof Readable)
299
+ release("launcher");
300
+ return { stdout, stderr };
301
+ },
302
+ pipeDestructor(name, destroy) {
303
+ destructors.set(name, destroy);
304
+ },
305
+ destroy() {
306
+ const failures = [];
307
+ for (const name of ["stdin", "stdout", "stderr"]) {
308
+ try {
309
+ const destroy = destructors.get(name);
310
+ if (destroy)
311
+ destroy();
312
+ else if (name === "stdout")
313
+ child.stdout.destroy();
314
+ else if (name === "stderr")
315
+ child.stderr.destroy();
316
+ else if ("stdin" in child && child.stdin instanceof Writable)
317
+ child.stdin.destroy();
318
+ } catch (cause) {
319
+ failures.push(cause);
320
+ }
321
+ }
322
+ if (failures.length)
323
+ throw new AggregateError(failures, "Command pipe teardown failed");
324
+ }
325
+ };
326
+ }
327
+
328
+ // src/process/launch.ts
329
+ function nativeCommandBudgets(options, driver) {
330
+ const cleanupTimeoutMs = driver?.cleanupTimeoutMs ?? options.cleanupTimeoutMs;
331
+ const timeoutMs = driver?.timeoutMs ?? options.timeoutMs;
332
+ for (const [name, value] of [
333
+ ["cleanup", cleanupTimeoutMs],
334
+ ["execution", timeoutMs],
335
+ ["close", driver?.closeTimeoutMs]
336
+ ])
337
+ if (value !== undefined && (!Number.isSafeInteger(value) || value <= 0))
338
+ throw new RangeError(`Command ${name} deadline must be a positive safe integer`);
339
+ return { cleanupTimeoutMs, timeoutMs };
340
+ }
341
+ var owners = new WeakMap;
342
+ function registerNativeCommandOwner(child, owner) {
343
+ owners.set(child, owner);
344
+ }
345
+ function nativeCommandOwner(child) {
346
+ return owners.get(child);
347
+ }
348
+ function outputStream(source, closed, maxBufferedBytes) {
349
+ if (source instanceof Readable2)
350
+ return {
351
+ bytes: source,
352
+ destroy() {
353
+ source.destroy();
354
+ }
355
+ };
356
+ const queue = [];
357
+ let buffered = 0;
358
+ let ended = false;
359
+ let failure;
360
+ let wake = Promise.withResolvers();
361
+ const notify = () => {
362
+ wake.resolve();
363
+ wake = Promise.withResolvers();
364
+ };
365
+ source.on("data", (chunk) => {
366
+ if (ended || failure)
367
+ return;
368
+ if (!(chunk instanceof Uint8Array)) {
369
+ failure = new TypeError("Expected binary command output");
370
+ notify();
371
+ return;
372
+ }
373
+ if (chunk.byteLength === 0)
374
+ return;
375
+ const available = maxBufferedBytes - buffered;
376
+ if (available > 0) {
377
+ const kept = Uint8Array.from(chunk.subarray(0, available));
378
+ queue.push(kept);
379
+ buffered += kept.byteLength;
380
+ }
381
+ if (chunk.byteLength > available)
382
+ failure = new NativeCommandError2("COMMAND_LIMIT", "Command output budget exceeded", {
383
+ reason: "output-budget"
384
+ });
385
+ notify();
386
+ });
387
+ closed.then(() => {
388
+ ended = true;
389
+ notify();
390
+ });
391
+ return {
392
+ bytes: {
393
+ async* [Symbol.asyncIterator]() {
394
+ for (;; ) {
395
+ const chunk = queue.shift();
396
+ if (chunk) {
397
+ buffered -= chunk.byteLength;
398
+ yield chunk;
399
+ } else if (failure)
400
+ throw failure;
401
+ else if (ended)
402
+ return;
403
+ else
404
+ await wake.promise;
405
+ }
406
+ }
407
+ },
408
+ destroy() {
409
+ ended = true;
410
+ queue.length = 0;
411
+ buffered = 0;
412
+ notify();
413
+ source.destroy();
414
+ }
415
+ };
416
+ }
417
+ function launchNativeCommand(options, driver, onSpawn, onFailure, onInputFailure, onAcquired) {
418
+ let native;
419
+ const launch = driver?.launch;
420
+ if (!launch)
421
+ native = spawnOwnedCommand({
422
+ executable: options.executable,
423
+ args: options.args,
424
+ cwd: options.cwd,
425
+ env: options.envPolicy === "ambient" ? { ...process.env, ...options.env } : options.env ?? {},
426
+ group: driver?.group ?? true
427
+ });
428
+ const child = launch ? launch() : native;
429
+ if (!child)
430
+ throw new Error("Native command launcher did not supply a process");
431
+ const transport = createCommandTransport(child);
432
+ onAcquired(transport);
433
+ transport.observe(onFailure);
434
+ const pipes = transport.capture();
435
+ const stdout = outputStream(pipes.stdout, transport.closed, driver?.maxBufferedBytes ?? 1024 * 1024);
436
+ transport.pipeDestructor("stdout", () => stdout.destroy());
437
+ const stderr = outputStream(pipes.stderr, transport.closed, driver?.maxBufferedBytes ?? 1024 * 1024);
438
+ transport.pipeDestructor("stderr", () => stderr.destroy());
439
+ const stdin = transport.stdin;
440
+ stdin?.on("error", (error) => {
441
+ if (!(("code" in error) && error.code === "EPIPE"))
442
+ onInputFailure(error);
443
+ });
444
+ return {
445
+ ...transport,
446
+ stdout: stdout.bytes,
447
+ stderr: stderr.bytes,
448
+ start() {
449
+ if (native)
450
+ onSpawn?.(native);
451
+ stdin?.end(options.stdin);
452
+ }
453
+ };
454
+ }
455
+
456
+ // src/process/leader-settlement.ts
457
+ function createLeaderCloseDeadline(leader, timeoutMs, controller) {
458
+ let finished = false;
459
+ let deadline;
460
+ const expired = () => controller.abort(deadline?.signal.reason);
461
+ if (timeoutMs !== undefined)
462
+ leader.then(() => {
463
+ if (finished)
464
+ return;
465
+ deadline = createCommandDeadline(timeoutMs, commandCleanupError(new Error("Command close deadline exceeded after leader exit")));
466
+ deadline.signal.addEventListener("abort", expired, { once: true });
467
+ });
468
+ return () => {
469
+ finished = true;
470
+ deadline?.cancel();
471
+ deadline?.signal.removeEventListener("abort", expired);
472
+ };
473
+ }
474
+ function createLeaderSettlement(options, signal) {
475
+ let pending;
476
+ return (event) => {
477
+ if (pending)
478
+ return pending;
479
+ pending = (async () => {
480
+ if (!options.onLeaderSettled)
481
+ return;
482
+ const controller = new AbortController;
483
+ const deadline = createCommandDeadline(options.cleanupTimeoutMs, new Error("Leader settlement deadline exceeded"));
484
+ const expired = () => controller.abort(deadline.signal.reason);
485
+ if (deadline.signal.aborted)
486
+ expired();
487
+ else
488
+ deadline.signal.addEventListener("abort", expired, { once: true });
489
+ const abort = () => controller.abort(signal.reason);
490
+ if (!signal.aborted)
491
+ signal.addEventListener("abort", abort, { once: true });
492
+ try {
493
+ await raceAbort(Promise.resolve(options.onLeaderSettled(event, controller.signal)), controller.signal);
494
+ } catch (cause) {
495
+ if (signal.aborted && cause === signal.reason)
496
+ throw cause;
497
+ throw commandCleanupError(new AggregateError([event, cause], "Leader settlement failed"));
498
+ } finally {
499
+ deadline.cancel();
500
+ deadline.signal.removeEventListener("abort", expired);
501
+ signal.removeEventListener("abort", abort);
502
+ controller.abort(new Error("Leader settlement completed"));
503
+ }
504
+ })();
505
+ pending.catch(() => {
506
+ return;
507
+ });
508
+ return pending;
509
+ };
510
+ }
511
+
512
+ // src/process/start-failure.ts
513
+ async function failedCommandStart(cause, cleanup) {
514
+ const error = new NativeCommandError2("COMMAND_UNAVAILABLE", "Command could not start", {
515
+ cause
516
+ });
517
+ await cleanup(error);
518
+ throw error;
519
+ }
520
+
521
+ // src/process/command-owner.ts
522
+ function startNativeCommand(input, onSpawn, driver) {
523
+ const options = NativeCommandOptionsSchema.parse(input);
524
+ options.signal?.throwIfAborted();
525
+ if (process.platform === "win32" && driver?.group !== false)
526
+ throw new NativeCommandError2("COMMAND_UNAVAILABLE", "POSIX process groups are required");
527
+ const { cleanupTimeoutMs, timeoutMs } = nativeCommandBudgets(options, driver);
528
+ const controller = new AbortController;
529
+ const abort = () => controller.abort(options.signal?.reason);
530
+ options.signal?.addEventListener("abort", abort, { once: true });
531
+ if (options.signal?.aborted)
532
+ abort();
533
+ const deadline = timeoutMs === undefined ? undefined : createCommandDeadline(timeoutMs, new NativeCommandError2("COMMAND_LIMIT", "Command deadline exceeded", {
534
+ reason: "deadline"
535
+ }));
536
+ const expired = () => controller.abort(deadline?.signal.reason);
537
+ if (deadline?.signal.aborted)
538
+ expired();
539
+ else
540
+ deadline?.signal.addEventListener("abort", expired, { once: true });
541
+ const settle = createLeaderSettlement({ ...options, cleanupTimeoutMs }, controller.signal);
542
+ let acquired;
543
+ let finished = false;
544
+ const completion = Promise.withResolvers();
545
+ const result = completion.promise.finally(() => {
546
+ finished = true;
547
+ });
548
+ result.catch(() => {
549
+ return;
550
+ });
551
+ const signalOwned = (force = driver?.force) => {
552
+ const child = acquired?.child;
553
+ if (!child)
554
+ return Promise.resolve();
555
+ return driver?.group === false || !ownsCommandGroup(child) ? Promise.resolve().then(() => {
556
+ if (child.exitCode === null && child.signalCode === null && !child.kill("SIGKILL"))
557
+ throw new Error("Command leader termination was refused");
558
+ }) : stopCommandGroup(child.pid, options.killGraceMs, cleanupTimeoutMs, force);
559
+ };
560
+ const owner = createCommandLifetime({
561
+ result,
562
+ controller,
563
+ finished: () => finished,
564
+ signal: () => signalOwned(true),
565
+ cleanupTimeoutMs
566
+ });
567
+ let spawnFailure;
568
+ let launched;
569
+ try {
570
+ launched = launchNativeCommand(options, driver, onSpawn, (error) => {
571
+ spawnFailure = new NativeCommandError2("COMMAND_UNAVAILABLE", "Command could not start", {
572
+ cause: error
573
+ });
574
+ controller.abort(spawnFailure);
575
+ }, (error) => controller.abort(error), (transport) => {
576
+ acquired = transport;
577
+ registerNativeCommandOwner(transport.child, owner);
578
+ });
579
+ } catch (cause) {
580
+ deadline?.cancel();
581
+ deadline?.signal.removeEventListener("abort", expired);
582
+ options.signal?.removeEventListener("abort", abort);
583
+ controller.abort(cause);
584
+ failedCommandStart(cause, (error) => cleanupNativeCommand({
585
+ error,
586
+ transport: acquired,
587
+ settle,
588
+ event: { kind: "error", cause },
589
+ signal: () => signalOwned(),
590
+ timeoutMs: cleanupTimeoutMs
591
+ })).then(completion.resolve, completion.reject);
592
+ return owner;
593
+ }
594
+ const stdout = [];
595
+ const stderr = [];
596
+ let total = 0;
597
+ const { stdout: output, stderr: errorOutput, leader, closed } = launched;
598
+ const cancelCloseDeadline = createLeaderCloseDeadline(leader, driver?.closeTimeoutMs, controller);
599
+ const drain = async (stream, channel, captured) => {
600
+ for await (const chunk of stream) {
601
+ controller.signal.throwIfAborted();
602
+ if (!(chunk instanceof Uint8Array))
603
+ throw new TypeError("Expected binary command output");
604
+ total += chunk.byteLength;
605
+ if (options.maxOutputBytes !== undefined && total > options.maxOutputBytes)
606
+ throw new NativeCommandError2("COMMAND_LIMIT", "Command output budget exceeded", {
607
+ reason: "output-budget"
608
+ });
609
+ if (options.capture)
610
+ captured.push(Uint8Array.from(chunk));
611
+ if (options.onOutput)
612
+ await raceAbort(Promise.resolve().then(() => {
613
+ controller.signal.throwIfAborted();
614
+ return options.onOutput?.(chunk, channel, controller.signal);
615
+ }), controller.signal);
616
+ }
617
+ };
618
+ const run = (async () => {
619
+ try {
620
+ launched.start();
621
+ const drains = Promise.all([
622
+ drain(output, "stdout", stdout),
623
+ drain(errorOutput, "stderr", stderr)
624
+ ]);
625
+ await raceAbort(Promise.all([drains, leader.then(settle)]), controller.signal);
626
+ const status = await raceAbort(closed, controller.signal);
627
+ if (spawnFailure !== undefined)
628
+ throw spawnFailure;
629
+ return { ...status, stdout: Buffer.concat(stdout), stderr: Buffer.concat(stderr) };
630
+ } catch (error) {
631
+ controller.abort(error);
632
+ await cleanupNativeCommand({
633
+ error,
634
+ transport: acquired,
635
+ settle,
636
+ signal: () => signalOwned(),
637
+ timeoutMs: cleanupTimeoutMs
638
+ });
639
+ throw error;
640
+ } finally {
641
+ finished = true;
642
+ cancelCloseDeadline();
643
+ deadline?.cancel();
644
+ deadline?.signal.removeEventListener("abort", expired);
645
+ options.signal?.removeEventListener("abort", abort);
646
+ controller.abort(new Error("Command completed"));
647
+ }
648
+ })();
649
+ run.then(completion.resolve, completion.reject);
650
+ return owner;
651
+ }
652
+
653
+ export { NativeCommandError2, stopCommandGroup, spawnOwnedCommand, ownsCommandGroup, nativeCommandOwner, startNativeCommand };