genaicode 2.3.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.
- package/CHANGELOG.md +25 -0
- package/README.md +59 -11
- package/dist/agents/cli-agent.d.ts +28 -0
- package/dist/agents/cli-agent.js +57 -0
- package/dist/agents/cli-agent.js.map +1 -0
- package/dist/agents/discovery.d.ts +10 -0
- package/dist/agents/discovery.js +31 -0
- package/dist/agents/discovery.js.map +1 -0
- package/dist/agents/drivers/claude.d.ts +25 -0
- package/dist/agents/drivers/claude.js +184 -0
- package/dist/agents/drivers/claude.js.map +1 -0
- package/dist/agents/drivers/codex-live.d.ts +17 -0
- package/dist/agents/drivers/codex-live.js +182 -0
- package/dist/agents/drivers/codex-live.js.map +1 -0
- package/dist/agents/drivers/codex.d.ts +27 -0
- package/dist/agents/drivers/codex.js +176 -0
- package/dist/agents/drivers/codex.js.map +1 -0
- package/dist/agents/drivers/copilot.d.ts +27 -0
- package/dist/agents/drivers/copilot.js +199 -0
- package/dist/agents/drivers/copilot.js.map +1 -0
- package/dist/agents/drivers/cursor.d.ts +23 -0
- package/dist/agents/drivers/cursor.js +174 -0
- package/dist/agents/drivers/cursor.js.map +1 -0
- package/dist/agents/drivers/gemini.d.ts +18 -0
- package/dist/agents/drivers/gemini.js +118 -0
- package/dist/agents/drivers/gemini.js.map +1 -0
- package/dist/agents/drivers/json.d.ts +6 -0
- package/dist/agents/drivers/json.js +20 -0
- package/dist/agents/drivers/json.js.map +1 -0
- package/dist/agents/drivers/muse-live.d.ts +17 -0
- package/dist/agents/drivers/muse-live.js +112 -0
- package/dist/agents/drivers/muse-live.js.map +1 -0
- package/dist/agents/drivers/muse.d.ts +12 -0
- package/dist/agents/drivers/muse.js +87 -0
- package/dist/agents/drivers/muse.js.map +1 -0
- package/dist/agents/drivers/opencode.d.ts +17 -0
- package/dist/agents/drivers/opencode.js +103 -0
- package/dist/agents/drivers/opencode.js.map +1 -0
- package/dist/agents/env.d.ts +16 -0
- package/dist/agents/env.js +46 -0
- package/dist/agents/env.js.map +1 -0
- package/dist/agents/event-queue.d.ts +44 -0
- package/dist/agents/event-queue.js +123 -0
- package/dist/agents/event-queue.js.map +1 -0
- package/dist/agents/hosted.d.ts +33 -0
- package/dist/agents/hosted.js +129 -0
- package/dist/agents/hosted.js.map +1 -0
- package/dist/agents/live-agent.d.ts +37 -0
- package/dist/agents/live-agent.js +142 -0
- package/dist/agents/live-agent.js.map +1 -0
- package/dist/agents/prepare.d.ts +33 -0
- package/dist/agents/prepare.js +52 -0
- package/dist/agents/prepare.js.map +1 -0
- package/dist/agents/process.d.ts +39 -0
- package/dist/agents/process.js +140 -0
- package/dist/agents/process.js.map +1 -0
- package/dist/agents/rpc.d.ts +29 -0
- package/dist/agents/rpc.js +101 -0
- package/dist/agents/rpc.js.map +1 -0
- package/dist/agents/runtime.d.ts +26 -0
- package/dist/agents/runtime.js +97 -0
- package/dist/agents/runtime.js.map +1 -0
- package/dist/agents/types.d.ts +158 -0
- package/dist/agents/types.js +2 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/agents/verify.d.ts +36 -0
- package/dist/agents/verify.js +43 -0
- package/dist/agents/verify.js.map +1 -0
- package/dist/agents.d.ts +36 -0
- package/dist/agents.js +19 -0
- package/dist/agents.js.map +1 -0
- package/dist/providers/google-converter.js +30 -14
- package/dist/providers/google-converter.js.map +1 -1
- package/dist/providers/google.d.ts +8 -0
- package/dist/providers/google.js.map +1 -1
- package/docs/agents.md +269 -0
- package/docs/pivot.md +4 -0
- package/docs/semver.md +5 -0
- package/package.json +5 -1
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export class RpcError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
constructor(message, code = -32000) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.code = code;
|
|
6
|
+
this.name = 'RpcError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Minimal JSON-RPC 2.0 peer over newline-delimited JSON. The caller owns the
|
|
11
|
+
* transport: it hands incoming values to `receive` and supplies `write`.
|
|
12
|
+
*/
|
|
13
|
+
export class RpcPeer {
|
|
14
|
+
write;
|
|
15
|
+
handlers;
|
|
16
|
+
nextId = 0;
|
|
17
|
+
failure;
|
|
18
|
+
pending = new Map();
|
|
19
|
+
constructor(write, handlers) {
|
|
20
|
+
this.write = write;
|
|
21
|
+
this.handlers = handlers;
|
|
22
|
+
}
|
|
23
|
+
request(method, params = {}, timeoutMs = 30_000) {
|
|
24
|
+
if (this.failure)
|
|
25
|
+
return Promise.reject(this.failure);
|
|
26
|
+
const id = ++this.nextId;
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
const timer = setTimeout(() => {
|
|
29
|
+
this.pending.delete(id);
|
|
30
|
+
reject(new RpcError(`No reply to ${method} within ${timeoutMs} ms; its outcome is unknown.`));
|
|
31
|
+
}, timeoutMs);
|
|
32
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
33
|
+
try {
|
|
34
|
+
this.send({ id, method, params });
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
clearTimeout(timer);
|
|
38
|
+
this.pending.delete(id);
|
|
39
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
notify(method, params = {}) {
|
|
44
|
+
this.send({ method, params });
|
|
45
|
+
}
|
|
46
|
+
/** Handle one incoming JSON value. Returns false when it is not a JSON-RPC message. */
|
|
47
|
+
receive(message) {
|
|
48
|
+
if (typeof message !== 'object' || message === null)
|
|
49
|
+
return false;
|
|
50
|
+
const { id, method, params, result, error } = message;
|
|
51
|
+
if (typeof method === 'string') {
|
|
52
|
+
if (id === undefined)
|
|
53
|
+
this.handlers.notification(method, params ?? {});
|
|
54
|
+
else
|
|
55
|
+
void this.answer(id, method, params ?? {});
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
if (id === undefined || !this.pending.has(id))
|
|
59
|
+
return false;
|
|
60
|
+
const waiter = this.pending.get(id);
|
|
61
|
+
this.pending.delete(id);
|
|
62
|
+
clearTimeout(waiter.timer);
|
|
63
|
+
if (error) {
|
|
64
|
+
waiter.reject(new RpcError(typeof error.message === 'string' ? error.message : 'Request rejected.', typeof error.code === 'number' ? error.code : undefined));
|
|
65
|
+
}
|
|
66
|
+
else
|
|
67
|
+
waiter.resolve(result ?? {});
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
/** Reject everything in flight and refuse new requests. */
|
|
71
|
+
fail(error) {
|
|
72
|
+
this.failure ??= error;
|
|
73
|
+
for (const waiter of this.pending.values()) {
|
|
74
|
+
clearTimeout(waiter.timer);
|
|
75
|
+
waiter.reject(error);
|
|
76
|
+
}
|
|
77
|
+
this.pending.clear();
|
|
78
|
+
}
|
|
79
|
+
async answer(id, method, params) {
|
|
80
|
+
try {
|
|
81
|
+
const result = await this.handlers.request(method, params);
|
|
82
|
+
this.send({ id, result: result ?? {} });
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
const code = error instanceof RpcError ? error.code : -32000;
|
|
86
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
87
|
+
try {
|
|
88
|
+
this.send({ id, error: { code, message } });
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Transport closed; the exit status reports why.
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
send(value) {
|
|
96
|
+
if (this.failure)
|
|
97
|
+
throw this.failure;
|
|
98
|
+
this.write(JSON.stringify({ jsonrpc: '2.0', ...value }));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=rpc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../src/agents/rpc.ts"],"names":[],"mappings":"AAQA,MAAM,OAAO,QAAS,SAAQ,KAAK;IAGtB;IAFX,YACE,OAAe,EACN,OAAO,CAAC,KAAK;QAEtB,KAAK,CAAC,OAAO,CAAC,CAAC;QAFN,SAAI,GAAJ,IAAI,CAAS;QAGtB,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,OAAO;IASC;IACA;IATX,MAAM,GAAG,CAAC,CAAC;IACX,OAAO,CAAoB;IAClB,OAAO,GAAG,IAAI,GAAG,EAG/B,CAAC;IAEJ,YACmB,KAA6B,EAC7B,QAAqB;QADrB,UAAK,GAAL,KAAK,CAAwB;QAC7B,aAAQ,GAAR,QAAQ,CAAa;IACrC,CAAC;IAEJ,OAAO,CAAC,MAAc,EAAE,SAAkB,EAAE,EAAE,SAAS,GAAG,MAAM;QAC9D,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtD,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC;QACzB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACxB,MAAM,CAAC,IAAI,QAAQ,CAAC,eAAe,MAAM,WAAW,SAAS,8BAA8B,CAAC,CAAC,CAAC;YAChG,CAAC,EAAE,SAAS,CAAC,CAAC;YACd,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YACjD,IAAI,CAAC;gBACH,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;YACpC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACxB,MAAM,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACpE,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,MAAc,EAAE,SAAkB,EAAE;QACzC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,uFAAuF;IACvF,OAAO,CAAC,OAAgB;QACtB,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAClE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,OAM7C,CAAC;QACF,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC/B,IAAI,EAAE,KAAK,SAAS;gBAAE,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC;;gBAClE,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC;YAChD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,EAAE,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,OAAO,KAAK,CAAC;QAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC;QACrC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACxB,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,CAAC,MAAM,CACX,IAAI,QAAQ,CACV,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,EACvE,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CACxD,CACF,CAAC;QACJ,CAAC;;YAAM,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,2DAA2D;IAC3D,IAAI,CAAC,KAAY;QACf,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC;QACvB,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC3C,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC3B,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,MAAM,CAAC,EAAa,EAAE,MAAc,EAAE,MAAe;QACjE,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAC3D,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,GAAG,KAAK,YAAY,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YAC7D,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,IAAI,CAAC;gBACH,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;YAC9C,CAAC;YAAC,MAAM,CAAC;gBACP,iDAAiD;YACnD,CAAC;QACH,CAAC;IACH,CAAC;IAEO,IAAI,CAAC,KAA8B;QACzC,IAAI,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,CAAC,OAAO,CAAC;QACrC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC;IAC3D,CAAC;CACF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { EventQueue } from './event-queue.js';
|
|
2
|
+
import type { ProcessExit } from './process.js';
|
|
3
|
+
import type { AgentEvent, AgentResult } from './types.js';
|
|
4
|
+
/** What a driver reports about the task's end, beyond the exit code. */
|
|
5
|
+
export interface AgentOutcome {
|
|
6
|
+
ok: boolean;
|
|
7
|
+
error?: string;
|
|
8
|
+
}
|
|
9
|
+
/** Collects events for iteration and folds them into the pieces of an `AgentResult`. */
|
|
10
|
+
export declare class RunRecorder {
|
|
11
|
+
private readonly name;
|
|
12
|
+
private readonly command;
|
|
13
|
+
readonly events: EventQueue<AgentEvent>;
|
|
14
|
+
private sessionId?;
|
|
15
|
+
private text?;
|
|
16
|
+
private usage?;
|
|
17
|
+
private costUsd?;
|
|
18
|
+
private lastError?;
|
|
19
|
+
private stderrTail;
|
|
20
|
+
constructor(name: string, command: string);
|
|
21
|
+
emit(event: AgentEvent): void;
|
|
22
|
+
/** Build the result, emit `done`, and end the event stream. */
|
|
23
|
+
finish(exit: ProcessExit, outcome: AgentOutcome | undefined): AgentResult;
|
|
24
|
+
private errorOf;
|
|
25
|
+
}
|
|
26
|
+
export declare function invalidCwd(cwd: string): string | undefined;
|