genaicode 2.1.0 → 2.4.0

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 (95) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/README.md +150 -35
  3. package/dist/agents/cli-agent.d.ts +28 -0
  4. package/dist/agents/cli-agent.js +57 -0
  5. package/dist/agents/cli-agent.js.map +1 -0
  6. package/dist/agents/discovery.d.ts +10 -0
  7. package/dist/agents/discovery.js +31 -0
  8. package/dist/agents/discovery.js.map +1 -0
  9. package/dist/agents/drivers/claude.d.ts +25 -0
  10. package/dist/agents/drivers/claude.js +184 -0
  11. package/dist/agents/drivers/claude.js.map +1 -0
  12. package/dist/agents/drivers/codex-live.d.ts +17 -0
  13. package/dist/agents/drivers/codex-live.js +182 -0
  14. package/dist/agents/drivers/codex-live.js.map +1 -0
  15. package/dist/agents/drivers/codex.d.ts +27 -0
  16. package/dist/agents/drivers/codex.js +176 -0
  17. package/dist/agents/drivers/codex.js.map +1 -0
  18. package/dist/agents/drivers/copilot.d.ts +27 -0
  19. package/dist/agents/drivers/copilot.js +199 -0
  20. package/dist/agents/drivers/copilot.js.map +1 -0
  21. package/dist/agents/drivers/cursor.d.ts +23 -0
  22. package/dist/agents/drivers/cursor.js +174 -0
  23. package/dist/agents/drivers/cursor.js.map +1 -0
  24. package/dist/agents/drivers/gemini.d.ts +18 -0
  25. package/dist/agents/drivers/gemini.js +118 -0
  26. package/dist/agents/drivers/gemini.js.map +1 -0
  27. package/dist/agents/drivers/json.d.ts +6 -0
  28. package/dist/agents/drivers/json.js +20 -0
  29. package/dist/agents/drivers/json.js.map +1 -0
  30. package/dist/agents/drivers/muse-live.d.ts +17 -0
  31. package/dist/agents/drivers/muse-live.js +112 -0
  32. package/dist/agents/drivers/muse-live.js.map +1 -0
  33. package/dist/agents/drivers/muse.d.ts +12 -0
  34. package/dist/agents/drivers/muse.js +87 -0
  35. package/dist/agents/drivers/muse.js.map +1 -0
  36. package/dist/agents/drivers/opencode.d.ts +17 -0
  37. package/dist/agents/drivers/opencode.js +103 -0
  38. package/dist/agents/drivers/opencode.js.map +1 -0
  39. package/dist/agents/env.d.ts +16 -0
  40. package/dist/agents/env.js +46 -0
  41. package/dist/agents/env.js.map +1 -0
  42. package/dist/agents/event-queue.d.ts +44 -0
  43. package/dist/agents/event-queue.js +123 -0
  44. package/dist/agents/event-queue.js.map +1 -0
  45. package/dist/agents/hosted.d.ts +33 -0
  46. package/dist/agents/hosted.js +129 -0
  47. package/dist/agents/hosted.js.map +1 -0
  48. package/dist/agents/live-agent.d.ts +37 -0
  49. package/dist/agents/live-agent.js +142 -0
  50. package/dist/agents/live-agent.js.map +1 -0
  51. package/dist/agents/prepare.d.ts +33 -0
  52. package/dist/agents/prepare.js +52 -0
  53. package/dist/agents/prepare.js.map +1 -0
  54. package/dist/agents/process.d.ts +39 -0
  55. package/dist/agents/process.js +140 -0
  56. package/dist/agents/process.js.map +1 -0
  57. package/dist/agents/rpc.d.ts +29 -0
  58. package/dist/agents/rpc.js +101 -0
  59. package/dist/agents/rpc.js.map +1 -0
  60. package/dist/agents/runtime.d.ts +26 -0
  61. package/dist/agents/runtime.js +97 -0
  62. package/dist/agents/runtime.js.map +1 -0
  63. package/dist/agents/types.d.ts +158 -0
  64. package/dist/agents/types.js +2 -0
  65. package/dist/agents/types.js.map +1 -0
  66. package/dist/agents/verify.d.ts +36 -0
  67. package/dist/agents/verify.js +43 -0
  68. package/dist/agents/verify.js.map +1 -0
  69. package/dist/agents.d.ts +36 -0
  70. package/dist/agents.js +19 -0
  71. package/dist/agents.js.map +1 -0
  72. package/dist/core/client.d.ts +7 -1
  73. package/dist/core/client.js +18 -3
  74. package/dist/core/client.js.map +1 -1
  75. package/dist/core/middleware.js +2 -0
  76. package/dist/core/middleware.js.map +1 -1
  77. package/dist/core/types.d.ts +51 -0
  78. package/dist/providers/anthropic-converter.js +32 -6
  79. package/dist/providers/anthropic-converter.js.map +1 -1
  80. package/dist/providers/anthropic.js +3 -1
  81. package/dist/providers/anthropic.js.map +1 -1
  82. package/dist/providers/google-converter.js +70 -3
  83. package/dist/providers/google-converter.js.map +1 -1
  84. package/dist/providers/google.d.ts +8 -0
  85. package/dist/providers/google.js +3 -0
  86. package/dist/providers/google.js.map +1 -1
  87. package/dist/providers/openai-converter.d.ts +2 -0
  88. package/dist/providers/openai-converter.js +16 -0
  89. package/dist/providers/openai-converter.js.map +1 -1
  90. package/dist/providers/openai.js +1 -0
  91. package/dist/providers/openai.js.map +1 -1
  92. package/docs/agents.md +269 -0
  93. package/docs/pivot.md +8 -1
  94. package/docs/semver.md +6 -0
  95. package/package.json +7 -2
