@orkestrel/process 0.0.5 → 0.0.6

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.
@@ -5,6 +5,22 @@ let _orkestrel_contract = require("@orkestrel/contract");
5
5
  var PROCESS_GRACE = 5e3;
6
6
  /** The window in milliseconds a termination waits for the child's native exit after the final kill. */
7
7
  var PROCESS_CONFIRMATION = 5e3;
8
+ /**
9
+ * The default window in milliseconds the package waits for the child's read ends to close after
10
+ * the child's native exit or after a termination this package initiated, before cutting them off.
11
+ *
12
+ * @remarks
13
+ * Measured on Windows 11 with Node v24.18.1 on 2026-08-21, spawning the `tests/src/server/fixtures`
14
+ * child modes as real children and timing the host `close` event against the host `exit` event.
15
+ * Every ordinary run closed within 0.02ms of the native exit, whether the child ended itself or a
16
+ * kill ended it, and a `taskkill /F /T` that reaped a descendant while the root was still alive
17
+ * closed within 0.01ms. The only finite late close came from a descendant that outlived its root and
18
+ * then ended on its own, at 127.44ms to 193.41ms — that lag is the descendant's own remaining life
19
+ * rather than a flush cost. A descendant that never ends never closes, so the distribution has no
20
+ * finite tail to cover and this value bounds it instead: 1000ms is over five times the slowest
21
+ * finite close measured, and it keeps an unreachable descendant from stretching a shutdown.
22
+ */
23
+ var PROCESS_DRAIN = 1e3;
8
24
  /** The default maximum retained stderr tail in bytes for a supervised {@link ProcessInterface}. */
9
25
  var PROCESS_EVIDENCE = 2048;
10
26
  /** The default soft high-water mark in bytes for a supervised {@link ProcessInterface} line backlog. */
