@orkestrel/process 0.0.1 → 0.0.3

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.
@@ -10,13 +10,66 @@ import { EmitterInterface } from '@orkestrel/emitter';
10
10
  */
11
11
  export declare function createDuplicateError(id: string): ProcessError;
12
12
 
13
+ /**
14
+ * Creates the failure raised when a public input is refused before anything is spawned.
15
+ *
16
+ * @param subject - The rejected input named as the caller wrote it, such as `option 'grace'`
17
+ * @param value - The rejected value, carried as `context.value`
18
+ * @returns A typed validation failure
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * createInvalidError("option 'grace'", -1).code // 'invalid'
23
+ * ```
24
+ */
25
+ export declare function createInvalidError(subject: string, value: unknown): ProcessError;
26
+
27
+ /**
28
+ * Creates the failure raised when a launch is attempted on a registry that is being destroyed.
29
+ *
30
+ * @param id - The id the refused launch asked for
31
+ * @returns A typed protocol failure
32
+ */
33
+ export declare function createProtocolError(id: string): ProcessError;
34
+
13
35
  /**
14
36
  * Creates the failure raised when a run does not complete successfully and rejection is requested.
15
37
  *
38
+ * @remarks
39
+ * The category is `timeout` only when the run's own timeout elapsed; every other failure, including
40
+ * an abort and an output overflow, is a `spawn` failure carrying its {@link RunResult}.
41
+ *
16
42
  * @param result - The buffered run outcome that failed
43
+ * @param cause - The underlying host fault, when one ended the run
17
44
  * @returns A typed run failure carrying its {@link RunResult}
18
45
  */
19
- export declare function createRunError(result: RunResult): ProcessError;
46
+ export declare function createRunError(result: RunResult, cause?: unknown): ProcessError;
47
+
48
+ /**
49
+ * Options for a detached fire-and-forget spawn.
50
+ *
51
+ * @remarks
52
+ * A detached child owns no stdio and is never awaited, so the contract carries only the directory it
53
+ * starts in. Its environment comes from the command's own `environment` and `isolated`.
54
+ */
55
+ export declare interface DetachOptions {
56
+ /** The working directory. Default: the current working directory. */
57
+ readonly workspace?: string;
58
+ }
59
+
60
+ /**
61
+ * Lookup inputs for resolving a command file to an executable path.
62
+ *
63
+ * @remarks
64
+ * `workspace` is searched before `PATH`, matching Windows command semantics. `environment` is the
65
+ * child's effective environment, so the lookup reads the same `PATH` and `PATHEXT` the child will.
66
+ */
67
+ export declare interface ExecutableOptions {
68
+ /** The directory searched first. Default: the current working directory. */
69
+ readonly workspace?: string;
70
+ /** The child's effective environment. Default: the parent process environment. */
71
+ readonly environment?: Readonly<Record<string, string | undefined>>;
72
+ }
20
73
 
21
74
  /**
22
75
  * Checks whether an unknown value is a {@link ProcessError}.
@@ -32,46 +85,63 @@ export declare function createRunError(result: RunResult): ProcessError;
32
85
  */
33
86
  export declare function isProcessError(value: unknown): value is ProcessError;
34
87
 
88
+ /** The default soft high-water mark in bytes for a supervised {@link ProcessInterface} line backlog. */
89
+ export declare const PROCESS_BACKLOG = 10485760;
90
+
91
+ /** The window in milliseconds a termination waits for the child's native exit after the final kill. */
92
+ export declare const PROCESS_CONFIRMATION = 5000;
93
+
35
94
  /** The default maximum retained stderr tail in bytes for a supervised {@link ProcessInterface}. */
36
95
  export declare const PROCESS_EVIDENCE = 2048;
37
96
 
38
- /** The default cooperative window in milliseconds between `SIGTERM` and `SIGKILL` during termination. */
97
+ /** The default cooperative POSIX window in milliseconds between `SIGTERM` and `SIGKILL` during termination. */
39
98
  export declare const PROCESS_GRACE = 5000;