@@ -0,0 +1,129 @@
1
+ import { RunRecorder } from './runtime.js';
2
+ const TERMINAL = new Set(['completed', 'failed', 'cancelled']);
3
+ /** Adapt a `HostedAgentProvider` to `CodingAgent`, so hosted and local agents share one API. */
4
+ export function hostedAgent(provider, options = {}) {
5
+ return {
6
+ name: provider.name,
7
+ command: provider.name,
8
+ capabilities: { ...provider.capabilities, steer: !!provider.send },
9
+ run: (task) => runHosted(provider, task, options.pollIntervalMs ?? 5_000),
10
+ };
11
+ }
12
+ function runHosted(provider, task, pollIntervalMs) {
13
+ const recorder = new RunRecorder(provider.name, provider.name);
14
+ const controller = new AbortController();
15
+ let stopReason;
16
+ let taskId;
17
+ const stop = (reason) => {
18
+ if (stopReason || controller.signal.aborted)
19
+ return;
20
+ stopReason = reason;
21
+ controller.abort();
22
+ };
23
+ const onAbort = () => stop('aborted');
24
+ task.signal?.addEventListener('abort', onAbort, { once: true });
25
+ if (task.signal?.aborted)
26
+ onAbort();
27
+ const timer = task.timeoutMs !== undefined ? setTimeout(() => stop('timeout'), task.timeoutMs) : undefined;
28
+ const exit = (reason, error) => ({
29
+ exitCode: null,
30
+ signal: null,
31
+ reason,
32
+ ...(error ? { error } : {}),
33
+ });
34
+ const work = async () => {
35
+ // Local-only fields (process env, callbacks, timers) never reach the provider.
36
+ const request = { ...task };
37
+ delete request.env;
38
+ delete request.signal;
39
+ delete request.onApproval;
40
+ delete request.timeoutMs;
41
+ try {
42
+ taskId = (await provider.start(request, controller.signal)).id;
43
+ }
44
+ catch (error) {
45
+ if (stopReason)
46
+ return { exit: exit(stopReason) };
47
+ return { exit: exit('spawn-error', error instanceof Error ? error : new Error(String(error))) };
48
+ }
49
+ recorder.emit({ type: 'session', sessionId: taskId });
50
+ let cursor;
51
+ while (!stopReason) {
52
+ let poll;
53
+ try {
54
+ poll = await provider.poll(taskId, cursor, controller.signal);
55
+ }
56
+ catch (error) {
57
+ if (stopReason)
58
+ break;
59
+ // Do not leave a task running (and billing) that nobody watches any more.
60
+ await provider.cancel(taskId).catch(() => undefined);
61
+ const message = error instanceof Error ? error.message : String(error);
62
+ return { exit: exit('closed'), outcome: { ok: false, error: `Polling ${provider.name} failed: ${message}` } };
63
+ }
64
+ // Aborted while the poll was in flight: cancel, whatever state it reported.
65
+ if (stopReason)
66
+ break;
67
+ for (const event of poll.events ?? [])
68
+ recorder.emit(event);
69
+ cursor = poll.cursor ?? cursor;
70
+ if (TERMINAL.has(poll.state)) {
71
+ if (poll.state === 'cancelled')
72
+ return { exit: exit('aborted') };
73
+ return {
74
+ exit: exit('closed'),
75
+ outcome: poll.state === 'completed'
76
+ ? { ok: true }
77
+ : { ok: false, error: poll.error ?? `${provider.name} task failed.` },
78
+ };
79
+ }
80
+ // A consumer that falls behind holds the next poll instead of buffering without bound.
81
+ await untilAborted(recorder.events.room(), controller.signal);
82
+ await delay(pollIntervalMs, controller.signal);
83
+ }
84
+ await provider.cancel(taskId).catch(() => undefined);
85
+ return { exit: exit(stopReason ?? 'aborted') };
86
+ };
87
+ const result = work().then(({ exit: ended, outcome }) => {
88
+ clearTimeout(timer);
89
+ task.signal?.removeEventListener('abort', onAbort);
90
+ return recorder.finish(ended, outcome);
91
+ });
92
+ return {
93
+ result,
94
+ abort: () => stop('aborted'),
95
+ ...(provider.send
96
+ ? {
97
+ steer: (text) => taskId && !stopReason
98
+ ? provider.send(taskId, text)
99
+ : Promise.reject(new Error(`${provider.name} is not accepting input.`)),
100
+ }
101
+ : {}),
102
+ [Symbol.asyncIterator]: () => recorder.events.iterate(),
103
+ };
104
+ }
105
+ function delay(ms, signal) {
106
+ return new Promise((resolve) => {
107
+ const timer = setTimeout(done, ms);
108
+ signal.addEventListener('abort', done, { once: true });
109
+ function done() {
110
+ clearTimeout(timer);
111
+ signal.removeEventListener('abort', done);
112
+ resolve();
113
+ }
114
+ });
115
+ }
116
+ /** Resolve when `wait` does or `signal` aborts, whichever comes first. */
117
+ function untilAborted(wait, signal) {
118
+ if (signal.aborted)
119
+ return Promise.resolve();
120
+ return new Promise((resolve) => {
121
+ const done = () => {
122
+ signal.removeEventListener('abort', done);
123
+ resolve();
124
+ };
125
+ signal.addEventListener('abort', done, { once: true });
126
+ void wait.then(done);
127
+ });
128
+ }
129
+ //# sourceMappingURL=hosted.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hosted.js","sourceRoot":"","sources":["../../src/agents/hosted.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import { type PreparedRun } from './prepare.js';
2
+ import { RpcPeer } from './rpc.js';
3
+ import { type AgentOutcome } from './runtime.js';
4
+ import type { AgentCapabilities, AgentEvent, AgentTask, ApprovalDecision, ApprovalRequest, CodingAgent } from './types.js';
5
+ /** What a live driver gets for one task. */
6
+ export interface LiveSession {
7
+ readonly task: AgentTask;
8
+ readonly rpc: RpcPeer;
9
+ emit(event: AgentEvent): void;
10
+ /** Called for each notification the agent sends. Set once, before the first request. */
11
+ onNotification(handler: (method: string, params: unknown) => void): void;
12
+ /** Called for each request the agent sends. Throw `RpcError` to decline. Unhandled requests are declined. */
13
+ onRequest(handler: (method: string, params: unknown) => unknown | Promise<unknown>): void;
14
+ /** Ask `task.onApproval` (deny when absent or when it throws), emitting request and decision events. */
15
+ approve(request: ApprovalRequest): Promise<ApprovalDecision>;
16
+ /** Make `AgentRun.steer` send input, or pass undefined once the task stops accepting it. */
17
+ setSteer(steer: ((text: string) => Promise<void>) | undefined): void;
18
+ }
19
+ export interface LiveAgentDefinition {
20
+ name: string;
21
+ command: string;
22
+ capabilities?: AgentCapabilities;
23
+ /** Arguments that start the agent's JSON-RPC server on stdio. */
24
+ args(task: AgentTask): string[];
25
+ /** Replaces `args` when a task needs setup: extra env, temp files to clean up. */
26
+ prepare?(task: AgentTask): PreparedRun;
27
+ env?(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
28
+ /** Run one task over the session. Resolve with the agent's verdict when its turn ends. */
29
+ drive(session: LiveSession): Promise<AgentOutcome>;
30
+ }
31
+ /**
32
+ * Build a `CodingAgent` from a CLI that serves JSON-RPC over stdio. The process
33
+ * stays up for the whole task, so the caller can `steer()` it and answer approvals.
34
+ */
35
+ export declare function liveAgent(definition: LiveAgentDefinition): CodingAgent;
36
+ /** RFC 9562 UUIDv7: time-ordered ids some agents require for idempotent commands. */
37
+ export declare function uuidv7(now?: number): string;
@@ -0,0 +1,142 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { planSpawn } from './prepare.js';
3
+ import { startProcess } from './process.js';
4
+ import { RpcError, RpcPeer } from './rpc.js';
5
+ import { invalidCwd, RunRecorder } from './runtime.js';
6
+ /**
7
+ * Build a `CodingAgent` from a CLI that serves JSON-RPC over stdio. The process
8
+ * stays up for the whole task, so the caller can `steer()` it and answer approvals.
9
+ */
10
+ export function liveAgent(definition) {
11
+ return {
12
+ name: definition.name,
13
+ command: definition.command,
14
+ capabilities: { steer: true, ...definition.capabilities },
15
+ run: (task) => runLiveAgent(definition, task),
16
+ };
17
+ }
18
+ function runLiveAgent(definition, task) {
19
+ const recorder = new RunRecorder(definition.name, definition.command);
20
+ const iterate = () => recorder.events.iterate();
21
+ let steer;
22
+ // A consumer that falls behind pauses the agent's output. A steer awaited from inside the
23
+ // loop needs its reply read, so output keeps flowing while one is in flight.
24
+ let pressure = false;
25
+ let steering = 0;
26
+ let flow = () => { };
27
+ const steerRun = async (text) => {
28
+ if (!steer)
29
+ throw new Error(`${definition.name} is not accepting input.`);
30
+ steering++;
31
+ flow();
32
+ try {
33
+ await steer(text);
34
+ }
35
+ finally {
36
+ steering--;
37
+ flow();
38
+ }
39
+ };
40
+ const plan = planSpawn(definition, task, invalidCwd(task.cwd));
41
+ if (!plan.ok) {
42
+ const result = recorder.finish({ exitCode: null, signal: null, reason: 'spawn-error', error: new Error(plan.error) }, undefined);
43
+ return { result: Promise.resolve(result), abort() { }, steer: steerRun, [Symbol.asyncIterator]: iterate };
44
+ }
45
+ let notificationHandler = () => { };
46
+ let requestHandler = (method) => {
47
+ throw new RpcError(`${method} is not supported by this client.`, -32601);
48
+ };
49
+ const handle = startProcess({
50
+ command: definition.command,
51
+ args: plan.args,
52
+ cwd: task.cwd,
53
+ env: plan.env,
54
+ timeoutMs: task.timeoutMs,
55
+ signal: task.signal,
56
+ stdin: true,
57
+ onLine(line) {
58
+ let value;
59
+ try {
60
+ value = JSON.parse(line);
61
+ }
62
+ catch {
63
+ recorder.emit({ type: 'raw', line });
64
+ return;
65
+ }
66
+ if (!rpc.receive(value))
67
+ recorder.emit({ type: 'raw', line });
68
+ },
69
+ onStderr: (text) => recorder.emit({ type: 'stderr', text }),
70
+ });
71
+ flow = () => (pressure && !steering ? handle.pause() : handle.resume());
72
+ recorder.events.onPressure = (paused) => {
73
+ pressure = paused;
74
+ flow();
75
+ };
76
+ const rpc = new RpcPeer((line) => handle.write(line), {
77
+ notification: (method, params) => notificationHandler(method, params),
78
+ request: (method, params) => requestHandler(method, params),
79
+ });
80
+ const session = {
81
+ task,
82
+ rpc,
83
+ emit: (event) => recorder.emit(event),
84
+ onNotification(handler) {
85
+ notificationHandler = handler;
86
+ },
87
+ onRequest(handler) {
88
+ requestHandler = handler;
89
+ },
90
+ async approve(request) {
91
+ recorder.emit({ type: 'approval-request', request });
92
+ let decision = 'deny';
93
+ try {
94
+ if (task.onApproval)
95
+ decision = (await task.onApproval(request)) === 'approve' ? 'approve' : 'deny';
96
+ }
97
+ catch {
98
+ decision = 'deny';
99
+ }
100
+ recorder.emit({ type: 'approval-resolved', id: request.id, decision });
101
+ return decision;
102
+ },
103
+ setSteer(next) {
104
+ steer = next;
105
+ },
106
+ };
107
+ const exited = handle.exit.then((exit) => {
108
+ plan.cleanup();
109
+ steer = undefined;
110
+ rpc.fail(new Error(`${definition.name} exited before the task finished.`));
111
+ return exit;
112
+ });
113
+ const outcome = definition.drive(session).then((verdict) => verdict, (error) => ({ ok: false, error: error instanceof Error ? error.message : String(error) }));
114
+ const result = Promise.race([outcome.then(() => undefined), exited]).then(async (early) => {
115
+ steer = undefined;
116
+ // Exiting before the turn ends is a failure even with exit code 0.
117
+ if (early)
118
+ return recorder.finish(early, (await settledOrUndefined(outcome)) ?? {
119
+ ok: false,
120
+ error: `${definition.name} exited before the task finished.`,
121
+ });
122
+ handle.close();
123
+ return recorder.finish(await exited, await outcome);
124
+ });
125
+ return { result, abort: handle.kill, steer: steerRun, [Symbol.asyncIterator]: iterate };
126
+ }
127
+ /** A driver's verdict when it already settled; undefined when it was still waiting. */
128
+ async function settledOrUndefined(outcome) {
129
+ const pending = Symbol('pending');
130
+ const value = await Promise.race([outcome, Promise.resolve(pending)]);
131
+ return value === pending ? undefined : value;
132
+ }
133
+ /** RFC 9562 UUIDv7: time-ordered ids some agents require for idempotent commands. */
134
+ export function uuidv7(now = Date.now()) {
135
+ const bytes = randomBytes(16);
136
+ bytes.writeUIntBE(now, 0, 6);
137
+ bytes[6] = 0x70 | (bytes[6] & 0x0f);
138
+ bytes[8] = 0x80 | (bytes[8] & 0x3f);
139
+ const hex = bytes.toString('hex');
140
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
141
+ }
142
+ //# sourceMappingURL=live-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-agent.js","sourceRoot":"","sources":["../../src/agents/live-agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { AgentCapabilities, AgentTask, McpServer } from './types.js';
2
+ /** Everything a driver needs to start one task's process. */
3
+ export interface PreparedRun {
4
+ args: string[];
5
+ /** Extra environment variables for the child. */
6
+ env?: Record<string, string>;
7
+ /** Called once the process has exited (temp files, for example). */
8
+ cleanup?(): void;
9
+ }
10
+ /** Reject a task the agent cannot honor before anything is spawned. */
11
+ export declare function unsupportedTask(name: string, capabilities: AgentCapabilities, task: AgentTask): string | undefined;
12
+ export declare function isHttpServer(server: McpServer): server is Extract<McpServer, {
13
+ url: string;
14
+ }>;
15
+ interface SpawnDefinition {
16
+ name: string;
17
+ capabilities?: AgentCapabilities;
18
+ args(task: AgentTask): string[];
19
+ prepare?(task: AgentTask): PreparedRun;
20
+ env?(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
21
+ }
22
+ export type SpawnPlan = {
23
+ ok: true;
24
+ args: string[];
25
+ env: NodeJS.ProcessEnv;
26
+ cleanup(): void;
27
+ } | {
28
+ ok: false;
29
+ error: string;
30
+ };
31
+ /** Check the task, then resolve arguments and environment for the child process. */
32
+ export declare function planSpawn(definition: SpawnDefinition, task: AgentTask, cwdError: string | undefined): SpawnPlan;
33
+ export {};
@@ -0,0 +1,52 @@
1
+ const MCP_NAME = /^[A-Za-z0-9_-]+$/;
2
+ /** Reject a task the agent cannot honor before anything is spawned. */
3
+ export function unsupportedTask(name, capabilities, task) {
4
+ const servers = task.mcpServers ?? [];
5
+ if (servers.length && !capabilities.mcp)
6
+ return `${name} does not support MCP servers in this driver.`;
7
+ const names = new Set();
8
+ for (const server of servers) {
9
+ if (!MCP_NAME.test(server.name))
10
+ return `Invalid MCP server name: ${JSON.stringify(server.name)}.`;
11
+ if (names.has(server.name))
12
+ return `Duplicate MCP server name: ${server.name}.`;
13
+ names.add(server.name);
14
+ }
15
+ return undefined;
16
+ }
17
+ export function isHttpServer(server) {
18
+ return 'url' in server;
19
+ }
20
+ /** Check the task, then resolve arguments and environment for the child process. */
21
+ export function planSpawn(definition, task, cwdError) {
22
+ const refused = unsupportedTask(definition.name, definition.capabilities ?? {}, task) ?? cwdError;
23
+ if (refused)
24
+ return { ok: false, error: refused };
25
+ let prepared;
26
+ try {
27
+ prepared = definition.prepare ? definition.prepare(task) : { args: definition.args(task) };
28
+ }
29
+ catch (error) {
30
+ return { ok: false, error: error instanceof Error ? error.message : String(error) };
31
+ }
32
+ const base = task.env ?? process.env;
33
+ const env = { ...(definition.env ? definition.env(base) : base), ...prepared.env };
34
+ let cleaned = false;
35
+ return {
36
+ ok: true,
37
+ args: prepared.args,
38
+ env,
39
+ cleanup() {
40
+ if (cleaned)
41
+ return;
42
+ cleaned = true;
43
+ try {
44
+ prepared.cleanup?.();
45
+ }
46
+ catch {
47
+ // Best effort: a leftover temp file must not change the task's result.
48
+ }
49
+ },
50
+ };
51
+ }
52
+ //# sourceMappingURL=prepare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare.js","sourceRoot":"","sources":["../../src/agents/prepare.ts"],"names":[],"mappings":"AAWA,MAAM,QAAQ,GAAG,kBAAkB,CAAC;AAEpC,uEAAuE;AACvE,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,YAA+B,EAAE,IAAe;IAC5F,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;IACtC,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG;QAAE,OAAO,GAAG,IAAI,+CAA+C,CAAC;IACvG,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,OAAO,4BAA4B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QACnG,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,OAAO,8BAA8B,MAAM,CAAC,IAAI,GAAG,CAAC;QAChF,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAiB;IAC5C,OAAO,KAAK,IAAI,MAAM,CAAC;AACzB,CAAC;AAcD,oFAAoF;AACpF,MAAM,UAAU,SAAS,CAAC,UAA2B,EAAE,IAAe,EAAE,QAA4B;IAClG,MAAM,OAAO,GAAG,eAAe,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,YAAY,IAAI,EAAE,EAAE,IAAI,CAAC,IAAI,QAAQ,CAAC;IAClG,IAAI,OAAO;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAClD,IAAI,QAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAC7F,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IACtF,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACrC,MAAM,GAAG,GAAG,EAAE,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC;IACnF,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,OAAO;QACL,EAAE,EAAE,IAAI;QACR,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,GAAG;QACH,OAAO;YACL,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,CAAC;gBACH,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;YACvB,CAAC;YAAC,MAAM,CAAC;gBACP,uEAAuE;YACzE,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,39 @@
1
+ export interface ProcessOptions {
2
+ command: string;
3
+ args: readonly string[];
4
+ cwd: string;
5
+ env: NodeJS.ProcessEnv;
6
+ timeoutMs?: number;
7
+ signal?: AbortSignal;
8
+ /** Time between SIGTERM and SIGKILL. */
9
+ killGraceMs?: number;
10
+ /** Keep stdin open for `write()` (JSON-RPC agents). Default: stdin is closed. */
11
+ stdin?: boolean;
12
+ onLine(line: string): void;
13
+ onStderr(text: string): void;
14
+ }
15
+ export interface ProcessExit {
16
+ exitCode: number | null;
17
+ signal: NodeJS.Signals | null;
18
+ /** `closed`: the caller ended a long-lived agent with `close()` after its work was done. */
19
+ reason: 'exit' | 'closed' | 'aborted' | 'timeout' | 'spawn-error' | 'overflow';
20
+ error?: Error;
21
+ }
22
+ export interface ProcessHandle {
23
+ exit: Promise<ProcessExit>;
24
+ /** Stop the process as aborted. */
25
+ kill(): void;
26
+ /** Stop the process as finished on purpose. */
27
+ close(): void;
28
+ /** Write one line to stdin. Requires `stdin: true`. */
29
+ write(line: string): void;
30
+ /** Stop reading stdout and stderr, so the agent blocks once the pipes fill. */
31
+ pause(): void;
32
+ /** Read again after `pause()`. */
33
+ resume(): void;
34
+ }
35
+ /**
36
+ * Spawn a child in its own process group and deliver stdout line by line.
37
+ * Stopping signals the whole group, so tools the agent started die with it.
38
+ */
39
+ export declare function startProcess(options: ProcessOptions): ProcessHandle;
@@ -0,0 +1,140 @@
1
+ import { spawn } from 'node:child_process';
2
+ const MAX_LINE_BYTES = 16 * 1024 * 1024;
3
+ /** After the agent exits, how long a background child that inherited its pipes may keep them open. */
4
+ const EXIT_DRAIN_MS = 500;
5
+ /**
6
+ * Spawn a child in its own process group and deliver stdout line by line.
7
+ * Stopping signals the whole group, so tools the agent started die with it.
8
+ */
9
+ export function startProcess(options) {
10
+ const groupKill = process.platform !== 'win32';
11
+ const child = spawn(options.command, [...options.args], {
12
+ cwd: options.cwd,
13
+ env: options.env,
14
+ stdio: [options.stdin ? 'pipe' : 'ignore', 'pipe', 'pipe'],
15
+ detached: groupKill,
16
+ });
17
+ let reason = 'exit';
18
+ let spawnError;
19
+ let escalation;
20
+ let timer;
21
+ const signal = (name) => {
22
+ try {
23
+ if (groupKill && child.pid)
24
+ process.kill(-child.pid, name);
25
+ else
26
+ child.kill(name);
27
+ }
28
+ catch {
29
+ child.kill(name);
30
+ }
31
+ };
32
+ let closed = false;
33
+ // Pausing holds the agent back only while it runs. Once it exits or is being stopped, the
34
+ // rest of its output is small, and a caller awaiting `exit` must not wait on the consumer.
35
+ let paused = false;
36
+ let pausable = true;
37
+ const release = () => {
38
+ pausable = false;
39
+ if (!paused)
40
+ return;
41
+ paused = false;
42
+ child.stdout.resume();
43
+ child.stderr.resume();
44
+ };
45
+ // Stops still apply after the agent exits: a leftover child in its group can hold the pipes open.
46
+ const stop = (why) => {
47
+ if (closed || reason !== 'exit')
48
+ return;
49
+ reason = why;
50
+ release();
51
+ signal('SIGTERM');
52
+ escalation = setTimeout(() => signal('SIGKILL'), options.killGraceMs ?? 2_000);
53
+ escalation.unref?.();
54
+ };
55
+ const onAbort = () => stop('aborted');
56
+ let buffered = '';
57
+ child.stdout.setEncoding('utf8');
58
+ child.stdout.on('data', (chunk) => {
59
+ buffered += chunk;
60
+ let end = buffered.indexOf('\n');
61
+ while (end >= 0) {
62
+ const line = buffered.slice(0, end).replace(/\r$/, '');
63
+ buffered = buffered.slice(end + 1);
64
+ if (line.trim())
65
+ options.onLine(line);
66
+ end = buffered.indexOf('\n');
67
+ }
68
+ if (buffered.length > MAX_LINE_BYTES) {
69
+ buffered = '';
70
+ stop('overflow');
71
+ }
72
+ });
73
+ child.stderr.setEncoding('utf8');
74
+ child.stderr.on('data', (chunk) => options.onStderr(chunk));
75
+ // `close` waits for every holder of stdout/stderr. After the agent exits, stop waiting for its leftovers.
76
+ let drain;
77
+ const armDrain = () => {
78
+ if (closed)
79
+ return;
80
+ drain = setTimeout(() => {
81
+ child.stdout.destroy();
82
+ child.stderr.destroy();
83
+ }, EXIT_DRAIN_MS);
84
+ drain.unref?.();
85
+ };
86
+ const exit = new Promise((resolve) => {
87
+ child.once('error', (error) => {
88
+ spawnError = error;
89
+ reason = 'spawn-error';
90
+ });
91
+ child.once('exit', () => {
92
+ release();
93
+ armDrain();
94
+ });
95
+ child.once('close', (exitCode, exitSignal) => {
96
+ closed = true;
97
+ clearTimeout(drain);
98
+ clearTimeout(timer);
99
+ clearTimeout(escalation);
100
+ options.signal?.removeEventListener('abort', onAbort);
101
+ if (buffered.trim())
102
+ options.onLine(buffered.replace(/\r$/, ''));
103
+ buffered = '';
104
+ resolve({ exitCode, signal: exitSignal, reason, error: spawnError });
105
+ });
106
+ });
107
+ if (options.timeoutMs !== undefined)
108
+ timer = setTimeout(() => stop('timeout'), options.timeoutMs);
109
+ options.signal?.addEventListener('abort', onAbort, { once: true });
110
+ if (options.signal?.aborted)
111
+ onAbort();
112
+ child.stdin?.on('error', () => {
113
+ // The agent exited mid-write; its exit status reports why.
114
+ });
115
+ return {
116
+ exit,
117
+ kill: () => stop('aborted'),
118
+ close: () => stop('closed'),
119
+ write(line) {
120
+ if (!child.stdin || child.stdin.destroyed)
121
+ throw new Error(`${options.command} is not accepting input.`);
122
+ child.stdin.write(line.endsWith('\n') ? line : `${line}\n`);
123
+ },
124
+ pause() {
125
+ if (paused || !pausable || closed)
126
+ return;
127
+ paused = true;
128
+ child.stdout.pause();
129
+ child.stderr.pause();
130
+ },
131
+ resume() {
132
+ if (!paused)
133
+ return;
134
+ paused = false;
135
+ child.stdout.resume();
136
+ child.stderr.resume();
137
+ },
138
+ };
139
+ }
140
+ //# sourceMappingURL=process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process.js","sourceRoot":"","sources":["../../src/agents/process.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export interface RpcHandlers {
2
+ notification(method: string, params: unknown): void;
3
+ /** Resolve with the result, or throw to send a JSON-RPC error. */
4
+ request(method: string, params: unknown): unknown | Promise<unknown>;
5
+ }
6
+ export declare class RpcError extends Error {
7
+ readonly code: number;
8
+ constructor(message: string, code?: number);
9
+ }
10
+ /**
11
+ * Minimal JSON-RPC 2.0 peer over newline-delimited JSON. The caller owns the
12
+ * transport: it hands incoming values to `receive` and supplies `write`.
13
+ */
14
+ export declare class RpcPeer {
15
+ private readonly write;
16
+ private readonly handlers;
17
+ private nextId;
18
+ private failure;
19
+ private readonly pending;
20
+ constructor(write: (line: string) => void, handlers: RpcHandlers);
21
+ request(method: string, params?: unknown, timeoutMs?: number): Promise<unknown>;
22
+ notify(method: string, params?: unknown): void;
23
+ /** Handle one incoming JSON value. Returns false when it is not a JSON-RPC message. */
24
+ receive(message: unknown): boolean;
25
+ /** Reject everything in flight and refuse new requests. */
26
+ fail(error: Error): void;
27
+ private answer;
28
+ private send;
29
+ }