stitchkit 0.108.0 → 0.108.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/agent-runtime/sandbox-process-owner.d.ts +3 -3
  3. package/dist/agent-runtime/sandbox-process-owner.d.ts.map +1 -1
  4. package/dist/agent-runtime/sandbox-process.d.ts +2 -2
  5. package/dist/agent-runtime/sandbox-process.d.ts.map +1 -1
  6. package/dist/agent-runtime/store-conformance-support.d.ts +5 -5
  7. package/dist/entrypoints/agent-runtime/coding-tools.js +2 -2
  8. package/dist/entrypoints/agent-runtime/sandbox.js +2 -2
  9. package/dist/entrypoints/process.js +1 -1
  10. package/dist/{index-4q9jvqg7.js → index-k0kzhdw9.js} +550 -22
  11. package/dist/{index-dwf0gymy.js → index-vyaehh67.js} +1 -1
  12. package/dist/process/bun-child.d.ts +48 -0
  13. package/dist/process/bun-child.d.ts.map +1 -0
  14. package/dist/process/command-owner.d.ts +2 -2
  15. package/dist/process/command-owner.d.ts.map +1 -1
  16. package/dist/process/contract.d.ts +5 -0
  17. package/dist/process/contract.d.ts.map +1 -1
  18. package/dist/process/launch.d.ts +3 -3
  19. package/dist/process/launch.d.ts.map +1 -1
  20. package/dist/process/owned-child.d.ts +5 -1
  21. package/dist/process/owned-child.d.ts.map +1 -1
  22. package/dist/process/owner-loss-control.d.ts +15 -0
  23. package/dist/process/owner-loss-control.d.ts.map +1 -0
  24. package/dist/process/owner-loss-guard.d.ts +3 -0
  25. package/dist/process/owner-loss-guard.d.ts.map +1 -0
  26. package/dist/process/owner-loss-protocol.d.ts +10 -0
  27. package/dist/process/owner-loss-protocol.d.ts.map +1 -0
  28. package/dist/process/owner-loss-socket.d.ts +4 -0
  29. package/dist/process/owner-loss-socket.d.ts.map +1 -0
  30. package/llms/process.txt +25 -10
  31. package/llms/stitchkit.txt +1 -1
  32. package/llms-full.txt +26 -11
  33. package/llms.txt +1 -1
  34. package/package.json +1 -1
@@ -0,0 +1,48 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { Readable, Writable } from 'node:stream';
3
+ import { type OwnerLossGuardInvocation } from './owner-loss-protocol.js';
4
+ /** What a spawned command exposes to its owner: the subset of a Node child the package uses. */
5
+ export interface OwnedChild extends EventEmitter {
6
+ readonly pid?: number;
7
+ readonly exitCode: number | null;
8
+ readonly signalCode: NodeJS.Signals | null;
9
+ readonly stdin: Writable;
10
+ readonly stdout: Readable;
11
+ readonly stderr: Readable;
12
+ kill(signal: NodeJS.Signals): boolean;
13
+ }
14
+ /** A child spawned with the caller's stdio: it carries no pipes. */
15
+ export interface ObservableChild extends EventEmitter {
16
+ readonly pid?: number;
17
+ readonly exitCode: number | null;
18
+ readonly signalCode: NodeJS.Signals | null;
19
+ kill(signal: NodeJS.Signals): boolean;
20
+ }
21
+ interface BunSpawnInput {
22
+ executable: string;
23
+ args: readonly string[];
24
+ cwd?: string;
25
+ env?: NodeJS.ProcessEnv;
26
+ group: boolean;
27
+ ownerLoss?: OwnerLossGuardInvocation;
28
+ }
29
+ /**
30
+ * Whether the host is Bun. Bun's `node:child_process` can lose a child's `exit` event under
31
+ * host load inside `bun test`; `Bun.spawn` observes the same exit reliably, so under Bun a
32
+ * command is launched through it and presented with the Node child's events and streams.
33
+ */
34
+ export declare function hostIsBun(): boolean;
35
+ /** `spawnOwnedCommand` for Bun: a command with piped stdio. */
36
+ export declare function spawnBunChild(input: BunSpawnInput): OwnedChild;
37
+ /** `spawnInheritedCommand` for Bun: a command with the caller's stdio. */
38
+ export declare function spawnBunInheritedChild(input: BunSpawnInput): ObservableChild;
39
+ export interface BunGuardTarget {
40
+ readonly pid: number;
41
+ readonly exitCode: number | null;
42
+ readonly signalCode: string | number | null;
43
+ readonly exited: Promise<unknown>;
44
+ }
45
+ /** Bun-native target observation for the standalone owner-loss guard. */
46
+ export declare function spawnBunGuardTarget(executable: string, args: readonly string[]): BunGuardTarget;
47
+ export {};
48
+ //# sourceMappingURL=bun-child.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bun-child.d.ts","sourceRoot":"","sources":["../../src/process/bun-child.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,KAAK,wBAAwB,EAAyB,MAAM,uBAAuB,CAAC;AAG7F,gGAAgG;AAChG,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC3C,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;CACvC;AAED,oEAAoE;AACpE,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC3C,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;CACvC;AAED,UAAU,aAAa;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,wBAAwB,CAAC;CACtC;AAED;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAqKD,+DAA+D;AAC/D,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,UAAU,CAgD9D;AAED,0EAA0E;AAC1E,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,aAAa,GAAG,eAAe,CAsC5E;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CACnC;AAED,yEAAyE;AACzE,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,cAAc,CAMhB"}
@@ -1,8 +1,8 @@
1
- import type { ChildProcessWithoutNullStreams } from 'node:child_process';
1
+ import type { OwnedChild } from './bun-child.js';
2
2
  import { type NativeCommandOptions } from './contract.js';