40
99
 
41
100
  /** The default maximum captured bytes for a one-shot run's stdout and stderr, each. */
42
101
  export declare const PROCESS_OUTPUT = 10485760;
43
102
 
103
+ /** The executable extensions a Windows lookup applies when the environment declares no `PATHEXT`. */
104
+ export declare const PROCESS_PATHEXT = ".COM;.EXE;.BAT;.CMD";
105
+
106
+ /** The largest timer delay in milliseconds the host schedules without truncating it to one. */
107
+ export declare const PROCESS_TIMER = 2147483647;
108
+
44
109
  /**
45
110
  * The public contracts for `@orkestrel/process`: a typed child-process toolkit.
46
111
  *
47
112
  * @remarks
48
113
  * Three tiers, smallest to largest:
49
114
  *
50
- * - **{@link ProcessInterface}** — one supervised child with eagerly framed stdout lines, a
51
- * byte-bounded stderr tail, a live stderr event, a writable stdin channel, a typed lifecycle
52
- * {@link ProcessEventMap} emitter, and bounded `SIGTERM` → grace → `SIGKILL` termination. The
53
- * low-level streaming primitive.
115
+ * - **{@link ProcessInterface}** — one supervised child with framed stdout lines under a bounded
116
+ * backlog, a byte-bounded stderr tail, a live stderr event, a writable stdin channel, a typed
117
+ * lifecycle {@link ProcessEventMap} emitter, and bounded termination. The low-level streaming
118
+ * primitive.
54
119
  * - **{@link RunResult} / run** — a one-shot runner that buffers a child to completion and settles
55
120
  * with its output and exit, the ergonomic layer for fire-and-collect commands.
56
121
  * - **{@link ProcessManagerInterface}** — a keyed registry of live {@link ProcessInterface}
57
122
  * children, launched and stopped by id, observed through its own {@link ProcessManagerEventMap}.
58
123
  *
59
- * Every contract here is host-independent (`AbortSignal`, `AsyncIterable`, `Promise`, and plain
60
- * `string` signal names). The Node implementations live in `@orkestrel/process/server`.
124
+ * Every contract here is host-independent (`AbortSignal`, `AsyncIterable`, `Promise`, `Uint8Array`,
125
+ * and plain `string` signal names). The Node implementations live in `@orkestrel/process/server`.
61
126
  */
62
127
  /**
63
128
  * One spawnable command: the executable, its argument vector, and optional environment overrides
64
129
  * and initial standard input.
65
130
  *
66
131
  * @remarks
67
- * `environment` merges over the parent process environment; an `undefined` value unsets a key.
68
- * `input` is written to the child's stdin immediately after spawn.
132
+ * `environment` merges over the parent process environment unless `isolated` is `true`, and an
133
+ * `undefined` value unsets a key. On Windows the merge is case-insensitive and the last writer
134
+ * wins, matching how the host resolves an environment variable. `input` is written to the child's
135
+ * stdin immediately after spawn. Every string here is spawn-bound: an empty `file`, or a NUL
136
+ * character anywhere, is refused with a {@link ProcessError} coded `invalid`.
69
137
  */
70
138
  export declare interface ProcessCommand {
71
139
  readonly file: string;
72
140
  readonly arguments: readonly string[];
73
141
  readonly environment?: Readonly<Record<string, string | undefined>>;
74
142
  readonly input?: string;
143
+ /** If `true`, the child environment is `environment` alone; if `false` or omitted, it merges over the parent environment. */
144
+ readonly isolated?: boolean;
75
145
  }
76
146
 
77
147
  /** A child-process failure with a stable machine-readable category. */
@@ -91,7 +161,7 @@ export declare class ProcessError extends Error {
91
161
  }
92
162
 
93
163
  /** The machine-readable {@link ProcessError} categories. */
94
- export declare type ProcessErrorCode = 'spawn' | 'timeout' | 'duplicate' | 'protocol';
164
+ export declare type ProcessErrorCode = 'spawn' | 'timeout' | 'duplicate' | 'protocol' | 'invalid';
95
165
 
