@gobing-ai/ts-runtime 0.4.12 → 0.4.14

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.
package/README.md CHANGED
@@ -597,8 +597,14 @@ unsub();
597
597
 
598
598
  `rejectOnError: true` throws on non-zero exits. `OutputPolicy` controls
599
599
  buffered vs streamed output. `ProcessOptions` supports timeout, env, cwd,
600
- maxOutput, forceBuffered, and optional registry fields (`source`, `teamId`,
601
- `agentId`). Inject the same `ProcessRegistry` into every executor that should
600
+ maxOutput, forceBuffered, an optional synchronous `onOutput({ stream, chunk,
601
+ timestamp })` observer, and registry fields (`source`, `teamId`, `agentId`).
602
+ `onOutput` observes live chunks while the returned `ProcessResult` retains the
603
+ complete buffered stdout/stderr; observers must enqueue and return, and thrown
604
+ observer errors are isolated from the child. When `signal` is supplied, one-shot
605
+ commands run in an isolated process group on Unix so abort terminates descendants
606
+ that could otherwise retain the output pipes; Windows falls back to direct-child
607
+ cancellation. Inject the same `ProcessRegistry` into every executor that should
602
608
  appear in one watch list; without a registry, behavior is unchanged.
603
609
 
604
610
  Cloudflare Workers do not expose process execution; check
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ export { createNodeFileSystem, findProjectRoot } from './file-system-node';
8
8
  export { atomicWriteFile, atomicWriteJson, createLogStream, ensureDirForFile, readJsonFile, walkDir, writeJsonFile, } from './fs';
9
9
  export * from './path';
10
10
  export { _resetRuntimeFactory, isCloudflareWorkerRuntime, loadRuntimeFactory } from './platform';
11
- export type { OutputPolicy, PipeProcess, PipeProcessOptions, ProcessEventDetail, ProcessEventSink, ProcessEvents, ProcessExecutorConfig, ProcessExitReason, ProcessOptions, ProcessResult, ProcessSignal, TracerPort, } from './process-executor';
11
+ export type { OutputPolicy, PipeProcess, PipeProcessOptions, ProcessEventDetail, ProcessEventSink, ProcessEvents, ProcessExecutorConfig, ProcessExitReason, ProcessOptions, ProcessOutputChunk, ProcessResult, ProcessSignal, TracerPort, } from './process-executor';
12
12
  export { NodeProcessExecutor, ProcessExecutor } from './process-executor';
13
13
  export type { InMemoryProcessRegistryOptions, ProcessExecution, ProcessExecutionBegin, ProcessExecutionComplete, ProcessExecutionFilter, ProcessExecutionSource, ProcessExecutionStatus, ProcessRegistry, ProcessRegistryEvent, } from './process-registry';
14
14
  export { createInMemoryProcessRegistry, InMemoryProcessRegistry } from './process-registry';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,+BAA+B,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAC9E,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EACH,eAAe,EACf,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,OAAO,EACP,aAAa,GAChB,MAAM,MAAM,CAAC;AACd,cAAc,QAAQ,CAAC;AACvB,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACjG,YAAY,EACR,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,aAAa,EACb,UAAU,GACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1E,YAAY,EACR,8BAA8B,EAC9B,gBAAgB,EAChB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,eAAe,EACf,oBAAoB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,6BAA6B,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC5F,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC1E,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AAIxB,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAEnF;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,YAAY,CAAC,cAAc,oBAAoB,EAAE,sBAAsB,CAAC,CAAC;AAE3G;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC,cAAc,oBAAoB,EAAE,qBAAqB,CAAC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,+BAA+B,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAC9E,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EACH,eAAe,EACf,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,OAAO,EACP,aAAa,GAChB,MAAM,MAAM,CAAC;AACd,cAAc,QAAQ,CAAC;AACvB,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACjG,YAAY,EACR,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,UAAU,GACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1E,YAAY,EACR,8BAA8B,EAC9B,gBAAgB,EAChB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,eAAe,EACf,oBAAoB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,6BAA6B,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC5F,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC1E,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AAIxB,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAEnF;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,YAAY,CAAC,cAAc,oBAAoB,EAAE,sBAAsB,CAAC,CAAC;AAE3G;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC,cAAc,oBAAoB,EAAE,qBAAqB,CAAC,CAAC"}
