@gobing-ai/ts-runtime 0.4.8 → 0.4.10

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
@@ -8,15 +8,14 @@ and Cloudflare Workers through a factory pattern that auto-detects the runtime.
8
8
 
9
9
  ## Overview
10
10
 
11
-
12
-
13
11
  **Key abstractions:**
14
12
 
15
13
  | Concept | Interface | Bun/Node impl | Cloudflare impl |
16
- |---------|-----------|---------------|-----------------|
14
+ | --------- | ----------- | --------------- | ----------------- |
17
15
  | Runtime factory | `RuntimeFactory` → `loadRuntimeFactory()` | `nodeBunFactory` | `cloudflareWorkersFactory` |
18
16
  | File system | `FileSystem` | `createNodeFileSystem()` (sync `node:fs`) | `createCfFileSystem()` (stub) |
19
- | Process execution | `ProcessExecutor` (class) | `run()` via execa, `runStreaming()` via `Bun.spawn` | throws |
17
+ | Process execution | `ProcessExecutor` (interface) | `NodeProcessExecutor` — `run()` via execa, `runStreaming()` via `Bun.spawn` | throws |
18
+ | Process registry | `ProcessRegistry` (optional) | `InMemoryProcessRegistry` / `createInMemoryProcessRegistry()` — list + subscribe all spawns | n/a (no process exec) |
20
19
  | SQL database | `createDbAdapter(config)` → `DbAdapter` | Bun SQLite via `@gobing-ai/ts-db` (optional peer) | throws `D1NotConfiguredError` (D1 round pending) |
21
20
  | Configuration | `Config` (Zod schema) | YAML + env vars | CONFIG_YAML blob + env vars |
22
21
  | Context | `RuntimeContext` | service locator | service locator |
@@ -88,10 +87,33 @@ classDiagram
88
87
  }
89
88
 
90
89
  class ProcessExecutor {
90
+ <<interface>>
91
91
  +run(options) Promise~ProcessResult~
92
92
  +runStreaming(options) PipeProcess
93
93
  }
94
94
 