3
3
  import { type NativeCommandLaunchDriver } from './launch.js';
4
4
  /** One-shot native execution; sandbox policy/admission is composed above this owner. */
5
- export declare function startNativeCommand(input: NativeCommandOptions, onSpawn?: (child: ChildProcessWithoutNullStreams) => void, driver?: NativeCommandLaunchDriver): {
5
+ export declare function startNativeCommand(input: NativeCommandOptions, onSpawn?: (child: OwnedChild) => void, driver?: NativeCommandLaunchDriver): {
6
6
  result: Promise<{
7
7
  exitCode: number | null;
8
8
  signal: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"command-owner.d.ts","sourceRoot":"","sources":["../../src/process/command-owner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AAIzE,OAAO,EAEL,KAAK,oBAAoB,EAI1B,MAAM,YAAY,CAAC;AAEpB,OAAO,EAEL,KAAK,yBAAyB,EAG/B,MAAM,UAAU,CAAC;AAOlB,wFAAwF;AACxF,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,oBAAoB,EAC3B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,8BAA8B,KAAK,IAAI,EACzD,MAAM,CAAC,EAAE,yBAAyB;;;;;;;;;;EAkKnC"}
1
+ {"version":3,"file":"command-owner.d.ts","sourceRoot":"","sources":["../../src/process/command-owner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,OAAO,EAEL,KAAK,oBAAoB,EAI1B,MAAM,YAAY,CAAC;AAEpB,OAAO,EAEL,KAAK,yBAAyB,EAG/B,MAAM,UAAU,CAAC;AAQlB,wFAAwF;AACxF,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,oBAAoB,EAC3B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,EACrC,MAAM,CAAC,EAAE,yBAAyB;;;;;;;;;;EA8KnC"}
@@ -77,6 +77,9 @@ export declare const NativeCommandOptionsSchema: z.ZodPipe<z.ZodObject<{
77
77
  caller: "caller";
78
78
  own: "own";
79
79
  }>>;
80
+ ownerLoss: z.ZodOptional<z.ZodEnum<{
81
+ terminate: "terminate";
82
+ }>>;
80
83
  stdio: z.ZodDefault<z.ZodEnum<{
81
84
  inherit: "inherit";
82
85
  pipe: "pipe";
@@ -121,6 +124,7 @@ export declare const NativeCommandOptionsSchema: z.ZodPipe<z.ZodObject<{
121
124
  }) => void) | undefined;
122
125
  drainTimeoutMs?: number | undefined;
123
126
  group: "caller" | "own";
127
+ ownerLoss?: "terminate" | undefined;
124
128
  stdio: "inherit" | "pipe";
125
129
  cleanupTimeoutMs: number;
126
130
  stop: {
@@ -149,6 +153,7 @@ export declare const NativeCommandOptionsSchema: z.ZodPipe<z.ZodObject<{
149
153
  }) => void) | undefined;
150
154
  drainTimeoutMs?: number | undefined;
151
155
  group: "caller" | "own";
156
+ ownerLoss?: "terminate" | undefined;
152
157
  stdio: "inherit" | "pipe";
153
158
  stop?: {
154
159
  target: "group" | "leader";
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/process/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,QAAA,MAAM,6BAA6B;;;;;;;;;;;;2BAajC,CAAC;AACH;;;;;;GAMG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF;;GAEG;AACH,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,gGAAgG;AAChG,eAAO,MAAM,yBAAyB,UAAY,CAAC;AAEnD,QAAA,MAAM,6BAA6B;;;;;;;;;;;;;;;kBAOjC,CAAC;AACH;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AACpF,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAiC3F,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;gDAqBpB,UAAU,WACR,QAAQ,GAAG,QAAQ,UACpB,WAAW,KAChB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;uDAKX,uBAAuB,UAAU,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;uDAMrE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmF3C,CAAC;AACN;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAC9E,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,0BAA0B,CAAC,CAAC;AACrF,QAAA,MAAM,yBAAyB;;;;;;iBAU7B,CAAC;AACH;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,QAAA,MAAM,8BAA8B;;;EAAwC,CAAC;AAE7E;;;;;;GAMG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;aAezB,IAAI,EAAE,eAAe,GAAG,qBAAqB,GAAG,iBAAiB;IAdnF,2GAA2G;IAC3G,SAAgB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,GAAG,SAAS,CAAC;IAEnF,YACE,IAAI,EAAE,eAAe,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,YAAY,GAAG;QAAE,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAA;KAAE,EACpF;IACF,YACE,IAAI,EAAE,eAAe,GAAG,qBAAqB,GAAG,iBAAiB,EACjE,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,YAAY,GAAG;QAAE,MAAM,CAAC,EAAE,KAAK,CAAA;KAAE,EAC3C;CAgBH"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/process/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,QAAA,MAAM,6BAA6B;;;;;;;;;;;;2BAajC,CAAC;AACH;;;;;;GAMG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF;;GAEG;AACH,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,gGAAgG;AAChG,eAAO,MAAM,yBAAyB,UAAY,CAAC;AAEnD,QAAA,MAAM,6BAA6B;;;;;;;;;;;;;;;kBAOjC,CAAC;AACH;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AACpF,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAiC3F,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;gDAqBpB,UAAU,WACR,QAAQ,GAAG,QAAQ,UACpB,WAAW,KAChB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;uDAKX,uBAAuB,UAAU,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;uDAMrE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4F3C,CAAC;AACN;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAC9E,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,0BAA0B,CAAC,CAAC;AACrF,QAAA,MAAM,yBAAyB;;;;;;iBAU7B,CAAC;AACH;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,QAAA,MAAM,8BAA8B;;;EAAwC,CAAC;AAE7E;;;;;;GAMG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;aAezB,IAAI,EAAE,eAAe,GAAG,qBAAqB,GAAG,iBAAiB;IAdnF,2GAA2G;IAC3G,SAAgB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,GAAG,SAAS,CAAC;IAEnF,YACE,IAAI,EAAE,eAAe,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,YAAY,GAAG;QAAE,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAA;KAAE,EACpF;IACF,YACE,IAAI,EAAE,eAAe,GAAG,qBAAqB,GAAG,iBAAiB,EACjE,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,YAAY,GAAG;QAAE,MAAM,CAAC,EAAE,KAAK,CAAA;KAAE,EAC3C;CAgBH"}
@@ -1,5 +1,5 @@
1
- import type { ChildProcessWithoutNullStreams } from 'node:child_process';
2
1
  import { Readable } from 'node:stream';
2
+ import type { OwnedChild } from './bun-child.js';
3
3
  import { type ParsedNativeCommandOptions } from './contract.js';
4
4
  import { type NativeCommandTransport } from './transport.js';
5
5
  /** A structural host launcher may supply pipes without importing Node ambient types. */
@@ -46,7 +46,7 @@ export declare function launchNativeCommand({ options, driver, onSpawn, onFailur
46
46
  options: ParsedNativeCommandOptions;
47
47
  driver: NativeCommandLaunchDriver | undefined;
48
48
  /** Called once the real child exists, when the command starts. */
49
- onSpawn?: (child: ChildProcessWithoutNullStreams) => void;
49
+ onSpawn?: (child: OwnedChild) => void;
50
50
  /** The process failed to start or reported an error. */
51
51
  onFailure: (error: Error) => void;
52
52
  /** Writing stdin failed for a reason other than a closed pipe. */
@@ -56,7 +56,7 @@ export declare function launchNativeCommand({ options, driver, onSpawn, onFailur
56
56
  }): {
57
57
  stdout: AsyncIterable<Uint8Array<ArrayBufferLike>>;
58
58
  stderr: AsyncIterable<Uint8Array<ArrayBufferLike>>;
59
- start(): void;
59
+ start(): Promise<number | undefined>;
60
60
  child: NativeCommandLaunchedProcess;
61
61
  leader: Promise<{
62
62
  kind: "exit";
@@ -1 +1 @@
1
- {"version":3,"file":"launch.d.ts","sourceRoot":"","sources":["../../src/process/launch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"launch.d.ts","sourceRoot":"","sources":["../../src/process/launch.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,6 @@
1
+ import { type OwnedChild } from './bun-child.js';
1
2
  import type { NativeCommandLaunchedProcess } from './launch.js';
3
+ import { type OwnerLossGuardInvocation } from './owner-loss-protocol.js';
2
4
  /** Only this native spawn can establish group ownership; structural PIDs cannot. */
3
5
  export declare function spawnOwnedCommand(input: {
4
6
  executable: string;
@@ -6,7 +8,8 @@ export declare function spawnOwnedCommand(input: {
6
8
  cwd?: string;
7
9
  env?: NodeJS.ProcessEnv;
8
10
  group: boolean;
9
- }): import("node:child_process").ChildProcessWithoutNullStreams;
11
+ ownerLoss?: OwnerLossGuardInvocation;
12
+ }): OwnedChild;
10
13
  /** The same ownership rule as {@link spawnOwnedCommand}, for a child that inherits stdio. */
11
14
  export declare function spawnInheritedCommand(input: {
12
15
  executable: string;
@@ -14,6 +17,7 @@ export declare function spawnInheritedCommand(input: {
14
17
  cwd?: string;
15
18
  env?: NodeJS.ProcessEnv;
16
19
  group: boolean;
20
+ ownerLoss?: OwnerLossGuardInvocation;
17
21
  }): NativeCommandLaunchedProcess;
18
22
  export declare function ownsCommandGroup(child: object): boolean;
19
23
  //# sourceMappingURL=owned-child.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"owned-child.d.ts","sourceRoot":"","sources":["../../src/process/owned-child.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA+B,4BAA4B,EAAE,MAAM,UAAU,CAAC;AAI1F,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,EAAE,OAAO,CAAC;CAChB,+DASA;AAmDD,6FAA6F;AAC7F,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,4BAA4B,CAW/B;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEvD"}
1
+ {"version":3,"file":"owned-child.d.ts","sourceRoot":"","sources":["../../src/process/owned-child.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,UAAU,EAGhB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAA+B,4BAA4B,EAAE,MAAM,UAAU,CAAC;AAM1F,OAAO,EAAE,KAAK,wBAAwB,EAAyB,MAAM,uBAAuB,CAAC;AAI7F,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,wBAAwB,CAAC;CACtC,GAAG,UAAU,CAIb;AAsFD,6FAA6F;AAC7F,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,wBAAwB,CAAC;CACtC,GAAG,4BAA4B,CAkC/B;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEvD"}
@@ -0,0 +1,15 @@
1
+ import type { Duplex } from 'node:stream';
2
+ interface GuardedChild {
3
+ readonly pid?: number;
4
+ on(event: 'exit', listener: (code: number | null, signal: string | null) => void): unknown;
5
+ }
6
+ /** Tear down a newly created guard group if its private control channel is unavailable. */
7
+ export declare function abortOwnerLossLaunch(pid: number | undefined): void;
8
+ /** Bind one private inherited control socket to the guard process that owns it. */
9
+ export declare function attachOwnerLossControl(child: GuardedChild, control: Duplex): void;
10
+ /** Preserve the guard registration when an inherited-stdio child gets its transport wrapper. */
11
+ export declare function transferOwnerLossControl(source: object, target: object): void;
12
+ /** Ordinary children are already started; guarded children first prove that their target exists. */
13
+ export declare function awaitCommandStart(child: GuardedChild): Promise<number | undefined>;
14
+ export {};
15
+ //# sourceMappingURL=owner-loss-control.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owner-loss-control.d.ts","sourceRoot":"","sources":["../../src/process/owner-loss-control.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAe1C,UAAU,YAAY;IACpB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,OAAO,CAAC;CAC5F;AASD,2FAA2F;AAC3F,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAOlE;AAQD,mFAAmF;AACnF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAuDjF;AAED,gGAAgG;AAChG,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAG7E;AAED,oGAAoG;AACpG,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAIxF"}
@@ -0,0 +1,3 @@
1
+ /** The built or source module that executes the guard protocol when launched directly. */
2
+ export declare function ownerLossGuardEntry(): string;
3
+ //# sourceMappingURL=owner-loss-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owner-loss-guard.d.ts","sourceRoot":"","sources":["../../src/process/owner-loss-guard.ts"],"names":[],"mappings":"AA+KA,0FAA0F;AAC1F,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C"}
@@ -0,0 +1,10 @@
1
+ export declare const OWNER_LOSS_GUARD_FLAG = "--stitchkit-owner-loss-guard-v1";
2
+ export interface OwnerLossGuardInvocation {
3
+ readonly entry: string;
4
+ readonly signalTarget: 'group' | 'leader';
5
+ }
6
+ /** The owner-loss guard is certified only on the two POSIX kernels exercised by release CI. */
7
+ export declare function ownerLossAvailable(platform: NodeJS.Platform): boolean;
8
+ /** Replace a direct command with the package-owned guard that becomes its process-group leader. */
9
+ export declare function ownerLossGuardCommand(guard: OwnerLossGuardInvocation, executable: string, args: readonly string[]): [string, ...string[]];
10
+ //# sourceMappingURL=owner-loss-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owner-loss-protocol.d.ts","sourceRoot":"","sources":["../../src/process/owner-loss-protocol.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,oCAAoC,CAAC;AAEvE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC3C;AAED,+FAA+F;AAC/F,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,GAAG,OAAO,CAErE;AAED,mGAAmG;AACnG,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,wBAAwB,EAC/B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CASvB"}
@@ -0,0 +1,4 @@
1
+ import { type Socket } from 'node:net';
2
+ /** Bun's runtime accepts an inherited socket fd here before its Node types expose the overload. */
3
+ export declare function connectOwnerLossSocket(fd: number): Socket;
4
+ //# sourceMappingURL=owner-loss-socket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owner-loss-socket.d.ts","sourceRoot":"","sources":["../../src/process/owner-loss-socket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AAEhD,mGAAmG;AACnG,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEzD"}
package/llms/process.txt CHANGED
@@ -139,6 +139,7 @@ console.log(captured.exitCode, new TextDecoder().decode(captured.stdout))
139
139
  const lifetime = new AbortController()
140
140
  await runNativeCommand({
141
141
  executable: '/usr/bin/git', args: ['status'], signal: lifetime.signal,
142
+ ownerLoss: 'terminate', // also stop its group if this JavaScript process is SIGKILLed
142
143
  onOutput: async (bytes, channel, outputSignal) => {
143
144
  outputSignal.throwIfAborted()
144
145
  await output.write(bytes, channel, outputSignal) // application-owned bounded sink
@@ -201,6 +202,17 @@ sink cause is kept; a cleanup failure is a `NativeCommandError` with `COMMAND_CL
201
202
  refuses with `COMMAND_UNAVAILABLE`; a descendant that has left the group on its own with `setsid` is
202
203
  outside this capability. This is one-shot execution, not a PTY, a supervisor or a daemon host.
203
204
 
205
+ `ownerLoss: 'terminate'` binds the command group to this JavaScript process even when it cannot run
206
+ cleanup. A package-owned guard becomes the process-group leader, starts the requested executable in
207
+ that group and holds one end of a private inherited kernel channel. The caller holds the other end.
208
+ `SIGKILL`, a crash or any abrupt caller exit closes that end; EOF makes the guard KILL its own group.
209
+ There is no liveness polling and no later PID lookup. Because the guard is still the group leader
210
+ when it signals, its PGID cannot have been reused by a neighbour. The option is available on Linux
211
+ and Darwin under Bun and Node, requires `group: 'own'`, and other platforms refuse it with
212
+ `COMMAND_UNAVAILABLE`. It adds one short-lived process and one descriptor per guarded command, so it
213
+ is opt-in. `onLeaderStarted({ pid })` reports the guard/group leader with this option; output, stdin,
214
+ exit status, deadlines, cancellation and `onLeaderSettled` retain the requested command's behaviour.
215
+
204
216
  ### Stopping a command: the `stop` policy
205
217
 
206
218
  A caller abort, the `timeoutMs` deadline, an exceeded output budget and a failing sink all stop the
@@ -235,13 +247,13 @@ dropped, never passed to `onOutput` and never captured, so a leader that writes
235
247
  does not meet a broken pipe. The result rejects with the abort reason once the group is gone and the
236
248
  pipes are closed, so it can take `graceMs` plus `cleanupTimeoutMs` after the abort.
237
249
 
238
- The grace is a timer inside the process that runs the command. If that process exits first, the
239
- timer is gone and the group, which is detached into its own session, keeps running: nothing in this
240
- package can bound it from outside. Abort `killOn` in your shutdown path, so the group is killed
241
- before the process exits, and let the supervisor own the case where the process dies without a
242
- shutdown. Under systemd, keep `KillMode=control-group` (the default) so the stop of the unit
243
- reaches every process in its cgroup, whatever its process group; launchd only kills the job's own
244
- process group, which a command's group is not.
250
+ The grace is a timer inside the process that runs the command. Without `ownerLoss`, if that process
251
+ exits first, the timer is gone and the group, which is detached into its own session, keeps running.
252
+ Abort `killOn` in your shutdown path so a deliberate shutdown kills the group before exit. For an
253
+ abrupt-exit guarantee, choose `ownerLoss: 'terminate'`; for all groups in a service, let the service
254
+ supervisor own the wider boundary. Under systemd, keep `KillMode=control-group` (the default) so the
255
+ stop of the unit reaches every process in its cgroup, whatever its process group; launchd only kills
256
+ the job's own process group, which an unguarded detached command's group is not.
245
257
 
246
258
  ### Stopping a group and its descendants
247
259
 
@@ -302,7 +314,7 @@ becomes `runNativeCommand`; shell policy, command admission, logging, redaction,
302
314
  decoder and the operator sink stay with the application. Long signal-only commands stay streaming;
303
315
  bounded tar or capture commands get their own explicit limits.
304
316
 
305
- A child the caller holds until it exits is the same call. A guardian that forwards its own SIGTERM
317
+ A child the caller holds until it exits is the same call. A host that forwards its own SIGTERM
306
318
  passes an abort signal and `stop: { target: 'leader', signal: 'SIGTERM', graceMs }`. It records the
307
319
  pid in `onLeaderStarted({ pid })`, which runs once right after the leader exists (a throw stops the
308
320
  command with that error), and the leader's exit code and signal in `onLeaderSettled`: `'exit'`
@@ -312,7 +324,9 @@ long the output pipes may stay open after the leader exited: a holder that left
312
324
  `setsid` keeps them open, and without the option the command waits for it until `timeoutMs` or
313
325
  the signal; with it the command ends with `COMMAND_CLEANUP` (a holder inside the group is already
314
326
  stopped by `descendants`). A worker whose whole group must stop on abort is the default
315
- `target: 'group'`. A command that uses the caller's terminal is the next section. Importing one leaf does not make
327
+ `target: 'group'`. Add `ownerLoss: 'terminate'` when the worker must also die after an abrupt host
328
+ loss; in that mode `onLeaderStarted` reports the package guard that leads the same group. A command
329
+ that uses the caller's terminal is the next section. Importing one leaf does not make
316
330
  installing the whole npm package smaller; choose a dependency after measuring packed size and its
317
331
  dependency closure.
318
332
 
@@ -346,6 +360,7 @@ its own, so:
346
360
  because a group signal would reach the caller;
347
361
  - `descendants` does not apply and is refused: what the leader leaves behind belongs to the
348
362
  caller's group, and `descendantsStopped` is always `false`;
363
+ - `ownerLoss` is refused: an owner-loss guard must lead a group that belongs only to the command;
349
364
  - a Ctrl-C reaches the caller too; handle `SIGINT` in the caller when it must outlive the command.
350
365
 
351
366
  The two options are independent: `stdio: 'inherit'` alone keeps colour and `isatty` for a command
@@ -677,7 +692,7 @@ Native POSIX Bun/Node one-shot command execution. See [native IO](../guide/nativ
677
692
  | Export | Kind | Purpose |
678
693
  |---|---|---|
679
694
  | `runNativeCommand` | function | caller-lifetime streaming or explicitly bounded binary capture |
680
- | `NativeCommandOptions` | type | executable/args, env policy, signal/deadline, bytes sink, finite cleanup limits, the `stop` policy and `descendants` (`'terminate-after-leader'`, the default: stop the group after the leader exits, or `'leave'`); `stdio` (`'pipe'`, or `'inherit'` for the caller's descriptors, refusing the pipe-only options) and `group` (`'own'`, or `'caller'`: joins the caller's process group, stops only the leader, refuses `descendants` and a group stop); `onLeaderStarted({ pid })` (once, after the leader exists), `drainTimeoutMs` (bound on the pipes staying open after the leader exited, `COMMAND_CLEANUP`); an unknown key is refused by name, a removed one (`killGraceMs`) with its replacement |
695
+ | `NativeCommandOptions` | type | executable/args, env policy, signal/deadline, bytes sink, finite cleanup limits, the `stop` policy and `descendants` (`'terminate-after-leader'`, the default: stop the group after the leader exits, or `'leave'`); `stdio` (`'pipe'`, or `'inherit'` for the caller's descriptors, refusing the pipe-only options) and `group` (`'own'`, or `'caller'`: joins the caller's process group, stops only the leader, refuses `descendants`, `ownerLoss` and a group stop); `ownerLoss: 'terminate'` (optional Linux/Darwin Bun/Node guard: kernel channel EOF after abrupt caller death KILLs its owned group, unsupported platforms refuse); `onLeaderStarted({ pid })` (once after the group leader exists; the package guard's PID under `ownerLoss`), `drainTimeoutMs` (bound on the pipes staying open after the leader exited, `COMMAND_CLEANUP`); an unknown key is refused by name, a removed one (`killGraceMs`) with its replacement |
681
696
  | `NativeCommandStopPolicy` | type | how a cancelled command stops: `target` `'group'` (signal every member) or `'leader'` (signal only the leader; its exit ends the grace), `signal` (default `SIGTERM`), `graceMs` (at most one hour) before KILL to the group, and `killOn`, an `AbortSignal` that skips the grace; default `{ target: 'group', signal: 'SIGTERM', graceMs: 100 }` |
682
697
  | `NativeCommandResult` | type | observed nullable exit code/signal, `descendantsStopped` (members left in the group after the leader exited were stopped) and captured stdout/stderr bytes |
683
698
  | `NativeCommandError` | class | COMMAND_LIMIT with machine reason `deadline` or `output-budget`; COMMAND_UNAVAILABLE / COMMAND_CLEANUP have no limit reason; COMMAND_CLEANUP means the command's resources were not proven closed, either past `cleanupTimeoutMs` after a stop or past `drainTimeoutMs` after the leader exited, and `cause` holds that bound's failure. Preserves internal cause and existing constructor; caller-created limits without supplied reason remain unclassified |
@@ -69,7 +69,7 @@ own, recorded as an ADR.
69
69
  | `stitchkit/cli` | server | stable | `createCli` / `createCliInvoker` — runtime and strict NodeNext declarations without MCP SDK / `ai` |
70
70
  | `stitchkit/cli/publish` | build and release tooling (Bun or Node, POSIX) | evolving | `publishCli` — commit a verified CLI distribution and move its public manifest last; see [CLI guide](cli.md#publishing-a-complete-version) |
71
71
  | `stitchkit/remote` | browser **and** server | stable | peer-free `implementRemote` for thin HTTP proxy processes |
72
- | `stitchkit/process` | server (Bun or Node, POSIX) | evolving | finite native commands, byte sinks, bounded capture and process-group cancellation |
72
+ | `stitchkit/process` | server (Bun or Node, POSIX) | evolving | finite native commands, byte sinks, bounded capture, process-group cancellation and opt-in Linux/Darwin owner-loss cleanup |
73
73
  | `stitchkit/files/packaging` | build time (Bun or Node) | evolving | installed native asset graph, integrity, Bun packaging plugin and the artifact loader check; no runtime install policy |
74
74
  | `stitchkit/files` | server (Bun or Node) | stable | peer-free managed local-file boundary |
75
75
  | `stitchkit/telegram` | server (Bun or Node) | evolving | peer-free Telegram platform primitives — Mini App `initData` verification, send-failure classification, resumable broadcasts, the operator channel with dedupe, a Bot API transport that separates a request that never left from an unknown outcome, local Bot API files, webhook ownership and durable webhook update intake |
package/llms-full.txt CHANGED
@@ -61,7 +61,7 @@ own, recorded as an ADR.
61
61
  | `stitchkit/cli` | server | stable | `createCli` / `createCliInvoker` — runtime and strict NodeNext declarations without MCP SDK / `ai` |
62
62
  | `stitchkit/cli/publish` | build and release tooling (Bun or Node, POSIX) | evolving | `publishCli` — commit a verified CLI distribution and move its public manifest last; see [CLI guide](cli.md#publishing-a-complete-version) |
63
63
  | `stitchkit/remote` | browser **and** server | stable | peer-free `implementRemote` for thin HTTP proxy processes |
64
- | `stitchkit/process` | server (Bun or Node, POSIX) | evolving | finite native commands, byte sinks, bounded capture and process-group cancellation |
64
+ | `stitchkit/process` | server (Bun or Node, POSIX) | evolving | finite native commands, byte sinks, bounded capture, process-group cancellation and opt-in Linux/Darwin owner-loss cleanup |
65
65
  | `stitchkit/files/packaging` | build time (Bun or Node) | evolving | installed native asset graph, integrity, Bun packaging plugin and the artifact loader check; no runtime install policy |
66
66
  | `stitchkit/files` | server (Bun or Node) | stable | peer-free managed local-file boundary |
67
67
  | `stitchkit/telegram` | server (Bun or Node) | evolving | peer-free Telegram platform primitives — Mini App `initData` verification, send-failure classification, resumable broadcasts, the operator channel with dedupe, a Bot API transport that separates a request that never left from an unknown outcome, local Bot API files, webhook ownership and durable webhook update intake |
@@ -8322,6 +8322,7 @@ console.log(captured.exitCode, new TextDecoder().decode(captured.stdout))
8322
8322
  const lifetime = new AbortController()
8323
8323
  await runNativeCommand({
8324
8324
  executable: '/usr/bin/git', args: ['status'], signal: lifetime.signal,
8325
+ ownerLoss: 'terminate', // also stop its group if this JavaScript process is SIGKILLed
8325
8326
  onOutput: async (bytes, channel, outputSignal) => {
8326
8327
  outputSignal.throwIfAborted()
8327
8328
  await output.write(bytes, channel, outputSignal) // application-owned bounded sink
@@ -8384,6 +8385,17 @@ sink cause is kept; a cleanup failure is a `NativeCommandError` with `COMMAND_CL
8384
8385
  refuses with `COMMAND_UNAVAILABLE`; a descendant that has left the group on its own with `setsid` is
8385
8386
  outside this capability. This is one-shot execution, not a PTY, a supervisor or a daemon host.
8386
8387
 
8388
+ `ownerLoss: 'terminate'` binds the command group to this JavaScript process even when it cannot run
8389
+ cleanup. A package-owned guard becomes the process-group leader, starts the requested executable in
8390
+ that group and holds one end of a private inherited kernel channel. The caller holds the other end.
8391
+ `SIGKILL`, a crash or any abrupt caller exit closes that end; EOF makes the guard KILL its own group.
8392
+ There is no liveness polling and no later PID lookup. Because the guard is still the group leader
8393
+ when it signals, its PGID cannot have been reused by a neighbour. The option is available on Linux
8394
+ and Darwin under Bun and Node, requires `group: 'own'`, and other platforms refuse it with
8395
+ `COMMAND_UNAVAILABLE`. It adds one short-lived process and one descriptor per guarded command, so it
8396
+ is opt-in. `onLeaderStarted({ pid })` reports the guard/group leader with this option; output, stdin,
8397
+ exit status, deadlines, cancellation and `onLeaderSettled` retain the requested command's behaviour.
8398
+
8387
8399
  ### Stopping a command: the `stop` policy
8388
8400
 
8389
8401
  A caller abort, the `timeoutMs` deadline, an exceeded output budget and a failing sink all stop the
@@ -8418,13 +8430,13 @@ dropped, never passed to `onOutput` and never captured, so a leader that writes
8418
8430
  does not meet a broken pipe. The result rejects with the abort reason once the group is gone and the
8419
8431
  pipes are closed, so it can take `graceMs` plus `cleanupTimeoutMs` after the abort.
8420
8432
 
8421
- The grace is a timer inside the process that runs the command. If that process exits first, the
8422
- timer is gone and the group, which is detached into its own session, keeps running: nothing in this
8423
- package can bound it from outside. Abort `killOn` in your shutdown path, so the group is killed
8424
- before the process exits, and let the supervisor own the case where the process dies without a
8425
- shutdown. Under systemd, keep `KillMode=control-group` (the default) so the stop of the unit
8426
- reaches every process in its cgroup, whatever its process group; launchd only kills the job's own
8427
- process group, which a command's group is not.
8433
+ The grace is a timer inside the process that runs the command. Without `ownerLoss`, if that process
8434
+ exits first, the timer is gone and the group, which is detached into its own session, keeps running.
8435
+ Abort `killOn` in your shutdown path so a deliberate shutdown kills the group before exit. For an
8436
+ abrupt-exit guarantee, choose `ownerLoss: 'terminate'`; for all groups in a service, let the service
8437
+ supervisor own the wider boundary. Under systemd, keep `KillMode=control-group` (the default) so the
8438
+ stop of the unit reaches every process in its cgroup, whatever its process group; launchd only kills
8439
+ the job's own process group, which an unguarded detached command's group is not.
8428
8440
 
8429
8441
  ### Stopping a group and its descendants
8430
8442
 
@@ -8485,7 +8497,7 @@ becomes `runNativeCommand`; shell policy, command admission, logging, redaction,
8485
8497
  decoder and the operator sink stay with the application. Long signal-only commands stay streaming;
8486
8498
  bounded tar or capture commands get their own explicit limits.
8487
8499
 
8488
- A child the caller holds until it exits is the same call. A guardian that forwards its own SIGTERM
8500
+ A child the caller holds until it exits is the same call. A host that forwards its own SIGTERM
8489
8501
  passes an abort signal and `stop: { target: 'leader', signal: 'SIGTERM', graceMs }`. It records the
8490
8502
  pid in `onLeaderStarted({ pid })`, which runs once right after the leader exists (a throw stops the
8491
8503
  command with that error), and the leader's exit code and signal in `onLeaderSettled`: `'exit'`
@@ -8495,7 +8507,9 @@ long the output pipes may stay open after the leader exited: a holder that left
8495
8507
  `setsid` keeps them open, and without the option the command waits for it until `timeoutMs` or
8496
8508
  the signal; with it the command ends with `COMMAND_CLEANUP` (a holder inside the group is already
8497
8509
  stopped by `descendants`). A worker whose whole group must stop on abort is the default
8498
- `target: 'group'`. A command that uses the caller's terminal is the next section. Importing one leaf does not make
8510
+ `target: 'group'`. Add `ownerLoss: 'terminate'` when the worker must also die after an abrupt host
8511
+ loss; in that mode `onLeaderStarted` reports the package guard that leads the same group. A command
8512
+ that uses the caller's terminal is the next section. Importing one leaf does not make
8499
8513
  installing the whole npm package smaller; choose a dependency after measuring packed size and its
8500
8514
  dependency closure.
8501
8515
 
@@ -8529,6 +8543,7 @@ its own, so:
8529
8543
  because a group signal would reach the caller;
8530
8544
  - `descendants` does not apply and is refused: what the leader leaves behind belongs to the
8531
8545
  caller's group, and `descendantsStopped` is always `false`;
8546
+ - `ownerLoss` is refused: an owner-loss guard must lead a group that belongs only to the command;
8532
8547
  - a Ctrl-C reaches the caller too; handle `SIGINT` in the caller when it must outlive the command.
8533
8548
 
8534
8549
  The two options are independent: `stdio: 'inherit'` alone keeps colour and `isatty` for a command
@@ -23044,7 +23059,7 @@ Native POSIX Bun/Node one-shot command execution. See [native IO](../guide/nativ
23044
23059
  | Export | Kind | Purpose |
23045
23060
  |---|---|---|
23046
23061
  | `runNativeCommand` | function | caller-lifetime streaming or explicitly bounded binary capture |
23047
- | `NativeCommandOptions` | type | executable/args, env policy, signal/deadline, bytes sink, finite cleanup limits, the `stop` policy and `descendants` (`'terminate-after-leader'`, the default: stop the group after the leader exits, or `'leave'`); `stdio` (`'pipe'`, or `'inherit'` for the caller's descriptors, refusing the pipe-only options) and `group` (`'own'`, or `'caller'`: joins the caller's process group, stops only the leader, refuses `descendants` and a group stop); `onLeaderStarted({ pid })` (once, after the leader exists), `drainTimeoutMs` (bound on the pipes staying open after the leader exited, `COMMAND_CLEANUP`); an unknown key is refused by name, a removed one (`killGraceMs`) with its replacement |
23062
+ | `NativeCommandOptions` | type | executable/args, env policy, signal/deadline, bytes sink, finite cleanup limits, the `stop` policy and `descendants` (`'terminate-after-leader'`, the default: stop the group after the leader exits, or `'leave'`); `stdio` (`'pipe'`, or `'inherit'` for the caller's descriptors, refusing the pipe-only options) and `group` (`'own'`, or `'caller'`: joins the caller's process group, stops only the leader, refuses `descendants`, `ownerLoss` and a group stop); `ownerLoss: 'terminate'` (optional Linux/Darwin Bun/Node guard: kernel channel EOF after abrupt caller death KILLs its owned group, unsupported platforms refuse); `onLeaderStarted({ pid })` (once after the group leader exists; the package guard's PID under `ownerLoss`), `drainTimeoutMs` (bound on the pipes staying open after the leader exited, `COMMAND_CLEANUP`); an unknown key is refused by name, a removed one (`killGraceMs`) with its replacement |
23048
23063
  | `NativeCommandStopPolicy` | type | how a cancelled command stops: `target` `'group'` (signal every member) or `'leader'` (signal only the leader; its exit ends the grace), `signal` (default `SIGTERM`), `graceMs` (at most one hour) before KILL to the group, and `killOn`, an `AbortSignal` that skips the grace; default `{ target: 'group', signal: 'SIGTERM', graceMs: 100 }` |
23049
23064
  | `NativeCommandResult` | type | observed nullable exit code/signal, `descendantsStopped` (members left in the group after the leader exited were stopped) and captured stdout/stderr bytes |
23050
23065
  | `NativeCommandError` | class | COMMAND_LIMIT with machine reason `deadline` or `output-budget`; COMMAND_UNAVAILABLE / COMMAND_CLEANUP have no limit reason; COMMAND_CLEANUP means the command's resources were not proven closed, either past `cleanupTimeoutMs` after a stop or past `drainTimeoutMs` after the leader exited, and `cause` holds that bound's failure. Preserves internal cause and existing constructor; caller-created limits without supplied reason remain unclassified |
package/llms.txt CHANGED
@@ -56,7 +56,7 @@ Load the slice for each entrypoint your code imports — `import … from 'stitc
56
56
  - **stitchkit/node**: [llms/node.txt](llms/node.txt) 3.1 KB
57
57
  - **stitchkit/agent-runtime/react**: [llms/agent-runtime-react.txt](llms/agent-runtime-react.txt) 1.0 KB
58
58
  - **stitchkit/agent-runtime/realtime**: [llms/agent-runtime-realtime.txt](llms/agent-runtime-realtime.txt) 2.6 KB
59
- - **stitchkit/process**: [llms/process.txt](llms/process.txt) 43.3 KB
59
+ - **stitchkit/process**: [llms/process.txt](llms/process.txt) 44.9 KB
60
60
  - **stitchkit/files/packaging**: [llms/files-packaging.txt](llms/files-packaging.txt) 3.5 KB
61
61
 
62
62
  ## Upgrading slices
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stitchkit",
3
- "version": "0.108.0",
3
+ "version": "0.108.2",
4
4
  "description": "Contract-first backend framework — one defineContract() into an HTTP API, MCP tools, AI-agent tools and a typed client. Bun and Node.",
5
5
  "keywords": [
6
6
  "bun",