@@ -151,6 +167,7 @@ function createExecuteError(result, cause) {
151
167
  //#endregion
152
168
  exports.PROCESS_BACKLOG = PROCESS_BACKLOG;
153
169
  exports.PROCESS_CONFIRMATION = PROCESS_CONFIRMATION;
170
+ exports.PROCESS_DRAIN = PROCESS_DRAIN;
154
171
  exports.PROCESS_ERROR_CODES = PROCESS_ERROR_CODES;
155
172
  exports.PROCESS_EVIDENCE = PROCESS_EVIDENCE;
156
173
  exports.PROCESS_GRACE = PROCESS_GRACE;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/core/constants.ts","../../../src/core/errors.ts"],"sourcesContent":["/** The default cooperative POSIX window in milliseconds between `SIGTERM` and `SIGKILL` during termination. */\nexport const PROCESS_GRACE = 5_000\n\n/** The window in milliseconds a termination waits for the child's native exit after the final kill. */\nexport const PROCESS_CONFIRMATION = 5_000\n\n/** The default maximum retained stderr tail in bytes for a supervised {@link ProcessInterface}. */\nexport const PROCESS_EVIDENCE = 2_048\n\n/** The default soft high-water mark in bytes for a supervised {@link ProcessInterface} line backlog. */\nexport const PROCESS_BACKLOG = 10_485_760\n\n/** The default maximum captured bytes for a one-shot run's stdout and stderr, each. */\nexport const PROCESS_OUTPUT = 10_485_760\n\n/** The largest timer delay in milliseconds the host schedules without truncating it to one. */\nexport const PROCESS_TIMER = 2_147_483_647\n\n/** The executable extensions a Windows lookup applies when the environment declares no `PATHEXT`. */\nexport const PROCESS_PATHEXT = '.COM;.EXE;.BAT;.CMD'\n\n/** The machine-readable failure categories a {@link ProcessError} carries, in declaration order. */\nexport const PROCESS_ERROR_CODES = Object.freeze([\n\t'spawn',\n\t'timeout',\n\t'input',\n\t'duplicate',\n\t'protocol',\n\t'invalid',\n] as const)\n","import type {\n\tProcessErrorCode,\n\tProcessErrorContext,\n\tProcessErrorOptions,\n\tExecuteResult,\n} from './types.js'\nimport { holds, isError } from '@orkestrel/contract'\nimport { PROCESS_ERROR_CODES } from './constants.js'\n\n/** A child-process failure with a stable machine-readable category. */\nexport class ProcessError extends Error {\n\toverride readonly name = 'ProcessError'\n\treadonly code: ProcessErrorCode\n\treadonly context?: ProcessErrorContext\n\t/** The buffered run outcome, present when a one-shot run produced the failure. */\n\treadonly result?: ExecuteResult\n\n\t/**\n\t * Create a process error.\n\t *\n\t * @param message - Human-readable failure description\n\t * @param options - Machine-readable category, optional context, optional cause, and optional run result\n\t */\n\tconstructor(message: string, options: ProcessErrorOptions) {\n\t\tconst cause = options.cause\n\t\tsuper(message, cause === undefined ? undefined : { cause })\n\t\tObject.defineProperty(this, Symbol.for('@orkestrel/process.error'), { value: true })\n\t\tthis.code = options.code\n\t\tif (options.context !== undefined) this.context = options.context\n\t\tif (options.result !== undefined) this.result = options.result\n\t}\n}\n\n/**\n * Checks whether an unknown value is a {@link ProcessError}.\n *\n * @remarks\n * Recognition combines a global own-property brand with the native `Error` base, the subclass\n * prototype, the fixed name, and a code {@link PROCESS_ERROR_CODES} declares. The brand is\n * recognized across duplicate installations and ESM/CommonJS module copies at 0.0.4 or later. A copy\n * earlier than 0.0.4 stamps no brand, so an error it throws stays outside the type, and so does a\n * plain or property-only lookalike.\n *\n * @param value - The value to inspect\n * @returns True only for a `ProcessError` instance; false otherwise\n *\n * @example\n * ```ts\n * isProcessError(new ProcessError('spawn failed', { code: 'spawn' })) // true\n * isProcessError(new Error('spawn failed')) // false\n * ```\n */\nexport function isProcessError(value: unknown): value is ProcessError {\n\tif (!isError(value)) return false\n\treturn holds(() => {\n\t\tif (Object.getPrototypeOf(value) === Error.prototype) return false\n\t\tif (value.name !== 'ProcessError' || !('code' in value)) return false\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(\n\t\t\tvalue,\n\t\t\tSymbol.for('@orkestrel/process.error'),\n\t\t)\n\t\tif (descriptor?.value !== true) return false\n\t\tconst code: unknown = value.code\n\t\treturn PROCESS_ERROR_CODES.some((declared) => declared === code)\n\t})\n}\n\n/**\n * Creates the failure raised when a manager launch reuses a live id.\n *\n * @param id - The id already occupied by a live child\n * @returns A typed duplicate-id failure\n */\nexport function createDuplicateError(id: string): ProcessError {\n\treturn new ProcessError(`Process '${id}' is already live`, {\n\t\tcode: 'duplicate',\n\t\tcontext: { id },\n\t})\n}\n\n/**\n * Creates the failure raised when a launch is attempted on a registry that is being destroyed.\n *\n * @param id - The id the refused launch asked for\n * @returns A typed protocol failure\n */\nexport function createProtocolError(id: string): ProcessError {\n\treturn new ProcessError(`Process '${id}' cannot launch: the registry is destroyed`, {\n\t\tcode: 'protocol',\n\t\tcontext: { id },\n\t})\n}\n\n/**\n * Creates the failure raised when a public input is refused before anything is spawned.\n *\n * @param subject - The rejected input named as the caller wrote it, such as `option 'grace'`\n * @param value - The rejected value, carried as `context.value`\n * @returns A typed validation failure\n *\n * @example\n * ```ts\n * createInvalidError(\"option 'grace'\", -1).code // 'invalid'\n * ```\n */\nexport function createInvalidError(subject: string, value: unknown): ProcessError {\n\treturn new ProcessError(`Invalid ${subject}`, { code: 'invalid', context: { value } })\n}\n\n/**\n * Creates the failure raised when a run does not complete successfully and rejection is requested.\n *\n * @remarks\n * The category is `timeout` only when the run's own timeout elapsed; every other failure,\n * including an abort and an output overflow, is a `spawn` failure carrying its\n * {@link ExecuteResult}.\n *\n * @param result - The buffered run outcome that failed\n * @param cause - The underlying host fault, when one ended the run\n * @returns A typed run failure carrying its {@link ExecuteResult}\n */\nexport function createExecuteError(result: ExecuteResult, cause?: unknown): ProcessError {\n\tlet reason = `exited with code ${String(result.code)}`\n\tif (result.signal !== null) reason = `was killed by ${result.signal}`\n\tif (result.truncated) reason = 'exceeded its output limit'\n\tif (result.aborted) reason = 'was aborted'\n\tif (result.expired) reason = 'timed out'\n\treturn new ProcessError(`Command '${result.command}' ${reason}`, {\n\t\tcode: result.expired ? 'timeout' : 'spawn',\n\t\tcontext: { command: result.command, code: result.code, signal: result.signal },\n\t\t...(cause === undefined ? {} : { cause }),\n\t\tresult,\n\t})\n}\n"],"mappings":";;;;AACA,IAAa,gBAAgB;;AAG7B,IAAa,uBAAuB;;AAGpC,IAAa,mBAAmB;;AAGhC,IAAa,kBAAkB;;AAG/B,IAAa,iBAAiB;;AAG9B,IAAa,gBAAgB;;AAG7B,IAAa,kBAAkB;;AAG/B,IAAa,sBAAsB,OAAO,OAAO;CAChD;CACA;CACA;CACA;CACA;CACA;AACD,CAAU;;;;ACnBV,IAAa,eAAb,cAAkC,MAAM;CACvC,OAAyB;CACzB;CACA;;CAEA;;;;;;;CAQA,YAAY,SAAiB,SAA8B;EAC1D,MAAM,QAAQ,QAAQ;EACtB,MAAM,SAAS,UAAU,KAAA,IAAY,KAAA,IAAY,EAAE,MAAM,CAAC;EAC1D,OAAO,eAAe,MAAM,OAAO,IAAI,0BAA0B,GAAG,EAAE,OAAO,KAAK,CAAC;EACnF,KAAK,OAAO,QAAQ;EACpB,IAAI,QAAQ,YAAY,KAAA,GAAW,KAAK,UAAU,QAAQ;EAC1D,IAAI,QAAQ,WAAW,KAAA,GAAW,KAAK,SAAS,QAAQ;CACzD;AACD;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,eAAe,OAAuC;CACrE,IAAI,EAAA,GAAC,oBAAA,QAAA,CAAQ,KAAK,GAAG,OAAO;CAC5B,QAAA,GAAO,oBAAA,MAAA,OAAY;EAClB,IAAI,OAAO,eAAe,KAAK,MAAM,MAAM,WAAW,OAAO;EAC7D,IAAI,MAAM,SAAS,kBAAkB,EAAE,UAAU,QAAQ,OAAO;EAKhE,IAJmB,OAAO,yBACzB,OACA,OAAO,IAAI,0BAA0B,CAElC,CAAA,EAAY,UAAU,MAAM,OAAO;EACvC,MAAM,OAAgB,MAAM;EAC5B,OAAO,oBAAoB,MAAM,aAAa,aAAa,IAAI;CAChE,CAAC;AACF;;;;;;;AAQA,SAAgB,qBAAqB,IAA0B;CAC9D,OAAO,IAAI,aAAa,YAAY,GAAG,oBAAoB;EAC1D,MAAM;EACN,SAAS,EAAE,GAAG;CACf,CAAC;AACF;;;;;;;AAQA,SAAgB,oBAAoB,IAA0B;CAC7D,OAAO,IAAI,aAAa,YAAY,GAAG,6CAA6C;EACnF,MAAM;EACN,SAAS,EAAE,GAAG;CACf,CAAC;AACF;;;;;;;;;;;;;AAcA,SAAgB,mBAAmB,SAAiB,OAA8B;CACjF,OAAO,IAAI,aAAa,WAAW,WAAW;EAAE,MAAM;EAAW,SAAS,EAAE,MAAM;CAAE,CAAC;AACtF;;;;;;;;;;;;;AAcA,SAAgB,mBAAmB,QAAuB,OAA+B;CACxF,IAAI,SAAS,oBAAoB,OAAO,OAAO,IAAI;CACnD,IAAI,OAAO,WAAW,MAAM,SAAS,iBAAiB,OAAO;CAC7D,IAAI,OAAO,WAAW,SAAS;CAC/B,IAAI,OAAO,SAAS,SAAS;CAC7B,IAAI,OAAO,SAAS,SAAS;CAC7B,OAAO,IAAI,aAAa,YAAY,OAAO,QAAQ,IAAI,UAAU;EAChE,MAAM,OAAO,UAAU,YAAY;EACnC,SAAS;GAAE,SAAS,OAAO;GAAS,MAAM,OAAO;GAAM,QAAQ,OAAO;EAAO;EAC7E,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;EACvC;CACD,CAAC;AACF"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/core/constants.ts","../../../src/core/errors.ts"],"sourcesContent":["/** The default cooperative POSIX window in milliseconds between `SIGTERM` and `SIGKILL` during termination. */\nexport const PROCESS_GRACE = 5_000\n\n/** The window in milliseconds a termination waits for the child's native exit after the final kill. */\nexport const PROCESS_CONFIRMATION = 5_000\n\n/**\n * The default window in milliseconds the package waits for the child's read ends to close after\n * the child's native exit or after a termination this package initiated, before cutting them off.\n *\n * @remarks\n * Measured on Windows 11 with Node v24.18.1 on 2026-08-21, spawning the `tests/src/server/fixtures`\n * child modes as real children and timing the host `close` event against the host `exit` event.\n * Every ordinary run closed within 0.02ms of the native exit, whether the child ended itself or a\n * kill ended it, and a `taskkill /F /T` that reaped a descendant while the root was still alive\n * closed within 0.01ms. The only finite late close came from a descendant that outlived its root and\n * then ended on its own, at 127.44ms to 193.41ms — that lag is the descendant's own remaining life\n * rather than a flush cost. A descendant that never ends never closes, so the distribution has no\n * finite tail to cover and this value bounds it instead: 1000ms is over five times the slowest\n * finite close measured, and it keeps an unreachable descendant from stretching a shutdown.\n */\nexport const PROCESS_DRAIN = 1_000\n\n/** The default maximum retained stderr tail in bytes for a supervised {@link ProcessInterface}. */\nexport const PROCESS_EVIDENCE = 2_048\n\n/** The default soft high-water mark in bytes for a supervised {@link ProcessInterface} line backlog. */\nexport const PROCESS_BACKLOG = 10_485_760\n\n/** The default maximum captured bytes for a one-shot run's stdout and stderr, each. */\nexport const PROCESS_OUTPUT = 10_485_760\n\n/** The largest timer delay in milliseconds the host schedules without truncating it to one. */\nexport const PROCESS_TIMER = 2_147_483_647\n\n/** The executable extensions a Windows lookup applies when the environment declares no `PATHEXT`. */\nexport const PROCESS_PATHEXT = '.COM;.EXE;.BAT;.CMD'\n\n/** The machine-readable failure categories a {@link ProcessError} carries, in declaration order. */\nexport const PROCESS_ERROR_CODES = Object.freeze([\n\t'spawn',\n\t'timeout',\n\t'input',\n\t'duplicate',\n\t'protocol',\n\t'invalid',\n] as const)\n","import type {\n\tProcessErrorCode,\n\tProcessErrorContext,\n\tProcessErrorOptions,\n\tExecuteResult,\n} from './types.js'\nimport { holds, isError } from '@orkestrel/contract'\nimport { PROCESS_ERROR_CODES } from './constants.js'\n\n/** A child-process failure with a stable machine-readable category. */\nexport class ProcessError extends Error {\n\toverride readonly name = 'ProcessError'\n\treadonly code: ProcessErrorCode\n\treadonly context?: ProcessErrorContext\n\t/** The buffered run outcome, present when a one-shot run produced the failure. */\n\treadonly result?: ExecuteResult\n\n\t/**\n\t * Create a process error.\n\t *\n\t * @param message - Human-readable failure description\n\t * @param options - Machine-readable category, optional context, optional cause, and optional run result\n\t */\n\tconstructor(message: string, options: ProcessErrorOptions) {\n\t\tconst cause = options.cause\n\t\tsuper(message, cause === undefined ? undefined : { cause })\n\t\tObject.defineProperty(this, Symbol.for('@orkestrel/process.error'), { value: true })\n\t\tthis.code = options.code\n\t\tif (options.context !== undefined) this.context = options.context\n\t\tif (options.result !== undefined) this.result = options.result\n\t}\n}\n\n/**\n * Checks whether an unknown value is a {@link ProcessError}.\n *\n * @remarks\n * Recognition combines a global own-property brand with the native `Error` base, the subclass\n * prototype, the fixed name, and a code {@link PROCESS_ERROR_CODES} declares. The brand is\n * recognized across duplicate installations and ESM/CommonJS module copies at 0.0.4 or later. A copy\n * earlier than 0.0.4 stamps no brand, so an error it throws stays outside the type, and so does a\n * plain or property-only lookalike.\n *\n * @param value - The value to inspect\n * @returns True only for a `ProcessError` instance; false otherwise\n *\n * @example\n * ```ts\n * isProcessError(new ProcessError('spawn failed', { code: 'spawn' })) // true\n * isProcessError(new Error('spawn failed')) // false\n * ```\n */\nexport function isProcessError(value: unknown): value is ProcessError {\n\tif (!isError(value)) return false\n\treturn holds(() => {\n\t\tif (Object.getPrototypeOf(value) === Error.prototype) return false\n\t\tif (value.name !== 'ProcessError' || !('code' in value)) return false\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(\n\t\t\tvalue,\n\t\t\tSymbol.for('@orkestrel/process.error'),\n\t\t)\n\t\tif (descriptor?.value !== true) return false\n\t\tconst code: unknown = value.code\n\t\treturn PROCESS_ERROR_CODES.some((declared) => declared === code)\n\t})\n}\n\n/**\n * Creates the failure raised when a manager launch reuses a live id.\n *\n * @param id - The id already occupied by a live child\n * @returns A typed duplicate-id failure\n */\nexport function createDuplicateError(id: string): ProcessError {\n\treturn new ProcessError(`Process '${id}' is already live`, {\n\t\tcode: 'duplicate',\n\t\tcontext: { id },\n\t})\n}\n\n/**\n * Creates the failure raised when a launch is attempted on a registry that is being destroyed.\n *\n * @param id - The id the refused launch asked for\n * @returns A typed protocol failure\n */\nexport function createProtocolError(id: string): ProcessError {\n\treturn new ProcessError(`Process '${id}' cannot launch: the registry is destroyed`, {\n\t\tcode: 'protocol',\n\t\tcontext: { id },\n\t})\n}\n\n/**\n * Creates the failure raised when a public input is refused before anything is spawned.\n *\n * @param subject - The rejected input named as the caller wrote it, such as `option 'grace'`\n * @param value - The rejected value, carried as `context.value`\n * @returns A typed validation failure\n *\n * @example\n * ```ts\n * createInvalidError(\"option 'grace'\", -1).code // 'invalid'\n * ```\n */\nexport function createInvalidError(subject: string, value: unknown): ProcessError {\n\treturn new ProcessError(`Invalid ${subject}`, { code: 'invalid', context: { value } })\n}\n\n/**\n * Creates the failure raised when a run does not complete successfully and rejection is requested.\n *\n * @remarks\n * The category is `timeout` only when the run's own timeout elapsed; every other failure,\n * including an abort and an output overflow, is a `spawn` failure carrying its\n * {@link ExecuteResult}.\n *\n * @param result - The buffered run outcome that failed\n * @param cause - The underlying host fault, when one ended the run\n * @returns A typed run failure carrying its {@link ExecuteResult}\n */\nexport function createExecuteError(result: ExecuteResult, cause?: unknown): ProcessError {\n\tlet reason = `exited with code ${String(result.code)}`\n\tif (result.signal !== null) reason = `was killed by ${result.signal}`\n\tif (result.truncated) reason = 'exceeded its output limit'\n\tif (result.aborted) reason = 'was aborted'\n\tif (result.expired) reason = 'timed out'\n\treturn new ProcessError(`Command '${result.command}' ${reason}`, {\n\t\tcode: result.expired ? 'timeout' : 'spawn',\n\t\tcontext: { command: result.command, code: result.code, signal: result.signal },\n\t\t...(cause === undefined ? {} : { cause }),\n\t\tresult,\n\t})\n}\n"],"mappings":";;;;AACA,IAAa,gBAAgB;;AAG7B,IAAa,uBAAuB;;;;;;;;;;;;;;;;AAiBpC,IAAa,gBAAgB;;AAG7B,IAAa,mBAAmB;;AAGhC,IAAa,kBAAkB;;AAG/B,IAAa,iBAAiB;;AAG9B,IAAa,gBAAgB;;AAG7B,IAAa,kBAAkB;;AAG/B,IAAa,sBAAsB,OAAO,OAAO;CAChD;CACA;CACA;CACA;CACA;CACA;AACD,CAAU;;;;ACpCV,IAAa,eAAb,cAAkC,MAAM;CACvC,OAAyB;CACzB;CACA;;CAEA;;;;;;;CAQA,YAAY,SAAiB,SAA8B;EAC1D,MAAM,QAAQ,QAAQ;EACtB,MAAM,SAAS,UAAU,KAAA,IAAY,KAAA,IAAY,EAAE,MAAM,CAAC;EAC1D,OAAO,eAAe,MAAM,OAAO,IAAI,0BAA0B,GAAG,EAAE,OAAO,KAAK,CAAC;EACnF,KAAK,OAAO,QAAQ;EACpB,IAAI,QAAQ,YAAY,KAAA,GAAW,KAAK,UAAU,QAAQ;EAC1D,IAAI,QAAQ,WAAW,KAAA,GAAW,KAAK,SAAS,QAAQ;CACzD;AACD;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,eAAe,OAAuC;CACrE,IAAI,EAAA,GAAC,oBAAA,QAAA,CAAQ,KAAK,GAAG,OAAO;CAC5B,QAAA,GAAO,oBAAA,MAAA,OAAY;EAClB,IAAI,OAAO,eAAe,KAAK,MAAM,MAAM,WAAW,OAAO;EAC7D,IAAI,MAAM,SAAS,kBAAkB,EAAE,UAAU,QAAQ,OAAO;EAKhE,IAJmB,OAAO,yBACzB,OACA,OAAO,IAAI,0BAA0B,CAElC,CAAA,EAAY,UAAU,MAAM,OAAO;EACvC,MAAM,OAAgB,MAAM;EAC5B,OAAO,oBAAoB,MAAM,aAAa,aAAa,IAAI;CAChE,CAAC;AACF;;;;;;;AAQA,SAAgB,qBAAqB,IAA0B;CAC9D,OAAO,IAAI,aAAa,YAAY,GAAG,oBAAoB;EAC1D,MAAM;EACN,SAAS,EAAE,GAAG;CACf,CAAC;AACF;;;;;;;AAQA,SAAgB,oBAAoB,IAA0B;CAC7D,OAAO,IAAI,aAAa,YAAY,GAAG,6CAA6C;EACnF,MAAM;EACN,SAAS,EAAE,GAAG;CACf,CAAC;AACF;;;;;;;;;;;;;AAcA,SAAgB,mBAAmB,SAAiB,OAA8B;CACjF,OAAO,IAAI,aAAa,WAAW,WAAW;EAAE,MAAM;EAAW,SAAS,EAAE,MAAM;CAAE,CAAC;AACtF;;;;;;;;;;;;;AAcA,SAAgB,mBAAmB,QAAuB,OAA+B;CACxF,IAAI,SAAS,oBAAoB,OAAO,OAAO,IAAI;CACnD,IAAI,OAAO,WAAW,MAAM,SAAS,iBAAiB,OAAO;CAC7D,IAAI,OAAO,WAAW,SAAS;CAC/B,IAAI,OAAO,SAAS,SAAS;CAC7B,IAAI,OAAO,SAAS,SAAS;CAC7B,OAAO,IAAI,aAAa,YAAY,OAAO,QAAQ,IAAI,UAAU;EAChE,MAAM,OAAO,UAAU,YAAY;EACnC,SAAS;GAAE,SAAS,OAAO;GAAS,MAAM,OAAO;GAAM,QAAQ,OAAO;EAAO;EAC7E,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;EACvC;CACD,CAAC;AACF"}