96
166
  /** Structured context carried by a {@link ProcessError}. */
97
167
  export declare interface ProcessErrorContext {
@@ -124,12 +194,16 @@ export declare interface ProcessErrorOptions {
124
194
  * observer subscribes to, alongside the `lines` stream and the `exit` promise.
125
195
  *
126
196
  * @remarks
127
- * Declared as a `type` alias so it satisfies the emitter's `EventMap` constraint structurally. A
128
- * listener throw is isolated by the emitter and routed to its `error` handler, never onto this map.
197
+ * Declared as a `type` alias so it satisfies the emitter's `EventMap` constraint structurally. The
198
+ * `error` event carries a child fault — a failure to spawn or a process-level error. It is distinct
199
+ * from the `error` handler in {@link ProcessOptions}: a listener throw is isolated by the emitter and
200
+ * routed to that handler, never emitted as this `error` event.
129
201
  */
130
202
  export declare type ProcessEventMap = {
131
203
  /** A decoded standard-error chunk arrived. */
132
204
  readonly stderr: readonly [chunk: string];
205
+ /** The child emitted an error — a spawn fault or process-level failure — carrying its cause. */
206
+ readonly error: readonly [error: unknown];
133
207
  /** The child settled — its terminal state, delivered once. */
134
208
  readonly exit: readonly [exit: ProcessExit];
135
209
  };
@@ -143,19 +217,25 @@ export declare interface ProcessExit {
143
217
  }
144
218
 
145
219
  /**
146
- * One supervised child process with eagerly framed output and bounded termination.
220
+ * One supervised child process with framed output, a bounded backlog, and bounded termination.
147
221
  *
148
222
  * @remarks
149
- * `lines` is pumped eagerly: stdout is drained whether or not a consumer iterates, so `exit`
150
- * resolves and a late consumer still receives every line. `evidence` is the decoded, byte-bounded
151
- * stderr tail — the diagnostic to attach to a failed exit. The typed `emitter` carries the live
152
- * `stderr` chunks and the terminal `exit`, alongside the `exit` promise. `send` never throws; it
153
- * returns whether the line reached an open channel. `stop` is idempotent.
223
+ * `lines` is pumped as soon as the child writes, and it is a single-consumer stream: each line goes
224
+ * to exactly one waiting iterator, so two iterators split the output between them rather than each
225
+ * receiving all of it. The policy for an unconsumed backlog follows
226
+ * consumer intent. Once an iterator has been requested, stdout pauses at the `backlog` mark and
227
+ * resumes at half of it, so the consumer loses nothing and the child feels real backpressure. While
228
+ * no iterator has ever been requested, stdout keeps draining so `exit` still resolves, and retention
229
+ * stops at the mark: a consumer attaching after that point receives the retained head, a gap, then
230
+ * the live stream. `evidence` is the decoded, byte-bounded stderr tail — the diagnostic to attach to
231
+ * a failed exit. The typed `emitter` carries the live `stderr` chunks, the child `error` cause, and
232
+ * the terminal `exit`, alongside the `exit` promise. `stop` and `destroy` are idempotent and never
233
+ * reject.
154
234
  */
155
235
  export declare interface ProcessInterface {
156
236
  /** The typed lifecycle observation surface. */
157
237
  readonly emitter: EmitterInterface<ProcessEventMap>;
158
- /** The eagerly captured stdout lines, in arrival order, ending when the child's stdout closes. */
238
+ /** The captured stdout lines, in arrival order, for one consumer, ending when the child's stdout closes. */
159
239
  readonly lines: AsyncIterable<string>;
160
240
  /** The decoded byte-bounded stderr tail. */
161
241
  readonly evidence: string;
@@ -164,18 +244,35 @@ export declare interface ProcessInterface {
164
244
  /**
165
245
  * Write one line to the open standard-input channel.
166
246
  *
247
+ * @remarks
248
+ * Never rejects. The promise settles when the host reports the line handled, so a line written
249
+ * to a child that is not reading stays pending until the child drains it or the channel closes.
250
+ * Every terminal teardown path destroys stdin, so a pending write always settles by teardown. A
251
+ * caller that needs its own deadline arms a timer and calls `stop`.
252
+ *
167
253
  * @param text - The line text without its trailing newline
168
- * @returns True when the channel accepted the line without backpressure; false otherwise
254
+ * @returns True when the line reached the host without error; false when the channel was closed, destroyed, ended, or the write failed
169
255
  */
170
- send(text: string): boolean;
256
+ send(text: string): Promise<boolean>;
171
257
  /**
172
258
  * Terminate the child process tree and await its observed exit.
173
259
  *
174
- * @returns A promise that resolves after bounded termination
260
+ * @remarks
261
+ * Never rejects. On Windows the whole tree is killed immediately through `taskkill`, with a
262
+ * direct kill as the fallback; on a POSIX host the process group receives `SIGTERM`, then
263
+ * `SIGKILL` after `grace`. No signal is initiated after the child's native exit is observed; the
264
+ * window between initiating a signal and the host delivering it belongs to the operating system.
265
+ *
266
+ * @returns True when the child's native exit was observed; false when the confirmation deadline elapsed without it
175
267
  */
176
- stop(): Promise<void>;
268
+ stop(): Promise<boolean>;
177
269
  /**
178
- * Stop the child and destroy the observation emitter.
270
+ * Stop the child, close its standard-input channel, and destroy the observation emitter.
271
+ *
272
+ * @remarks
273
+ * Always resolves, including when termination was never confirmed. Resolving does not imply the
274
+ * child's stdio has closed: a descendant holding an inherited pipe keeps the close event pending,
275
+ * so `exit` and `lines` can still be outstanding after this barrier settles.
179
276
  *
180
277
  * @returns The stable barrier shared by every call
181
278
  */
@@ -201,10 +298,12 @@ export declare type ProcessManagerEventMap = {
201
298
  *
202
299
  * @remarks
203
300
  * A child that settles removes itself from the registry, so `count` and `processes` reflect only
204
- * live children, and its departure emits `exit`. `launch` throws a {@link ProcessError} coded
205
- * `duplicate` when the id is already live — spawn faults surface through the returned child's
206
- * `exit`, not from `launch`. The typed `emitter` carries the `launch` and `exit` moments across
207
- * every child.
301
+ * live children, and its departure emits `exit`. Eviction follows the child's own `exit` promise,
302
+ * which no listener can forge, so it lands one microtask after the child's public `exit` event: a
303
+ * listener on that event still sees the child registered. `launch` throws a {@link ProcessError}
304
+ * coded `duplicate` when the id is already live and `protocol` after `destroy` has begun — spawn
305
+ * faults surface through the returned child's `exit`, not from `launch`. The typed `emitter` carries
306
+ * the `launch` and `exit` moments across every child.
208
307
  */
209
308
  export declare interface ProcessManagerInterface {
210
309
  /** The typed fleet-level observation surface. */
@@ -227,35 +326,49 @@ export declare interface ProcessManagerInterface {
227
326
  /**
228
327
  * Spawn and register one child under `id`.
229
328
  *
329
+ * @remarks
330
+ * Every option is read before the child is spawned, so a caller's own option getter runs while
331
+ * nothing has started and a throw from one strands no process. A getter that begins `destroy`
332
+ * without throwing is the one remaining race, and it leaves a bounded residual: the child is
333
+ * already spawned, so the launch is refused with `protocol` and that child is torn down
334
+ * asynchronously, bounded by `grace` plus the confirmation window. The `destroy` barrier settled
335
+ * before the refusal, so awaiting it does not cover that teardown.
336
+ *
230
337
  * @param id - The registry key, unique among live children
231
338
  * @param options - The child construction options
232
339
  * @returns The launched child
233
- * @throws A {@link ProcessError} coded `duplicate` when `id` is already live
340
+ * @throws A {@link ProcessError} coded `duplicate` when `id` is already live, `protocol` when the registry is being destroyed, or `invalid` when an option or command string is malformed
234
341
  */
235
342
  launch(id: string, options: ProcessOptions): ProcessInterface;
236
343
  /**
237
344
  * Terminate the named children and await their exit.
238
345
  *
239
346
  * @param ids - The registry keys to stop
240
- * @returns True when every named child stopped, false when any id was not live
347
+ * @returns True when every named child was live and its exit was confirmed; false otherwise
241
348
  */
242
349
  stop(ids: readonly string[]): Promise<boolean>;
243
350
  /**
244
351
  * Terminate one child and await its exit.
245
352
  *
246
353
  * @param id - The registry key to stop
247
- * @returns True when the child was live and stopped, false when the id was not live
354
+ * @returns True when the child was live and its exit was confirmed; false when the id was not live or the confirmation deadline elapsed
248
355
  */
249
356
  stop(id: string): Promise<boolean>;
250
357
  /**
251
358
  * Terminate every live child and await their exit.
252
359
  *
253
- * @returns A promise that resolves after all children stop
360
+ * @returns A promise that resolves after every child stops
254
361
  */
255
362
  stop(): Promise<void>;
256
363
  /**
257
364
  * Stop every child, then destroy the registry emitter last.
258
365
  *
366
+ * @remarks
367
+ * Always resolves, and refuses a later `launch` with a {@link ProcessError} coded `protocol`.
368
+ * Every child is destroyed, not merely stopped, so each child's own observation emitter is
369
+ * destroyed too and every subscription on it goes silently inert. The registry emitter is
370
+ * destroyed last.
371
+ *
259
372
  * @returns The stable barrier shared by every call
260
373
  */
261
374
  destroy(): Promise<void>;
@@ -277,10 +390,13 @@ export declare interface ProcessManagerOptions {
277
390
  * Construction options for one supervised child process.
278
391
  *
279
392
  * @remarks
280
- * `grace` is the sole timing knob: after `stop`, the child is sent `SIGTERM`, then `SIGKILL` if it
281
- * has not exited within `grace` milliseconds. There is no completion deadline — a caller that wants
282
- * one arms its own timer and calls `stop`. `on` installs initial {@link ProcessEventMap} listeners
283
- * and `error` receives isolated listener failures.
393
+ * `grace` is the cooperative window between `SIGTERM` and `SIGKILL` on a POSIX host; Windows has no
394
+ * cooperative phase, so the value is unused there. There is no completion deadline — a caller that
395
+ * wants one arms its own timer and calls `stop`. `backlog` bounds the unconsumed `lines` backlog.
396
+ * `on` installs initial {@link ProcessEventMap} listeners and `error` receives isolated listener
397
+ * failures. Every numeric option is validated at construction: a timer value outside
398
+ * `[0, PROCESS_TIMER]`, a negative or fractional byte value, or a `backlog` below `1` throws a
399
+ * {@link ProcessError} coded `invalid`.
284
400
  */
285
401
  export declare interface ProcessOptions {
286
402
  readonly on?: EmitterHooks<ProcessEventMap>;
@@ -288,24 +404,58 @@ export declare interface ProcessOptions {
288
404
  readonly command: ProcessCommand;
289
405
  /** The working directory the child runs in. */
290
406
  readonly workspace: string;
291
- /** Cooperative termination window in milliseconds between `SIGTERM` and `SIGKILL`. */
292
- readonly grace: number;
407
+ /** Cooperative POSIX window in milliseconds between `SIGTERM` and `SIGKILL`. Default: {@link PROCESS_GRACE}. */
408
+ readonly grace?: number;
293
409
  /** Maximum retained stderr tail in bytes. Default: {@link PROCESS_EVIDENCE}. */
294
410
  readonly evidence?: number;
411
+ /** Soft high-water mark in bytes for the unconsumed `lines` backlog. Default: {@link PROCESS_BACKLOG}. */
412
+ readonly backlog?: number;
295
413
  /** If `true`, stdin stays open for {@link ProcessInterface.send}; if `false` or omitted, stdin closes after any initial `input`. */
296
414
  readonly writable?: boolean;
297
415
  /** Aborting this signal terminates the child through the same bounded `stop`. */
298
416
  readonly signal?: AbortSignal;
299
417
  }
300
418
 
419
+ /**
420
+ * The captured bytes and terminal facts one settled {@link RunResult} is built from.
421
+ *
422
+ * @remarks
423
+ * Both byte fields are trimmed to `limit` on a code-point boundary when the result is built, so a
424
+ * caller passes the raw retained head and never a decoded string. `cause` carries the host fault
425
+ * that ended the run, when one did; its presence alone marks the run failed.
426
+ */
427
+ export declare interface RunInput {
428
+ /** The diagnostic command line. */
429
+ readonly command: string;
430
+ /** The retained standard-output bytes. */
431
+ readonly stdout: Uint8Array;
432
+ /** The retained standard-error bytes. */
433
+ readonly stderr: Uint8Array;
434
+ readonly code: number | null;
435
+ readonly signal: string | null;
436
+ /** If `true`, the run's own timeout elapsed; if `false`, it did not. */
437
+ readonly expired: boolean;
438
+ /** If `true`, the caller's signal aborted the run; if `false`, it did not. */
439
+ readonly aborted: boolean;
440
+ /** If `true`, a stream exceeded `limit`; if `false`, both fit. */
441
+ readonly truncated: boolean;
442
+ /** The maximum retained bytes for each stream. */
443
+ readonly limit: number;
444
+ /** The host fault that ended the run, when one did. */
445
+ readonly cause?: unknown;
446
+ }
447
+
301
448
  /**
302
449
  * Options for a one-shot run.
303
450
  *
304
451
  * @remarks
305
- * A run is a fire-and-collect function, not a lifecycle entity, so it carries no emitter. `reject`
306
- * follows the command-runner convention: by default a non-zero exit rejects with a
307
- * {@link ProcessError} carrying the {@link RunResult}; `reject: false` resolves with the result
308
- * instead, so the caller inspects `failed`.
452
+ * A run is a fire-and-collect function, not a lifecycle entity, so it carries no emitter. `strict`
453
+ * decides how a failure is delivered: by default a non-zero exit rejects with a
454
+ * {@link ProcessError} carrying the {@link RunResult}; `strict: false` resolves with the result
455
+ * instead, so the caller inspects `failed`. An invalid option or command rejects before the child is
456
+ * spawned, with a {@link ProcessError} coded `invalid`. An unbounded run awaits stdio completion
457
+ * rather than process exit, so give `timeout` a value wherever a descendant may inherit the child's
458
+ * stdio and hold the pipe open past the child's own exit.
309
459
  */
310
460
  export declare interface RunOptions {
311
461
  /** The working directory. Default: the current working directory. */
@@ -316,12 +466,12 @@ export declare interface RunOptions {
316
466
  readonly input?: string;
317
467
  /** Milliseconds before the child is terminated. `0` or omitted disables the timeout. */
318
468
  readonly timeout?: number;
319
- /** Cooperative window between `SIGTERM` and `SIGKILL` when terminating. Default: {@link PROCESS_GRACE}. */
469
+ /** Cooperative POSIX window between `SIGTERM` and `SIGKILL` when terminating. Default: {@link PROCESS_GRACE}. */
320
470
  readonly grace?: number;
321
- /** Aborting this signal terminates the run. */
471
+ /** Aborting this signal terminates the run and reports `aborted`. */
322
472
  readonly signal?: AbortSignal;
323
473
  /** If `false`, resolve with the result on failure instead of rejecting. Default: `true`. */
324
- readonly reject?: boolean;
474
+ readonly strict?: boolean;
325
475
  /** Maximum captured bytes for stdout and for stderr, each. Default: {@link PROCESS_OUTPUT}. */
326
476
  readonly limit?: number;
327
477
  }
@@ -330,22 +480,71 @@ export declare interface RunOptions {
330
480
  * The settled outcome of a one-shot run: the buffered output and the terminal state.
331
481
  *
332
482
  * @remarks
333
- * `failed` is `true` when the child exited non-zero, was killed by a signal, timed out, or failed to
334
- * spawn. `timedOut` is `true` only when the run's own `timeout` elapsed.
483
+ * `failed` is `true` when the child exited non-zero, was killed by a signal, expired, was aborted, or
484
+ * failed to spawn. `expired` and `aborted` are the two ways the run ended the child rather than the
485
+ * child ending itself, and only the first of them observed is recorded. `truncated` is independent of
486
+ * both: it reports that a stream exceeded `limit`, which fails a synchronous run and does not fail an
487
+ * asynchronous one.
335
488
  */
336
489
  export declare interface RunResult {
337
490
  /** The command line that was run, for diagnostics. */
338
491
  readonly command: string;
339
- /** The complete captured standard output, byte-bounded by `limit`. */
492
+ /** The captured standard output, byte-bounded by `limit`. */
340
493
  readonly stdout: string;
341
- /** The complete captured standard error, byte-bounded by `limit`. */
494
+ /** The captured standard error, byte-bounded by `limit`. */
342
495
  readonly stderr: string;
343
496
  readonly code: number | null;
344
497
  readonly signal: string | null;
345
498
  /** True if the run did not complete successfully. */
346
499
  readonly failed: boolean;
347
500
  /** True if the run's `timeout` elapsed before completion. */
348
- readonly timedOut: boolean;
501
+ readonly expired: boolean;
502
+ /** True if the caller's `signal` aborted the run before completion. */
503
+ readonly aborted: boolean;
504
+ /** True if either stream exceeded `limit`, so the captured text is the retained head. */
505
+ readonly truncated: boolean;
506
+ }
507
+
508
+ /**
509
+ * Options for a synchronous one-shot run.
510
+ *
511
+ * @remarks
512
+ * The synchronous host offers neither a cooperative termination window nor in-flight cancellation,
513
+ * so this contract carries no `grace` and no `signal`. A `timeout` and an output overflow both end
514
+ * the child with `SIGKILL`; an overflow reports `truncated` and `failed` together, which is where
515
+ * the synchronous and asynchronous runners genuinely differ.
516
+ */
517
+ export declare interface RunSyncOptions {
518
+ /** The working directory. Default: the current working directory. */
519
+ readonly workspace?: string;
520
+ /** Environment overrides merged over the parent environment; an `undefined` value unsets a key. */
521
+ readonly environment?: Readonly<Record<string, string | undefined>>;
522
+ /** Standard input written to the child. */
523
+ readonly input?: string;
524
+ /** Milliseconds before the host kills the child. `0` or omitted disables the timeout. */
525
+ readonly timeout?: number;
526
+ /** If `false`, return the result on failure instead of throwing. Default: `true`. */
527
+ readonly strict?: boolean;
528
+ /** Maximum captured bytes for stdout and for stderr, each. Default: {@link PROCESS_OUTPUT}. */
529
+ readonly limit?: number;
530
+ }
531
+
532
+ /**
533
+ * The resolved spawn form of one command: the executable to launch, the argument vector to pass,
534
+ * and whether the host receives that vector verbatim.
535
+ *
536
+ * @remarks
537
+ * No spawn in this package uses an implicit shell. `verbatim` is `true` only for a Windows `.cmd` or
538
+ * `.bat` script, which runs through an explicitly quoted `cmd.exe /d /s /c` command line, and an
539
+ * argument that batch target could corrupt — one carrying `%`, which `cmd.exe` expands before it
540
+ * parses quotes — is refused rather than passed. A shell metacharacter in an argument is therefore
541
+ * data rather than syntax on every path.
542
+ */
543
+ export declare interface SpawnInput {
544
+ readonly file: string;
545
+ readonly arguments: readonly string[];
546
+ /** If `true`, pass the argument vector to the host verbatim; if `false`, let the host quote it. */
547
+ readonly verbatim: boolean;
349
548
  }
350
549
 
351
550
  export { }