@@ -31,8 +31,19 @@ export interface ProcessOptions {
31
31
  label?: string;
32
32
  rejectOnError?: boolean;
33
33
  forceBuffered?: boolean;
34
- /** AbortSignal forwarded to execa as `cancelSignal` — aborts the child process when fired. */
34
+ /**
35
+ * AbortSignal forwarded to execa and, on Unix, to the child's isolated
36
+ * process group so descendants cannot outlive a cancelled one-shot run.
37
+ */
35
38
  signal?: AbortSignal;
39
+ /**
40
+ * Optional non-blocking observer for incremental stdout/stderr.
41
+ *
42
+ * The executor invokes this synchronously from the child stream and isolates
43
+ * observer failures. Consumers must enqueue and return; the buffered
44
+ * {@link ProcessResult} remains authoritative.
45
+ */
46
+ onOutput?: (output: ProcessOutputChunk) => void;
36
47
  /**
37
48
  * Registry metadata (spur#0264). Defaults: source `'one-shot'` for `run`.
38
49
  * Pass `source: 'supervisor'` (and optional teamId/agentId) when the spawn is
@@ -42,6 +53,12 @@ export interface ProcessOptions {
42
53
  teamId?: string;
43
54
  agentId?: string;
44
55
  }
56
+ /** One incremental process-output observation. */
57
+ export interface ProcessOutputChunk {
58
+ readonly stream: 'stdout' | 'stderr';
59
+ readonly chunk: string;
60
+ readonly timestamp: string;
61
+ }
45
62
  /** Result of a completed child process, including exit code, captured output, and duration. */
46
63
  export interface ProcessResult {
47
64
  command: string;
@@ -1 +1 @@
1
- {"version":3,"file":"process-executor.d.ts","sourceRoot":"","sources":["../src/process-executor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"process-executor.d.ts","sourceRoot":"","sources":["../src/process-executor.ts"],"names":[],"mappings":"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"}
@@ -52,7 +52,11 @@ export class NodeProcessExecutor {
52
52
  ...(options.label !== undefined ? { label: options.label } : {}),
53
53
  });
54
54
  try {
55
- const result = await execa(options.command, args, execaOptions);
55
+ const subprocess = execa(options.command, args, execaOptions);
56
+ const stopGroupCancellation = observeProcessGroupCancellation(subprocess, options.signal);
57
+ observeOutput(subprocess.stdout, 'stdout', options.onOutput);
58
+ observeOutput(subprocess.stderr, 'stderr', options.onOutput);
59
+ const result = await subprocess.finally(stopGroupCancellation);
56
60
  // execa@9 Result does not expose pid — buffered runs leave pid unset.
57
61
  const processResult = {
58
62
  command: options.command,
@@ -352,8 +356,51 @@ function buildExecaOptions(opts) {
352
356
  ...(opts.env !== undefined ? { env: opts.env } : {}),
353
357
  ...(opts.timeout !== undefined ? { timeout: opts.timeout } : {}),
354
358
  ...(opts.maxOutput !== undefined ? { maxBuffer: opts.maxOutput } : {}),
355
- ...(opts.signal !== undefined ? { cancelSignal: opts.signal } : {}),
359
+ ...(opts.signal !== undefined
360
+ ? {
361
+ cancelSignal: opts.signal,
362
+ // Node's negative-pid group signal requires the child to lead
363
+ // a distinct process group. Windows has no equivalent.
364
+ ...(process.platform !== 'win32' ? { detached: true } : {}),
365
+ }
366
+ : {}),
367
+ };
368
+ }
369
+ function observeProcessGroupCancellation(subprocess, signal) {
370
+ const pid = subprocess.pid;
371
+ if (signal === undefined || process.platform === 'win32' || pid === undefined)
372
+ return () => { };
373
+ const abort = () => {
374
+ try {
375
+ process.kill(-pid, 'SIGTERM');
376
+ }
377
+ catch {
378
+ // The leader may already have exited through execa's cancelSignal.
379
+ // Fall back to the direct child without changing cancellation semantics.
380
+ subprocess.kill('SIGTERM');
381
+ }
356
382
  };
383
+ if (signal.aborted)
384
+ abort();
385
+ else
386
+ signal.addEventListener('abort', abort, { once: true });
387
+ return () => signal.removeEventListener('abort', abort);
388
+ }
389
+ function observeOutput(stream, name, observer) {
390
+ if (!stream || !observer)
391
+ return;
392
+ stream.on('data', (chunk) => {
393
+ try {
394
+ observer({
395
+ stream: name,
396
+ chunk: asString(chunk),
397
+ timestamp: new Date().toISOString(),
398
+ });
399
+ }
400
+ catch {
401
+ // Observability is best-effort and must never interrupt child I/O.
402
+ }
403
+ });
357
404
  }
358
405
  function asString(value) {
359
406
  if (typeof value === 'string')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/ts-runtime",
3
- "version": "0.4.12",
3
+ "version": "0.4.14",
4
4
  "description": "@gobing-ai/ts-runtime — Runtime abstractions for Bun, Node, and Cloudflare Workers.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -58,17 +58,17 @@
58
58
  "release": "echo 'Manual publish is disabled. Releases go through GitHub Actions via Trusted Publishing — push a tag: git tag @gobing-ai/ts-runtime-v<version> && git push --tags' && exit 1"
59
59
  },
60
60
  "dependencies": {
61
- "@gobing-ai/ts-utils": "^0.4.12",
61
+ "@gobing-ai/ts-utils": "^0.4.14",
62
62
  "execa": "^9.5.0",
63
63
  "yaml": "^2.7.0",
64
64
  "zod": "^4.1.0"
65
65
  },
66
66
  "devDependencies": {
67
- "@gobing-ai/ts-db": "^0.4.12",
67
+ "@gobing-ai/ts-db": "^0.4.14",
68
68
  "@types/bun": "1.3.14"
69
69
  },
70
70
  "peerDependencies": {
71
- "@gobing-ai/ts-db": "^0.4.12"
71
+ "@gobing-ai/ts-db": "^0.4.14"
72
72
  },
73
73
  "peerDependenciesMeta": {
74
74
  "@gobing-ai/ts-db": {
package/src/index.ts CHANGED
@@ -26,6 +26,7 @@ export type {
26
26
  ProcessExecutorConfig,
27
27
  ProcessExitReason,
28
28
  ProcessOptions,
29
+ ProcessOutputChunk,
29
30
  ProcessResult,
30
31
  ProcessSignal,
31
32
  TracerPort,
@@ -33,8 +33,19 @@ export interface ProcessOptions {
33
33
  label?: string;
34
34
  rejectOnError?: boolean;
35
35
  forceBuffered?: boolean;
36
- /** AbortSignal forwarded to execa as `cancelSignal` — aborts the child process when fired. */
36
+ /**
37
+ * AbortSignal forwarded to execa and, on Unix, to the child's isolated
38
+ * process group so descendants cannot outlive a cancelled one-shot run.
39
+ */
37
40
  signal?: AbortSignal;
41
+ /**
42
+ * Optional non-blocking observer for incremental stdout/stderr.
43
+ *
44
+ * The executor invokes this synchronously from the child stream and isolates
45
+ * observer failures. Consumers must enqueue and return; the buffered
46
+ * {@link ProcessResult} remains authoritative.
47
+ */
48
+ onOutput?: (output: ProcessOutputChunk) => void;
38
49
  /**
39
50
  * Registry metadata (spur#0264). Defaults: source `'one-shot'` for `run`.
40
51
  * Pass `source: 'supervisor'` (and optional teamId/agentId) when the spawn is
@@ -45,6 +56,13 @@ export interface ProcessOptions {
45
56
  agentId?: string;
46
57
  }
47
58
 
59
+ /** One incremental process-output observation. */
60
+ export interface ProcessOutputChunk {
61
+ readonly stream: 'stdout' | 'stderr';
62
+ readonly chunk: string;
63
+ readonly timestamp: string;
64
+ }
65
+
48
66
  /** Result of a completed child process, including exit code, captured output, and duration. */
49
67
  export interface ProcessResult {
50
68
  command: string;
@@ -205,7 +223,11 @@ export class NodeProcessExecutor implements ProcessExecutor {
205
223
  });
206
224
 
207
225
  try {
208
- const result = await execa(options.command, args, execaOptions);
226
+ const subprocess = execa(options.command, args, execaOptions);
227
+ const stopGroupCancellation = observeProcessGroupCancellation(subprocess, options.signal);
228
+ observeOutput(subprocess.stdout, 'stdout', options.onOutput);
229
+ observeOutput(subprocess.stderr, 'stderr', options.onOutput);
230
+ const result = await subprocess.finally(stopGroupCancellation);
209
231
  // execa@9 Result does not expose pid — buffered runs leave pid unset.
210
232
  const processResult = {
211
233
  command: options.command,
@@ -584,8 +606,54 @@ function buildExecaOptions(opts: {
584
606
  ...(opts.env !== undefined ? { env: opts.env } : {}),
585
607
  ...(opts.timeout !== undefined ? { timeout: opts.timeout } : {}),
586
608
  ...(opts.maxOutput !== undefined ? { maxBuffer: opts.maxOutput } : {}),
587
- ...(opts.signal !== undefined ? { cancelSignal: opts.signal } : {}),
609
+ ...(opts.signal !== undefined
610
+ ? {
611
+ cancelSignal: opts.signal,
612
+ // Node's negative-pid group signal requires the child to lead
613
+ // a distinct process group. Windows has no equivalent.
614
+ ...(process.platform !== 'win32' ? { detached: true } : {}),
615
+ }
616
+ : {}),
617
+ };
618
+ }
619
+
620
+ function observeProcessGroupCancellation(
621
+ subprocess: { pid?: number; kill(signal?: NodeJS.Signals | number): boolean },
622
+ signal: AbortSignal | undefined,
623
+ ): () => void {
624
+ const pid = subprocess.pid;
625
+ if (signal === undefined || process.platform === 'win32' || pid === undefined) return () => {};
626
+ const abort = (): void => {
627
+ try {
628
+ process.kill(-pid, 'SIGTERM');
629
+ } catch {
630
+ // The leader may already have exited through execa's cancelSignal.
631
+ // Fall back to the direct child without changing cancellation semantics.
632
+ subprocess.kill('SIGTERM');
633
+ }
588
634
  };
635
+ if (signal.aborted) abort();
636
+ else signal.addEventListener('abort', abort, { once: true });
637
+ return () => signal.removeEventListener('abort', abort);
638
+ }
639
+
640
+ function observeOutput(
641
+ stream: NodeJS.ReadableStream | null | undefined,
642
+ name: ProcessOutputChunk['stream'],
643
+ observer: ProcessOptions['onOutput'],
644
+ ): void {
645
+ if (!stream || !observer) return;
646
+ stream.on('data', (chunk: string | Uint8Array) => {
647
+ try {
648
+ observer({
649
+ stream: name,
650
+ chunk: asString(chunk),
651
+ timestamp: new Date().toISOString(),
652
+ });
653
+ } catch {
654
+ // Observability is best-effort and must never interrupt child I/O.
655
+ }
656
+ });
589
657
  }
590
658
 
591
659
  function asString(value: string | string[] | unknown[] | Uint8Array | undefined): string {