@@ -222,6 +222,23 @@ export declare const PROCESS_BACKLOG = 10485760;
222
222
  /** The window in milliseconds a termination waits for the child's native exit after the final kill. */
223
223
  export declare const PROCESS_CONFIRMATION = 5000;
224
224
 
225
+ /**
226
+ * The default window in milliseconds the package waits for the child's read ends to close after
227
+ * the child's native exit or after a termination this package initiated, before cutting them off.
228
+ *
229
+ * @remarks
230
+ * Measured on Windows 11 with Node v24.18.1 on 2026-08-21, spawning the `tests/src/server/fixtures`
231
+ * child modes as real children and timing the host `close` event against the host `exit` event.
232
+ * Every ordinary run closed within 0.02ms of the native exit, whether the child ended itself or a
233
+ * kill ended it, and a `taskkill /F /T` that reaped a descendant while the root was still alive
234
+ * closed within 0.01ms. The only finite late close came from a descendant that outlived its root and
235
+ * then ended on its own, at 127.44ms to 193.41ms — that lag is the descendant's own remaining life
236
+ * rather than a flush cost. A descendant that never ends never closes, so the distribution has no
237
+ * finite tail to cover and this value bounds it instead: 1000ms is over five times the slowest
238
+ * finite close measured, and it keeps an unreachable descendant from stretching a shutdown.
239
+ */
240
+ export declare const PROCESS_DRAIN = 1000;
241
+
225
242
  /** The machine-readable failure categories a {@link ProcessError} carries, in declaration order. */
226
243
  export declare const PROCESS_ERROR_CODES: readonly ["spawn", "timeout", "input", "duplicate", "protocol", "invalid"];
227
244
 
@@ -349,12 +366,24 @@ export declare type ProcessEventMap = {
349
366
  readonly exit: readonly [exit: ProcessExit];
350
367
  };
351
368
 
352
- /** The observed terminal state of a child process: its exit code, or the signal that ended it. */
369
+ /**
370
+ * The observed terminal state of a child process: its exit code or the signal that ended it, and
371
+ * how its observation ended.
372
+ *
373
+ * @remarks
374
+ * This value exists only at the terminal moment, so every field on it is already final and no
375
+ * consumer can read one too early. `drained` reports whether the diagnostics are complete;
376
+ * {@link ProcessInterface.truncated} reports that the `lines` stream omitted stdout lines. They are
377
+ * independent facts about different streams, and one child reports both when a retention bound
378
+ * dropped lines and the drain bound cut stderr off.
379
+ */
353
380
  export declare interface ProcessExit {
354
381
  /** The exit code, or `null` when a signal ended the process. A spawn fault reports the host's negative errno for `Process` and `execute`. */
355
382
  readonly code: number | null;
356
383
  /** The terminating signal name, or `null` when the process exited on its own. */
357
384
  readonly signal: string | null;
385
+ /** True when the terminal moment arrived because the child's streams closed; false when the `drain` bound elapsed first and later diagnostics may have existed. */
386
+ readonly drained: boolean;
358
387
  }
359
388
 
360
389
  /**
@@ -375,14 +404,22 @@ export declare interface ProcessExit {
375
404
  * its own capture `limit`. The typed `emitter` carries the live `stderr` chunks, the child `error` cause, and the
376
405
  * terminal `exit`, alongside the `exit` promise. `stop` and `destroy` are idempotent and never reject.
377
406
  *
407
+ * The same terminal moment governs every observation surface. It arrives when the child's streams close,
408
+ * or when the `drain` bound armed by the native exit or by a termination this package initiated
409
+ * elapses first, and
410
+ * {@link ProcessExit.drained} reports which. At that moment `evidence` freezes, `lines` ends, `exit`
411
+ * settles, and `settled` turns true — together, so a consumer reading `evidence` and a consumer
412
+ * iterating `lines` never see a different child. `stop`, `destroy`, an abort of the `signal` option,
413
+ * a natural exit, and a spawn fault all reach it.
414
+ *
378
415
  * The spawn is eager, so `pid` is fixed by the time construction returns; a spawn that produced no
379
416
  * child reports `undefined` for that child's whole lifetime. An assigned id survives the exit and
380
417
  * reports no liveness on its own, because the host reuses a dead child's id. Derive liveness as
381
418
  * `pid !== undefined && code === null && signal === null`, and derive it again before every use of
382
419
  * the id. `code` and `signal` mirror the host child's own terminal record, so they carry the native
383
- * exit as soon as the host has it, while the `exit` promise settles on stdio close — a descendant
384
- * holding inherited stdio keeps that close pending past the native exit, and a supervisor inside
385
- * that window reads the terminal state here.
420
+ * exit as soon as the host has it, while the `exit` promise settles at the terminal moment — a
421
+ * descendant holding inherited stdio keeps the stream close pending past the native exit, and a
422
+ * supervisor inside that window reads the terminal state here.
386
423
  */