95
+ class NodeProcessExecutor {
96
+ +run(options) Promise~ProcessResult~
97
+ +runStreaming(options) PipeProcess
98
+ }
99
+
100
+ class ProcessRegistry {
101
+ <<interface>>
102
+ +listExecutions(filter?) ProcessExecution[]
103
+ +getExecution(id) ProcessExecution?
104
+ +subscribe(listener) unsub
105
+ +begin(input) string
106
+ +update(id, patch) void
107
+ +complete(id, update?) void
108
+ +clear() void
109
+ }
110
+
111
+ class InMemoryProcessRegistry {
112
+ +listExecutions(filter?) ProcessExecution[]
113
+ +begin(input) string
114
+ +complete(id, update?) void
115
+ }
116
+
95
117
  class PipeProcess {
96
118
  <<interface>>
97
119
  +pid number?
@@ -133,8 +155,11 @@ classDiagram
133
155
  FileSystem <|.. createNodeFileSystem : implements
134
156
  FileSystem <|.. createCfFileSystem : implements
135
157
  ProcessExecutor --> PipeProcess : creates
158
+ ProcessExecutor <|.. NodeProcessExecutor : implements
159
+ ProcessRegistry <|.. InMemoryProcessRegistry : implements
160
+ NodeProcessExecutor ..> ProcessRegistry : optional registry
136
161
  nodeBunFactory --> createNodeFileSystem : creates
137
- nodeBunFactory --> ProcessExecutor : creates
162
+ nodeBunFactory --> NodeProcessExecutor : creates
138
163
  cloudflareWorkersFactory --> createCfFileSystem : creates
139
164
  RuntimeContext --> FileSystem : "fileSystem"
140
165
  RuntimeContext --> Config : "config"
@@ -232,7 +257,7 @@ There are three ways a config file can name its schema. **Prefer the bundled pac
232
257
  the most secure and performant default:
233
258
 
234
259
  | Style | Example | Resolution | Notes |
235
- |-------|---------|------------|-------|
260
+ | ------- | --------- | ------------ | ------- |
236
261
  | **Package specifier** (recommended) | `$schema: "@gobing-ai/ts-rule-engine/schemas/rule-file.schema.json"` | Resolved through `node_modules` via the module resolver, then read from disk | No network, no path guessing; survives hoisting/pnpm/monorepo layouts. Schemas ship in each package's `schemas/` (declared in `files`). **Quote the value** — YAML treats a leading `@` as reserved. |
237
262
  | Relative path | `$schema: ./schemas/rule-file.schema.json` | Resolved against the config file's directory | Fine for repo-local schemas; brittle if the config moves. |
238
263
  | Remote URL | `$schema: https://json-schema.org/.../rule-file.schema.json` | Fetched over HTTP(S) — **off by default** | SSRF/DoS surface for third-party configs. Opt in with `{ allowRemote: true }` (5s timeout) or supply your own `fetch`. |
@@ -251,7 +276,6 @@ await loadStructuredConfig('rules.yaml', { fetch: myFetch }); // or in
251
276
  > `node_modules` keeps validation entirely local — no outbound request, no dependency on a schema host's
252
277
  > availability, and no chance for a malicious config to point validation at an internal URL.
253
278
 
254
-
255
279
  ### 5. Path utilities
256
280
 
257
281
  Runtime-portable path math that avoids `node:path` so the same logic works on Cloudflare Workers
@@ -284,6 +308,7 @@ The `./extension` subpath exposes a generic, domain-agnostic extension/capabilit
284
308
  with origin metadata, a trust-gated extension loader, and a path guard — without knowing anything
285
309
  about evaluators, resolvers, actions, or guards. Each engine owns its domain-specific kinds,
286
310
  schemas, error types, and override semantics.
311
+
287
312
  #### Capability registry
288
313
 
289
314
  ```ts
@@ -462,6 +487,7 @@ process.on('SIGTERM', async () => {
462
487
  await ctx.dispose();
463
488
  process.exit(0);
464
489
  });
490
+
465
491
  ```
466
492
 
467
493
  ## Usage
@@ -513,6 +539,7 @@ const config = buildConfigFromObject({
513
539
  database: { url: ':memory:' },
514
540
  });
515
541
  ```
542
+
516
543
  // From YAML file
517
544
  const config = buildConfigFromYaml(yamlText);
518
545
 
@@ -521,16 +548,19 @@ const config = buildConfigFromObject({
521
548
  app: { name: 'api', env: 'production', port: 3000 },
522
549
  database: { url: ':memory:' },
523
550
  });
551
+
524
552
  ```
525
553
 
526
554
  ### Process execution
527
555
 
528
- `ProcessExecutor` is a single class wrapping `execa` (buffered) and `Bun.spawn` (streaming):
556
+ `ProcessExecutor` is the canonical interface for process execution. `NodeProcessExecutor` is the concrete implementation wrapping `execa` (buffered) and `Bun.spawn` (streaming):
529
557
 
530
558
  ```ts
531
- import { ProcessExecutor } from '@gobing-ai/ts-runtime';
559
+ import { NodeProcessExecutor, createInMemoryProcessRegistry } from '@gobing-ai/ts-runtime';
532
560
 
533
- const exec = new ProcessExecutor({ defaultTimeout: 30_000 });
561
+ // Optional: shared registry so every run/runStreaming is listable (spur#0264 / M1).
562
+ const registry = createInMemoryProcessRegistry();
563
+ const exec = new NodeProcessExecutor({ defaultTimeout: 30_000, registry });
534
564
 
535
565
  // Buffered — captures stdout/stderr, no throw on non-zero
536
566
  const result = await exec.run({
@@ -538,27 +568,45 @@ const result = await exec.run({
538
568
  args: ['status', '--short'],
539
569
  cwd: '/path/to/repo',
540
570
  rejectOnError: true,
571
+ // Optional registry metadata (defaults: run → source 'one-shot')
572
+ label: 'git.status',
541
573
  });
542
574
 
543
575
  console.log(result.stdout); // 'M src/index.ts\n'
544
576
  console.log(`Duration: ${result.durationMs}ms`);
545
577
 
546
578
  // Streaming — interactive subprocess with stdin control
547
- const proc = exec.runStreaming({ command: 'cat' });
579
+ const proc = exec.runStreaming({
580
+ command: 'cat',
581
+ source: 'supervisor', // tag supervised agent loops
582
+ agentId: 'alpha-claude',
583
+ });
548
584
  proc.writeStdin('hello\n');
549
585
  proc.endStdin();
550
586
  const exitCode = await proc.exited; // 0
587
+
588
+ // Watch list snapshot + live subscription
589
+ console.log(registry.listExecutions());
590
+ const unsub = registry.subscribe((event) => {
591
+ if (event.type === 'started' || event.type === 'exited') {
592
+ console.log(event.type, event.execution.id, event.execution.command);
593
+ }
594
+ });
595
+ unsub();
551
596
  ```
552
597
 
553
598
  `rejectOnError: true` throws on non-zero exits. `OutputPolicy` controls
554
599
  buffered vs streamed output. `ProcessOptions` supports timeout, env, cwd,
555
- maxOutput, and forceBuffered.
600
+ maxOutput, forceBuffered, and optional registry fields (`source`, `teamId`,
601
+ `agentId`). Inject the same `ProcessRegistry` into every executor that should
602
+ appear in one watch list; without a registry, behavior is unchanged.
556
603
 
557
604
  Cloudflare Workers do not expose process execution; check
558
605
  `factory.capabilities.hasProcessExecution` first.
559
606
 
560
- Old classes (`NodeProcessExecutor`, `BunSyncProcessExecutor`, `BunPipeProcessSpawner`)
561
- are kept as deprecated backward-compatible wrappers.
607
+ The `ProcessExecutor` const (value alias for `NodeProcessExecutor`), `BunSyncProcessExecutor`,
608
+ and `BunPipeProcessSpawner` are kept as deprecated backward-compatible wrappers. Prefer
609
+ `NodeProcessExecutor` or `nodeBunFactory.createProcessExecutor()` in new code.
562
610
 
563
611
  ### SpanContext (for telemetry)
564
612
 
package/dist/context.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { buildConfigFromObject } from './config.js';
2
2
  import { createNodeFileSystem } from './file-system-node.js';
3
3
  import { loadRuntimeFactory } from './platform.js';
4
- import { ProcessExecutor } from './process-executor.js';
4
+ import { nodeBunFactory } from './runtime-node-bun.js';
5
5
  /** Injectable service container scoped to a runtime environment (process, request, event, or test). */
6
6
  export class RuntimeContext {
7
7
  scope;
@@ -22,7 +22,7 @@ export class RuntimeContext {
22
22
  this.register('config', (options.services?.config ?? buildConfigFromObject({})));
23
23
  this.register('fileSystem', (options.services?.fileSystem ?? createNodeFileSystem()));
24
24
  if (this.capabilities.hasProcessExecution && options.services?.processExecutor === undefined) {
25
- this.register('processExecutor', new ProcessExecutor());
25
+ this.register('processExecutor', nodeBunFactory.createProcessExecutor());
26
26
  }
27
27
  for (const [key, value] of Object.entries(options.services ?? {})) {
28
28
  if (value !== undefined) {
package/dist/index.d.ts CHANGED
@@ -9,13 +9,15 @@ export { atomicWriteFile, atomicWriteJson, createLogStream, ensureDirForFile, re
9
9
  export * from './path';
10
10
  export { _resetRuntimeFactory, isCloudflareWorkerRuntime, loadRuntimeFactory } from './platform';
11
11
  export type { OutputPolicy, PipeProcess, PipeProcessOptions, ProcessEventDetail, ProcessEventSink, ProcessEvents, ProcessExecutorConfig, ProcessExitReason, ProcessOptions, ProcessResult, ProcessSignal, TracerPort, } from './process-executor';
12
- export { ProcessExecutor } from './process-executor';
12
+ export { NodeProcessExecutor, ProcessExecutor } from './process-executor';
13
+ export type { InMemoryProcessRegistryOptions, ProcessExecution, ProcessExecutionBegin, ProcessExecutionComplete, ProcessExecutionFilter, ProcessExecutionSource, ProcessExecutionStatus, ProcessRegistry, ProcessRegistryEvent, } from './process-registry';
14
+ export { createInMemoryProcessRegistry, InMemoryProcessRegistry } from './process-registry';
13
15
  export { cloudflareWorkersFactory } from './runtime-cf';
14
16
  export type { RuntimeFactory } from './runtime-factory';
15
17
  export { _resetNodeFileSystem, nodeBunFactory } from './runtime-node-bun';
16
18
  export * from './schema-validation';
17
19
  export * from './types';
18
- export { BunPipeProcessSpawner, BunSyncProcessExecutor, NodeProcessExecutor } from './process-executor';
20
+ export { BunPipeProcessSpawner, BunSyncProcessExecutor } from './process-executor';
19
21
  /**
20
22
  * @deprecated Use {@link ProcessExecutor} directly for async execution.
21
23
  * Use `Bun.spawnSync` or `child_process.spawnSync` for sync.
@@ -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,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,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,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAExG;;;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,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"}
package/dist/index.js CHANGED
@@ -7,10 +7,11 @@ export { createNodeFileSystem, findProjectRoot } from './file-system-node.js';
7
7
  export { atomicWriteFile, atomicWriteJson, createLogStream, ensureDirForFile, readJsonFile, walkDir, writeJsonFile, } from './fs.js';
8
8
  export * from './path.js';
9
9
  export { _resetRuntimeFactory, isCloudflareWorkerRuntime, loadRuntimeFactory } from './platform.js';
10
- export { ProcessExecutor } from './process-executor.js';
10
+ export { NodeProcessExecutor, ProcessExecutor } from './process-executor.js';
11
+ export { createInMemoryProcessRegistry, InMemoryProcessRegistry } from './process-registry.js';
11
12
  export { cloudflareWorkersFactory } from './runtime-cf.js';
12
13
  export { _resetNodeFileSystem, nodeBunFactory } from './runtime-node-bun.js';
13
14
  export * from './schema-validation.js';
14
15
  export * from './types.js';
15
16
  // ── Deprecated re-exports (backward compatibility) ──────────────────────
16
- export { BunPipeProcessSpawner, BunSyncProcessExecutor, NodeProcessExecutor } from './process-executor.js';
17
+ export { BunPipeProcessSpawner, BunSyncProcessExecutor } from './process-executor.js';
@@ -1,3 +1,4 @@
1
+ import type { ProcessExecutionSource, ProcessRegistry } from './process-registry';
1
2
  /** Controls how stdout/stderr is captured: buffered in memory or streamed to the caller's terminal. */
2
3
  export type OutputPolicy = {
3
4
  mode: 'buffered';
@@ -12,6 +13,12 @@ export interface ProcessExecutorConfig {
12
13
  output?: OutputPolicy;
13
14
  events?: ProcessEventSink;
14
15
  tracer?: TracerPort;
16
+ /**
17
+ * Optional process registry (spur#0264). When set, every `run` / `runStreaming`
18
+ * invocation is recorded for list/subscribe consumers (e.g. Spur Processes tab).
19
+ * Share one registry across all executors that should appear in the same watch list.
20
+ */
21
+ registry?: ProcessRegistry;
15
22
  }
16
23
  /** Options for spawning a child process. */
17
24
  export interface ProcessOptions {
@@ -26,6 +33,14 @@ export interface ProcessOptions {
26
33
  forceBuffered?: boolean;
27
34
  /** AbortSignal forwarded to execa as `cancelSignal` — aborts the child process when fired. */
28
35
  signal?: AbortSignal;
36
+ /**
37
+ * Registry metadata (spur#0264). Defaults: source `'one-shot'` for `run`.
38
+ * Pass `source: 'supervisor'` (and optional teamId/agentId) when the spawn is
39
+ * a supervised team agent loop.
40
+ */
41
+ source?: ProcessExecutionSource;
42
+ teamId?: string;
43
+ agentId?: string;
29
44
  }
30
45
  /** Result of a completed child process, including exit code, captured output, and duration. */
31
46
  export interface ProcessResult {
@@ -71,6 +86,13 @@ export interface PipeProcessOptions {
71
86
  cwd?: string;
72
87
  env?: Record<string, string>;
73
88
  label?: string;
89
+ /**
90
+ * Registry metadata (spur#0264). Defaults: source `'other'` for streaming.
91
+ * Supervised agent loops should pass `source: 'supervisor'` + agentId.
92
+ */
93
+ source?: ProcessExecutionSource;
94
+ teamId?: string;
95
+ agentId?: string;
74
96
  }
75
97
  /** Signal values accepted by subprocess kill. */
76
98
  type BunSubprocess = ReturnType<typeof Bun.spawn>;
@@ -87,12 +109,37 @@ export interface PipeProcess {
87
109
  kill(signal?: ProcessSignal): void;
88
110
  }
89
111
  /**
90
- * Runtime-agnostic process executor wrapping `execa`.
112
+ * Runtime-agnostic process executor contract.
91
113
  *
92
114
  * Every invocation supports timeout enforcement, output capture, and
93
- * configurable output policy (buffered vs streamed).
115
+ * configurable output policy (buffered vs streamed). Concrete implementations
116
+ * are obtained through `RuntimeFactory.createProcessExecutor`; the Node/Bun
117
+ * implementation is {@link NodeProcessExecutor}. Test doubles implement this
118
+ * interface structurally — no concrete subclassing required.
94
119
  */
95
- export declare class ProcessExecutor {
120
+ export interface ProcessExecutor {
121
+ /**
122
+ * Run a command, buffered by default. Returns a structured {@link ProcessResult}.
123
+ * Does NOT throw on non-zero exit codes unless `rejectOnError` is set.
124
+ */
125
+ run(options: ProcessOptions): Promise<ProcessResult>;
126
+ /**
127
+ * Spawn a long-running interactive process with streaming I/O.
128
+ *
129
+ * Returns a {@link PipeProcess} handle with streaming stdout/stderr and
130
+ * stdin write support.
131
+ */
132
+ runStreaming(options: PipeProcessOptions): PipeProcess;
133
+ }
134
+ /**
135
+ * Concrete Node/Bun implementation of {@link ProcessExecutor}, wrapping `execa`
136
+ * for buffered execution and `Bun.spawn` for streaming pipe execution.
137
+ *
138
+ * Obtain a default instance through `RuntimeFactory.createProcessExecutor`
139
+ * (e.g. `nodeBunFactory.createProcessExecutor()`); construct directly only in
140
+ * runtime-factory wiring or concrete implementation tests.
141
+ */
142
+ export declare class NodeProcessExecutor implements ProcessExecutor {
96
143
  private readonly config;
97
144
  constructor(config?: ProcessExecutorConfig);
98
145
  /**
@@ -109,15 +156,19 @@ export declare class ProcessExecutor {
109
156
  */
110
157
  runStreaming(options: PipeProcessOptions): PipeProcess;
111
158
  private trace;
159
+ private beginRegistry;
160
+ private completeRegistry;
112
161
  private emitExitedFromResult;
113
162
  private emitProcessEvent;
114
163
  }
115
164
  /**
116
- * @deprecated Use {@link ProcessExecutor} directly.
117
- * This subclass is kept for backward compatibility.
165
+ * @deprecated Construct {@link NodeProcessExecutor} directly or obtain a default
166
+ * through `RuntimeFactory.createProcessExecutor` (e.g. `nodeBunFactory.createProcessExecutor()`).
167
+ * This value alias preserves source compatibility for `new ProcessExecutor(...)` callers
168
+ * during the interface extraction release; it will be removed in a future release.
169
+ * `import type { ProcessExecutor }` resolves to the canonical interface, not this alias.
118
170
  */
119
- export declare class NodeProcessExecutor extends ProcessExecutor {
120
- }
171
+ export declare const ProcessExecutor: typeof NodeProcessExecutor;
121
172
  /**
122
173
  * @deprecated Use `Bun.spawnSync` or `child_process.spawnSync` directly.
123
174
  * Synchronous process execution is no longer recommended from ts-runtime.
@@ -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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"}
@@ -1,13 +1,15 @@
1
1
  import { isatty } from 'node:tty';
2
2
  import { execa } from 'execa';
3
- // ── ProcessExecutor ───────────────────────────────────────────────────────
3
+ // ── NodeProcessExecutor (concrete Node/Bun implementation) ───────────────
4
4
  /**
5
- * Runtime-agnostic process executor wrapping `execa`.
5
+ * Concrete Node/Bun implementation of {@link ProcessExecutor}, wrapping `execa`
6
+ * for buffered execution and `Bun.spawn` for streaming pipe execution.
6
7
  *
7
- * Every invocation supports timeout enforcement, output capture, and
8
- * configurable output policy (buffered vs streamed).
8
+ * Obtain a default instance through `RuntimeFactory.createProcessExecutor`
9
+ * (e.g. `nodeBunFactory.createProcessExecutor()`); construct directly only in
10
+ * runtime-factory wiring or concrete implementation tests.
9
11
  */
10
- export class ProcessExecutor {
12
+ export class NodeProcessExecutor {
11
13
  config;
12
14
  constructor(config = {}) {
13
15
  this.config = config;
@@ -32,17 +34,26 @@ export class ProcessExecutor {
32
34
  signal: options.signal,
33
35
  });
34
36
  const startedAt = Date.now();
37
+ const startedIso = new Date(startedAt).toISOString();
38
+ const registryId = this.beginRegistry(options.command, args, {
39
+ label: options.label,
40
+ source: options.source ?? 'one-shot',
41
+ teamId: options.teamId,
42
+ agentId: options.agentId,
43
+ startedAt: startedIso,
44
+ });
35
45
  this.emitProcessEvent('process.started', {
36
46
  command: options.command,
37
47
  args,
38
48
  exitCode: null,
39
49
  durationMs: 0,
40
50
  reason: 'exit',
41
- timestamp: new Date(startedAt).toISOString(),
51
+ timestamp: startedIso,
42
52
  ...(options.label !== undefined ? { label: options.label } : {}),
43
53
  });
44
54
  try {
45
55
  const result = await execa(options.command, args, execaOptions);
56
+ // execa@9 Result does not expose pid — buffered runs leave pid unset.
46
57
  const processResult = {
47
58
  command: options.command,
48
59
  args,
@@ -52,6 +63,7 @@ export class ProcessExecutor {
52
63
  ...(result.signalDescription !== undefined ? { signal: result.signalDescription } : {}),
53
64
  durationMs: result.durationMs,
54
65
  };
66
+ this.completeRegistry(registryId, processResult.exitCode);
55
67
  this.emitExitedFromResult(options, processResult, result);
56
68
  return processResult;
57
69
  }
@@ -70,6 +82,7 @@ export class ProcessExecutor {
70
82
  : {}),
71
83
  durationMs: failed.durationMs ?? Date.now() - startedAt,
72
84
  };
85
+ this.completeRegistry(registryId, processResult.exitCode);
73
86
  this.emitExitedFromResult(options, processResult, error, error);
74
87
  if (options.rejectOnError)
75
88
  throw error;
@@ -85,15 +98,24 @@ export class ProcessExecutor {
85
98
  runStreaming(options) {
86
99
  const args = options.args ?? [];
87
100
  void this.config.tracer?.traceAsync('process.runStreaming', async () => undefined).catch(() => undefined);
101
+ const startedAt = Date.now();
102
+ const startedIso = new Date(startedAt).toISOString();
103
+ // Begin registry before spawn so failed spawns still appear (then complete as error).
104
+ const registryId = this.beginRegistry(options.command, args, {
105
+ label: options.label,
106
+ source: options.source ?? 'other',
107
+ teamId: options.teamId,
108
+ agentId: options.agentId,
109
+ startedAt: startedIso,
110
+ });
88
111
  try {
89
- const startedAt = Date.now();
90
112
  this.emitProcessEvent('process.started', {
91
113
  command: options.command,
92
114
  args,
93
115
  exitCode: null,
94
116
  durationMs: 0,
95
117
  reason: 'exit',
96
- timestamp: new Date(startedAt).toISOString(),
118
+ timestamp: startedIso,
97
119
  ...(options.label !== undefined ? { label: options.label } : {}),
98
120
  });
99
121
  const subprocess = Bun.spawn({
@@ -104,14 +126,21 @@ export class ProcessExecutor {
104
126
  ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),
105
127
  ...(options.env !== undefined ? { env: options.env } : {}),
106
128
  });
107
- return new ObservedPipeProcess(new BunPipeProcess(subprocess), this.config.events, {
129
+ const pipe = new BunPipeProcess(subprocess);
130
+ if (pipe.pid !== null) {
131
+ this.config.registry?.update(registryId, { pid: pipe.pid });
132
+ }
133
+ return new ObservedPipeProcess(pipe, this.config.events, {
108
134
  command: options.command,
109
135
  args,
110
136
  startedAt,
137
+ registry: this.config.registry,
138
+ registryId,
111
139
  ...(options.label !== undefined ? { label: options.label } : {}),
112
140
  });
113
141
  }
114
142
  catch (error) {
143
+ this.completeRegistry(registryId, null);
115
144
  this.emitProcessEvent('process.exited', {
116
145
  command: options.command,
117
146
  args,
@@ -130,6 +159,28 @@ export class ProcessExecutor {
130
159
  return await fn();
131
160
  return await this.config.tracer.traceAsync(name, async () => await fn());
132
161
  }
162
+ beginRegistry(command, args, meta) {
163
+ const registry = this.config.registry;
164
+ if (!registry)
165
+ return '';
166
+ return registry.begin({
167
+ command,
168
+ args,
169
+ source: meta.source,
170
+ startedAt: meta.startedAt,
171
+ ...(meta.label !== undefined ? { label: meta.label } : {}),
172
+ ...(meta.teamId !== undefined ? { teamId: meta.teamId } : {}),
173
+ ...(meta.agentId !== undefined ? { agentId: meta.agentId } : {}),
174
+ });
175
+ }
176
+ completeRegistry(id, exitCode, pid) {
177
+ if (!id || !this.config.registry)
178
+ return;
179
+ this.config.registry.complete(id, {
180
+ exitCode,
181
+ ...(pid !== undefined ? { pid } : {}),
182
+ });
183
+ }
133
184
  emitExitedFromResult(options, result, completion, error) {
134
185
  const reason = isTimedOut(completion)
135
186
  ? 'timeout'
@@ -161,6 +212,12 @@ class ObservedPipeProcess {
161
212
  constructor(inner, events, context) {
162
213
  this.inner = inner;
163
214
  this.exited = inner.exited.then((exitCode) => {
215
+ if (context.registry && context.registryId) {
216
+ context.registry.complete(context.registryId, {
217
+ exitCode,
218
+ ...(inner.pid !== null ? { pid: inner.pid } : {}),
219
+ });
220
+ }
164
221
  events?.emit('process.exited', {
165
222
  command: context.command,
166
223
  args: context.args,
@@ -224,13 +281,16 @@ class BunPipeProcess {
224
281
  this.subprocess.kill(signal);
225
282
  }
226
283
  }
227
- // ── Deprecated backward-compatible subclasses ─────────────────────────────
284
+ // ── Deprecated constructible ProcessExecutor value alias ──────────────────
228
285
  /**
229
- * @deprecated Use {@link ProcessExecutor} directly.
230
- * This subclass is kept for backward compatibility.
286
+ * @deprecated Construct {@link NodeProcessExecutor} directly or obtain a default
287
+ * through `RuntimeFactory.createProcessExecutor` (e.g. `nodeBunFactory.createProcessExecutor()`).
288
+ * This value alias preserves source compatibility for `new ProcessExecutor(...)` callers
289
+ * during the interface extraction release; it will be removed in a future release.
290
+ * `import type { ProcessExecutor }` resolves to the canonical interface, not this alias.
231
291
  */
232
- export class NodeProcessExecutor extends ProcessExecutor {
233
- }
292
+ export const ProcessExecutor = NodeProcessExecutor;
293
+ // ── Deprecated backward-compatible helpers ────────────────────────────────
234
294
  /**
235
295
  * @deprecated Use `Bun.spawnSync` or `child_process.spawnSync` directly.
236
296
  * Synchronous process execution is no longer recommended from ts-runtime.