387
424
  export declare interface ProcessInterface {
388
425
  /** The host process id, fixed when construction returns, or `undefined` when the spawn produced none. */
@@ -394,7 +431,7 @@ export declare interface ProcessInterface {
394
431
  /** The typed lifecycle observation surface. */
395
432
  readonly emitter: EmitterInterface<ProcessEventMap>;
396
433
  /**
397
- * The captured stdout lines, in arrival order, for one consumer, ending when the child's stdout closes.
434
+ * The captured stdout lines, in arrival order, for one consumer, ending at the terminal moment.
398
435
  *
399
436
  * @remarks
400
437
  * A line feed, a CRLF pair, and a bare carriage return each terminate a line, and a CRLF split
@@ -402,13 +439,58 @@ export declare interface ProcessInterface {
402
439
  * return therefore yields one line per redraw, and consecutive carriage returns yield an empty
403
440
  * line between them. A final line written with no trailing terminator is delivered when stdout
404
441
  * closes.
442
+ *
443
+ * The stream ends at the terminal moment rather than throwing there, so teardown is not an error
444
+ * path: a pending `next()` resolves `done: true` and a `for await` loop exits normally. Lines
445
+ * already framed and queued are delivered before that end, so a consumer that stops a chatty
446
+ * child still reads what the child had produced, and only bytes that would have arrived after the
447
+ * terminal moment are lost — whether that moment came from the read ends closing, from the
448
+ * `drain` bound after a native exit, or from a requested termination. An unframed trailing partial
449
+ * written before an undrained cutoff is not promised, because only the stream's own end flushes
450
+ * one. A read started after the end yields nothing further.
405
451
  */
406
452
  readonly lines: AsyncIterable<string>;
407
- /** The decoded byte-bounded stderr tail. */
453
+ /**
454
+ * The decoded byte-bounded stderr tail.
455
+ *
456
+ * @remarks
457
+ * The live tail before the terminal moment and the frozen value after it, on every path — a
458
+ * natural exit, `stop`, `destroy`, an abort of the `signal` option, and a spawn fault. Every read
459
+ * after that moment returns the same string, so a consumer needs no private copy and cannot
460
+ * observe the tail moving under it. When {@link ProcessExit.drained} is false the frozen value is
461
+ * the tail as of the cutoff, and later diagnostics may have existed.
462
+ */
408
463
  readonly evidence: string;
409
464
  /** True when the `lines` stream omitted output because a retention bound was reached. */
410
465
  readonly truncated: boolean;
411
- /** The terminal child state, observed once from the close event. */
466
+ /**
467
+ * True after the `exit` promise settled.
468
+ *
469
+ * @remarks
470
+ * The terminal moment has arrived: `evidence` is frozen, `lines` has ended, and the
471
+ * {@link ProcessExit} value exists. Reached on every path, including a spawn that produced no
472
+ * child.
473
+ */
474
+ readonly settled: boolean;
475
+ /**
476
+ * True after a termination began.
477
+ *
478
+ * @remarks
479
+ * Monotonic. It turns true when `stop`, `destroy`, or an abort of the `signal` option begins a
480
+ * termination, and it stays true from then on, including after `settled` turns true. It reports
481
+ * that a termination was initiated, not that one is in flight, because the initiation is the fact
482
+ * a consumer acts on: a child that was asked to end is not a child to send new work to. A child
483
+ * that exited on its own reports `false` here with `settled` true.
484
+ */
485
+ readonly stopping: boolean;
486
+ /**
487
+ * The terminal child state, delivered once.
488
+ *
489
+ * @remarks
490
+ * Never rejects. It settles at the terminal moment: when the child's streams close, or when the
491
+ * `drain` bound elapsed first. The native exit arms that bound as well as an initiated
492
+ * termination, so a child nobody terminates still settles it within `drain` of ending.
493
+ */
412
494
  readonly exit: Promise<ProcessExit>;
413
495
  /**
414
496
  * Write one line to the open standard-input channel.
@@ -429,7 +511,7 @@ export declare interface ProcessInterface {
429
511
  */
430
512
  send(text: string): Promise<boolean>;
431
513
  /**
432
- * Terminate the child process tree and await its observed exit.
514
+ * Terminate the child process tree, await its observed exit, and reach the terminal moment.
433
515
  *
434
516
  * @remarks
435
517
  * Never rejects. On Windows the whole tree is killed immediately through `taskkill`, with a
@@ -437,16 +519,25 @@ export declare interface ProcessInterface {
437
519
  * `SIGKILL` after `grace`. No signal is initiated after the child's native exit is observed; the
438
520
  * window between initiating a signal and the host delivering it belongs to the operating system.
439
521
  *
522
+ * Observation ends here as well as under `destroy`, bounded by `drain`: `evidence` freezes,
523
+ * `lines` ends, and `exit` settles. A caller that stops a child and keeps reading it therefore
524
+ * reaches the end of the stream instead of waiting on a child it already ended, and needs no
525
+ * second call to release it.
526
+ *
440
527
  * @returns True when the child's native exit was observed; false when the confirmation deadline elapsed without it
441
528
  */
442
529
  stop(): Promise<boolean>;
443
530
  /**
444
- * Stop the child, close its standard-input channel, and destroy the observation emitter.
531
+ * Stop the child, close its standard-input channel, reach the terminal moment, and destroy the
532
+ * observation emitter.
445
533
  *
446
534
  * @remarks
447
- * Always resolves, including when termination was never confirmed. Resolving does not imply the
448
- * child's stdio has closed: a descendant holding an inherited pipe keeps the close event pending,
449
- * so `exit` and `lines` can still be outstanding after this barrier settles.
535
+ * Always resolves, including when termination was never confirmed. The barrier settles after the
536
+ * terminal moment, so `evidence` is frozen, `lines` has ended, and `exit` has settled by the time
537
+ * a caller resumes. The wait for the child's streams is bounded by `drain`, so a descendant
538
+ * holding an inherited pipe cannot hold this barrier open, and {@link ProcessExit.drained} reports
539
+ * which way the moment arrived. The emitter is destroyed after the frozen state exists, so a
540
+ * consumer watching the `stderr` event and a consumer reading `evidence` end on the same bytes.
450
541
  *
451
542
  * @returns The stable barrier shared by every call
452
543
  */
@@ -503,11 +594,11 @@ export declare interface ProcessManagerInterface {
503
594
  * @remarks
504
595
  * Every option is read before the child is spawned, so a caller's own option getter runs while
505
596
  * nothing has started and a throw from one strands no process. A getter that begins `destroy`
506
- * without throwing is the one remaining race, and it leaves a bounded residual: the child is
507
- * already spawned, so the launch is refused with `protocol` and that child is torn down
508
- * asynchronously, bounded by `grace` plus the confirmation window. The `protocol` refusal throws
509
- * synchronously before the `destroy` barrier settles. The barrier does not cover that child's
510
- * asynchronous teardown.
597
+ * without throwing is the one remaining race: the child is already spawned, so the launch is
598
+ * refused with `protocol` and that child is destroyed rather than adopted, its teardown bounded
599
+ * by `grace` plus the confirmation window. The `protocol` refusal throws synchronously, and the
600
+ * `destroy` barrier covers that teardown, so the refused child reaches its terminal moment before
601
+ * the barrier resolves.
511
602
  *
512
603
  * @param id - The registry key, unique among live children
513
604
  * @param options - The child construction options
@@ -566,8 +657,17 @@ export declare interface ProcessManagerOptions {
566
657
  *
567
658
  * @remarks
568
659
  * `grace` is the cooperative window between `SIGTERM` and `SIGKILL` on a POSIX host; Windows has no
569
- * cooperative phase, so the value is unused there. There is no completion deadline — a caller that
570
- * wants one arms its own timer and calls `stop`. `backlog` bounds the unconsumed `lines` backlog.
660
+ * cooperative phase, so the value is unused there. There is no completion deadline for a running
661
+ * child: nothing here ends a child that is still working, the `exit` promise carries no deadline of
662
+ * its own, and a caller that wants one arms its own timer and calls `stop`. `drain` does not weaken
663
+ * that. It bounds a single window — between the child's ending and the release of that child's read
664
+ * ends — so it cannot end a running child. The child's native exit arms it, and so does the return
665
+ * of a termination this package initiated through `stop`, `destroy`, or an abort of `signal`; a
666
+ * termination whose confirmation window elapsed can therefore reach the cutoff while the child still
667
+ * runs. The bound exists because a descendant holding an inherited pipe defers the host's stream
668
+ * close for that descendant's whole life, which the package cannot reach and cannot outwait: without
669
+ * the bound, a child that ended would hand the caller an unbounded wait.
670
+ * `backlog` bounds the unconsumed `lines` backlog.
571
671
  * During termination, retained lines are capped at twice `backlog`; later lines are dropped without
572
672
  * pausing stdout, and {@link ProcessInterface.truncated} reports the omission. `on` installs initial
573
673
  * {@link ProcessEventMap} listeners and `error` receives isolated listener failures. Every numeric
@@ -585,6 +685,8 @@ export declare interface ProcessOptions {
585
685
  readonly workspace: string;
586
686
  /** Cooperative POSIX window in milliseconds between `SIGTERM` and `SIGKILL`. Default: {@link PROCESS_GRACE}. */
587
687
  readonly grace?: number;
688
+ /** Milliseconds the package waits for the child's read ends to close after the native exit or an initiated termination, before cutting them off; `0` cuts them off as soon as the bound is armed. Default: {@link PROCESS_DRAIN}. */
689
+ readonly drain?: number;
588
690
  /** Maximum retained stderr tail in bytes. Default: {@link PROCESS_EVIDENCE}. */
589
691
  readonly evidence?: number;
590
692
  /** Soft high-water mark in bytes for the unconsumed `lines` backlog; termination retains at most twice this value. Default: {@link PROCESS_BACKLOG}. */
@@ -222,6 +222,23 @@ export declare const PROCESS_BACKLOG = 10485760;
222
222
  /** The window in milliseconds a termination waits for the child's native exit after the final kill. */
223
223
  export declare const PROCESS_CONFIRMATION = 5000;
224
224
 
225
+ /**
226
+ * The default window in milliseconds the package waits for the child's read ends to close after
227
+ * the child's native exit or after a termination this package initiated, before cutting them off.
228
+ *
229
+ * @remarks
230
+ * Measured on Windows 11 with Node v24.18.1 on 2026-08-21, spawning the `tests/src/server/fixtures`
231
+ * child modes as real children and timing the host `close` event against the host `exit` event.
232
+ * Every ordinary run closed within 0.02ms of the native exit, whether the child ended itself or a
233
+ * kill ended it, and a `taskkill /F /T` that reaped a descendant while the root was still alive
234
+ * closed within 0.01ms. The only finite late close came from a descendant that outlived its root and
235
+ * then ended on its own, at 127.44ms to 193.41ms — that lag is the descendant's own remaining life
236
+ * rather than a flush cost. A descendant that never ends never closes, so the distribution has no
237
+ * finite tail to cover and this value bounds it instead: 1000ms is over five times the slowest
238
+ * finite close measured, and it keeps an unreachable descendant from stretching a shutdown.
239
+ */
240
+ export declare const PROCESS_DRAIN = 1000;
241
+
225
242
  /** The machine-readable failure categories a {@link ProcessError} carries, in declaration order. */
226
243
  export declare const PROCESS_ERROR_CODES: readonly ["spawn", "timeout", "input", "duplicate", "protocol", "invalid"];
227
244
 
@@ -349,12 +366,24 @@ export declare type ProcessEventMap = {
349
366
  readonly exit: readonly [exit: ProcessExit];
350
367
  };
351
368
 
352
- /** The observed terminal state of a child process: its exit code, or the signal that ended it. */
369
+ /**
370
+ * The observed terminal state of a child process: its exit code or the signal that ended it, and
371
+ * how its observation ended.
372
+ *
373
+ * @remarks
374
+ * This value exists only at the terminal moment, so every field on it is already final and no
375
+ * consumer can read one too early. `drained` reports whether the diagnostics are complete;
376
+ * {@link ProcessInterface.truncated} reports that the `lines` stream omitted stdout lines. They are
377
+ * independent facts about different streams, and one child reports both when a retention bound
378
+ * dropped lines and the drain bound cut stderr off.
379
+ */
353
380
  export declare interface ProcessExit {
354
381
  /** The exit code, or `null` when a signal ended the process. A spawn fault reports the host's negative errno for `Process` and `execute`. */
355
382
  readonly code: number | null;
356
383
  /** The terminating signal name, or `null` when the process exited on its own. */
357
384
  readonly signal: string | null;
385
+ /** True when the terminal moment arrived because the child's streams closed; false when the `drain` bound elapsed first and later diagnostics may have existed. */
386
+ readonly drained: boolean;
358
387
  }
359
388
 
360
389
  /**
@@ -375,14 +404,22 @@ export declare interface ProcessExit {
375
404
  * its own capture `limit`. The typed `emitter` carries the live `stderr` chunks, the child `error` cause, and the
376
405
  * terminal `exit`, alongside the `exit` promise. `stop` and `destroy` are idempotent and never reject.
377
406
  *
407
+ * The same terminal moment governs every observation surface. It arrives when the child's streams close,
408
+ * or when the `drain` bound armed by the native exit or by a termination this package initiated
409
+ * elapses first, and
410
+ * {@link ProcessExit.drained} reports which. At that moment `evidence` freezes, `lines` ends, `exit`
411
+ * settles, and `settled` turns true — together, so a consumer reading `evidence` and a consumer
412
+ * iterating `lines` never see a different child. `stop`, `destroy`, an abort of the `signal` option,
413
+ * a natural exit, and a spawn fault all reach it.
414
+ *
378
415
  * The spawn is eager, so `pid` is fixed by the time construction returns; a spawn that produced no
379
416
  * child reports `undefined` for that child's whole lifetime. An assigned id survives the exit and
380
417
  * reports no liveness on its own, because the host reuses a dead child's id. Derive liveness as
381
418
  * `pid !== undefined && code === null && signal === null`, and derive it again before every use of
382
419
  * the id. `code` and `signal` mirror the host child's own terminal record, so they carry the native
383
- * exit as soon as the host has it, while the `exit` promise settles on stdio close — a descendant
384
- * holding inherited stdio keeps that close pending past the native exit, and a supervisor inside
385
- * that window reads the terminal state here.
420
+ * exit as soon as the host has it, while the `exit` promise settles at the terminal moment — a
421
+ * descendant holding inherited stdio keeps the stream close pending past the native exit, and a
422
+ * supervisor inside that window reads the terminal state here.
386
423
  */
387
424
  export declare interface ProcessInterface {
388
425
  /** The host process id, fixed when construction returns, or `undefined` when the spawn produced none. */
@@ -394,7 +431,7 @@ export declare interface ProcessInterface {
394
431
  /** The typed lifecycle observation surface. */
395
432
  readonly emitter: EmitterInterface<ProcessEventMap>;
396
433
  /**
397
- * The captured stdout lines, in arrival order, for one consumer, ending when the child's stdout closes.
434
+ * The captured stdout lines, in arrival order, for one consumer, ending at the terminal moment.
398
435
  *
399
436
  * @remarks
400
437
  * A line feed, a CRLF pair, and a bare carriage return each terminate a line, and a CRLF split
@@ -402,13 +439,58 @@ export declare interface ProcessInterface {
402
439
  * return therefore yields one line per redraw, and consecutive carriage returns yield an empty
403
440
  * line between them. A final line written with no trailing terminator is delivered when stdout
404
441
  * closes.
442
+ *
443
+ * The stream ends at the terminal moment rather than throwing there, so teardown is not an error
444
+ * path: a pending `next()` resolves `done: true` and a `for await` loop exits normally. Lines
445
+ * already framed and queued are delivered before that end, so a consumer that stops a chatty
446
+ * child still reads what the child had produced, and only bytes that would have arrived after the
447
+ * terminal moment are lost — whether that moment came from the read ends closing, from the
448
+ * `drain` bound after a native exit, or from a requested termination. An unframed trailing partial
449
+ * written before an undrained cutoff is not promised, because only the stream's own end flushes
450
+ * one. A read started after the end yields nothing further.
405
451
  */
406
452
  readonly lines: AsyncIterable<string>;
407
- /** The decoded byte-bounded stderr tail. */
453
+ /**
454
+ * The decoded byte-bounded stderr tail.
455
+ *
456
+ * @remarks
457
+ * The live tail before the terminal moment and the frozen value after it, on every path — a
458
+ * natural exit, `stop`, `destroy`, an abort of the `signal` option, and a spawn fault. Every read
459
+ * after that moment returns the same string, so a consumer needs no private copy and cannot
460
+ * observe the tail moving under it. When {@link ProcessExit.drained} is false the frozen value is
461
+ * the tail as of the cutoff, and later diagnostics may have existed.
462
+ */
408
463
  readonly evidence: string;
409
464
  /** True when the `lines` stream omitted output because a retention bound was reached. */
410
465
  readonly truncated: boolean;
411
- /** The terminal child state, observed once from the close event. */
466
+ /**
467
+ * True after the `exit` promise settled.
468
+ *
469
+ * @remarks
470
+ * The terminal moment has arrived: `evidence` is frozen, `lines` has ended, and the
471
+ * {@link ProcessExit} value exists. Reached on every path, including a spawn that produced no
472
+ * child.
473
+ */
474
+ readonly settled: boolean;
475
+ /**
476
+ * True after a termination began.
477
+ *
478
+ * @remarks
479
+ * Monotonic. It turns true when `stop`, `destroy`, or an abort of the `signal` option begins a
480
+ * termination, and it stays true from then on, including after `settled` turns true. It reports
481
+ * that a termination was initiated, not that one is in flight, because the initiation is the fact
482
+ * a consumer acts on: a child that was asked to end is not a child to send new work to. A child
483
+ * that exited on its own reports `false` here with `settled` true.
484
+ */
485
+ readonly stopping: boolean;
486
+ /**
487
+ * The terminal child state, delivered once.
488
+ *
489
+ * @remarks
490
+ * Never rejects. It settles at the terminal moment: when the child's streams close, or when the
491
+ * `drain` bound elapsed first. The native exit arms that bound as well as an initiated
492
+ * termination, so a child nobody terminates still settles it within `drain` of ending.
493
+ */
412
494
  readonly exit: Promise<ProcessExit>;
413
495
  /**
414
496
  * Write one line to the open standard-input channel.
@@ -429,7 +511,7 @@ export declare interface ProcessInterface {
429
511
  */
430
512
  send(text: string): Promise<boolean>;
431
513
  /**
432
- * Terminate the child process tree and await its observed exit.
514
+ * Terminate the child process tree, await its observed exit, and reach the terminal moment.
433
515
  *
434
516
  * @remarks
435
517
  * Never rejects. On Windows the whole tree is killed immediately through `taskkill`, with a
@@ -437,16 +519,25 @@ export declare interface ProcessInterface {
437
519
  * `SIGKILL` after `grace`. No signal is initiated after the child's native exit is observed; the
438
520
  * window between initiating a signal and the host delivering it belongs to the operating system.
439
521
  *
522
+ * Observation ends here as well as under `destroy`, bounded by `drain`: `evidence` freezes,
523
+ * `lines` ends, and `exit` settles. A caller that stops a child and keeps reading it therefore
524
+ * reaches the end of the stream instead of waiting on a child it already ended, and needs no
525
+ * second call to release it.
526
+ *
440
527
  * @returns True when the child's native exit was observed; false when the confirmation deadline elapsed without it
441
528
  */
442
529
  stop(): Promise<boolean>;
443
530
  /**
444
- * Stop the child, close its standard-input channel, and destroy the observation emitter.
531
+ * Stop the child, close its standard-input channel, reach the terminal moment, and destroy the
532
+ * observation emitter.
445
533
  *
446
534
  * @remarks
447
- * Always resolves, including when termination was never confirmed. Resolving does not imply the
448
- * child's stdio has closed: a descendant holding an inherited pipe keeps the close event pending,
449
- * so `exit` and `lines` can still be outstanding after this barrier settles.
535
+ * Always resolves, including when termination was never confirmed. The barrier settles after the
536
+ * terminal moment, so `evidence` is frozen, `lines` has ended, and `exit` has settled by the time
537
+ * a caller resumes. The wait for the child's streams is bounded by `drain`, so a descendant
538
+ * holding an inherited pipe cannot hold this barrier open, and {@link ProcessExit.drained} reports
539
+ * which way the moment arrived. The emitter is destroyed after the frozen state exists, so a
540
+ * consumer watching the `stderr` event and a consumer reading `evidence` end on the same bytes.
450
541
  *
451
542
  * @returns The stable barrier shared by every call
452
543
  */
@@ -503,11 +594,11 @@ export declare interface ProcessManagerInterface {
503
594
  * @remarks
504
595
  * Every option is read before the child is spawned, so a caller's own option getter runs while
505
596
  * nothing has started and a throw from one strands no process. A getter that begins `destroy`
506
- * without throwing is the one remaining race, and it leaves a bounded residual: the child is
507
- * already spawned, so the launch is refused with `protocol` and that child is torn down
508
- * asynchronously, bounded by `grace` plus the confirmation window. The `protocol` refusal throws
509
- * synchronously before the `destroy` barrier settles. The barrier does not cover that child's
510
- * asynchronous teardown.
597
+ * without throwing is the one remaining race: the child is already spawned, so the launch is
598
+ * refused with `protocol` and that child is destroyed rather than adopted, its teardown bounded
599
+ * by `grace` plus the confirmation window. The `protocol` refusal throws synchronously, and the
600
+ * `destroy` barrier covers that teardown, so the refused child reaches its terminal moment before
601
+ * the barrier resolves.
511
602
  *
512
603
  * @param id - The registry key, unique among live children
513
604
  * @param options - The child construction options
@@ -566,8 +657,17 @@ export declare interface ProcessManagerOptions {
566
657
  *
567
658
  * @remarks
568
659
  * `grace` is the cooperative window between `SIGTERM` and `SIGKILL` on a POSIX host; Windows has no
569
- * cooperative phase, so the value is unused there. There is no completion deadline — a caller that
570
- * wants one arms its own timer and calls `stop`. `backlog` bounds the unconsumed `lines` backlog.
660
+ * cooperative phase, so the value is unused there. There is no completion deadline for a running
661
+ * child: nothing here ends a child that is still working, the `exit` promise carries no deadline of
662
+ * its own, and a caller that wants one arms its own timer and calls `stop`. `drain` does not weaken
663
+ * that. It bounds a single window — between the child's ending and the release of that child's read
664
+ * ends — so it cannot end a running child. The child's native exit arms it, and so does the return
665
+ * of a termination this package initiated through `stop`, `destroy`, or an abort of `signal`; a
666
+ * termination whose confirmation window elapsed can therefore reach the cutoff while the child still
667
+ * runs. The bound exists because a descendant holding an inherited pipe defers the host's stream
668
+ * close for that descendant's whole life, which the package cannot reach and cannot outwait: without
669
+ * the bound, a child that ended would hand the caller an unbounded wait.
670
+ * `backlog` bounds the unconsumed `lines` backlog.
571
671
  * During termination, retained lines are capped at twice `backlog`; later lines are dropped without
572
672
  * pausing stdout, and {@link ProcessInterface.truncated} reports the omission. `on` installs initial
573
673
  * {@link ProcessEventMap} listeners and `error` receives isolated listener failures. Every numeric
@@ -585,6 +685,8 @@ export declare interface ProcessOptions {
585
685
  readonly workspace: string;
586
686
  /** Cooperative POSIX window in milliseconds between `SIGTERM` and `SIGKILL`. Default: {@link PROCESS_GRACE}. */
587
687
  readonly grace?: number;
688
+ /** Milliseconds the package waits for the child's read ends to close after the native exit or an initiated termination, before cutting them off; `0` cuts them off as soon as the bound is armed. Default: {@link PROCESS_DRAIN}. */
689
+ readonly drain?: number;
588
690
  /** Maximum retained stderr tail in bytes. Default: {@link PROCESS_EVIDENCE}. */
589
691
  readonly evidence?: number;
590
692
  /** Soft high-water mark in bytes for the unconsumed `lines` backlog; termination retains at most twice this value. Default: {@link PROCESS_BACKLOG}. */
@@ -4,6 +4,22 @@ import { holds, isError } from "@orkestrel/contract";
4
4
  var PROCESS_GRACE = 5e3;
5
5
  /** The window in milliseconds a termination waits for the child's native exit after the final kill. */
6
6
  var PROCESS_CONFIRMATION = 5e3;
7
+ /**
8
+ * The default window in milliseconds the package waits for the child's read ends to close after
9
+ * the child's native exit or after a termination this package initiated, before cutting them off.
10
+ *
11
+ * @remarks
12
+ * Measured on Windows 11 with Node v24.18.1 on 2026-08-21, spawning the `tests/src/server/fixtures`
13
+ * child modes as real children and timing the host `close` event against the host `exit` event.
14
+ * Every ordinary run closed within 0.02ms of the native exit, whether the child ended itself or a
15
+ * kill ended it, and a `taskkill /F /T` that reaped a descendant while the root was still alive
16
+ * closed within 0.01ms. The only finite late close came from a descendant that outlived its root and
17
+ * then ended on its own, at 127.44ms to 193.41ms — that lag is the descendant's own remaining life
18
+ * rather than a flush cost. A descendant that never ends never closes, so the distribution has no
19
+ * finite tail to cover and this value bounds it instead: 1000ms is over five times the slowest
20
+ * finite close measured, and it keeps an unreachable descendant from stretching a shutdown.
21
+ */
22
+ var PROCESS_DRAIN = 1e3;
7
23
  /** The default maximum retained stderr tail in bytes for a supervised {@link ProcessInterface}. */
8
24
  var PROCESS_EVIDENCE = 2048;
9
25
  /** The default soft high-water mark in bytes for a supervised {@link ProcessInterface} line backlog. */
@@ -148,6 +164,6 @@ function createExecuteError(result, cause) {
148
164
  });
149
165
  }
150
166
  //#endregion
151
- export { PROCESS_BACKLOG, PROCESS_CONFIRMATION, PROCESS_ERROR_CODES, PROCESS_EVIDENCE, PROCESS_GRACE, PROCESS_OUTPUT, PROCESS_PATHEXT, PROCESS_TIMER, ProcessError, createDuplicateError, createExecuteError, createInvalidError, createProtocolError, isProcessError };
167
+ export { PROCESS_BACKLOG, PROCESS_CONFIRMATION, PROCESS_DRAIN, PROCESS_ERROR_CODES, PROCESS_EVIDENCE, PROCESS_GRACE, PROCESS_OUTPUT, PROCESS_PATHEXT, PROCESS_TIMER, ProcessError, createDuplicateError, createExecuteError, createInvalidError, createProtocolError, isProcessError };
152
168
 
153
169
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/core/constants.ts","../../../src/core/errors.ts"],"sourcesContent":["/** The default cooperative POSIX window in milliseconds between `SIGTERM` and `SIGKILL` during termination. */\nexport const PROCESS_GRACE = 5_000\n\n/** The window in milliseconds a termination waits for the child's native exit after the final kill. */\nexport const PROCESS_CONFIRMATION = 5_000\n\n/** The default maximum retained stderr tail in bytes for a supervised {@link ProcessInterface}. */\nexport const PROCESS_EVIDENCE = 2_048\n\n/** The default soft high-water mark in bytes for a supervised {@link ProcessInterface} line backlog. */\nexport const PROCESS_BACKLOG = 10_485_760\n\n/** The default maximum captured bytes for a one-shot run's stdout and stderr, each. */\nexport const PROCESS_OUTPUT = 10_485_760\n\n/** The largest timer delay in milliseconds the host schedules without truncating it to one. */\nexport const PROCESS_TIMER = 2_147_483_647\n\n/** The executable extensions a Windows lookup applies when the environment declares no `PATHEXT`. */\nexport const PROCESS_PATHEXT = '.COM;.EXE;.BAT;.CMD'\n\n/** The machine-readable failure categories a {@link ProcessError} carries, in declaration order. */\nexport const PROCESS_ERROR_CODES = Object.freeze([\n\t'spawn',\n\t'timeout',\n\t'input',\n\t'duplicate',\n\t'protocol',\n\t'invalid',\n] as const)\n","import type {\n\tProcessErrorCode,\n\tProcessErrorContext,\n\tProcessErrorOptions,\n\tExecuteResult,\n} from './types.js'\nimport { holds, isError } from '@orkestrel/contract'\nimport { PROCESS_ERROR_CODES } from './constants.js'\n\n/** A child-process failure with a stable machine-readable category. */\nexport class ProcessError extends Error {\n\toverride readonly name = 'ProcessError'\n\treadonly code: ProcessErrorCode\n\treadonly context?: ProcessErrorContext\n\t/** The buffered run outcome, present when a one-shot run produced the failure. */\n\treadonly result?: ExecuteResult\n\n\t/**\n\t * Create a process error.\n\t *\n\t * @param message - Human-readable failure description\n\t * @param options - Machine-readable category, optional context, optional cause, and optional run result\n\t */\n\tconstructor(message: string, options: ProcessErrorOptions) {\n\t\tconst cause = options.cause\n\t\tsuper(message, cause === undefined ? undefined : { cause })\n\t\tObject.defineProperty(this, Symbol.for('@orkestrel/process.error'), { value: true })\n\t\tthis.code = options.code\n\t\tif (options.context !== undefined) this.context = options.context\n\t\tif (options.result !== undefined) this.result = options.result\n\t}\n}\n\n/**\n * Checks whether an unknown value is a {@link ProcessError}.\n *\n * @remarks\n * Recognition combines a global own-property brand with the native `Error` base, the subclass\n * prototype, the fixed name, and a code {@link PROCESS_ERROR_CODES} declares. The brand is\n * recognized across duplicate installations and ESM/CommonJS module copies at 0.0.4 or later. A copy\n * earlier than 0.0.4 stamps no brand, so an error it throws stays outside the type, and so does a\n * plain or property-only lookalike.\n *\n * @param value - The value to inspect\n * @returns True only for a `ProcessError` instance; false otherwise\n *\n * @example\n * ```ts\n * isProcessError(new ProcessError('spawn failed', { code: 'spawn' })) // true\n * isProcessError(new Error('spawn failed')) // false\n * ```\n */\nexport function isProcessError(value: unknown): value is ProcessError {\n\tif (!isError(value)) return false\n\treturn holds(() => {\n\t\tif (Object.getPrototypeOf(value) === Error.prototype) return false\n\t\tif (value.name !== 'ProcessError' || !('code' in value)) return false\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(\n\t\t\tvalue,\n\t\t\tSymbol.for('@orkestrel/process.error'),\n\t\t)\n\t\tif (descriptor?.value !== true) return false\n\t\tconst code: unknown = value.code\n\t\treturn PROCESS_ERROR_CODES.some((declared) => declared === code)\n\t})\n}\n\n/**\n * Creates the failure raised when a manager launch reuses a live id.\n *\n * @param id - The id already occupied by a live child\n * @returns A typed duplicate-id failure\n */\nexport function createDuplicateError(id: string): ProcessError {\n\treturn new ProcessError(`Process '${id}' is already live`, {\n\t\tcode: 'duplicate',\n\t\tcontext: { id },\n\t})\n}\n\n/**\n * Creates the failure raised when a launch is attempted on a registry that is being destroyed.\n *\n * @param id - The id the refused launch asked for\n * @returns A typed protocol failure\n */\nexport function createProtocolError(id: string): ProcessError {\n\treturn new ProcessError(`Process '${id}' cannot launch: the registry is destroyed`, {\n\t\tcode: 'protocol',\n\t\tcontext: { id },\n\t})\n}\n\n/**\n * Creates the failure raised when a public input is refused before anything is spawned.\n *\n * @param subject - The rejected input named as the caller wrote it, such as `option 'grace'`\n * @param value - The rejected value, carried as `context.value`\n * @returns A typed validation failure\n *\n * @example\n * ```ts\n * createInvalidError(\"option 'grace'\", -1).code // 'invalid'\n * ```\n */\nexport function createInvalidError(subject: string, value: unknown): ProcessError {\n\treturn new ProcessError(`Invalid ${subject}`, { code: 'invalid', context: { value } })\n}\n\n/**\n * Creates the failure raised when a run does not complete successfully and rejection is requested.\n *\n * @remarks\n * The category is `timeout` only when the run's own timeout elapsed; every other failure,\n * including an abort and an output overflow, is a `spawn` failure carrying its\n * {@link ExecuteResult}.\n *\n * @param result - The buffered run outcome that failed\n * @param cause - The underlying host fault, when one ended the run\n * @returns A typed run failure carrying its {@link ExecuteResult}\n */\nexport function createExecuteError(result: ExecuteResult, cause?: unknown): ProcessError {\n\tlet reason = `exited with code ${String(result.code)}`\n\tif (result.signal !== null) reason = `was killed by ${result.signal}`\n\tif (result.truncated) reason = 'exceeded its output limit'\n\tif (result.aborted) reason = 'was aborted'\n\tif (result.expired) reason = 'timed out'\n\treturn new ProcessError(`Command '${result.command}' ${reason}`, {\n\t\tcode: result.expired ? 'timeout' : 'spawn',\n\t\tcontext: { command: result.command, code: result.code, signal: result.signal },\n\t\t...(cause === undefined ? {} : { cause }),\n\t\tresult,\n\t})\n}\n"],"mappings":";;;AACA,IAAa,gBAAgB;;AAG7B,IAAa,uBAAuB;;AAGpC,IAAa,mBAAmB;;AAGhC,IAAa,kBAAkB;;AAG/B,IAAa,iBAAiB;;AAG9B,IAAa,gBAAgB;;AAG7B,IAAa,kBAAkB;;AAG/B,IAAa,sBAAsB,OAAO,OAAO;CAChD;CACA;CACA;CACA;CACA;CACA;AACD,CAAU;;;;ACnBV,IAAa,eAAb,cAAkC,MAAM;CACvC,OAAyB;CACzB;CACA;;CAEA;;;;;;;CAQA,YAAY,SAAiB,SAA8B;EAC1D,MAAM,QAAQ,QAAQ;EACtB,MAAM,SAAS,UAAU,KAAA,IAAY,KAAA,IAAY,EAAE,MAAM,CAAC;EAC1D,OAAO,eAAe,MAAM,OAAO,IAAI,0BAA0B,GAAG,EAAE,OAAO,KAAK,CAAC;EACnF,KAAK,OAAO,QAAQ;EACpB,IAAI,QAAQ,YAAY,KAAA,GAAW,KAAK,UAAU,QAAQ;EAC1D,IAAI,QAAQ,WAAW,KAAA,GAAW,KAAK,SAAS,QAAQ;CACzD;AACD;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,eAAe,OAAuC;CACrE,IAAI,CAAC,QAAQ,KAAK,GAAG,OAAO;CAC5B,OAAO,YAAY;EAClB,IAAI,OAAO,eAAe,KAAK,MAAM,MAAM,WAAW,OAAO;EAC7D,IAAI,MAAM,SAAS,kBAAkB,EAAE,UAAU,QAAQ,OAAO;EAKhE,IAJmB,OAAO,yBACzB,OACA,OAAO,IAAI,0BAA0B,CAElC,CAAA,EAAY,UAAU,MAAM,OAAO;EACvC,MAAM,OAAgB,MAAM;EAC5B,OAAO,oBAAoB,MAAM,aAAa,aAAa,IAAI;CAChE,CAAC;AACF;;;;;;;AAQA,SAAgB,qBAAqB,IAA0B;CAC9D,OAAO,IAAI,aAAa,YAAY,GAAG,oBAAoB;EAC1D,MAAM;EACN,SAAS,EAAE,GAAG;CACf,CAAC;AACF;;;;;;;AAQA,SAAgB,oBAAoB,IAA0B;CAC7D,OAAO,IAAI,aAAa,YAAY,GAAG,6CAA6C;EACnF,MAAM;EACN,SAAS,EAAE,GAAG;CACf,CAAC;AACF;;;;;;;;;;;;;AAcA,SAAgB,mBAAmB,SAAiB,OAA8B;CACjF,OAAO,IAAI,aAAa,WAAW,WAAW;EAAE,MAAM;EAAW,SAAS,EAAE,MAAM;CAAE,CAAC;AACtF;;;;;;;;;;;;;AAcA,SAAgB,mBAAmB,QAAuB,OAA+B;CACxF,IAAI,SAAS,oBAAoB,OAAO,OAAO,IAAI;CACnD,IAAI,OAAO,WAAW,MAAM,SAAS,iBAAiB,OAAO;CAC7D,IAAI,OAAO,WAAW,SAAS;CAC/B,IAAI,OAAO,SAAS,SAAS;CAC7B,IAAI,OAAO,SAAS,SAAS;CAC7B,OAAO,IAAI,aAAa,YAAY,OAAO,QAAQ,IAAI,UAAU;EAChE,MAAM,OAAO,UAAU,YAAY;EACnC,SAAS;GAAE,SAAS,OAAO;GAAS,MAAM,OAAO;GAAM,QAAQ,OAAO;EAAO;EAC7E,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;EACvC;CACD,CAAC;AACF"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/core/constants.ts","../../../src/core/errors.ts"],"sourcesContent":["/** The default cooperative POSIX window in milliseconds between `SIGTERM` and `SIGKILL` during termination. */\nexport const PROCESS_GRACE = 5_000\n\n/** The window in milliseconds a termination waits for the child's native exit after the final kill. */\nexport const PROCESS_CONFIRMATION = 5_000\n\n/**\n * The default window in milliseconds the package waits for the child's read ends to close after\n * the child's native exit or after a termination this package initiated, before cutting them off.\n *\n * @remarks\n * Measured on Windows 11 with Node v24.18.1 on 2026-08-21, spawning the `tests/src/server/fixtures`\n * child modes as real children and timing the host `close` event against the host `exit` event.\n * Every ordinary run closed within 0.02ms of the native exit, whether the child ended itself or a\n * kill ended it, and a `taskkill /F /T` that reaped a descendant while the root was still alive\n * closed within 0.01ms. The only finite late close came from a descendant that outlived its root and\n * then ended on its own, at 127.44ms to 193.41ms — that lag is the descendant's own remaining life\n * rather than a flush cost. A descendant that never ends never closes, so the distribution has no\n * finite tail to cover and this value bounds it instead: 1000ms is over five times the slowest\n * finite close measured, and it keeps an unreachable descendant from stretching a shutdown.\n */\nexport const PROCESS_DRAIN = 1_000\n\n/** The default maximum retained stderr tail in bytes for a supervised {@link ProcessInterface}. */\nexport const PROCESS_EVIDENCE = 2_048\n\n/** The default soft high-water mark in bytes for a supervised {@link ProcessInterface} line backlog. */\nexport const PROCESS_BACKLOG = 10_485_760\n\n/** The default maximum captured bytes for a one-shot run's stdout and stderr, each. */\nexport const PROCESS_OUTPUT = 10_485_760\n\n/** The largest timer delay in milliseconds the host schedules without truncating it to one. */\nexport const PROCESS_TIMER = 2_147_483_647\n\n/** The executable extensions a Windows lookup applies when the environment declares no `PATHEXT`. */\nexport const PROCESS_PATHEXT = '.COM;.EXE;.BAT;.CMD'\n\n/** The machine-readable failure categories a {@link ProcessError} carries, in declaration order. */\nexport const PROCESS_ERROR_CODES = Object.freeze([\n\t'spawn',\n\t'timeout',\n\t'input',\n\t'duplicate',\n\t'protocol',\n\t'invalid',\n] as const)\n","import type {\n\tProcessErrorCode,\n\tProcessErrorContext,\n\tProcessErrorOptions,\n\tExecuteResult,\n} from './types.js'\nimport { holds, isError } from '@orkestrel/contract'\nimport { PROCESS_ERROR_CODES } from './constants.js'\n\n/** A child-process failure with a stable machine-readable category. */\nexport class ProcessError extends Error {\n\toverride readonly name = 'ProcessError'\n\treadonly code: ProcessErrorCode\n\treadonly context?: ProcessErrorContext\n\t/** The buffered run outcome, present when a one-shot run produced the failure. */\n\treadonly result?: ExecuteResult\n\n\t/**\n\t * Create a process error.\n\t *\n\t * @param message - Human-readable failure description\n\t * @param options - Machine-readable category, optional context, optional cause, and optional run result\n\t */\n\tconstructor(message: string, options: ProcessErrorOptions) {\n\t\tconst cause = options.cause\n\t\tsuper(message, cause === undefined ? undefined : { cause })\n\t\tObject.defineProperty(this, Symbol.for('@orkestrel/process.error'), { value: true })\n\t\tthis.code = options.code\n\t\tif (options.context !== undefined) this.context = options.context\n\t\tif (options.result !== undefined) this.result = options.result\n\t}\n}\n\n/**\n * Checks whether an unknown value is a {@link ProcessError}.\n *\n * @remarks\n * Recognition combines a global own-property brand with the native `Error` base, the subclass\n * prototype, the fixed name, and a code {@link PROCESS_ERROR_CODES} declares. The brand is\n * recognized across duplicate installations and ESM/CommonJS module copies at 0.0.4 or later. A copy\n * earlier than 0.0.4 stamps no brand, so an error it throws stays outside the type, and so does a\n * plain or property-only lookalike.\n *\n * @param value - The value to inspect\n * @returns True only for a `ProcessError` instance; false otherwise\n *\n * @example\n * ```ts\n * isProcessError(new ProcessError('spawn failed', { code: 'spawn' })) // true\n * isProcessError(new Error('spawn failed')) // false\n * ```\n */\nexport function isProcessError(value: unknown): value is ProcessError {\n\tif (!isError(value)) return false\n\treturn holds(() => {\n\t\tif (Object.getPrototypeOf(value) === Error.prototype) return false\n\t\tif (value.name !== 'ProcessError' || !('code' in value)) return false\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(\n\t\t\tvalue,\n\t\t\tSymbol.for('@orkestrel/process.error'),\n\t\t)\n\t\tif (descriptor?.value !== true) return false\n\t\tconst code: unknown = value.code\n\t\treturn PROCESS_ERROR_CODES.some((declared) => declared === code)\n\t})\n}\n\n/**\n * Creates the failure raised when a manager launch reuses a live id.\n *\n * @param id - The id already occupied by a live child\n * @returns A typed duplicate-id failure\n */\nexport function createDuplicateError(id: string): ProcessError {\n\treturn new ProcessError(`Process '${id}' is already live`, {\n\t\tcode: 'duplicate',\n\t\tcontext: { id },\n\t})\n}\n\n/**\n * Creates the failure raised when a launch is attempted on a registry that is being destroyed.\n *\n * @param id - The id the refused launch asked for\n * @returns A typed protocol failure\n */\nexport function createProtocolError(id: string): ProcessError {\n\treturn new ProcessError(`Process '${id}' cannot launch: the registry is destroyed`, {\n\t\tcode: 'protocol',\n\t\tcontext: { id },\n\t})\n}\n\n/**\n * Creates the failure raised when a public input is refused before anything is spawned.\n *\n * @param subject - The rejected input named as the caller wrote it, such as `option 'grace'`\n * @param value - The rejected value, carried as `context.value`\n * @returns A typed validation failure\n *\n * @example\n * ```ts\n * createInvalidError(\"option 'grace'\", -1).code // 'invalid'\n * ```\n */\nexport function createInvalidError(subject: string, value: unknown): ProcessError {\n\treturn new ProcessError(`Invalid ${subject}`, { code: 'invalid', context: { value } })\n}\n\n/**\n * Creates the failure raised when a run does not complete successfully and rejection is requested.\n *\n * @remarks\n * The category is `timeout` only when the run's own timeout elapsed; every other failure,\n * including an abort and an output overflow, is a `spawn` failure carrying its\n * {@link ExecuteResult}.\n *\n * @param result - The buffered run outcome that failed\n * @param cause - The underlying host fault, when one ended the run\n * @returns A typed run failure carrying its {@link ExecuteResult}\n */\nexport function createExecuteError(result: ExecuteResult, cause?: unknown): ProcessError {\n\tlet reason = `exited with code ${String(result.code)}`\n\tif (result.signal !== null) reason = `was killed by ${result.signal}`\n\tif (result.truncated) reason = 'exceeded its output limit'\n\tif (result.aborted) reason = 'was aborted'\n\tif (result.expired) reason = 'timed out'\n\treturn new ProcessError(`Command '${result.command}' ${reason}`, {\n\t\tcode: result.expired ? 'timeout' : 'spawn',\n\t\tcontext: { command: result.command, code: result.code, signal: result.signal },\n\t\t...(cause === undefined ? {} : { cause }),\n\t\tresult,\n\t})\n}\n"],"mappings":";;;AACA,IAAa,gBAAgB;;AAG7B,IAAa,uBAAuB;;;;;;;;;;;;;;;;AAiBpC,IAAa,gBAAgB;;AAG7B,IAAa,mBAAmB;;AAGhC,IAAa,kBAAkB;;AAG/B,IAAa,iBAAiB;;AAG9B,IAAa,gBAAgB;;AAG7B,IAAa,kBAAkB;;AAG/B,IAAa,sBAAsB,OAAO,OAAO;CAChD;CACA;CACA;CACA;CACA;CACA;AACD,CAAU;;;;ACpCV,IAAa,eAAb,cAAkC,MAAM;CACvC,OAAyB;CACzB;CACA;;CAEA;;;;;;;CAQA,YAAY,SAAiB,SAA8B;EAC1D,MAAM,QAAQ,QAAQ;EACtB,MAAM,SAAS,UAAU,KAAA,IAAY,KAAA,IAAY,EAAE,MAAM,CAAC;EAC1D,OAAO,eAAe,MAAM,OAAO,IAAI,0BAA0B,GAAG,EAAE,OAAO,KAAK,CAAC;EACnF,KAAK,OAAO,QAAQ;EACpB,IAAI,QAAQ,YAAY,KAAA,GAAW,KAAK,UAAU,QAAQ;EAC1D,IAAI,QAAQ,WAAW,KAAA,GAAW,KAAK,SAAS,QAAQ;CACzD;AACD;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,eAAe,OAAuC;CACrE,IAAI,CAAC,QAAQ,KAAK,GAAG,OAAO;CAC5B,OAAO,YAAY;EAClB,IAAI,OAAO,eAAe,KAAK,MAAM,MAAM,WAAW,OAAO;EAC7D,IAAI,MAAM,SAAS,kBAAkB,EAAE,UAAU,QAAQ,OAAO;EAKhE,IAJmB,OAAO,yBACzB,OACA,OAAO,IAAI,0BAA0B,CAElC,CAAA,EAAY,UAAU,MAAM,OAAO;EACvC,MAAM,OAAgB,MAAM;EAC5B,OAAO,oBAAoB,MAAM,aAAa,aAAa,IAAI;CAChE,CAAC;AACF;;;;;;;AAQA,SAAgB,qBAAqB,IAA0B;CAC9D,OAAO,IAAI,aAAa,YAAY,GAAG,oBAAoB;EAC1D,MAAM;EACN,SAAS,EAAE,GAAG;CACf,CAAC;AACF;;;;;;;AAQA,SAAgB,oBAAoB,IAA0B;CAC7D,OAAO,IAAI,aAAa,YAAY,GAAG,6CAA6C;EACnF,MAAM;EACN,SAAS,EAAE,GAAG;CACf,CAAC;AACF;;;;;;;;;;;;;AAcA,SAAgB,mBAAmB,SAAiB,OAA8B;CACjF,OAAO,IAAI,aAAa,WAAW,WAAW;EAAE,MAAM;EAAW,SAAS,EAAE,MAAM;CAAE,CAAC;AACtF;;;;;;;;;;;;;AAcA,SAAgB,mBAAmB,QAAuB,OAA+B;CACxF,IAAI,SAAS,oBAAoB,OAAO,OAAO,IAAI;CACnD,IAAI,OAAO,WAAW,MAAM,SAAS,iBAAiB,OAAO;CAC7D,IAAI,OAAO,WAAW,SAAS;CAC/B,IAAI,OAAO,SAAS,SAAS;CAC7B,IAAI,OAAO,SAAS,SAAS;CAC7B,OAAO,IAAI,aAAa,YAAY,OAAO,QAAQ,IAAI,UAAU;EAChE,MAAM,OAAO,UAAU,YAAY;EACnC,SAAS;GAAE,SAAS,OAAO;GAAS,MAAM,OAAO;GAAM,QAAQ,OAAO;EAAO;EAC7E,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;EACvC;CACD,CAAC;AACF"}