@wrongstack/acp 0.31.1 → 0.41.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/dist/agent.d.ts +8 -0
- package/dist/agent.js +10 -5
- package/dist/agent.js.map +1 -1
- package/dist/client.js +4 -4
- package/dist/client.js.map +1 -1
- package/dist/index.js +13 -8
- package/dist/index.js.map +1 -1
- package/package.json +22 -2
package/dist/agent.d.ts
CHANGED
|
@@ -83,6 +83,14 @@ declare class WrongStackACPServer {
|
|
|
83
83
|
* 1. Send the startup marker `[wstack-acp]` so the client
|
|
84
84
|
* knows which stdout line is the protocol boundary.
|
|
85
85
|
* 2. Loop: read messages, dispatch to handler, until EOF or error.
|
|
86
|
+
*
|
|
87
|
+
* Single dispatch path: every inbound message is read exactly once
|
|
88
|
+
* from the transport and passed to the protocol handler exactly once.
|
|
89
|
+
* An earlier version combined a `transport.onMessage` callback with
|
|
90
|
+
* this read loop, which caused every message to be processed twice
|
|
91
|
+
* (once by the callback, once by the loop) — duplicate tool calls
|
|
92
|
+
* and duplicate responses to the client. See the ACP double-dispatch
|
|
93
|
+
* fix in the security audit (P1-001).
|
|
86
94
|
*/
|
|
87
95
|
start(): Promise<void>;
|
|
88
96
|
/** Stop the server. */
|
package/dist/agent.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import '@wrongstack/core';
|
|
1
|
+
import { writeErr } from '@wrongstack/core';
|
|
2
2
|
import 'child_process';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
|
|
@@ -381,13 +381,18 @@ var WrongStackACPServer = class {
|
|
|
381
381
|
* 1. Send the startup marker `[wstack-acp]` so the client
|
|
382
382
|
* knows which stdout line is the protocol boundary.
|
|
383
383
|
* 2. Loop: read messages, dispatch to handler, until EOF or error.
|
|
384
|
+
*
|
|
385
|
+
* Single dispatch path: every inbound message is read exactly once
|
|
386
|
+
* from the transport and passed to the protocol handler exactly once.
|
|
387
|
+
* An earlier version combined a `transport.onMessage` callback with
|
|
388
|
+
* this read loop, which caused every message to be processed twice
|
|
389
|
+
* (once by the callback, once by the loop) — duplicate tool calls
|
|
390
|
+
* and duplicate responses to the client. See the ACP double-dispatch
|
|
391
|
+
* fix in the security audit (P1-001).
|
|
384
392
|
*/
|
|
385
393
|
async start() {
|
|
386
394
|
this.transport.sendStartupMarker();
|
|
387
395
|
this.running = true;
|
|
388
|
-
this.transport.onMessage((msg) => {
|
|
389
|
-
void this.handler.handleMessage(msg);
|
|
390
|
-
});
|
|
391
396
|
while (this.running) {
|
|
392
397
|
const msg = await this.transport.read();
|
|
393
398
|
if (!msg) break;
|
|
@@ -409,7 +414,7 @@ async function main() {
|
|
|
409
414
|
var isEntrypoint = process.argv[1] !== void 0 && fileURLToPath(import.meta.url) === process.argv[1];
|
|
410
415
|
if (isEntrypoint) {
|
|
411
416
|
main().catch((err) => {
|
|
412
|
-
|
|
417
|
+
writeErr(`[wstack-acp fatal] ${err}
|
|
413
418
|
`);
|
|
414
419
|
process.exit(1);
|
|
415
420
|
});
|
package/dist/agent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/agent/stdio-transport.ts","../src/agent/tools-registry.ts","../src/agent/protocol-handler.ts","../src/agent/wrongstack-acp-agent.ts"],"names":[],"mappings":"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","file":"agent.js","sourcesContent":["/**\n * StdioTransport — bidirectional stdin/stdout communication for ACP.\n *\n * ACP uses newline-delimited JSON-RPC 2.0 messages over stdio:\n * client → agent: JSON-RPC request/notification on stdin\n * agent → client: JSON-RPC response/notification on stdout\n *\n * Start message: clients look for the `[wstack-acp]` marker on stdout before\n * treating subsequent lines as protocol messages.\n */\nimport { buildChildEnv } from '@wrongstack/core';\nimport type { ACPMessage } from '../types/acp-messages.js';\n\nexport interface AgentServerTransport {\n send(msg: ACPMessage): Promise<void>;\n sendRaw(chunk: string): void;\n read(): Promise<ACPMessage | null>;\n close(): void;\n onMessage(handler: (msg: ACPMessage) => void): () => void;\n}\n\nexport class StdioTransport implements AgentServerTransport {\n private readonly stdin = process.stdin;\n private readonly stdout = process.stdout;\n private readonly stderr = process.stderr;\n\n private buffer = '';\n private readonly handlers = new Set<(msg: ACPMessage) => void>();\n private closed = false;\n private resolveRead: ((msg: ACPMessage | null) => void) | null = null;\n private messageQueue: ACPMessage[] = [];\n\n constructor() {\n this.stdin.resume();\n this.stdin.setEncoding('utf8');\n this.stdin.on('data', (chunk: string) => this.onData(chunk));\n this.stdin.on('end', () => this.handleClose());\n this.stdin.on('error', (err: Error) => this.failAll(err));\n }\n\n sendStartupMarker(): void {\n this.stdout.write('[wstack-acp]\\n', 'utf8');\n }\n\n send(msg: ACPMessage): Promise<void> {\n if (this.closed) return Promise.resolve();\n return new Promise((resolve) => {\n const line = JSON.stringify(msg) + '\\n';\n this.stdout.write(line, 'utf8', () => resolve());\n });\n }\n\n sendRaw(chunk: string): void {\n this.stdout.write(chunk, 'utf8');\n }\n\n read(): Promise<ACPMessage | null> {\n if (this.messageQueue.length > 0) return Promise.resolve(this.messageQueue.shift()!);\n if (this.closed) return Promise.resolve(null);\n return new Promise((resolve) => {\n this.resolveRead = resolve;\n });\n }\n\n onMessage(handler: (msg: ACPMessage) => void): () => void {\n this.handlers.add(handler);\n return () => this.handlers.delete(handler);\n }\n\n close(): void {\n this.closed = true;\n this.stdin.pause();\n this.resolveRead?.(null);\n this.resolveRead = null;\n }\n\n private onData(chunk: string): void {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() ?? '';\n\n for (const raw of lines) {\n if (!raw.trim()) continue;\n try {\n this.dispatch(JSON.parse(raw) as ACPMessage);\n } catch (err) {\n this.stderr.write(`[wstack-acp parse error] ${err}\\n`, 'utf8');\n }\n }\n }\n\n private dispatch(msg: ACPMessage): void {\n if (this.resolveRead) {\n const resolve = this.resolveRead;\n this.resolveRead = null;\n resolve(msg);\n } else {\n this.messageQueue.push(msg);\n }\n for (const handler of this.handlers) {\n try {\n handler(msg);\n } catch (err) {\n this.stderr.write(`[wstack-acp handler error] ${err}\\n`, 'utf8');\n }\n }\n }\n\n private handleClose(): void {\n this.closed = true;\n this.resolveRead?.(null);\n this.resolveRead = null;\n }\n\n private failAll(err: Error): void {\n this.stderr.write(`[wstack-acp stdin error] ${err.message}\\n`, 'utf8');\n this.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// ClientTransport — spawns a child ACP agent process (DIR-1)\n// ---------------------------------------------------------------------------\n\nimport { spawn } from 'node:child_process';\nimport type { EventEmitter } from 'node:events';\n\nexport interface ClientTransportOptions {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n handshakeTimeoutMs?: number;\n}\n\nexport interface ACPChildProcess extends EventEmitter {\n stdout: NodeJS.ReadableStream;\n stdin: NodeJS.WritableStream;\n stderr: NodeJS.ReadableStream;\n pid: number | undefined;\n kill(): void;\n}\n\nexport class ClientTransport {\n private child: ACPChildProcess | null = null;\n private buffer = '';\n private readonly handlers = new Set<(msg: ACPMessage) => void>();\n private closed = false;\n private resolveRead: ((msg: ACPMessage | null) => void) | null = null;\n private messageQueue: ACPMessage[] = [];\n private readonly opts: Required<Pick<ClientTransportOptions, 'handshakeTimeoutMs'>> &\n ClientTransportOptions;\n\n constructor(options: ClientTransportOptions) {\n this.opts = {\n handshakeTimeoutMs: 30_000,\n ...options,\n };\n }\n\n async start(): Promise<void> {\n if (this.child) return;\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(`ACP child process failed to start within ${this.opts.handshakeTimeoutMs}ms`),\n );\n }, this.opts.handshakeTimeoutMs);\n\n try {\n this.child = spawn(this.opts.command, this.opts.args ?? [], {\n env: { ...buildChildEnv(), ...this.opts.env },\n cwd: this.opts.cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n }) as unknown as ACPChildProcess;\n } catch (err) {\n clearTimeout(timeout);\n reject(err);\n return;\n }\n\n const child = this.child;\n\n child.stdout.setEncoding('utf8');\n\n const waitForMarker = (chunk: string) => {\n this.buffer += chunk;\n const idx = this.buffer.indexOf('[wstack-acp]\\n');\n if (idx !== -1) {\n this.buffer = this.buffer.slice(idx + '[wstack-acp]\\n'.length);\n child.stdout.removeListener('data', waitForMarker);\n child.stdout.on('data', (c: string) => this.onChildData(c));\n child.stderr.on('data', (c: string) => this.onChildError(c));\n child.on('close', (code: number | null) => this.onChildClose(code));\n clearTimeout(timeout);\n resolve();\n }\n };\n\n child.stdout.on('data', waitForMarker);\n child.stdout.on('error', (err: Error) => {\n clearTimeout(timeout);\n reject(err);\n });\n child.on('error', (err: Error) => {\n clearTimeout(timeout);\n reject(err);\n });\n });\n }\n\n send(msg: ACPMessage): Promise<void> {\n if (!this.child) return Promise.reject(new Error('ClientTransport not started'));\n return new Promise((resolve, reject) => {\n const line = JSON.stringify(msg) + '\\n';\n this.child!.stdin.write(line, 'utf8', (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n }\n\n read(): Promise<ACPMessage | null> {\n if (this.messageQueue.length > 0) return Promise.resolve(this.messageQueue.shift()!);\n if (this.closed) return Promise.resolve(null);\n return new Promise((resolve) => {\n this.resolveRead = resolve;\n });\n }\n\n onMessage(handler: (msg: ACPMessage) => void): () => void {\n this.handlers.add(handler);\n return () => this.handlers.delete(handler);\n }\n\n stop(): void {\n if (!this.child) return;\n this.closed = true;\n try {\n this.child.kill();\n } catch {\n // already dead\n }\n this.child = null;\n }\n\n private onChildData(chunk: string): void {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() ?? '';\n\n for (const raw of lines) {\n if (!raw.trim()) continue;\n try {\n this.dispatch(JSON.parse(raw) as ACPMessage);\n } catch {\n // skip malformed\n }\n }\n }\n\n private onChildError(chunk: string): void {\n process.stderr.write(`[acp-child stderr] ${chunk}`, 'utf8');\n }\n\n private onChildClose(code: number | null): void {\n this.closed = true;\n this.resolveRead?.(null);\n this.resolveRead = null;\n if (code !== 0 && code !== null) {\n process.stderr.write(`[acp-child exited with code ${code}]\\n`, 'utf8');\n }\n }\n\n private dispatch(msg: ACPMessage): void {\n if (this.resolveRead) {\n const resolve = this.resolveRead;\n this.resolveRead = null;\n resolve(msg);\n } else {\n this.messageQueue.push(msg);\n }\n for (const handler of this.handlers) {\n try {\n handler(msg);\n } catch {\n // non-fatal\n }\n }\n }\n}\n","/**\n * Tools registry for ACP agent-side.\n *\n * Translates WrongStack Tool definitions → ACP ACPToolDefinition format.\n * Provides tool lookup and result assembly for the ACP protocol handler.\n */\nimport type {Tool} from '@wrongstack/core';\nimport type {\n ACPToolDefinition,\n ACPToolList,\n ACPInputSchema,\n ACPToolResult,\n ContentBlock,\n} from '../types/acp-messages.js';\n\nexport class ACPToolsRegistry {\n private tools = new Map<string, Tool>();\n private readonly owner: string;\n\n constructor(owner = 'wrongstack') {\n this.owner = owner;\n }\n\n /**\n * Register one or more tools.\n * Throws on duplicate name unless force=true.\n */\n register(tools: Tool[]): void {\n for (const tool of tools) {\n this.tools.set(tool.name, tool);\n }\n }\n\n /**\n * Replace the current tool set.\n */\n setTools(tools: Tool[]): void {\n this.tools.clear();\n for (const tool of tools) this.tools.set(tool.name, tool);\n }\n\n get(name: string): Tool | undefined {\n return this.tools.get(name);\n }\n\n has(name: string): boolean {\n return this.tools.has(name);\n }\n\n list(): Tool[] {\n return Array.from(this.tools.values());\n }\n\n /** Build the ACP tools/list payload from registered tools. */\n buildToolList(): ACPToolList {\n return {\n tools: Array.from(this.tools.values()).map((t) =>\n toACPToolDefinition(t, this.owner),\n ),\n };\n }\n\n /**\n * Execute a tool by name and return ACP-formatted result.\n * Returns null if the tool is not found.\n */\n async execute(\n name: string,\n args: Record<string, unknown>,\n ctx: unknown,\n signal: AbortSignal,\n ): Promise<ACPToolResult | null> {\n const tool = this.tools.get(name);\n if (!tool) return null;\n\n try {\n const result = await tool.execute(args, ctx as Parameters<Tool['execute']>[1], {\n signal,\n });\n return toACPToolResult(result);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {content: [{type: 'text', text: msg}], isError: true} satisfies ACPToolResult;\n }\n }\n}\n\n/** Convert a WrongStack Tool → ACP ACPToolDefinition */\nfunction toACPToolDefinition(tool: Tool, _owner: string): ACPToolDefinition {\n return {\n name: tool.name,\n description: tool.description,\n inputSchema: toACPInputSchema(tool.inputSchema),\n annotations: {\n title: tool.name,\n description: tool.usageHint ?? tool.description,\n priority: toolToPriority(tool),\n alwaysAccept: tool.permission === 'auto',\n },\n };\n}\n\n/** Minimal JSON Schema → ACP input schema. ACP uses JSON Schema draft-07. */\nfunction toACPInputSchema(src: unknown): ACPInputSchema {\n if (!src || typeof src !== 'object') {\n return {};\n }\n const s = src as Record<string, unknown>;\n\n // Recursively convert properties\n if (s.properties && typeof s.properties === 'object') {\n const props: Record<string, ACPInputSchema> = {};\n for (const [k, v] of Object.entries(s.properties as Record<string, unknown>)) {\n props[k] = toACPInputSchema(v);\n }\n return {\n type: typeof s.type === 'string' ? s.type : undefined,\n properties: props,\n required: Array.isArray(s.required) ? (s.required as string[]) : undefined,\n items: s.items ? toACPInputSchema(s.items) : undefined,\n enum: Array.isArray(s.enum) ? s.enum : undefined,\n description: typeof s.description === 'string' ? s.description : undefined,\n default: s.default,\n minimum: typeof s.minimum === 'number' ? s.minimum : undefined,\n maximum: typeof s.maximum === 'number' ? s.maximum : undefined,\n };\n }\n\n return {\n type: typeof s.type === 'string' ? s.type : undefined,\n items: s.items ? toACPInputSchema(s.items) : undefined,\n enum: Array.isArray(s.enum) ? s.enum : undefined,\n description: typeof s.description === 'string' ? s.description : undefined,\n default: s.default,\n minimum: typeof s.minimum === 'number' ? s.minimum : undefined,\n maximum: typeof s.maximum === 'number' ? s.maximum : undefined,\n };\n}\n\n/** Convert a WrongStack ToolResult → ACP ContentBlock[] */\nfunction toACPToolResult(result: unknown): ACPToolResult {\n const blocks: ContentBlock[] = [];\n\n if (result === undefined || result === null) {\n return {content: [{type: 'text', text: 'ok'}]};\n }\n\n if (typeof result === 'string') {\n blocks.push({type: 'text', text: result});\n } else if (typeof result === 'object') {\n blocks.push({type: 'text', text: JSON.stringify(result, null, 2)});\n } else {\n blocks.push({type: 'text', text: String(result)});\n }\n\n return {content: blocks};\n}\n\nfunction toolToPriority(tool: Tool): 'high' | 'medium' | 'low' {\n if (tool.riskTier === 'destructive') return 'high';\n if (tool.riskTier === 'standard' || tool.permission === 'confirm') return 'medium';\n return 'low';\n}\n","/**\n * ACPProtocolHandler — state machine for ACP server-side message handling.\n *\n * ACP turn lifecycle:\n * idle → [initialize] → await-turn → [tools/call] → executing\n * → [tool result sent] → idle\n *\n * We implement this as a simple switch on the method name, since the ACP\n * protocol is request/response based (not streaming) on the wire.\n *\n * Concurrency: ACP allows Cancellations and multiple concurrent tool calls\n * within a turn. We handle each tools/call in its own Promise.all.\n */\nimport type {\n ACPMessage,\n ACPRequest,\n ACPNotification,\n ACPInitializeParams,\n ACPToolCallRequest,\n ACPToolResult,\n ACPToolCallResponse,\n} from '../types/acp-messages.js';\nimport type {AgentServerTransport} from './stdio-transport.js';\n\nexport const WRONGSTACK_VERSION = '0.1.0';\nconst WRONGSTACK_CAPABILITIES = [\n 'code-generation',\n 'async-tools',\n 'streaming',\n 'progress',\n];\n\nexport class ACPProtocolHandler {\n private initialized = false;\n private readonly signal = new AbortController();\n private pendingCalls = new Map<string | number, Promise<unknown>>();\n\n constructor(\n private readonly transport: AgentServerTransport,\n private readonly registry: import('./tools-registry.js').ACPToolsRegistry,\n private readonly context: unknown,\n ) {}\n\n /** Wire an external abort signal from the ACP client */\n wireAbortController(abortController: AbortController): void {\n abortController.signal.addEventListener('abort', () => {\n for (const id of this.pendingCalls.keys()) {\n this.transport.send({id, method: 'cancel', result: {ok: true}}).catch(() => {});\n }\n });\n }\n\n /** Process one inbound message. Returns true if this was a terminal message. */\n async handleMessage(msg: ACPMessage): Promise<boolean> {\n if (msg.id !== undefined) {\n return this.handleRequest(msg as ACPRequest);\n }\n return this.handleNotification(msg as ACPNotification);\n }\n\n private async handleRequest(req: ACPRequest): Promise<boolean> {\n if (req.method !== 'initialize' && !this.initialized) {\n await this.sendError(req.id ?? null, -32000, 'Not initialized');\n return false;\n }\n\n // All requests after initialization check have a guaranteed id\n const id = req.id as string | number;\n\n switch (req.method) {\n case 'initialize':\n return this.handleInitialize(req as ACPRequest & {params: ACPInitializeParams}, id);\n case 'ping':\n await this.transport.send({id, method: 'ping', result: {pong: true}});\n return false;\n case 'tools/call':\n return this.handleToolCall(req as ACPRequest & {params: ACPToolCallRequest['params']}, id);\n case 'tools/list':\n return this.handleToolsList(id);\n case 'cancel':\n return this.handleCancel(id);\n case 'session/list':\n return this.handleSessionList(id);\n case 'sessionInfoUpdate':\n await this.transport.send({id, method: 'sessionInfoUpdate', result: {ok: true}});\n return false;\n default:\n await this.sendError(id, -32601, `Unknown method: ${req.method}`);\n return false;\n }\n }\n\n private async handleNotification(n: ACPNotification): Promise<boolean> {\n if (n.method === 'cancel') {\n this.handleCancelNotification(n as ACPNotification & {params?: {reason?: string}});\n }\n return false;\n }\n\n private async handleInitialize(\n req: ACPRequest & {params: ACPInitializeParams},\n id: string | number,\n ): Promise<boolean> {\n this.initialized = true;\n\n const result = {\n capabilities: WRONGSTACK_CAPABILITIES,\n agentName: 'WrongStack',\n agentVersion: WRONGSTACK_VERSION,\n protocolVersion: req.params?.protocolVersion ?? '2024-11',\n ...this.registry.buildToolList(),\n };\n\n await this.transport.send({id, method: 'initialize', result});\n return false;\n }\n\n private async handleToolsList(id: string | number): Promise<boolean> {\n await this.transport.send({\n id,\n method: 'tools/list',\n result: this.registry.buildToolList(),\n });\n return false;\n }\n\n private async handleToolCall(\n req: ACPRequest & {params: {name: string; arguments: Record<string, unknown>}},\n id: string | number,\n ): Promise<boolean> {\n const {name, arguments: args} = req.params;\n\n const runPromise = (async () => {\n if (!this.registry.has(name)) {\n return {\n content: [{type: 'text', text: `Tool not found: ${name}`}],\n isError: true,\n } satisfies ACPToolResult;\n }\n\n const result = await this.registry.execute(\n name,\n args,\n this.context,\n this.signal.signal,\n );\n return result ?? {content: [{type: 'text', text: 'Tool returned null'}], isError: false};\n })();\n\n this.pendingCalls.set(id, runPromise);\n\n try {\n const toolResult = (await runPromise) as ACPToolResult;\n this.pendingCalls.delete(id);\n\n const response: ACPToolCallResponse = {method: 'tools/call', id, result: toolResult};\n await this.transport.send(response);\n } catch (err) {\n this.pendingCalls.delete(id);\n const msg = err instanceof Error ? err.message : String(err);\n await this.transport.send({\n id,\n method: 'tools/call',\n result: {content: [{type: 'text', text: msg}], isError: true},\n });\n }\n\n return false;\n }\n\n private async handleCancel(id: string | number): Promise<boolean> {\n this.pendingCalls.delete(id);\n await this.transport.send({id, method: 'cancel', result: {ok: true}});\n return false;\n }\n\n private handleCancelNotification(\n _n: ACPNotification & {params?: {reason?: string}},\n ): void {\n // Broadcast cancellation to all pending — best-effort\n }\n\n private async handleSessionList(id: string | number): Promise<boolean> {\n await this.transport.send({\n id,\n method: 'session/list',\n result: {sessions: []},\n });\n return false;\n }\n\n private async sendError(id: string | number | null, code: number, message: string): Promise<void> {\n if (id === null) return;\n await this.transport.send({id, method: '', error: {code, message}});\n }\n}\n","/**\n * WrongStackACPServer — ACP server-side entry point.\n *\n * Exposes WrongStack as an ACP-compatible agent. ACP clients (Zed, JetBrains,\n * VS Code ACP extension) spawn this as a subprocess, send JSON-RPC messages\n * over stdio, and receive tool responses.\n *\n * Usage:\n * node dist/agent/wrongstack-acp-agent.js\n *\n * Or via the CLI:\n * wstack acp-server\n *\n * Startup: sends `[wstack-acp]\\n` to stdout so the client knows which process\n * is the ACP server before protocol messages begin.\n */\nimport {fileURLToPath} from 'node:url';\nimport {StdioTransport} from './stdio-transport.js';\nimport {ACPToolsRegistry} from './tools-registry.js';\nimport {ACPProtocolHandler} from './protocol-handler.js';\nimport type {Tool} from '@wrongstack/core';\n\nexport interface WrongStackACPServerOptions {\n /**\n * Initial tool set. Typically loaded from the WrongStack tool registry\n * via `api.tools.list()` so the ACP server exposes exactly the tools the\n * CLI has configured.\n */\n tools: Tool[];\n /**\n * Owner label for tool metadata. Passed to ACPToolsRegistry.\n * @default 'wrongstack'\n */\n owner?: string;\n}\n\nexport class WrongStackACPServer {\n private readonly transport: StdioTransport;\n private readonly registry: ACPToolsRegistry;\n private readonly handler: ACPProtocolHandler;\n private running = false;\n\n constructor(opts: WrongStackACPServerOptions) {\n this.transport = new StdioTransport();\n this.registry = new ACPToolsRegistry(opts.owner);\n this.registry.register(opts.tools);\n this.handler = new ACPProtocolHandler(\n this.transport,\n this.registry,\n /* TODO: load WrongStack Context */ {},\n );\n }\n\n /**\n * Start the server. Blocks until the client disconnects.\n *\n * 1. Send the startup marker `[wstack-acp]` so the client\n * knows which stdout line is the protocol boundary.\n * 2. Loop: read messages, dispatch to handler, until EOF or error.\n */\n async start(): Promise<void> {\n this.transport.sendStartupMarker();\n this.running = true;\n\n // Handle messages via callback + read loop hybrid\n this.transport.onMessage((msg) => {\n void this.handler.handleMessage(msg); // fire-and-forget; ordering is per-message\n });\n\n while (this.running) {\n const msg = await this.transport.read();\n if (!msg) break; // EOF\n const terminal = await this.handler.handleMessage(msg);\n if (terminal) break;\n }\n\n this.transport.close();\n }\n\n /** Stop the server. */\n stop(): void {\n this.running = false;\n this.transport.close();\n }\n}\n\n/**\n * Bootstrap function for `node dist/agent/wrongstack-acp-agent.js`.\n * Instantiates the server with the default tool set.\n *\n * Tool loading: the ACP agent is a subprocess without the full CLI context,\n * so it needs to receive its tools from the parent via environment or a\n * pre-main bootstrap. For now, it uses an empty tool set unless tools are\n * explicitly passed via constructor options.\n *\n * In practice the CLI will instantiate and run WrongStackACPServer directly,\n * passing `api.tools.list()` as the tool set.\n */\nasync function main(): Promise<void> {\n const server = new WrongStackACPServer({tools: []});\n await server.start();\n}\n\n// Only auto-start when this file is the process entrypoint (e.g.\n// `node dist/agent/wrongstack-acp-agent.js`). Importing the module — which the\n// CLI does to reuse `WrongStackACPServer` — must stay side-effect-free, or\n// every launch would start an ACP server and hijack stdin.\nconst isEntrypoint = process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1];\nif (isEntrypoint) {\n main().catch((err) => {\n process.stderr.write(`[wstack-acp fatal] ${err}\\n`);\n process.exit(1);\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/agent/stdio-transport.ts","../src/agent/tools-registry.ts","../src/agent/protocol-handler.ts","../src/agent/wrongstack-acp-agent.ts"],"names":["writeErr"],"mappings":"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","file":"agent.js","sourcesContent":["/**\n * StdioTransport — bidirectional stdin/stdout communication for ACP.\n *\n * ACP uses newline-delimited JSON-RPC 2.0 messages over stdio:\n * client → agent: JSON-RPC request/notification on stdin\n * agent → client: JSON-RPC response/notification on stdout\n *\n * Start message: clients look for the `[wstack-acp]` marker on stdout before\n * treating subsequent lines as protocol messages.\n */\nimport { buildChildEnv, writeErr } from '@wrongstack/core';\nimport type { ACPMessage } from '../types/acp-messages.js';\n\nexport interface AgentServerTransport {\n send(msg: ACPMessage): Promise<void>;\n sendRaw(chunk: string): void;\n read(): Promise<ACPMessage | null>;\n close(): void;\n onMessage(handler: (msg: ACPMessage) => void): () => void;\n}\n\nexport class StdioTransport implements AgentServerTransport {\n private readonly stdin = process.stdin;\n private readonly stdout = process.stdout;\n private readonly stderr = process.stderr;\n\n private buffer = '';\n private readonly handlers = new Set<(msg: ACPMessage) => void>();\n private closed = false;\n private resolveRead: ((msg: ACPMessage | null) => void) | null = null;\n private messageQueue: ACPMessage[] = [];\n\n constructor() {\n this.stdin.resume();\n this.stdin.setEncoding('utf8');\n this.stdin.on('data', (chunk: string) => this.onData(chunk));\n this.stdin.on('end', () => this.handleClose());\n this.stdin.on('error', (err: Error) => this.failAll(err));\n }\n\n sendStartupMarker(): void {\n this.stdout.write('[wstack-acp]\\n', 'utf8');\n }\n\n send(msg: ACPMessage): Promise<void> {\n if (this.closed) return Promise.resolve();\n return new Promise((resolve) => {\n const line = JSON.stringify(msg) + '\\n';\n this.stdout.write(line, 'utf8', () => resolve());\n });\n }\n\n sendRaw(chunk: string): void {\n this.stdout.write(chunk, 'utf8');\n }\n\n read(): Promise<ACPMessage | null> {\n if (this.messageQueue.length > 0) return Promise.resolve(this.messageQueue.shift()!);\n if (this.closed) return Promise.resolve(null);\n return new Promise((resolve) => {\n this.resolveRead = resolve;\n });\n }\n\n onMessage(handler: (msg: ACPMessage) => void): () => void {\n this.handlers.add(handler);\n return () => this.handlers.delete(handler);\n }\n\n close(): void {\n this.closed = true;\n this.stdin.pause();\n this.resolveRead?.(null);\n this.resolveRead = null;\n }\n\n private onData(chunk: string): void {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() ?? '';\n\n for (const raw of lines) {\n if (!raw.trim()) continue;\n try {\n this.dispatch(JSON.parse(raw) as ACPMessage);\n } catch (err) {\n this.stderr.write(`[wstack-acp parse error] ${err}\\n`, 'utf8');\n }\n }\n }\n\n private dispatch(msg: ACPMessage): void {\n if (this.resolveRead) {\n const resolve = this.resolveRead;\n this.resolveRead = null;\n resolve(msg);\n } else {\n this.messageQueue.push(msg);\n }\n for (const handler of this.handlers) {\n try {\n handler(msg);\n } catch (err) {\n this.stderr.write(`[wstack-acp handler error] ${err}\\n`, 'utf8');\n }\n }\n }\n\n private handleClose(): void {\n this.closed = true;\n this.resolveRead?.(null);\n this.resolveRead = null;\n }\n\n private failAll(err: Error): void {\n this.stderr.write(`[wstack-acp stdin error] ${err.message}\\n`, 'utf8');\n this.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// ClientTransport — spawns a child ACP agent process (DIR-1)\n// ---------------------------------------------------------------------------\n\nimport { spawn } from 'node:child_process';\nimport type { EventEmitter } from 'node:events';\n\nexport interface ClientTransportOptions {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n handshakeTimeoutMs?: number;\n}\n\nexport interface ACPChildProcess extends EventEmitter {\n stdout: NodeJS.ReadableStream;\n stdin: NodeJS.WritableStream;\n stderr: NodeJS.ReadableStream;\n pid: number | undefined;\n kill(): void;\n}\n\nexport class ClientTransport {\n private child: ACPChildProcess | null = null;\n private buffer = '';\n private readonly handlers = new Set<(msg: ACPMessage) => void>();\n private closed = false;\n private resolveRead: ((msg: ACPMessage | null) => void) | null = null;\n private messageQueue: ACPMessage[] = [];\n private readonly opts: Required<Pick<ClientTransportOptions, 'handshakeTimeoutMs'>> &\n ClientTransportOptions;\n\n constructor(options: ClientTransportOptions) {\n this.opts = {\n handshakeTimeoutMs: 30_000,\n ...options,\n };\n }\n\n async start(): Promise<void> {\n if (this.child) return;\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(`ACP child process failed to start within ${this.opts.handshakeTimeoutMs}ms`),\n );\n }, this.opts.handshakeTimeoutMs);\n\n try {\n this.child = spawn(this.opts.command, this.opts.args ?? [], {\n env: { ...buildChildEnv(), ...this.opts.env },\n cwd: this.opts.cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n }) as unknown as ACPChildProcess;\n } catch (err) {\n clearTimeout(timeout);\n reject(err);\n return;\n }\n\n const child = this.child;\n\n child.stdout.setEncoding('utf8');\n\n const waitForMarker = (chunk: string) => {\n this.buffer += chunk;\n const idx = this.buffer.indexOf('[wstack-acp]\\n');\n if (idx !== -1) {\n this.buffer = this.buffer.slice(idx + '[wstack-acp]\\n'.length);\n child.stdout.removeListener('data', waitForMarker);\n child.stdout.on('data', (c: string) => this.onChildData(c));\n child.stderr.on('data', (c: string) => this.onChildError(c));\n child.on('close', (code: number | null) => this.onChildClose(code));\n clearTimeout(timeout);\n resolve();\n }\n };\n\n child.stdout.on('data', waitForMarker);\n child.stdout.on('error', (err: Error) => {\n clearTimeout(timeout);\n reject(err);\n });\n child.on('error', (err: Error) => {\n clearTimeout(timeout);\n reject(err);\n });\n });\n }\n\n send(msg: ACPMessage): Promise<void> {\n if (!this.child) return Promise.reject(new Error('ClientTransport not started'));\n return new Promise((resolve, reject) => {\n const line = JSON.stringify(msg) + '\\n';\n this.child!.stdin.write(line, 'utf8', (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n }\n\n read(): Promise<ACPMessage | null> {\n if (this.messageQueue.length > 0) return Promise.resolve(this.messageQueue.shift()!);\n if (this.closed) return Promise.resolve(null);\n return new Promise((resolve) => {\n this.resolveRead = resolve;\n });\n }\n\n onMessage(handler: (msg: ACPMessage) => void): () => void {\n this.handlers.add(handler);\n return () => this.handlers.delete(handler);\n }\n\n stop(): void {\n if (!this.child) return;\n this.closed = true;\n try {\n this.child.kill();\n } catch {\n // already dead\n }\n this.child = null;\n }\n\n private onChildData(chunk: string): void {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() ?? '';\n\n for (const raw of lines) {\n if (!raw.trim()) continue;\n try {\n this.dispatch(JSON.parse(raw) as ACPMessage);\n } catch {\n // skip malformed\n }\n }\n }\n\n private onChildError(chunk: string): void {\n writeErr(`[acp-child stderr] ${chunk}`);\n }\n\n private onChildClose(code: number | null): void {\n this.closed = true;\n this.resolveRead?.(null);\n this.resolveRead = null;\n if (code !== 0 && code !== null) {\n writeErr(`[acp-child exited with code ${code}]\\n`);\n }\n }\n\n private dispatch(msg: ACPMessage): void {\n if (this.resolveRead) {\n const resolve = this.resolveRead;\n this.resolveRead = null;\n resolve(msg);\n } else {\n this.messageQueue.push(msg);\n }\n for (const handler of this.handlers) {\n try {\n handler(msg);\n } catch {\n // non-fatal\n }\n }\n }\n}\n","/**\n * Tools registry for ACP agent-side.\n *\n * Translates WrongStack Tool definitions → ACP ACPToolDefinition format.\n * Provides tool lookup and result assembly for the ACP protocol handler.\n */\nimport type {Tool} from '@wrongstack/core';\nimport type {\n ACPToolDefinition,\n ACPToolList,\n ACPInputSchema,\n ACPToolResult,\n ContentBlock,\n} from '../types/acp-messages.js';\n\nexport class ACPToolsRegistry {\n private tools = new Map<string, Tool>();\n private readonly owner: string;\n\n constructor(owner = 'wrongstack') {\n this.owner = owner;\n }\n\n /**\n * Register one or more tools.\n * Throws on duplicate name unless force=true.\n */\n register(tools: Tool[]): void {\n for (const tool of tools) {\n this.tools.set(tool.name, tool);\n }\n }\n\n /**\n * Replace the current tool set.\n */\n setTools(tools: Tool[]): void {\n this.tools.clear();\n for (const tool of tools) this.tools.set(tool.name, tool);\n }\n\n get(name: string): Tool | undefined {\n return this.tools.get(name);\n }\n\n has(name: string): boolean {\n return this.tools.has(name);\n }\n\n list(): Tool[] {\n return Array.from(this.tools.values());\n }\n\n /** Build the ACP tools/list payload from registered tools. */\n buildToolList(): ACPToolList {\n return {\n tools: Array.from(this.tools.values()).map((t) =>\n toACPToolDefinition(t, this.owner),\n ),\n };\n }\n\n /**\n * Execute a tool by name and return ACP-formatted result.\n * Returns null if the tool is not found.\n */\n async execute(\n name: string,\n args: Record<string, unknown>,\n ctx: unknown,\n signal: AbortSignal,\n ): Promise<ACPToolResult | null> {\n const tool = this.tools.get(name);\n if (!tool) return null;\n\n try {\n const result = await tool.execute(args, ctx as Parameters<Tool['execute']>[1], {\n signal,\n });\n return toACPToolResult(result);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {content: [{type: 'text', text: msg}], isError: true} satisfies ACPToolResult;\n }\n }\n}\n\n/** Convert a WrongStack Tool → ACP ACPToolDefinition */\nfunction toACPToolDefinition(tool: Tool, _owner: string): ACPToolDefinition {\n return {\n name: tool.name,\n description: tool.description,\n inputSchema: toACPInputSchema(tool.inputSchema),\n annotations: {\n title: tool.name,\n description: tool.usageHint ?? tool.description,\n priority: toolToPriority(tool),\n alwaysAccept: tool.permission === 'auto',\n },\n };\n}\n\n/** Minimal JSON Schema → ACP input schema. ACP uses JSON Schema draft-07. */\nfunction toACPInputSchema(src: unknown): ACPInputSchema {\n if (!src || typeof src !== 'object') {\n return {};\n }\n const s = src as Record<string, unknown>;\n\n // Recursively convert properties\n if (s.properties && typeof s.properties === 'object') {\n const props: Record<string, ACPInputSchema> = {};\n for (const [k, v] of Object.entries(s.properties as Record<string, unknown>)) {\n props[k] = toACPInputSchema(v);\n }\n return {\n type: typeof s.type === 'string' ? s.type : undefined,\n properties: props,\n required: Array.isArray(s.required) ? (s.required as string[]) : undefined,\n items: s.items ? toACPInputSchema(s.items) : undefined,\n enum: Array.isArray(s.enum) ? s.enum : undefined,\n description: typeof s.description === 'string' ? s.description : undefined,\n default: s.default,\n minimum: typeof s.minimum === 'number' ? s.minimum : undefined,\n maximum: typeof s.maximum === 'number' ? s.maximum : undefined,\n };\n }\n\n return {\n type: typeof s.type === 'string' ? s.type : undefined,\n items: s.items ? toACPInputSchema(s.items) : undefined,\n enum: Array.isArray(s.enum) ? s.enum : undefined,\n description: typeof s.description === 'string' ? s.description : undefined,\n default: s.default,\n minimum: typeof s.minimum === 'number' ? s.minimum : undefined,\n maximum: typeof s.maximum === 'number' ? s.maximum : undefined,\n };\n}\n\n/** Convert a WrongStack ToolResult → ACP ContentBlock[] */\nfunction toACPToolResult(result: unknown): ACPToolResult {\n const blocks: ContentBlock[] = [];\n\n if (result === undefined || result === null) {\n return {content: [{type: 'text', text: 'ok'}]};\n }\n\n if (typeof result === 'string') {\n blocks.push({type: 'text', text: result});\n } else if (typeof result === 'object') {\n blocks.push({type: 'text', text: JSON.stringify(result, null, 2)});\n } else {\n blocks.push({type: 'text', text: String(result)});\n }\n\n return {content: blocks};\n}\n\nfunction toolToPriority(tool: Tool): 'high' | 'medium' | 'low' {\n if (tool.riskTier === 'destructive') return 'high';\n if (tool.riskTier === 'standard' || tool.permission === 'confirm') return 'medium';\n return 'low';\n}\n","/**\n * ACPProtocolHandler — state machine for ACP server-side message handling.\n *\n * ACP turn lifecycle:\n * idle → [initialize] → await-turn → [tools/call] → executing\n * → [tool result sent] → idle\n *\n * We implement this as a simple switch on the method name, since the ACP\n * protocol is request/response based (not streaming) on the wire.\n *\n * Concurrency: ACP allows Cancellations and multiple concurrent tool calls\n * within a turn. We handle each tools/call in its own Promise.all.\n */\nimport type {\n ACPMessage,\n ACPRequest,\n ACPNotification,\n ACPInitializeParams,\n ACPToolCallRequest,\n ACPToolResult,\n ACPToolCallResponse,\n} from '../types/acp-messages.js';\nimport type {AgentServerTransport} from './stdio-transport.js';\n\nexport const WRONGSTACK_VERSION = '0.1.0';\nconst WRONGSTACK_CAPABILITIES = [\n 'code-generation',\n 'async-tools',\n 'streaming',\n 'progress',\n];\n\nexport class ACPProtocolHandler {\n private initialized = false;\n private readonly signal = new AbortController();\n private pendingCalls = new Map<string | number, Promise<unknown>>();\n\n constructor(\n private readonly transport: AgentServerTransport,\n private readonly registry: import('./tools-registry.js').ACPToolsRegistry,\n private readonly context: unknown,\n ) {}\n\n /** Wire an external abort signal from the ACP client */\n wireAbortController(abortController: AbortController): void {\n abortController.signal.addEventListener('abort', () => {\n for (const id of this.pendingCalls.keys()) {\n this.transport.send({id, method: 'cancel', result: {ok: true}}).catch(() => {});\n }\n });\n }\n\n /** Process one inbound message. Returns true if this was a terminal message. */\n async handleMessage(msg: ACPMessage): Promise<boolean> {\n if (msg.id !== undefined) {\n return this.handleRequest(msg as ACPRequest);\n }\n return this.handleNotification(msg as ACPNotification);\n }\n\n private async handleRequest(req: ACPRequest): Promise<boolean> {\n if (req.method !== 'initialize' && !this.initialized) {\n await this.sendError(req.id ?? null, -32000, 'Not initialized');\n return false;\n }\n\n // All requests after initialization check have a guaranteed id\n const id = req.id as string | number;\n\n switch (req.method) {\n case 'initialize':\n return this.handleInitialize(req as ACPRequest & {params: ACPInitializeParams}, id);\n case 'ping':\n await this.transport.send({id, method: 'ping', result: {pong: true}});\n return false;\n case 'tools/call':\n return this.handleToolCall(req as ACPRequest & {params: ACPToolCallRequest['params']}, id);\n case 'tools/list':\n return this.handleToolsList(id);\n case 'cancel':\n return this.handleCancel(id);\n case 'session/list':\n return this.handleSessionList(id);\n case 'sessionInfoUpdate':\n await this.transport.send({id, method: 'sessionInfoUpdate', result: {ok: true}});\n return false;\n default:\n await this.sendError(id, -32601, `Unknown method: ${req.method}`);\n return false;\n }\n }\n\n private async handleNotification(n: ACPNotification): Promise<boolean> {\n if (n.method === 'cancel') {\n this.handleCancelNotification(n as ACPNotification & {params?: {reason?: string}});\n }\n return false;\n }\n\n private async handleInitialize(\n req: ACPRequest & {params: ACPInitializeParams},\n id: string | number,\n ): Promise<boolean> {\n this.initialized = true;\n\n const result = {\n capabilities: WRONGSTACK_CAPABILITIES,\n agentName: 'WrongStack',\n agentVersion: WRONGSTACK_VERSION,\n protocolVersion: req.params?.protocolVersion ?? '2024-11',\n ...this.registry.buildToolList(),\n };\n\n await this.transport.send({id, method: 'initialize', result});\n return false;\n }\n\n private async handleToolsList(id: string | number): Promise<boolean> {\n await this.transport.send({\n id,\n method: 'tools/list',\n result: this.registry.buildToolList(),\n });\n return false;\n }\n\n private async handleToolCall(\n req: ACPRequest & {params: {name: string; arguments: Record<string, unknown>}},\n id: string | number,\n ): Promise<boolean> {\n const {name, arguments: args} = req.params;\n\n const runPromise = (async () => {\n if (!this.registry.has(name)) {\n return {\n content: [{type: 'text', text: `Tool not found: ${name}`}],\n isError: true,\n } satisfies ACPToolResult;\n }\n\n const result = await this.registry.execute(\n name,\n args,\n this.context,\n this.signal.signal,\n );\n return result ?? {content: [{type: 'text', text: 'Tool returned null'}], isError: false};\n })();\n\n this.pendingCalls.set(id, runPromise);\n\n try {\n const toolResult = (await runPromise) as ACPToolResult;\n this.pendingCalls.delete(id);\n\n const response: ACPToolCallResponse = {method: 'tools/call', id, result: toolResult};\n await this.transport.send(response);\n } catch (err) {\n this.pendingCalls.delete(id);\n const msg = err instanceof Error ? err.message : String(err);\n await this.transport.send({\n id,\n method: 'tools/call',\n result: {content: [{type: 'text', text: msg}], isError: true},\n });\n }\n\n return false;\n }\n\n private async handleCancel(id: string | number): Promise<boolean> {\n this.pendingCalls.delete(id);\n await this.transport.send({id, method: 'cancel', result: {ok: true}});\n return false;\n }\n\n private handleCancelNotification(\n _n: ACPNotification & {params?: {reason?: string}},\n ): void {\n // Broadcast cancellation to all pending — best-effort\n }\n\n private async handleSessionList(id: string | number): Promise<boolean> {\n await this.transport.send({\n id,\n method: 'session/list',\n result: {sessions: []},\n });\n return false;\n }\n\n private async sendError(id: string | number | null, code: number, message: string): Promise<void> {\n if (id === null) return;\n await this.transport.send({id, method: '', error: {code, message}});\n }\n}\n","/**\n * WrongStackACPServer — ACP server-side entry point.\n *\n * Exposes WrongStack as an ACP-compatible agent. ACP clients (Zed, JetBrains,\n * VS Code ACP extension) spawn this as a subprocess, send JSON-RPC messages\n * over stdio, and receive tool responses.\n *\n * Usage:\n * node dist/agent/wrongstack-acp-agent.js\n *\n * Or via the CLI:\n * wstack acp-server\n *\n * Startup: sends `[wstack-acp]\\n` to stdout so the client knows which process\n * is the ACP server before protocol messages begin.\n */\nimport { fileURLToPath } from 'node:url';\nimport { writeErr } from '@wrongstack/core';\nimport type { Tool } from '@wrongstack/core';\nimport { ACPProtocolHandler } from './protocol-handler.js';\nimport { StdioTransport } from './stdio-transport.js';\nimport { ACPToolsRegistry } from './tools-registry.js';\n\nexport interface WrongStackACPServerOptions {\n /**\n * Initial tool set. Typically loaded from the WrongStack tool registry\n * via `api.tools.list()` so the ACP server exposes exactly the tools the\n * CLI has configured.\n */\n tools: Tool[];\n /**\n * Owner label for tool metadata. Passed to ACPToolsRegistry.\n * @default 'wrongstack'\n */\n owner?: string;\n}\n\nexport class WrongStackACPServer {\n private readonly transport: StdioTransport;\n private readonly registry: ACPToolsRegistry;\n private readonly handler: ACPProtocolHandler;\n private running = false;\n\n constructor(opts: WrongStackACPServerOptions) {\n this.transport = new StdioTransport();\n this.registry = new ACPToolsRegistry(opts.owner);\n this.registry.register(opts.tools);\n this.handler = new ACPProtocolHandler(\n this.transport,\n this.registry,\n /* TODO: load WrongStack Context */ {},\n );\n }\n\n /**\n * Start the server. Blocks until the client disconnects.\n *\n * 1. Send the startup marker `[wstack-acp]` so the client\n * knows which stdout line is the protocol boundary.\n * 2. Loop: read messages, dispatch to handler, until EOF or error.\n *\n * Single dispatch path: every inbound message is read exactly once\n * from the transport and passed to the protocol handler exactly once.\n * An earlier version combined a `transport.onMessage` callback with\n * this read loop, which caused every message to be processed twice\n * (once by the callback, once by the loop) — duplicate tool calls\n * and duplicate responses to the client. See the ACP double-dispatch\n * fix in the security audit (P1-001).\n */\n async start(): Promise<void> {\n this.transport.sendStartupMarker();\n this.running = true;\n\n while (this.running) {\n const msg = await this.transport.read();\n if (!msg) break; // EOF\n const terminal = await this.handler.handleMessage(msg);\n if (terminal) break;\n }\n\n this.transport.close();\n }\n\n /** Stop the server. */\n stop(): void {\n this.running = false;\n this.transport.close();\n }\n}\n\n/**\n * Bootstrap function for `node dist/agent/wrongstack-acp-agent.js`.\n * Instantiates the server with the default tool set.\n *\n * Tool loading: the ACP agent is a subprocess without the full CLI context,\n * so it needs to receive its tools from the parent via environment or a\n * pre-main bootstrap. For now, it uses an empty tool set unless tools are\n * explicitly passed via constructor options.\n *\n * In practice the CLI will instantiate and run WrongStackACPServer directly,\n * passing `api.tools.list()` as the tool set.\n */\nasync function main(): Promise<void> {\n const server = new WrongStackACPServer({ tools: [] });\n await server.start();\n}\n\n// Only auto-start when this file is the process entrypoint (e.g.\n// `node dist/agent/wrongstack-acp-agent.js`). Importing the module — which the\n// CLI does to reuse `WrongStackACPServer` — must stay side-effect-free, or\n// every launch would start an ACP server and hijack stdin.\nconst isEntrypoint =\n process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1];\nif (isEntrypoint) {\n main().catch((err) => {\n writeErr(`[wstack-acp fatal] ${err}\\n`);\n process.exit(1);\n });\n}\n"]}
|
package/dist/client.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildChildEnv } from '@wrongstack/core';
|
|
1
|
+
import { buildChildEnv, writeErr } from '@wrongstack/core';
|
|
2
2
|
import { spawn } from 'child_process';
|
|
3
3
|
|
|
4
4
|
// src/agent/stdio-transport.ts
|
|
@@ -104,15 +104,15 @@ var ClientTransport = class {
|
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
onChildError(chunk) {
|
|
107
|
-
|
|
107
|
+
writeErr(`[acp-child stderr] ${chunk}`);
|
|
108
108
|
}
|
|
109
109
|
onChildClose(code) {
|
|
110
110
|
this.closed = true;
|
|
111
111
|
this.resolveRead?.(null);
|
|
112
112
|
this.resolveRead = null;
|
|
113
113
|
if (code !== 0 && code !== null) {
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
writeErr(`[acp-child exited with code ${code}]
|
|
115
|
+
`);
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
dispatch(msg) {
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/agent/stdio-transport.ts","../src/client/tool-translator.ts","../src/integration/acp-subagent-runner.ts"],"names":[],"mappings":"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","file":"client.js","sourcesContent":["/**\n * StdioTransport — bidirectional stdin/stdout communication for ACP.\n *\n * ACP uses newline-delimited JSON-RPC 2.0 messages over stdio:\n * client → agent: JSON-RPC request/notification on stdin\n * agent → client: JSON-RPC response/notification on stdout\n *\n * Start message: clients look for the `[wstack-acp]` marker on stdout before\n * treating subsequent lines as protocol messages.\n */\nimport { buildChildEnv } from '@wrongstack/core';\nimport type { ACPMessage } from '../types/acp-messages.js';\n\nexport interface AgentServerTransport {\n send(msg: ACPMessage): Promise<void>;\n sendRaw(chunk: string): void;\n read(): Promise<ACPMessage | null>;\n close(): void;\n onMessage(handler: (msg: ACPMessage) => void): () => void;\n}\n\nexport class StdioTransport implements AgentServerTransport {\n private readonly stdin = process.stdin;\n private readonly stdout = process.stdout;\n private readonly stderr = process.stderr;\n\n private buffer = '';\n private readonly handlers = new Set<(msg: ACPMessage) => void>();\n private closed = false;\n private resolveRead: ((msg: ACPMessage | null) => void) | null = null;\n private messageQueue: ACPMessage[] = [];\n\n constructor() {\n this.stdin.resume();\n this.stdin.setEncoding('utf8');\n this.stdin.on('data', (chunk: string) => this.onData(chunk));\n this.stdin.on('end', () => this.handleClose());\n this.stdin.on('error', (err: Error) => this.failAll(err));\n }\n\n sendStartupMarker(): void {\n this.stdout.write('[wstack-acp]\\n', 'utf8');\n }\n\n send(msg: ACPMessage): Promise<void> {\n if (this.closed) return Promise.resolve();\n return new Promise((resolve) => {\n const line = JSON.stringify(msg) + '\\n';\n this.stdout.write(line, 'utf8', () => resolve());\n });\n }\n\n sendRaw(chunk: string): void {\n this.stdout.write(chunk, 'utf8');\n }\n\n read(): Promise<ACPMessage | null> {\n if (this.messageQueue.length > 0) return Promise.resolve(this.messageQueue.shift()!);\n if (this.closed) return Promise.resolve(null);\n return new Promise((resolve) => {\n this.resolveRead = resolve;\n });\n }\n\n onMessage(handler: (msg: ACPMessage) => void): () => void {\n this.handlers.add(handler);\n return () => this.handlers.delete(handler);\n }\n\n close(): void {\n this.closed = true;\n this.stdin.pause();\n this.resolveRead?.(null);\n this.resolveRead = null;\n }\n\n private onData(chunk: string): void {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() ?? '';\n\n for (const raw of lines) {\n if (!raw.trim()) continue;\n try {\n this.dispatch(JSON.parse(raw) as ACPMessage);\n } catch (err) {\n this.stderr.write(`[wstack-acp parse error] ${err}\\n`, 'utf8');\n }\n }\n }\n\n private dispatch(msg: ACPMessage): void {\n if (this.resolveRead) {\n const resolve = this.resolveRead;\n this.resolveRead = null;\n resolve(msg);\n } else {\n this.messageQueue.push(msg);\n }\n for (const handler of this.handlers) {\n try {\n handler(msg);\n } catch (err) {\n this.stderr.write(`[wstack-acp handler error] ${err}\\n`, 'utf8');\n }\n }\n }\n\n private handleClose(): void {\n this.closed = true;\n this.resolveRead?.(null);\n this.resolveRead = null;\n }\n\n private failAll(err: Error): void {\n this.stderr.write(`[wstack-acp stdin error] ${err.message}\\n`, 'utf8');\n this.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// ClientTransport — spawns a child ACP agent process (DIR-1)\n// ---------------------------------------------------------------------------\n\nimport { spawn } from 'node:child_process';\nimport type { EventEmitter } from 'node:events';\n\nexport interface ClientTransportOptions {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n handshakeTimeoutMs?: number;\n}\n\nexport interface ACPChildProcess extends EventEmitter {\n stdout: NodeJS.ReadableStream;\n stdin: NodeJS.WritableStream;\n stderr: NodeJS.ReadableStream;\n pid: number | undefined;\n kill(): void;\n}\n\nexport class ClientTransport {\n private child: ACPChildProcess | null = null;\n private buffer = '';\n private readonly handlers = new Set<(msg: ACPMessage) => void>();\n private closed = false;\n private resolveRead: ((msg: ACPMessage | null) => void) | null = null;\n private messageQueue: ACPMessage[] = [];\n private readonly opts: Required<Pick<ClientTransportOptions, 'handshakeTimeoutMs'>> &\n ClientTransportOptions;\n\n constructor(options: ClientTransportOptions) {\n this.opts = {\n handshakeTimeoutMs: 30_000,\n ...options,\n };\n }\n\n async start(): Promise<void> {\n if (this.child) return;\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(`ACP child process failed to start within ${this.opts.handshakeTimeoutMs}ms`),\n );\n }, this.opts.handshakeTimeoutMs);\n\n try {\n this.child = spawn(this.opts.command, this.opts.args ?? [], {\n env: { ...buildChildEnv(), ...this.opts.env },\n cwd: this.opts.cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n }) as unknown as ACPChildProcess;\n } catch (err) {\n clearTimeout(timeout);\n reject(err);\n return;\n }\n\n const child = this.child;\n\n child.stdout.setEncoding('utf8');\n\n const waitForMarker = (chunk: string) => {\n this.buffer += chunk;\n const idx = this.buffer.indexOf('[wstack-acp]\\n');\n if (idx !== -1) {\n this.buffer = this.buffer.slice(idx + '[wstack-acp]\\n'.length);\n child.stdout.removeListener('data', waitForMarker);\n child.stdout.on('data', (c: string) => this.onChildData(c));\n child.stderr.on('data', (c: string) => this.onChildError(c));\n child.on('close', (code: number | null) => this.onChildClose(code));\n clearTimeout(timeout);\n resolve();\n }\n };\n\n child.stdout.on('data', waitForMarker);\n child.stdout.on('error', (err: Error) => {\n clearTimeout(timeout);\n reject(err);\n });\n child.on('error', (err: Error) => {\n clearTimeout(timeout);\n reject(err);\n });\n });\n }\n\n send(msg: ACPMessage): Promise<void> {\n if (!this.child) return Promise.reject(new Error('ClientTransport not started'));\n return new Promise((resolve, reject) => {\n const line = JSON.stringify(msg) + '\\n';\n this.child!.stdin.write(line, 'utf8', (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n }\n\n read(): Promise<ACPMessage | null> {\n if (this.messageQueue.length > 0) return Promise.resolve(this.messageQueue.shift()!);\n if (this.closed) return Promise.resolve(null);\n return new Promise((resolve) => {\n this.resolveRead = resolve;\n });\n }\n\n onMessage(handler: (msg: ACPMessage) => void): () => void {\n this.handlers.add(handler);\n return () => this.handlers.delete(handler);\n }\n\n stop(): void {\n if (!this.child) return;\n this.closed = true;\n try {\n this.child.kill();\n } catch {\n // already dead\n }\n this.child = null;\n }\n\n private onChildData(chunk: string): void {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() ?? '';\n\n for (const raw of lines) {\n if (!raw.trim()) continue;\n try {\n this.dispatch(JSON.parse(raw) as ACPMessage);\n } catch {\n // skip malformed\n }\n }\n }\n\n private onChildError(chunk: string): void {\n process.stderr.write(`[acp-child stderr] ${chunk}`, 'utf8');\n }\n\n private onChildClose(code: number | null): void {\n this.closed = true;\n this.resolveRead?.(null);\n this.resolveRead = null;\n if (code !== 0 && code !== null) {\n process.stderr.write(`[acp-child exited with code ${code}]\\n`, 'utf8');\n }\n }\n\n private dispatch(msg: ACPMessage): void {\n if (this.resolveRead) {\n const resolve = this.resolveRead;\n this.resolveRead = null;\n resolve(msg);\n } else {\n this.messageQueue.push(msg);\n }\n for (const handler of this.handlers) {\n try {\n handler(msg);\n } catch {\n // non-fatal\n }\n }\n }\n}\n","/**\n * ToolTranslator — bidirectional translation between WrongStack tools and\n * ACP tool representations.\n *\n * Used by DIR-1 (WrongStack as ACP client) to:\n * - Map WrongStack TaskSpec → ACP task payload\n * - Map ACP tool responses → TaskResult\n *\n * Used by DIR-2 (WrongStack as ACP server) to:\n * - Convert the WrongStack Tool.inputSchema → ACPToolDefinition.inputSchema\n * - (handled by tools-registry.ts — same logic lives there)\n *\n * For DIR-1 async tool calls: ACP agents send progress notifications while\n * a tool is running, then send a final result. The translator handles this\n * by polling for the final [result] notification on the transport.\n */\nimport type {ACPMessage, ACPToolDefinition, ACPToolCallResponse, ContentBlock} from '../types/acp-messages.js';\nimport type {TaskSpec, TaskResult} from '@wrongstack/core';\n\nexport interface ToolTranslatorOptions {\n /**\n * If true (default), wrap tool calls in an async poll loop that waits\n * for progress notifications until a final result arrives.\n */\n asyncTools?: boolean;\n pollIntervalMs?: number;\n totalTimeoutMs?: number;\n}\n\nconst DEFAULT_OPTIONS: Required<ToolTranslatorOptions> = {\n asyncTools: true,\n pollIntervalMs: 500,\n totalTimeoutMs: 120_000,\n};\n\n/** Convert an ACP ACPToolDefinition → a JSON schema object recognisable by WrongStack */\nexport function acpToolToSchema(def: ACPToolDefinition): Record<string, unknown> {\n if (!def.inputSchema) return {type: 'object', properties: {}};\n return def.inputSchema as Record<string, unknown>;\n}\n\n/** Extract tool result text from ACP ContentBlock[] */\nexport function extractTextFromContent(blocks: ContentBlock[]): string {\n const parts: string[] = [];\n for (const b of blocks) {\n if (b.type === 'text') parts.push(b.text);\n else if (b.type === 'resource') parts.push(`[resource: ${b.resource.uri}]`);\n else if (b.type === 'image') parts.push(`[image: ${b.data.slice(0, 20)}...]`);\n else if (b.type === 'progress') {\n if (b.messages?.length) parts.push(b.messages.join('\\n'));\n }\n }\n return parts.join('\\n');\n}\n\n/** Build a TaskSpec from an ACP task payload */\nexport function buildTaskSpec(payload: {\n taskId: string;\n task: string;\n subagentId?: string;\n}): TaskSpec {\n return {\n id: payload.taskId,\n description: payload.task,\n subagentId: payload.subagentId,\n };\n}\n\n/** Parse an ACP tools/call response → TaskResult */\nexport function parseToolResponse(\n taskId: string,\n subagentId: string,\n response: ACPToolCallResponse,\n): TaskResult {\n const blocks = response.result.content;\n const text = extractTextFromContent(blocks);\n\n // Detect error state from isError flag or error-like text\n const isError =\n response.result.isError || text.toLowerCase().includes('error') ||\n text.toLowerCase().includes('failed');\n\n return {\n taskId,\n subagentId,\n status: isError ? 'failed' : 'success',\n result: text,\n iterations: 1,\n toolCalls: 1,\n durationMs: 0,\n };\n}\n\n/** ToolTranslator for DIR-1 — wraps ACP client transport, adds task semantics */\nexport class ToolTranslator {\n private readonly opts: Required<ToolTranslatorOptions>;\n private readonly pending = new Map<string | number, {\n resolve: (v: ACPToolCallResponse) => void;\n reject: (e: Error) => void;\n timeout: ReturnType<typeof setTimeout>;\n }>();\n\n constructor(opts: ToolTranslatorOptions = {}) {\n this.opts = {...DEFAULT_OPTIONS, ...opts};\n }\n\n /**\n * Start listening to a transport for tool responses and cancellations.\n * Call this once after constructing the translator and before sending tasks.\n */\n attachToTransport(\n transport: {onMessage: (h: (msg: ACPMessage) => void) => () => void; send: (msg: ACPMessage) => Promise<void>},\n ): void {\n transport.onMessage((msg) => {\n if (msg.method === 'tools/call' && msg.id !== undefined) {\n const pending = this.pending.get(msg.id);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(msg.id!);\n pending.resolve(msg as unknown as ACPToolCallResponse);\n }\n }\n\n // Handle cancellation notifications\n if (msg.method === 'cancel' && msg.id !== undefined) {\n const pending = this.pending.get(msg.id);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(msg.id!);\n pending.reject(new Error('Call cancelled by client'));\n }\n }\n });\n }\n\n /**\n * Send a tool call over the transport and wait for a response.\n * If asyncTools is true, polls for progress and resolves when the final\n * response arrives.\n */\n async callTool(\n transport: {send: (msg: ACPMessage) => Promise<void>},\n name: string,\n args: Record<string, unknown>,\n callId: string | number = crypto.randomUUID(),\n ): Promise<ACPToolCallResponse> {\n await transport.send({\n method: 'tools/call',\n id: callId,\n params: {name, arguments: args},\n });\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.pending.delete(callId);\n reject(new Error(`Tool call ${name} timed out after ${this.opts.totalTimeoutMs}ms`));\n }, this.opts.totalTimeoutMs);\n\n this.pending.set(callId, {resolve, reject, timeout});\n });\n }\n\n cancelAll(): void {\n for (const [, p] of this.pending) {\n clearTimeout(p.timeout);\n }\n this.pending.clear();\n }\n}\n","/**\n * ACPSubagentRunner — SubagentRunner implementation for DIR-1.\n *\n * Wraps an external ACP agent (Cline, Gemini CLI, Codex CLI, Copilot, etc.)\n * as a WrongStack subagent. The external agent runs its own agent loop;\n * we send it a task via ACP and return the result.\n *\n * Connected to Director / MultiAgentCoordinator via the SubagentRunner\n * interface (same as AgentSubagentRunner).\n */\nimport type {SubagentRunContext, SubagentRunner, TaskSpec} from '@wrongstack/core';\nimport {ClientTransport} from '../agent/stdio-transport.js';\nimport type {ACPToolCallResponse} from '../types/acp-messages.js';\nimport {ToolTranslator, parseToolResponse} from '../client/tool-translator.js';\nimport type {ToolTranslatorOptions} from '../client/tool-translator.js';\n\nexport interface ACPSubagentRunnerOptions {\n /** ACP agent command or npm package (e.g. 'npx', 'gemini', 'gh') */\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n /** Subagent role — used for protocol negotiation and prompt overrides */\n role?: string;\n toolTranslatorOpts?: ToolTranslatorOptions;\n}\n\n/** Map WrongStack ACP agent role → how to spawn it. */\nexport const ACP_AGENT_COMMANDS: Record<string, ACPSubagentRunnerOptions> = {\n cline: {\n command: 'npx',\n args: ['-y', '@agentify/cline'],\n role: 'cline',\n },\n 'gemini-cli': {\n command: 'gemini',\n role: 'gemini-cli',\n },\n copilot: {\n command: 'gh',\n args: ['copilot', 'agent'],\n role: 'copilot',\n },\n openhands: {\n command: 'openhands',\n role: 'openhands',\n },\n goose: {\n command: 'goose',\n role: 'goose',\n },\n};\n\n/**\n * Build an ACPSubagentRunner for a given role, or a generic one from explicit options.\n */\nexport async function makeACPSubagentRunner(\n options: ACPSubagentRunnerOptions,\n): Promise<SubagentRunner> {\n const transport = new ClientTransport({\n command: options.command,\n args: options.args,\n env: options.env,\n cwd: options.cwd,\n handshakeTimeoutMs: 30_000,\n });\n\n const translator = new ToolTranslator(options.toolTranslatorOpts);\n const activeAbort = new AbortController();\n\n let sessionStarted = false;\n\n const startSession = async (): Promise<void> => {\n if (sessionStarted) return;\n await transport.start();\n\n await transport.send({\n method: 'initialize',\n id: '1',\n params: {\n capabilities: ['code-generation', 'async-tools', 'streaming', 'progress'],\n protocolVersion: '2024-11',\n sessionId: options.role ?? 'wrongstack-subagent',\n },\n });\n\n const initResp = await transport.read();\n if (!initResp || initResp.error) {\n throw new Error(`ACP initialize failed: ${initResp?.error?.message ?? 'no response'}`);\n }\n\n translator.attachToTransport({\n onMessage: (h) => transport.onMessage(h),\n send: (m) => transport.send(m),\n });\n\n sessionStarted = true;\n };\n\n const runner: SubagentRunner = async (\n task: TaskSpec,\n ctx: SubagentRunContext,\n ): Promise<{result?: unknown; iterations: number; toolCalls: number}> => {\n ctx.signal.addEventListener('abort', () => {\n activeAbort.abort();\n transport.stop();\n });\n\n await startSession();\n\n const callId = crypto.randomUUID();\n let toolResult: ACPToolCallResponse | null = null;\n\n const resultPromise = new Promise<ACPToolCallResponse>((resolve, reject) => {\n const budgetMs = ctx.budget.limits.timeoutMs ?? 300_000;\n\n const timeout = setTimeout(() => {\n reject(new Error(`ACP task timed out for subagent ${ctx.subagentId} (${budgetMs}ms budget)`));\n }, budgetMs);\n\n transport.onMessage((msg) => {\n if (msg.method === 'tools/call' && msg.id !== undefined) {\n clearTimeout(timeout);\n resolve(msg as unknown as ACPToolCallResponse);\n }\n });\n\n ctx.signal.addEventListener('abort', () => {\n clearTimeout(timeout);\n reject(new Error('Task aborted by parent'));\n });\n });\n\n try {\n // Most ACP agents accept a free-form task string as their primary input.\n // Use the tools/call protocol with a special 'task' pseudo-tool if the\n // agent advertises it; otherwise send it as an initialize session detail\n // or a custom agent/run message. The agent will respond on stdout.\n await transport.send({\n method: 'agent/run',\n id: callId,\n params: {\n task: task.description,\n sessionId: ctx.subagentId,\n },\n });\n\n toolResult = await resultPromise;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n result: `ACP subagent error: ${msg}`,\n iterations: 0,\n toolCalls: 0,\n };\n }\n\n if (!toolResult) {\n return {result: 'ACP subagent returned no result', iterations: 1, toolCalls: 1};\n }\n\n const parsed = parseToolResponse(task.id, ctx.subagentId, toolResult);\n return {\n result: parsed.result ?? parsed.error,\n iterations: parsed.iterations,\n toolCalls: parsed.toolCalls,\n };\n };\n\n return runner;\n}\n\n/** Returns the runner and a stop function to clean up the transport. */\nexport async function makeACPSubagentRunnerWithStop(\n options: ACPSubagentRunnerOptions,\n): Promise<{runner: SubagentRunner; stop: () => void}> {\n const transport = new ClientTransport({\n command: options.command,\n args: options.args,\n env: options.env,\n cwd: options.cwd,\n handshakeTimeoutMs: 30_000,\n });\n\n const translator = new ToolTranslator(options.toolTranslatorOpts);\n const activeAbort = new AbortController();\n\n let sessionStarted = false;\n\n const startSession = async (): Promise<void> => {\n if (sessionStarted) return;\n await transport.start();\n\n await transport.send({\n method: 'initialize',\n id: '1',\n params: {\n capabilities: ['code-generation', 'async-tools', 'streaming', 'progress'],\n protocolVersion: '2024-11',\n sessionId: options.role ?? 'wrongstack-subagent',\n },\n });\n\n const initResp = await transport.read();\n if (!initResp || initResp.error) {\n throw new Error(`ACP initialize failed: ${initResp?.error?.message ?? 'no response'}`);\n }\n\n translator.attachToTransport({\n onMessage: (h) => transport.onMessage(h),\n send: (m) => transport.send(m),\n });\n\n sessionStarted = true;\n };\n\n const stop = () => {\n activeAbort.abort();\n transport.stop();\n };\n\n const runner: SubagentRunner = async (\n task: TaskSpec,\n ctx: SubagentRunContext,\n ): Promise<{result?: unknown; iterations: number; toolCalls: number}> => {\n ctx.signal.addEventListener('abort', () => {\n activeAbort.abort();\n transport.stop();\n });\n\n await startSession();\n\n const callId = crypto.randomUUID();\n let toolResult: ACPToolCallResponse | null = null;\n\n const resultPromise = new Promise<ACPToolCallResponse>((resolve, reject) => {\n const budgetMs = ctx.budget.limits.timeoutMs ?? 300_000;\n\n const timeout = setTimeout(() => {\n reject(new Error(`ACP task timed out for subagent ${ctx.subagentId} (${budgetMs}ms budget)`));\n }, budgetMs);\n\n transport.onMessage((msg) => {\n if (msg.method === 'tools/call' && msg.id !== undefined) {\n clearTimeout(timeout);\n resolve(msg as unknown as ACPToolCallResponse);\n }\n });\n\n ctx.signal.addEventListener('abort', () => {\n clearTimeout(timeout);\n reject(new Error('Task aborted by parent'));\n });\n });\n\n try {\n await transport.send({\n method: 'agent/run',\n id: callId,\n params: {\n task: task.description,\n sessionId: ctx.subagentId,\n },\n });\n\n toolResult = await resultPromise;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n result: `ACP subagent error: ${msg}`,\n iterations: 0,\n toolCalls: 0,\n };\n }\n\n if (!toolResult) {\n return {result: 'ACP subagent returned no result', iterations: 1, toolCalls: 1};\n }\n\n const parsed = parseToolResponse(task.id, ctx.subagentId, toolResult);\n return {\n result: parsed.result ?? parsed.error,\n iterations: parsed.iterations,\n toolCalls: parsed.toolCalls,\n };\n };\n\n return {runner, stop};\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/agent/stdio-transport.ts","../src/client/tool-translator.ts","../src/integration/acp-subagent-runner.ts"],"names":[],"mappings":"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","file":"client.js","sourcesContent":["/**\n * StdioTransport — bidirectional stdin/stdout communication for ACP.\n *\n * ACP uses newline-delimited JSON-RPC 2.0 messages over stdio:\n * client → agent: JSON-RPC request/notification on stdin\n * agent → client: JSON-RPC response/notification on stdout\n *\n * Start message: clients look for the `[wstack-acp]` marker on stdout before\n * treating subsequent lines as protocol messages.\n */\nimport { buildChildEnv, writeErr } from '@wrongstack/core';\nimport type { ACPMessage } from '../types/acp-messages.js';\n\nexport interface AgentServerTransport {\n send(msg: ACPMessage): Promise<void>;\n sendRaw(chunk: string): void;\n read(): Promise<ACPMessage | null>;\n close(): void;\n onMessage(handler: (msg: ACPMessage) => void): () => void;\n}\n\nexport class StdioTransport implements AgentServerTransport {\n private readonly stdin = process.stdin;\n private readonly stdout = process.stdout;\n private readonly stderr = process.stderr;\n\n private buffer = '';\n private readonly handlers = new Set<(msg: ACPMessage) => void>();\n private closed = false;\n private resolveRead: ((msg: ACPMessage | null) => void) | null = null;\n private messageQueue: ACPMessage[] = [];\n\n constructor() {\n this.stdin.resume();\n this.stdin.setEncoding('utf8');\n this.stdin.on('data', (chunk: string) => this.onData(chunk));\n this.stdin.on('end', () => this.handleClose());\n this.stdin.on('error', (err: Error) => this.failAll(err));\n }\n\n sendStartupMarker(): void {\n this.stdout.write('[wstack-acp]\\n', 'utf8');\n }\n\n send(msg: ACPMessage): Promise<void> {\n if (this.closed) return Promise.resolve();\n return new Promise((resolve) => {\n const line = JSON.stringify(msg) + '\\n';\n this.stdout.write(line, 'utf8', () => resolve());\n });\n }\n\n sendRaw(chunk: string): void {\n this.stdout.write(chunk, 'utf8');\n }\n\n read(): Promise<ACPMessage | null> {\n if (this.messageQueue.length > 0) return Promise.resolve(this.messageQueue.shift()!);\n if (this.closed) return Promise.resolve(null);\n return new Promise((resolve) => {\n this.resolveRead = resolve;\n });\n }\n\n onMessage(handler: (msg: ACPMessage) => void): () => void {\n this.handlers.add(handler);\n return () => this.handlers.delete(handler);\n }\n\n close(): void {\n this.closed = true;\n this.stdin.pause();\n this.resolveRead?.(null);\n this.resolveRead = null;\n }\n\n private onData(chunk: string): void {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() ?? '';\n\n for (const raw of lines) {\n if (!raw.trim()) continue;\n try {\n this.dispatch(JSON.parse(raw) as ACPMessage);\n } catch (err) {\n this.stderr.write(`[wstack-acp parse error] ${err}\\n`, 'utf8');\n }\n }\n }\n\n private dispatch(msg: ACPMessage): void {\n if (this.resolveRead) {\n const resolve = this.resolveRead;\n this.resolveRead = null;\n resolve(msg);\n } else {\n this.messageQueue.push(msg);\n }\n for (const handler of this.handlers) {\n try {\n handler(msg);\n } catch (err) {\n this.stderr.write(`[wstack-acp handler error] ${err}\\n`, 'utf8');\n }\n }\n }\n\n private handleClose(): void {\n this.closed = true;\n this.resolveRead?.(null);\n this.resolveRead = null;\n }\n\n private failAll(err: Error): void {\n this.stderr.write(`[wstack-acp stdin error] ${err.message}\\n`, 'utf8');\n this.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// ClientTransport — spawns a child ACP agent process (DIR-1)\n// ---------------------------------------------------------------------------\n\nimport { spawn } from 'node:child_process';\nimport type { EventEmitter } from 'node:events';\n\nexport interface ClientTransportOptions {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n handshakeTimeoutMs?: number;\n}\n\nexport interface ACPChildProcess extends EventEmitter {\n stdout: NodeJS.ReadableStream;\n stdin: NodeJS.WritableStream;\n stderr: NodeJS.ReadableStream;\n pid: number | undefined;\n kill(): void;\n}\n\nexport class ClientTransport {\n private child: ACPChildProcess | null = null;\n private buffer = '';\n private readonly handlers = new Set<(msg: ACPMessage) => void>();\n private closed = false;\n private resolveRead: ((msg: ACPMessage | null) => void) | null = null;\n private messageQueue: ACPMessage[] = [];\n private readonly opts: Required<Pick<ClientTransportOptions, 'handshakeTimeoutMs'>> &\n ClientTransportOptions;\n\n constructor(options: ClientTransportOptions) {\n this.opts = {\n handshakeTimeoutMs: 30_000,\n ...options,\n };\n }\n\n async start(): Promise<void> {\n if (this.child) return;\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(`ACP child process failed to start within ${this.opts.handshakeTimeoutMs}ms`),\n );\n }, this.opts.handshakeTimeoutMs);\n\n try {\n this.child = spawn(this.opts.command, this.opts.args ?? [], {\n env: { ...buildChildEnv(), ...this.opts.env },\n cwd: this.opts.cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n }) as unknown as ACPChildProcess;\n } catch (err) {\n clearTimeout(timeout);\n reject(err);\n return;\n }\n\n const child = this.child;\n\n child.stdout.setEncoding('utf8');\n\n const waitForMarker = (chunk: string) => {\n this.buffer += chunk;\n const idx = this.buffer.indexOf('[wstack-acp]\\n');\n if (idx !== -1) {\n this.buffer = this.buffer.slice(idx + '[wstack-acp]\\n'.length);\n child.stdout.removeListener('data', waitForMarker);\n child.stdout.on('data', (c: string) => this.onChildData(c));\n child.stderr.on('data', (c: string) => this.onChildError(c));\n child.on('close', (code: number | null) => this.onChildClose(code));\n clearTimeout(timeout);\n resolve();\n }\n };\n\n child.stdout.on('data', waitForMarker);\n child.stdout.on('error', (err: Error) => {\n clearTimeout(timeout);\n reject(err);\n });\n child.on('error', (err: Error) => {\n clearTimeout(timeout);\n reject(err);\n });\n });\n }\n\n send(msg: ACPMessage): Promise<void> {\n if (!this.child) return Promise.reject(new Error('ClientTransport not started'));\n return new Promise((resolve, reject) => {\n const line = JSON.stringify(msg) + '\\n';\n this.child!.stdin.write(line, 'utf8', (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n }\n\n read(): Promise<ACPMessage | null> {\n if (this.messageQueue.length > 0) return Promise.resolve(this.messageQueue.shift()!);\n if (this.closed) return Promise.resolve(null);\n return new Promise((resolve) => {\n this.resolveRead = resolve;\n });\n }\n\n onMessage(handler: (msg: ACPMessage) => void): () => void {\n this.handlers.add(handler);\n return () => this.handlers.delete(handler);\n }\n\n stop(): void {\n if (!this.child) return;\n this.closed = true;\n try {\n this.child.kill();\n } catch {\n // already dead\n }\n this.child = null;\n }\n\n private onChildData(chunk: string): void {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() ?? '';\n\n for (const raw of lines) {\n if (!raw.trim()) continue;\n try {\n this.dispatch(JSON.parse(raw) as ACPMessage);\n } catch {\n // skip malformed\n }\n }\n }\n\n private onChildError(chunk: string): void {\n writeErr(`[acp-child stderr] ${chunk}`);\n }\n\n private onChildClose(code: number | null): void {\n this.closed = true;\n this.resolveRead?.(null);\n this.resolveRead = null;\n if (code !== 0 && code !== null) {\n writeErr(`[acp-child exited with code ${code}]\\n`);\n }\n }\n\n private dispatch(msg: ACPMessage): void {\n if (this.resolveRead) {\n const resolve = this.resolveRead;\n this.resolveRead = null;\n resolve(msg);\n } else {\n this.messageQueue.push(msg);\n }\n for (const handler of this.handlers) {\n try {\n handler(msg);\n } catch {\n // non-fatal\n }\n }\n }\n}\n","/**\n * ToolTranslator — bidirectional translation between WrongStack tools and\n * ACP tool representations.\n *\n * Used by DIR-1 (WrongStack as ACP client) to:\n * - Map WrongStack TaskSpec → ACP task payload\n * - Map ACP tool responses → TaskResult\n *\n * Used by DIR-2 (WrongStack as ACP server) to:\n * - Convert the WrongStack Tool.inputSchema → ACPToolDefinition.inputSchema\n * - (handled by tools-registry.ts — same logic lives there)\n *\n * For DIR-1 async tool calls: ACP agents send progress notifications while\n * a tool is running, then send a final result. The translator handles this\n * by polling for the final [result] notification on the transport.\n */\nimport type {ACPMessage, ACPToolDefinition, ACPToolCallResponse, ContentBlock} from '../types/acp-messages.js';\nimport type {TaskSpec, TaskResult} from '@wrongstack/core';\n\nexport interface ToolTranslatorOptions {\n /**\n * If true (default), wrap tool calls in an async poll loop that waits\n * for progress notifications until a final result arrives.\n */\n asyncTools?: boolean;\n pollIntervalMs?: number;\n totalTimeoutMs?: number;\n}\n\nconst DEFAULT_OPTIONS: Required<ToolTranslatorOptions> = {\n asyncTools: true,\n pollIntervalMs: 500,\n totalTimeoutMs: 120_000,\n};\n\n/** Convert an ACP ACPToolDefinition → a JSON schema object recognisable by WrongStack */\nexport function acpToolToSchema(def: ACPToolDefinition): Record<string, unknown> {\n if (!def.inputSchema) return {type: 'object', properties: {}};\n return def.inputSchema as Record<string, unknown>;\n}\n\n/** Extract tool result text from ACP ContentBlock[] */\nexport function extractTextFromContent(blocks: ContentBlock[]): string {\n const parts: string[] = [];\n for (const b of blocks) {\n if (b.type === 'text') parts.push(b.text);\n else if (b.type === 'resource') parts.push(`[resource: ${b.resource.uri}]`);\n else if (b.type === 'image') parts.push(`[image: ${b.data.slice(0, 20)}...]`);\n else if (b.type === 'progress') {\n if (b.messages?.length) parts.push(b.messages.join('\\n'));\n }\n }\n return parts.join('\\n');\n}\n\n/** Build a TaskSpec from an ACP task payload */\nexport function buildTaskSpec(payload: {\n taskId: string;\n task: string;\n subagentId?: string;\n}): TaskSpec {\n return {\n id: payload.taskId,\n description: payload.task,\n subagentId: payload.subagentId,\n };\n}\n\n/** Parse an ACP tools/call response → TaskResult */\nexport function parseToolResponse(\n taskId: string,\n subagentId: string,\n response: ACPToolCallResponse,\n): TaskResult {\n const blocks = response.result.content;\n const text = extractTextFromContent(blocks);\n\n // Detect error state from isError flag or error-like text\n const isError =\n response.result.isError || text.toLowerCase().includes('error') ||\n text.toLowerCase().includes('failed');\n\n return {\n taskId,\n subagentId,\n status: isError ? 'failed' : 'success',\n result: text,\n iterations: 1,\n toolCalls: 1,\n durationMs: 0,\n };\n}\n\n/** ToolTranslator for DIR-1 — wraps ACP client transport, adds task semantics */\nexport class ToolTranslator {\n private readonly opts: Required<ToolTranslatorOptions>;\n private readonly pending = new Map<string | number, {\n resolve: (v: ACPToolCallResponse) => void;\n reject: (e: Error) => void;\n timeout: ReturnType<typeof setTimeout>;\n }>();\n\n constructor(opts: ToolTranslatorOptions = {}) {\n this.opts = {...DEFAULT_OPTIONS, ...opts};\n }\n\n /**\n * Start listening to a transport for tool responses and cancellations.\n * Call this once after constructing the translator and before sending tasks.\n */\n attachToTransport(\n transport: {onMessage: (h: (msg: ACPMessage) => void) => () => void; send: (msg: ACPMessage) => Promise<void>},\n ): void {\n transport.onMessage((msg) => {\n if (msg.method === 'tools/call' && msg.id !== undefined) {\n const pending = this.pending.get(msg.id);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(msg.id!);\n pending.resolve(msg as unknown as ACPToolCallResponse);\n }\n }\n\n // Handle cancellation notifications\n if (msg.method === 'cancel' && msg.id !== undefined) {\n const pending = this.pending.get(msg.id);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(msg.id!);\n pending.reject(new Error('Call cancelled by client'));\n }\n }\n });\n }\n\n /**\n * Send a tool call over the transport and wait for a response.\n * If asyncTools is true, polls for progress and resolves when the final\n * response arrives.\n */\n async callTool(\n transport: {send: (msg: ACPMessage) => Promise<void>},\n name: string,\n args: Record<string, unknown>,\n callId: string | number = crypto.randomUUID(),\n ): Promise<ACPToolCallResponse> {\n await transport.send({\n method: 'tools/call',\n id: callId,\n params: {name, arguments: args},\n });\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.pending.delete(callId);\n reject(new Error(`Tool call ${name} timed out after ${this.opts.totalTimeoutMs}ms`));\n }, this.opts.totalTimeoutMs);\n\n this.pending.set(callId, {resolve, reject, timeout});\n });\n }\n\n cancelAll(): void {\n for (const [, p] of this.pending) {\n clearTimeout(p.timeout);\n }\n this.pending.clear();\n }\n}\n","/**\n * ACPSubagentRunner — SubagentRunner implementation for DIR-1.\n *\n * Wraps an external ACP agent (Cline, Gemini CLI, Codex CLI, Copilot, etc.)\n * as a WrongStack subagent. The external agent runs its own agent loop;\n * we send it a task via ACP and return the result.\n *\n * Connected to Director / MultiAgentCoordinator via the SubagentRunner\n * interface (same as AgentSubagentRunner).\n */\nimport type {SubagentRunContext, SubagentRunner, TaskSpec} from '@wrongstack/core';\nimport {ClientTransport} from '../agent/stdio-transport.js';\nimport type {ACPToolCallResponse} from '../types/acp-messages.js';\nimport {ToolTranslator, parseToolResponse} from '../client/tool-translator.js';\nimport type {ToolTranslatorOptions} from '../client/tool-translator.js';\n\nexport interface ACPSubagentRunnerOptions {\n /** ACP agent command or npm package (e.g. 'npx', 'gemini', 'gh') */\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n /** Subagent role — used for protocol negotiation and prompt overrides */\n role?: string;\n toolTranslatorOpts?: ToolTranslatorOptions;\n}\n\n/** Map WrongStack ACP agent role → how to spawn it. */\nexport const ACP_AGENT_COMMANDS: Record<string, ACPSubagentRunnerOptions> = {\n cline: {\n command: 'npx',\n args: ['-y', '@agentify/cline'],\n role: 'cline',\n },\n 'gemini-cli': {\n command: 'gemini',\n role: 'gemini-cli',\n },\n copilot: {\n command: 'gh',\n args: ['copilot', 'agent'],\n role: 'copilot',\n },\n openhands: {\n command: 'openhands',\n role: 'openhands',\n },\n goose: {\n command: 'goose',\n role: 'goose',\n },\n};\n\n/**\n * Build an ACPSubagentRunner for a given role, or a generic one from explicit options.\n */\nexport async function makeACPSubagentRunner(\n options: ACPSubagentRunnerOptions,\n): Promise<SubagentRunner> {\n const transport = new ClientTransport({\n command: options.command,\n args: options.args,\n env: options.env,\n cwd: options.cwd,\n handshakeTimeoutMs: 30_000,\n });\n\n const translator = new ToolTranslator(options.toolTranslatorOpts);\n const activeAbort = new AbortController();\n\n let sessionStarted = false;\n\n const startSession = async (): Promise<void> => {\n if (sessionStarted) return;\n await transport.start();\n\n await transport.send({\n method: 'initialize',\n id: '1',\n params: {\n capabilities: ['code-generation', 'async-tools', 'streaming', 'progress'],\n protocolVersion: '2024-11',\n sessionId: options.role ?? 'wrongstack-subagent',\n },\n });\n\n const initResp = await transport.read();\n if (!initResp || initResp.error) {\n throw new Error(`ACP initialize failed: ${initResp?.error?.message ?? 'no response'}`);\n }\n\n translator.attachToTransport({\n onMessage: (h) => transport.onMessage(h),\n send: (m) => transport.send(m),\n });\n\n sessionStarted = true;\n };\n\n const runner: SubagentRunner = async (\n task: TaskSpec,\n ctx: SubagentRunContext,\n ): Promise<{result?: unknown; iterations: number; toolCalls: number}> => {\n ctx.signal.addEventListener('abort', () => {\n activeAbort.abort();\n transport.stop();\n });\n\n await startSession();\n\n const callId = crypto.randomUUID();\n let toolResult: ACPToolCallResponse | null = null;\n\n const resultPromise = new Promise<ACPToolCallResponse>((resolve, reject) => {\n const budgetMs = ctx.budget.limits.timeoutMs ?? 300_000;\n\n const timeout = setTimeout(() => {\n reject(new Error(`ACP task timed out for subagent ${ctx.subagentId} (${budgetMs}ms budget)`));\n }, budgetMs);\n\n transport.onMessage((msg) => {\n if (msg.method === 'tools/call' && msg.id !== undefined) {\n clearTimeout(timeout);\n resolve(msg as unknown as ACPToolCallResponse);\n }\n });\n\n ctx.signal.addEventListener('abort', () => {\n clearTimeout(timeout);\n reject(new Error('Task aborted by parent'));\n });\n });\n\n try {\n // Most ACP agents accept a free-form task string as their primary input.\n // Use the tools/call protocol with a special 'task' pseudo-tool if the\n // agent advertises it; otherwise send it as an initialize session detail\n // or a custom agent/run message. The agent will respond on stdout.\n await transport.send({\n method: 'agent/run',\n id: callId,\n params: {\n task: task.description,\n sessionId: ctx.subagentId,\n },\n });\n\n toolResult = await resultPromise;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n result: `ACP subagent error: ${msg}`,\n iterations: 0,\n toolCalls: 0,\n };\n }\n\n if (!toolResult) {\n return {result: 'ACP subagent returned no result', iterations: 1, toolCalls: 1};\n }\n\n const parsed = parseToolResponse(task.id, ctx.subagentId, toolResult);\n return {\n result: parsed.result ?? parsed.error,\n iterations: parsed.iterations,\n toolCalls: parsed.toolCalls,\n };\n };\n\n return runner;\n}\n\n/** Returns the runner and a stop function to clean up the transport. */\nexport async function makeACPSubagentRunnerWithStop(\n options: ACPSubagentRunnerOptions,\n): Promise<{runner: SubagentRunner; stop: () => void}> {\n const transport = new ClientTransport({\n command: options.command,\n args: options.args,\n env: options.env,\n cwd: options.cwd,\n handshakeTimeoutMs: 30_000,\n });\n\n const translator = new ToolTranslator(options.toolTranslatorOpts);\n const activeAbort = new AbortController();\n\n let sessionStarted = false;\n\n const startSession = async (): Promise<void> => {\n if (sessionStarted) return;\n await transport.start();\n\n await transport.send({\n method: 'initialize',\n id: '1',\n params: {\n capabilities: ['code-generation', 'async-tools', 'streaming', 'progress'],\n protocolVersion: '2024-11',\n sessionId: options.role ?? 'wrongstack-subagent',\n },\n });\n\n const initResp = await transport.read();\n if (!initResp || initResp.error) {\n throw new Error(`ACP initialize failed: ${initResp?.error?.message ?? 'no response'}`);\n }\n\n translator.attachToTransport({\n onMessage: (h) => transport.onMessage(h),\n send: (m) => transport.send(m),\n });\n\n sessionStarted = true;\n };\n\n const stop = () => {\n activeAbort.abort();\n transport.stop();\n };\n\n const runner: SubagentRunner = async (\n task: TaskSpec,\n ctx: SubagentRunContext,\n ): Promise<{result?: unknown; iterations: number; toolCalls: number}> => {\n ctx.signal.addEventListener('abort', () => {\n activeAbort.abort();\n transport.stop();\n });\n\n await startSession();\n\n const callId = crypto.randomUUID();\n let toolResult: ACPToolCallResponse | null = null;\n\n const resultPromise = new Promise<ACPToolCallResponse>((resolve, reject) => {\n const budgetMs = ctx.budget.limits.timeoutMs ?? 300_000;\n\n const timeout = setTimeout(() => {\n reject(new Error(`ACP task timed out for subagent ${ctx.subagentId} (${budgetMs}ms budget)`));\n }, budgetMs);\n\n transport.onMessage((msg) => {\n if (msg.method === 'tools/call' && msg.id !== undefined) {\n clearTimeout(timeout);\n resolve(msg as unknown as ACPToolCallResponse);\n }\n });\n\n ctx.signal.addEventListener('abort', () => {\n clearTimeout(timeout);\n reject(new Error('Task aborted by parent'));\n });\n });\n\n try {\n await transport.send({\n method: 'agent/run',\n id: callId,\n params: {\n task: task.description,\n sessionId: ctx.subagentId,\n },\n });\n\n toolResult = await resultPromise;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n result: `ACP subagent error: ${msg}`,\n iterations: 0,\n toolCalls: 0,\n };\n }\n\n if (!toolResult) {\n return {result: 'ACP subagent returned no result', iterations: 1, toolCalls: 1};\n }\n\n const parsed = parseToolResponse(task.id, ctx.subagentId, toolResult);\n return {\n result: parsed.result ?? parsed.error,\n iterations: parsed.iterations,\n toolCalls: parsed.toolCalls,\n };\n };\n\n return {runner, stop};\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildChildEnv } from '@wrongstack/core';
|
|
1
|
+
import { writeErr, buildChildEnv } from '@wrongstack/core';
|
|
2
2
|
import { spawn } from 'child_process';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
|
|
@@ -193,15 +193,15 @@ var ClientTransport = class {
|
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
onChildError(chunk) {
|
|
196
|
-
|
|
196
|
+
writeErr(`[acp-child stderr] ${chunk}`);
|
|
197
197
|
}
|
|
198
198
|
onChildClose(code) {
|
|
199
199
|
this.closed = true;
|
|
200
200
|
this.resolveRead?.(null);
|
|
201
201
|
this.resolveRead = null;
|
|
202
202
|
if (code !== 0 && code !== null) {
|
|
203
|
-
|
|
204
|
-
|
|
203
|
+
writeErr(`[acp-child exited with code ${code}]
|
|
204
|
+
`);
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
207
|
dispatch(msg) {
|
|
@@ -510,13 +510,18 @@ var WrongStackACPServer = class {
|
|
|
510
510
|
* 1. Send the startup marker `[wstack-acp]` so the client
|
|
511
511
|
* knows which stdout line is the protocol boundary.
|
|
512
512
|
* 2. Loop: read messages, dispatch to handler, until EOF or error.
|
|
513
|
+
*
|
|
514
|
+
* Single dispatch path: every inbound message is read exactly once
|
|
515
|
+
* from the transport and passed to the protocol handler exactly once.
|
|
516
|
+
* An earlier version combined a `transport.onMessage` callback with
|
|
517
|
+
* this read loop, which caused every message to be processed twice
|
|
518
|
+
* (once by the callback, once by the loop) — duplicate tool calls
|
|
519
|
+
* and duplicate responses to the client. See the ACP double-dispatch
|
|
520
|
+
* fix in the security audit (P1-001).
|
|
513
521
|
*/
|
|
514
522
|
async start() {
|
|
515
523
|
this.transport.sendStartupMarker();
|
|
516
524
|
this.running = true;
|
|
517
|
-
this.transport.onMessage((msg) => {
|
|
518
|
-
void this.handler.handleMessage(msg);
|
|
519
|
-
});
|
|
520
525
|
while (this.running) {
|
|
521
526
|
const msg = await this.transport.read();
|
|
522
527
|
if (!msg) break;
|
|
@@ -538,7 +543,7 @@ async function main() {
|
|
|
538
543
|
var isEntrypoint = process.argv[1] !== void 0 && fileURLToPath(import.meta.url) === process.argv[1];
|
|
539
544
|
if (isEntrypoint) {
|
|
540
545
|
main().catch((err) => {
|
|
541
|
-
|
|
546
|
+
writeErr(`[wstack-acp fatal] ${err}
|
|
542
547
|
`);
|
|
543
548
|
process.exit(1);
|
|
544
549
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/agent/stdio-transport.ts","../src/agent/tools-registry.ts","../src/agent/protocol-handler.ts","../src/agent/wrongstack-acp-agent.ts","../src/client/tool-translator.ts","../src/integration/acp-subagent-runner.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * StdioTransport — bidirectional stdin/stdout communication for ACP.\n *\n * ACP uses newline-delimited JSON-RPC 2.0 messages over stdio:\n * client → agent: JSON-RPC request/notification on stdin\n * agent → client: JSON-RPC response/notification on stdout\n *\n * Start message: clients look for the `[wstack-acp]` marker on stdout before\n * treating subsequent lines as protocol messages.\n */\nimport { buildChildEnv } from '@wrongstack/core';\nimport type { ACPMessage } from '../types/acp-messages.js';\n\nexport interface AgentServerTransport {\n send(msg: ACPMessage): Promise<void>;\n sendRaw(chunk: string): void;\n read(): Promise<ACPMessage | null>;\n close(): void;\n onMessage(handler: (msg: ACPMessage) => void): () => void;\n}\n\nexport class StdioTransport implements AgentServerTransport {\n private readonly stdin = process.stdin;\n private readonly stdout = process.stdout;\n private readonly stderr = process.stderr;\n\n private buffer = '';\n private readonly handlers = new Set<(msg: ACPMessage) => void>();\n private closed = false;\n private resolveRead: ((msg: ACPMessage | null) => void) | null = null;\n private messageQueue: ACPMessage[] = [];\n\n constructor() {\n this.stdin.resume();\n this.stdin.setEncoding('utf8');\n this.stdin.on('data', (chunk: string) => this.onData(chunk));\n this.stdin.on('end', () => this.handleClose());\n this.stdin.on('error', (err: Error) => this.failAll(err));\n }\n\n sendStartupMarker(): void {\n this.stdout.write('[wstack-acp]\\n', 'utf8');\n }\n\n send(msg: ACPMessage): Promise<void> {\n if (this.closed) return Promise.resolve();\n return new Promise((resolve) => {\n const line = JSON.stringify(msg) + '\\n';\n this.stdout.write(line, 'utf8', () => resolve());\n });\n }\n\n sendRaw(chunk: string): void {\n this.stdout.write(chunk, 'utf8');\n }\n\n read(): Promise<ACPMessage | null> {\n if (this.messageQueue.length > 0) return Promise.resolve(this.messageQueue.shift()!);\n if (this.closed) return Promise.resolve(null);\n return new Promise((resolve) => {\n this.resolveRead = resolve;\n });\n }\n\n onMessage(handler: (msg: ACPMessage) => void): () => void {\n this.handlers.add(handler);\n return () => this.handlers.delete(handler);\n }\n\n close(): void {\n this.closed = true;\n this.stdin.pause();\n this.resolveRead?.(null);\n this.resolveRead = null;\n }\n\n private onData(chunk: string): void {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() ?? '';\n\n for (const raw of lines) {\n if (!raw.trim()) continue;\n try {\n this.dispatch(JSON.parse(raw) as ACPMessage);\n } catch (err) {\n this.stderr.write(`[wstack-acp parse error] ${err}\\n`, 'utf8');\n }\n }\n }\n\n private dispatch(msg: ACPMessage): void {\n if (this.resolveRead) {\n const resolve = this.resolveRead;\n this.resolveRead = null;\n resolve(msg);\n } else {\n this.messageQueue.push(msg);\n }\n for (const handler of this.handlers) {\n try {\n handler(msg);\n } catch (err) {\n this.stderr.write(`[wstack-acp handler error] ${err}\\n`, 'utf8');\n }\n }\n }\n\n private handleClose(): void {\n this.closed = true;\n this.resolveRead?.(null);\n this.resolveRead = null;\n }\n\n private failAll(err: Error): void {\n this.stderr.write(`[wstack-acp stdin error] ${err.message}\\n`, 'utf8');\n this.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// ClientTransport — spawns a child ACP agent process (DIR-1)\n// ---------------------------------------------------------------------------\n\nimport { spawn } from 'node:child_process';\nimport type { EventEmitter } from 'node:events';\n\nexport interface ClientTransportOptions {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n handshakeTimeoutMs?: number;\n}\n\nexport interface ACPChildProcess extends EventEmitter {\n stdout: NodeJS.ReadableStream;\n stdin: NodeJS.WritableStream;\n stderr: NodeJS.ReadableStream;\n pid: number | undefined;\n kill(): void;\n}\n\nexport class ClientTransport {\n private child: ACPChildProcess | null = null;\n private buffer = '';\n private readonly handlers = new Set<(msg: ACPMessage) => void>();\n private closed = false;\n private resolveRead: ((msg: ACPMessage | null) => void) | null = null;\n private messageQueue: ACPMessage[] = [];\n private readonly opts: Required<Pick<ClientTransportOptions, 'handshakeTimeoutMs'>> &\n ClientTransportOptions;\n\n constructor(options: ClientTransportOptions) {\n this.opts = {\n handshakeTimeoutMs: 30_000,\n ...options,\n };\n }\n\n async start(): Promise<void> {\n if (this.child) return;\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(`ACP child process failed to start within ${this.opts.handshakeTimeoutMs}ms`),\n );\n }, this.opts.handshakeTimeoutMs);\n\n try {\n this.child = spawn(this.opts.command, this.opts.args ?? [], {\n env: { ...buildChildEnv(), ...this.opts.env },\n cwd: this.opts.cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n }) as unknown as ACPChildProcess;\n } catch (err) {\n clearTimeout(timeout);\n reject(err);\n return;\n }\n\n const child = this.child;\n\n child.stdout.setEncoding('utf8');\n\n const waitForMarker = (chunk: string) => {\n this.buffer += chunk;\n const idx = this.buffer.indexOf('[wstack-acp]\\n');\n if (idx !== -1) {\n this.buffer = this.buffer.slice(idx + '[wstack-acp]\\n'.length);\n child.stdout.removeListener('data', waitForMarker);\n child.stdout.on('data', (c: string) => this.onChildData(c));\n child.stderr.on('data', (c: string) => this.onChildError(c));\n child.on('close', (code: number | null) => this.onChildClose(code));\n clearTimeout(timeout);\n resolve();\n }\n };\n\n child.stdout.on('data', waitForMarker);\n child.stdout.on('error', (err: Error) => {\n clearTimeout(timeout);\n reject(err);\n });\n child.on('error', (err: Error) => {\n clearTimeout(timeout);\n reject(err);\n });\n });\n }\n\n send(msg: ACPMessage): Promise<void> {\n if (!this.child) return Promise.reject(new Error('ClientTransport not started'));\n return new Promise((resolve, reject) => {\n const line = JSON.stringify(msg) + '\\n';\n this.child!.stdin.write(line, 'utf8', (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n }\n\n read(): Promise<ACPMessage | null> {\n if (this.messageQueue.length > 0) return Promise.resolve(this.messageQueue.shift()!);\n if (this.closed) return Promise.resolve(null);\n return new Promise((resolve) => {\n this.resolveRead = resolve;\n });\n }\n\n onMessage(handler: (msg: ACPMessage) => void): () => void {\n this.handlers.add(handler);\n return () => this.handlers.delete(handler);\n }\n\n stop(): void {\n if (!this.child) return;\n this.closed = true;\n try {\n this.child.kill();\n } catch {\n // already dead\n }\n this.child = null;\n }\n\n private onChildData(chunk: string): void {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() ?? '';\n\n for (const raw of lines) {\n if (!raw.trim()) continue;\n try {\n this.dispatch(JSON.parse(raw) as ACPMessage);\n } catch {\n // skip malformed\n }\n }\n }\n\n private onChildError(chunk: string): void {\n process.stderr.write(`[acp-child stderr] ${chunk}`, 'utf8');\n }\n\n private onChildClose(code: number | null): void {\n this.closed = true;\n this.resolveRead?.(null);\n this.resolveRead = null;\n if (code !== 0 && code !== null) {\n process.stderr.write(`[acp-child exited with code ${code}]\\n`, 'utf8');\n }\n }\n\n private dispatch(msg: ACPMessage): void {\n if (this.resolveRead) {\n const resolve = this.resolveRead;\n this.resolveRead = null;\n resolve(msg);\n } else {\n this.messageQueue.push(msg);\n }\n for (const handler of this.handlers) {\n try {\n handler(msg);\n } catch {\n // non-fatal\n }\n }\n }\n}\n","/**\n * Tools registry for ACP agent-side.\n *\n * Translates WrongStack Tool definitions → ACP ACPToolDefinition format.\n * Provides tool lookup and result assembly for the ACP protocol handler.\n */\nimport type {Tool} from '@wrongstack/core';\nimport type {\n ACPToolDefinition,\n ACPToolList,\n ACPInputSchema,\n ACPToolResult,\n ContentBlock,\n} from '../types/acp-messages.js';\n\nexport class ACPToolsRegistry {\n private tools = new Map<string, Tool>();\n private readonly owner: string;\n\n constructor(owner = 'wrongstack') {\n this.owner = owner;\n }\n\n /**\n * Register one or more tools.\n * Throws on duplicate name unless force=true.\n */\n register(tools: Tool[]): void {\n for (const tool of tools) {\n this.tools.set(tool.name, tool);\n }\n }\n\n /**\n * Replace the current tool set.\n */\n setTools(tools: Tool[]): void {\n this.tools.clear();\n for (const tool of tools) this.tools.set(tool.name, tool);\n }\n\n get(name: string): Tool | undefined {\n return this.tools.get(name);\n }\n\n has(name: string): boolean {\n return this.tools.has(name);\n }\n\n list(): Tool[] {\n return Array.from(this.tools.values());\n }\n\n /** Build the ACP tools/list payload from registered tools. */\n buildToolList(): ACPToolList {\n return {\n tools: Array.from(this.tools.values()).map((t) =>\n toACPToolDefinition(t, this.owner),\n ),\n };\n }\n\n /**\n * Execute a tool by name and return ACP-formatted result.\n * Returns null if the tool is not found.\n */\n async execute(\n name: string,\n args: Record<string, unknown>,\n ctx: unknown,\n signal: AbortSignal,\n ): Promise<ACPToolResult | null> {\n const tool = this.tools.get(name);\n if (!tool) return null;\n\n try {\n const result = await tool.execute(args, ctx as Parameters<Tool['execute']>[1], {\n signal,\n });\n return toACPToolResult(result);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {content: [{type: 'text', text: msg}], isError: true} satisfies ACPToolResult;\n }\n }\n}\n\n/** Convert a WrongStack Tool → ACP ACPToolDefinition */\nfunction toACPToolDefinition(tool: Tool, _owner: string): ACPToolDefinition {\n return {\n name: tool.name,\n description: tool.description,\n inputSchema: toACPInputSchema(tool.inputSchema),\n annotations: {\n title: tool.name,\n description: tool.usageHint ?? tool.description,\n priority: toolToPriority(tool),\n alwaysAccept: tool.permission === 'auto',\n },\n };\n}\n\n/** Minimal JSON Schema → ACP input schema. ACP uses JSON Schema draft-07. */\nfunction toACPInputSchema(src: unknown): ACPInputSchema {\n if (!src || typeof src !== 'object') {\n return {};\n }\n const s = src as Record<string, unknown>;\n\n // Recursively convert properties\n if (s.properties && typeof s.properties === 'object') {\n const props: Record<string, ACPInputSchema> = {};\n for (const [k, v] of Object.entries(s.properties as Record<string, unknown>)) {\n props[k] = toACPInputSchema(v);\n }\n return {\n type: typeof s.type === 'string' ? s.type : undefined,\n properties: props,\n required: Array.isArray(s.required) ? (s.required as string[]) : undefined,\n items: s.items ? toACPInputSchema(s.items) : undefined,\n enum: Array.isArray(s.enum) ? s.enum : undefined,\n description: typeof s.description === 'string' ? s.description : undefined,\n default: s.default,\n minimum: typeof s.minimum === 'number' ? s.minimum : undefined,\n maximum: typeof s.maximum === 'number' ? s.maximum : undefined,\n };\n }\n\n return {\n type: typeof s.type === 'string' ? s.type : undefined,\n items: s.items ? toACPInputSchema(s.items) : undefined,\n enum: Array.isArray(s.enum) ? s.enum : undefined,\n description: typeof s.description === 'string' ? s.description : undefined,\n default: s.default,\n minimum: typeof s.minimum === 'number' ? s.minimum : undefined,\n maximum: typeof s.maximum === 'number' ? s.maximum : undefined,\n };\n}\n\n/** Convert a WrongStack ToolResult → ACP ContentBlock[] */\nfunction toACPToolResult(result: unknown): ACPToolResult {\n const blocks: ContentBlock[] = [];\n\n if (result === undefined || result === null) {\n return {content: [{type: 'text', text: 'ok'}]};\n }\n\n if (typeof result === 'string') {\n blocks.push({type: 'text', text: result});\n } else if (typeof result === 'object') {\n blocks.push({type: 'text', text: JSON.stringify(result, null, 2)});\n } else {\n blocks.push({type: 'text', text: String(result)});\n }\n\n return {content: blocks};\n}\n\nfunction toolToPriority(tool: Tool): 'high' | 'medium' | 'low' {\n if (tool.riskTier === 'destructive') return 'high';\n if (tool.riskTier === 'standard' || tool.permission === 'confirm') return 'medium';\n return 'low';\n}\n","/**\n * ACPProtocolHandler — state machine for ACP server-side message handling.\n *\n * ACP turn lifecycle:\n * idle → [initialize] → await-turn → [tools/call] → executing\n * → [tool result sent] → idle\n *\n * We implement this as a simple switch on the method name, since the ACP\n * protocol is request/response based (not streaming) on the wire.\n *\n * Concurrency: ACP allows Cancellations and multiple concurrent tool calls\n * within a turn. We handle each tools/call in its own Promise.all.\n */\nimport type {\n ACPMessage,\n ACPRequest,\n ACPNotification,\n ACPInitializeParams,\n ACPToolCallRequest,\n ACPToolResult,\n ACPToolCallResponse,\n} from '../types/acp-messages.js';\nimport type {AgentServerTransport} from './stdio-transport.js';\n\nexport const WRONGSTACK_VERSION = '0.1.0';\nconst WRONGSTACK_CAPABILITIES = [\n 'code-generation',\n 'async-tools',\n 'streaming',\n 'progress',\n];\n\nexport class ACPProtocolHandler {\n private initialized = false;\n private readonly signal = new AbortController();\n private pendingCalls = new Map<string | number, Promise<unknown>>();\n\n constructor(\n private readonly transport: AgentServerTransport,\n private readonly registry: import('./tools-registry.js').ACPToolsRegistry,\n private readonly context: unknown,\n ) {}\n\n /** Wire an external abort signal from the ACP client */\n wireAbortController(abortController: AbortController): void {\n abortController.signal.addEventListener('abort', () => {\n for (const id of this.pendingCalls.keys()) {\n this.transport.send({id, method: 'cancel', result: {ok: true}}).catch(() => {});\n }\n });\n }\n\n /** Process one inbound message. Returns true if this was a terminal message. */\n async handleMessage(msg: ACPMessage): Promise<boolean> {\n if (msg.id !== undefined) {\n return this.handleRequest(msg as ACPRequest);\n }\n return this.handleNotification(msg as ACPNotification);\n }\n\n private async handleRequest(req: ACPRequest): Promise<boolean> {\n if (req.method !== 'initialize' && !this.initialized) {\n await this.sendError(req.id ?? null, -32000, 'Not initialized');\n return false;\n }\n\n // All requests after initialization check have a guaranteed id\n const id = req.id as string | number;\n\n switch (req.method) {\n case 'initialize':\n return this.handleInitialize(req as ACPRequest & {params: ACPInitializeParams}, id);\n case 'ping':\n await this.transport.send({id, method: 'ping', result: {pong: true}});\n return false;\n case 'tools/call':\n return this.handleToolCall(req as ACPRequest & {params: ACPToolCallRequest['params']}, id);\n case 'tools/list':\n return this.handleToolsList(id);\n case 'cancel':\n return this.handleCancel(id);\n case 'session/list':\n return this.handleSessionList(id);\n case 'sessionInfoUpdate':\n await this.transport.send({id, method: 'sessionInfoUpdate', result: {ok: true}});\n return false;\n default:\n await this.sendError(id, -32601, `Unknown method: ${req.method}`);\n return false;\n }\n }\n\n private async handleNotification(n: ACPNotification): Promise<boolean> {\n if (n.method === 'cancel') {\n this.handleCancelNotification(n as ACPNotification & {params?: {reason?: string}});\n }\n return false;\n }\n\n private async handleInitialize(\n req: ACPRequest & {params: ACPInitializeParams},\n id: string | number,\n ): Promise<boolean> {\n this.initialized = true;\n\n const result = {\n capabilities: WRONGSTACK_CAPABILITIES,\n agentName: 'WrongStack',\n agentVersion: WRONGSTACK_VERSION,\n protocolVersion: req.params?.protocolVersion ?? '2024-11',\n ...this.registry.buildToolList(),\n };\n\n await this.transport.send({id, method: 'initialize', result});\n return false;\n }\n\n private async handleToolsList(id: string | number): Promise<boolean> {\n await this.transport.send({\n id,\n method: 'tools/list',\n result: this.registry.buildToolList(),\n });\n return false;\n }\n\n private async handleToolCall(\n req: ACPRequest & {params: {name: string; arguments: Record<string, unknown>}},\n id: string | number,\n ): Promise<boolean> {\n const {name, arguments: args} = req.params;\n\n const runPromise = (async () => {\n if (!this.registry.has(name)) {\n return {\n content: [{type: 'text', text: `Tool not found: ${name}`}],\n isError: true,\n } satisfies ACPToolResult;\n }\n\n const result = await this.registry.execute(\n name,\n args,\n this.context,\n this.signal.signal,\n );\n return result ?? {content: [{type: 'text', text: 'Tool returned null'}], isError: false};\n })();\n\n this.pendingCalls.set(id, runPromise);\n\n try {\n const toolResult = (await runPromise) as ACPToolResult;\n this.pendingCalls.delete(id);\n\n const response: ACPToolCallResponse = {method: 'tools/call', id, result: toolResult};\n await this.transport.send(response);\n } catch (err) {\n this.pendingCalls.delete(id);\n const msg = err instanceof Error ? err.message : String(err);\n await this.transport.send({\n id,\n method: 'tools/call',\n result: {content: [{type: 'text', text: msg}], isError: true},\n });\n }\n\n return false;\n }\n\n private async handleCancel(id: string | number): Promise<boolean> {\n this.pendingCalls.delete(id);\n await this.transport.send({id, method: 'cancel', result: {ok: true}});\n return false;\n }\n\n private handleCancelNotification(\n _n: ACPNotification & {params?: {reason?: string}},\n ): void {\n // Broadcast cancellation to all pending — best-effort\n }\n\n private async handleSessionList(id: string | number): Promise<boolean> {\n await this.transport.send({\n id,\n method: 'session/list',\n result: {sessions: []},\n });\n return false;\n }\n\n private async sendError(id: string | number | null, code: number, message: string): Promise<void> {\n if (id === null) return;\n await this.transport.send({id, method: '', error: {code, message}});\n }\n}\n","/**\n * WrongStackACPServer — ACP server-side entry point.\n *\n * Exposes WrongStack as an ACP-compatible agent. ACP clients (Zed, JetBrains,\n * VS Code ACP extension) spawn this as a subprocess, send JSON-RPC messages\n * over stdio, and receive tool responses.\n *\n * Usage:\n * node dist/agent/wrongstack-acp-agent.js\n *\n * Or via the CLI:\n * wstack acp-server\n *\n * Startup: sends `[wstack-acp]\\n` to stdout so the client knows which process\n * is the ACP server before protocol messages begin.\n */\nimport {fileURLToPath} from 'node:url';\nimport {StdioTransport} from './stdio-transport.js';\nimport {ACPToolsRegistry} from './tools-registry.js';\nimport {ACPProtocolHandler} from './protocol-handler.js';\nimport type {Tool} from '@wrongstack/core';\n\nexport interface WrongStackACPServerOptions {\n /**\n * Initial tool set. Typically loaded from the WrongStack tool registry\n * via `api.tools.list()` so the ACP server exposes exactly the tools the\n * CLI has configured.\n */\n tools: Tool[];\n /**\n * Owner label for tool metadata. Passed to ACPToolsRegistry.\n * @default 'wrongstack'\n */\n owner?: string;\n}\n\nexport class WrongStackACPServer {\n private readonly transport: StdioTransport;\n private readonly registry: ACPToolsRegistry;\n private readonly handler: ACPProtocolHandler;\n private running = false;\n\n constructor(opts: WrongStackACPServerOptions) {\n this.transport = new StdioTransport();\n this.registry = new ACPToolsRegistry(opts.owner);\n this.registry.register(opts.tools);\n this.handler = new ACPProtocolHandler(\n this.transport,\n this.registry,\n /* TODO: load WrongStack Context */ {},\n );\n }\n\n /**\n * Start the server. Blocks until the client disconnects.\n *\n * 1. Send the startup marker `[wstack-acp]` so the client\n * knows which stdout line is the protocol boundary.\n * 2. Loop: read messages, dispatch to handler, until EOF or error.\n */\n async start(): Promise<void> {\n this.transport.sendStartupMarker();\n this.running = true;\n\n // Handle messages via callback + read loop hybrid\n this.transport.onMessage((msg) => {\n void this.handler.handleMessage(msg); // fire-and-forget; ordering is per-message\n });\n\n while (this.running) {\n const msg = await this.transport.read();\n if (!msg) break; // EOF\n const terminal = await this.handler.handleMessage(msg);\n if (terminal) break;\n }\n\n this.transport.close();\n }\n\n /** Stop the server. */\n stop(): void {\n this.running = false;\n this.transport.close();\n }\n}\n\n/**\n * Bootstrap function for `node dist/agent/wrongstack-acp-agent.js`.\n * Instantiates the server with the default tool set.\n *\n * Tool loading: the ACP agent is a subprocess without the full CLI context,\n * so it needs to receive its tools from the parent via environment or a\n * pre-main bootstrap. For now, it uses an empty tool set unless tools are\n * explicitly passed via constructor options.\n *\n * In practice the CLI will instantiate and run WrongStackACPServer directly,\n * passing `api.tools.list()` as the tool set.\n */\nasync function main(): Promise<void> {\n const server = new WrongStackACPServer({tools: []});\n await server.start();\n}\n\n// Only auto-start when this file is the process entrypoint (e.g.\n// `node dist/agent/wrongstack-acp-agent.js`). Importing the module — which the\n// CLI does to reuse `WrongStackACPServer` — must stay side-effect-free, or\n// every launch would start an ACP server and hijack stdin.\nconst isEntrypoint = process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1];\nif (isEntrypoint) {\n main().catch((err) => {\n process.stderr.write(`[wstack-acp fatal] ${err}\\n`);\n process.exit(1);\n });\n}\n","/**\n * ToolTranslator — bidirectional translation between WrongStack tools and\n * ACP tool representations.\n *\n * Used by DIR-1 (WrongStack as ACP client) to:\n * - Map WrongStack TaskSpec → ACP task payload\n * - Map ACP tool responses → TaskResult\n *\n * Used by DIR-2 (WrongStack as ACP server) to:\n * - Convert the WrongStack Tool.inputSchema → ACPToolDefinition.inputSchema\n * - (handled by tools-registry.ts — same logic lives there)\n *\n * For DIR-1 async tool calls: ACP agents send progress notifications while\n * a tool is running, then send a final result. The translator handles this\n * by polling for the final [result] notification on the transport.\n */\nimport type {ACPMessage, ACPToolDefinition, ACPToolCallResponse, ContentBlock} from '../types/acp-messages.js';\nimport type {TaskSpec, TaskResult} from '@wrongstack/core';\n\nexport interface ToolTranslatorOptions {\n /**\n * If true (default), wrap tool calls in an async poll loop that waits\n * for progress notifications until a final result arrives.\n */\n asyncTools?: boolean;\n pollIntervalMs?: number;\n totalTimeoutMs?: number;\n}\n\nconst DEFAULT_OPTIONS: Required<ToolTranslatorOptions> = {\n asyncTools: true,\n pollIntervalMs: 500,\n totalTimeoutMs: 120_000,\n};\n\n/** Convert an ACP ACPToolDefinition → a JSON schema object recognisable by WrongStack */\nexport function acpToolToSchema(def: ACPToolDefinition): Record<string, unknown> {\n if (!def.inputSchema) return {type: 'object', properties: {}};\n return def.inputSchema as Record<string, unknown>;\n}\n\n/** Extract tool result text from ACP ContentBlock[] */\nexport function extractTextFromContent(blocks: ContentBlock[]): string {\n const parts: string[] = [];\n for (const b of blocks) {\n if (b.type === 'text') parts.push(b.text);\n else if (b.type === 'resource') parts.push(`[resource: ${b.resource.uri}]`);\n else if (b.type === 'image') parts.push(`[image: ${b.data.slice(0, 20)}...]`);\n else if (b.type === 'progress') {\n if (b.messages?.length) parts.push(b.messages.join('\\n'));\n }\n }\n return parts.join('\\n');\n}\n\n/** Build a TaskSpec from an ACP task payload */\nexport function buildTaskSpec(payload: {\n taskId: string;\n task: string;\n subagentId?: string;\n}): TaskSpec {\n return {\n id: payload.taskId,\n description: payload.task,\n subagentId: payload.subagentId,\n };\n}\n\n/** Parse an ACP tools/call response → TaskResult */\nexport function parseToolResponse(\n taskId: string,\n subagentId: string,\n response: ACPToolCallResponse,\n): TaskResult {\n const blocks = response.result.content;\n const text = extractTextFromContent(blocks);\n\n // Detect error state from isError flag or error-like text\n const isError =\n response.result.isError || text.toLowerCase().includes('error') ||\n text.toLowerCase().includes('failed');\n\n return {\n taskId,\n subagentId,\n status: isError ? 'failed' : 'success',\n result: text,\n iterations: 1,\n toolCalls: 1,\n durationMs: 0,\n };\n}\n\n/** ToolTranslator for DIR-1 — wraps ACP client transport, adds task semantics */\nexport class ToolTranslator {\n private readonly opts: Required<ToolTranslatorOptions>;\n private readonly pending = new Map<string | number, {\n resolve: (v: ACPToolCallResponse) => void;\n reject: (e: Error) => void;\n timeout: ReturnType<typeof setTimeout>;\n }>();\n\n constructor(opts: ToolTranslatorOptions = {}) {\n this.opts = {...DEFAULT_OPTIONS, ...opts};\n }\n\n /**\n * Start listening to a transport for tool responses and cancellations.\n * Call this once after constructing the translator and before sending tasks.\n */\n attachToTransport(\n transport: {onMessage: (h: (msg: ACPMessage) => void) => () => void; send: (msg: ACPMessage) => Promise<void>},\n ): void {\n transport.onMessage((msg) => {\n if (msg.method === 'tools/call' && msg.id !== undefined) {\n const pending = this.pending.get(msg.id);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(msg.id!);\n pending.resolve(msg as unknown as ACPToolCallResponse);\n }\n }\n\n // Handle cancellation notifications\n if (msg.method === 'cancel' && msg.id !== undefined) {\n const pending = this.pending.get(msg.id);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(msg.id!);\n pending.reject(new Error('Call cancelled by client'));\n }\n }\n });\n }\n\n /**\n * Send a tool call over the transport and wait for a response.\n * If asyncTools is true, polls for progress and resolves when the final\n * response arrives.\n */\n async callTool(\n transport: {send: (msg: ACPMessage) => Promise<void>},\n name: string,\n args: Record<string, unknown>,\n callId: string | number = crypto.randomUUID(),\n ): Promise<ACPToolCallResponse> {\n await transport.send({\n method: 'tools/call',\n id: callId,\n params: {name, arguments: args},\n });\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.pending.delete(callId);\n reject(new Error(`Tool call ${name} timed out after ${this.opts.totalTimeoutMs}ms`));\n }, this.opts.totalTimeoutMs);\n\n this.pending.set(callId, {resolve, reject, timeout});\n });\n }\n\n cancelAll(): void {\n for (const [, p] of this.pending) {\n clearTimeout(p.timeout);\n }\n this.pending.clear();\n }\n}\n","/**\n * ACPSubagentRunner — SubagentRunner implementation for DIR-1.\n *\n * Wraps an external ACP agent (Cline, Gemini CLI, Codex CLI, Copilot, etc.)\n * as a WrongStack subagent. The external agent runs its own agent loop;\n * we send it a task via ACP and return the result.\n *\n * Connected to Director / MultiAgentCoordinator via the SubagentRunner\n * interface (same as AgentSubagentRunner).\n */\nimport type {SubagentRunContext, SubagentRunner, TaskSpec} from '@wrongstack/core';\nimport {ClientTransport} from '../agent/stdio-transport.js';\nimport type {ACPToolCallResponse} from '../types/acp-messages.js';\nimport {ToolTranslator, parseToolResponse} from '../client/tool-translator.js';\nimport type {ToolTranslatorOptions} from '../client/tool-translator.js';\n\nexport interface ACPSubagentRunnerOptions {\n /** ACP agent command or npm package (e.g. 'npx', 'gemini', 'gh') */\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n /** Subagent role — used for protocol negotiation and prompt overrides */\n role?: string;\n toolTranslatorOpts?: ToolTranslatorOptions;\n}\n\n/** Map WrongStack ACP agent role → how to spawn it. */\nexport const ACP_AGENT_COMMANDS: Record<string, ACPSubagentRunnerOptions> = {\n cline: {\n command: 'npx',\n args: ['-y', '@agentify/cline'],\n role: 'cline',\n },\n 'gemini-cli': {\n command: 'gemini',\n role: 'gemini-cli',\n },\n copilot: {\n command: 'gh',\n args: ['copilot', 'agent'],\n role: 'copilot',\n },\n openhands: {\n command: 'openhands',\n role: 'openhands',\n },\n goose: {\n command: 'goose',\n role: 'goose',\n },\n};\n\n/**\n * Build an ACPSubagentRunner for a given role, or a generic one from explicit options.\n */\nexport async function makeACPSubagentRunner(\n options: ACPSubagentRunnerOptions,\n): Promise<SubagentRunner> {\n const transport = new ClientTransport({\n command: options.command,\n args: options.args,\n env: options.env,\n cwd: options.cwd,\n handshakeTimeoutMs: 30_000,\n });\n\n const translator = new ToolTranslator(options.toolTranslatorOpts);\n const activeAbort = new AbortController();\n\n let sessionStarted = false;\n\n const startSession = async (): Promise<void> => {\n if (sessionStarted) return;\n await transport.start();\n\n await transport.send({\n method: 'initialize',\n id: '1',\n params: {\n capabilities: ['code-generation', 'async-tools', 'streaming', 'progress'],\n protocolVersion: '2024-11',\n sessionId: options.role ?? 'wrongstack-subagent',\n },\n });\n\n const initResp = await transport.read();\n if (!initResp || initResp.error) {\n throw new Error(`ACP initialize failed: ${initResp?.error?.message ?? 'no response'}`);\n }\n\n translator.attachToTransport({\n onMessage: (h) => transport.onMessage(h),\n send: (m) => transport.send(m),\n });\n\n sessionStarted = true;\n };\n\n const runner: SubagentRunner = async (\n task: TaskSpec,\n ctx: SubagentRunContext,\n ): Promise<{result?: unknown; iterations: number; toolCalls: number}> => {\n ctx.signal.addEventListener('abort', () => {\n activeAbort.abort();\n transport.stop();\n });\n\n await startSession();\n\n const callId = crypto.randomUUID();\n let toolResult: ACPToolCallResponse | null = null;\n\n const resultPromise = new Promise<ACPToolCallResponse>((resolve, reject) => {\n const budgetMs = ctx.budget.limits.timeoutMs ?? 300_000;\n\n const timeout = setTimeout(() => {\n reject(new Error(`ACP task timed out for subagent ${ctx.subagentId} (${budgetMs}ms budget)`));\n }, budgetMs);\n\n transport.onMessage((msg) => {\n if (msg.method === 'tools/call' && msg.id !== undefined) {\n clearTimeout(timeout);\n resolve(msg as unknown as ACPToolCallResponse);\n }\n });\n\n ctx.signal.addEventListener('abort', () => {\n clearTimeout(timeout);\n reject(new Error('Task aborted by parent'));\n });\n });\n\n try {\n // Most ACP agents accept a free-form task string as their primary input.\n // Use the tools/call protocol with a special 'task' pseudo-tool if the\n // agent advertises it; otherwise send it as an initialize session detail\n // or a custom agent/run message. The agent will respond on stdout.\n await transport.send({\n method: 'agent/run',\n id: callId,\n params: {\n task: task.description,\n sessionId: ctx.subagentId,\n },\n });\n\n toolResult = await resultPromise;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n result: `ACP subagent error: ${msg}`,\n iterations: 0,\n toolCalls: 0,\n };\n }\n\n if (!toolResult) {\n return {result: 'ACP subagent returned no result', iterations: 1, toolCalls: 1};\n }\n\n const parsed = parseToolResponse(task.id, ctx.subagentId, toolResult);\n return {\n result: parsed.result ?? parsed.error,\n iterations: parsed.iterations,\n toolCalls: parsed.toolCalls,\n };\n };\n\n return runner;\n}\n\n/** Returns the runner and a stop function to clean up the transport. */\nexport async function makeACPSubagentRunnerWithStop(\n options: ACPSubagentRunnerOptions,\n): Promise<{runner: SubagentRunner; stop: () => void}> {\n const transport = new ClientTransport({\n command: options.command,\n args: options.args,\n env: options.env,\n cwd: options.cwd,\n handshakeTimeoutMs: 30_000,\n });\n\n const translator = new ToolTranslator(options.toolTranslatorOpts);\n const activeAbort = new AbortController();\n\n let sessionStarted = false;\n\n const startSession = async (): Promise<void> => {\n if (sessionStarted) return;\n await transport.start();\n\n await transport.send({\n method: 'initialize',\n id: '1',\n params: {\n capabilities: ['code-generation', 'async-tools', 'streaming', 'progress'],\n protocolVersion: '2024-11',\n sessionId: options.role ?? 'wrongstack-subagent',\n },\n });\n\n const initResp = await transport.read();\n if (!initResp || initResp.error) {\n throw new Error(`ACP initialize failed: ${initResp?.error?.message ?? 'no response'}`);\n }\n\n translator.attachToTransport({\n onMessage: (h) => transport.onMessage(h),\n send: (m) => transport.send(m),\n });\n\n sessionStarted = true;\n };\n\n const stop = () => {\n activeAbort.abort();\n transport.stop();\n };\n\n const runner: SubagentRunner = async (\n task: TaskSpec,\n ctx: SubagentRunContext,\n ): Promise<{result?: unknown; iterations: number; toolCalls: number}> => {\n ctx.signal.addEventListener('abort', () => {\n activeAbort.abort();\n transport.stop();\n });\n\n await startSession();\n\n const callId = crypto.randomUUID();\n let toolResult: ACPToolCallResponse | null = null;\n\n const resultPromise = new Promise<ACPToolCallResponse>((resolve, reject) => {\n const budgetMs = ctx.budget.limits.timeoutMs ?? 300_000;\n\n const timeout = setTimeout(() => {\n reject(new Error(`ACP task timed out for subagent ${ctx.subagentId} (${budgetMs}ms budget)`));\n }, budgetMs);\n\n transport.onMessage((msg) => {\n if (msg.method === 'tools/call' && msg.id !== undefined) {\n clearTimeout(timeout);\n resolve(msg as unknown as ACPToolCallResponse);\n }\n });\n\n ctx.signal.addEventListener('abort', () => {\n clearTimeout(timeout);\n reject(new Error('Task aborted by parent'));\n });\n });\n\n try {\n await transport.send({\n method: 'agent/run',\n id: callId,\n params: {\n task: task.description,\n sessionId: ctx.subagentId,\n },\n });\n\n toolResult = await resultPromise;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n result: `ACP subagent error: ${msg}`,\n iterations: 0,\n toolCalls: 0,\n };\n }\n\n if (!toolResult) {\n return {result: 'ACP subagent returned no result', iterations: 1, toolCalls: 1};\n }\n\n const parsed = parseToolResponse(task.id, ctx.subagentId, toolResult);\n return {\n result: parsed.result ?? parsed.error,\n iterations: parsed.iterations,\n toolCalls: parsed.toolCalls,\n };\n };\n\n return {runner, stop};\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/agent/stdio-transport.ts","../src/agent/tools-registry.ts","../src/agent/protocol-handler.ts","../src/agent/wrongstack-acp-agent.ts","../src/client/tool-translator.ts","../src/integration/acp-subagent-runner.ts"],"names":["writeErr"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * StdioTransport — bidirectional stdin/stdout communication for ACP.\n *\n * ACP uses newline-delimited JSON-RPC 2.0 messages over stdio:\n * client → agent: JSON-RPC request/notification on stdin\n * agent → client: JSON-RPC response/notification on stdout\n *\n * Start message: clients look for the `[wstack-acp]` marker on stdout before\n * treating subsequent lines as protocol messages.\n */\nimport { buildChildEnv, writeErr } from '@wrongstack/core';\nimport type { ACPMessage } from '../types/acp-messages.js';\n\nexport interface AgentServerTransport {\n send(msg: ACPMessage): Promise<void>;\n sendRaw(chunk: string): void;\n read(): Promise<ACPMessage | null>;\n close(): void;\n onMessage(handler: (msg: ACPMessage) => void): () => void;\n}\n\nexport class StdioTransport implements AgentServerTransport {\n private readonly stdin = process.stdin;\n private readonly stdout = process.stdout;\n private readonly stderr = process.stderr;\n\n private buffer = '';\n private readonly handlers = new Set<(msg: ACPMessage) => void>();\n private closed = false;\n private resolveRead: ((msg: ACPMessage | null) => void) | null = null;\n private messageQueue: ACPMessage[] = [];\n\n constructor() {\n this.stdin.resume();\n this.stdin.setEncoding('utf8');\n this.stdin.on('data', (chunk: string) => this.onData(chunk));\n this.stdin.on('end', () => this.handleClose());\n this.stdin.on('error', (err: Error) => this.failAll(err));\n }\n\n sendStartupMarker(): void {\n this.stdout.write('[wstack-acp]\\n', 'utf8');\n }\n\n send(msg: ACPMessage): Promise<void> {\n if (this.closed) return Promise.resolve();\n return new Promise((resolve) => {\n const line = JSON.stringify(msg) + '\\n';\n this.stdout.write(line, 'utf8', () => resolve());\n });\n }\n\n sendRaw(chunk: string): void {\n this.stdout.write(chunk, 'utf8');\n }\n\n read(): Promise<ACPMessage | null> {\n if (this.messageQueue.length > 0) return Promise.resolve(this.messageQueue.shift()!);\n if (this.closed) return Promise.resolve(null);\n return new Promise((resolve) => {\n this.resolveRead = resolve;\n });\n }\n\n onMessage(handler: (msg: ACPMessage) => void): () => void {\n this.handlers.add(handler);\n return () => this.handlers.delete(handler);\n }\n\n close(): void {\n this.closed = true;\n this.stdin.pause();\n this.resolveRead?.(null);\n this.resolveRead = null;\n }\n\n private onData(chunk: string): void {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() ?? '';\n\n for (const raw of lines) {\n if (!raw.trim()) continue;\n try {\n this.dispatch(JSON.parse(raw) as ACPMessage);\n } catch (err) {\n this.stderr.write(`[wstack-acp parse error] ${err}\\n`, 'utf8');\n }\n }\n }\n\n private dispatch(msg: ACPMessage): void {\n if (this.resolveRead) {\n const resolve = this.resolveRead;\n this.resolveRead = null;\n resolve(msg);\n } else {\n this.messageQueue.push(msg);\n }\n for (const handler of this.handlers) {\n try {\n handler(msg);\n } catch (err) {\n this.stderr.write(`[wstack-acp handler error] ${err}\\n`, 'utf8');\n }\n }\n }\n\n private handleClose(): void {\n this.closed = true;\n this.resolveRead?.(null);\n this.resolveRead = null;\n }\n\n private failAll(err: Error): void {\n this.stderr.write(`[wstack-acp stdin error] ${err.message}\\n`, 'utf8');\n this.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// ClientTransport — spawns a child ACP agent process (DIR-1)\n// ---------------------------------------------------------------------------\n\nimport { spawn } from 'node:child_process';\nimport type { EventEmitter } from 'node:events';\n\nexport interface ClientTransportOptions {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n handshakeTimeoutMs?: number;\n}\n\nexport interface ACPChildProcess extends EventEmitter {\n stdout: NodeJS.ReadableStream;\n stdin: NodeJS.WritableStream;\n stderr: NodeJS.ReadableStream;\n pid: number | undefined;\n kill(): void;\n}\n\nexport class ClientTransport {\n private child: ACPChildProcess | null = null;\n private buffer = '';\n private readonly handlers = new Set<(msg: ACPMessage) => void>();\n private closed = false;\n private resolveRead: ((msg: ACPMessage | null) => void) | null = null;\n private messageQueue: ACPMessage[] = [];\n private readonly opts: Required<Pick<ClientTransportOptions, 'handshakeTimeoutMs'>> &\n ClientTransportOptions;\n\n constructor(options: ClientTransportOptions) {\n this.opts = {\n handshakeTimeoutMs: 30_000,\n ...options,\n };\n }\n\n async start(): Promise<void> {\n if (this.child) return;\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(`ACP child process failed to start within ${this.opts.handshakeTimeoutMs}ms`),\n );\n }, this.opts.handshakeTimeoutMs);\n\n try {\n this.child = spawn(this.opts.command, this.opts.args ?? [], {\n env: { ...buildChildEnv(), ...this.opts.env },\n cwd: this.opts.cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n }) as unknown as ACPChildProcess;\n } catch (err) {\n clearTimeout(timeout);\n reject(err);\n return;\n }\n\n const child = this.child;\n\n child.stdout.setEncoding('utf8');\n\n const waitForMarker = (chunk: string) => {\n this.buffer += chunk;\n const idx = this.buffer.indexOf('[wstack-acp]\\n');\n if (idx !== -1) {\n this.buffer = this.buffer.slice(idx + '[wstack-acp]\\n'.length);\n child.stdout.removeListener('data', waitForMarker);\n child.stdout.on('data', (c: string) => this.onChildData(c));\n child.stderr.on('data', (c: string) => this.onChildError(c));\n child.on('close', (code: number | null) => this.onChildClose(code));\n clearTimeout(timeout);\n resolve();\n }\n };\n\n child.stdout.on('data', waitForMarker);\n child.stdout.on('error', (err: Error) => {\n clearTimeout(timeout);\n reject(err);\n });\n child.on('error', (err: Error) => {\n clearTimeout(timeout);\n reject(err);\n });\n });\n }\n\n send(msg: ACPMessage): Promise<void> {\n if (!this.child) return Promise.reject(new Error('ClientTransport not started'));\n return new Promise((resolve, reject) => {\n const line = JSON.stringify(msg) + '\\n';\n this.child!.stdin.write(line, 'utf8', (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n }\n\n read(): Promise<ACPMessage | null> {\n if (this.messageQueue.length > 0) return Promise.resolve(this.messageQueue.shift()!);\n if (this.closed) return Promise.resolve(null);\n return new Promise((resolve) => {\n this.resolveRead = resolve;\n });\n }\n\n onMessage(handler: (msg: ACPMessage) => void): () => void {\n this.handlers.add(handler);\n return () => this.handlers.delete(handler);\n }\n\n stop(): void {\n if (!this.child) return;\n this.closed = true;\n try {\n this.child.kill();\n } catch {\n // already dead\n }\n this.child = null;\n }\n\n private onChildData(chunk: string): void {\n this.buffer += chunk;\n const lines = this.buffer.split('\\n');\n this.buffer = lines.pop() ?? '';\n\n for (const raw of lines) {\n if (!raw.trim()) continue;\n try {\n this.dispatch(JSON.parse(raw) as ACPMessage);\n } catch {\n // skip malformed\n }\n }\n }\n\n private onChildError(chunk: string): void {\n writeErr(`[acp-child stderr] ${chunk}`);\n }\n\n private onChildClose(code: number | null): void {\n this.closed = true;\n this.resolveRead?.(null);\n this.resolveRead = null;\n if (code !== 0 && code !== null) {\n writeErr(`[acp-child exited with code ${code}]\\n`);\n }\n }\n\n private dispatch(msg: ACPMessage): void {\n if (this.resolveRead) {\n const resolve = this.resolveRead;\n this.resolveRead = null;\n resolve(msg);\n } else {\n this.messageQueue.push(msg);\n }\n for (const handler of this.handlers) {\n try {\n handler(msg);\n } catch {\n // non-fatal\n }\n }\n }\n}\n","/**\n * Tools registry for ACP agent-side.\n *\n * Translates WrongStack Tool definitions → ACP ACPToolDefinition format.\n * Provides tool lookup and result assembly for the ACP protocol handler.\n */\nimport type {Tool} from '@wrongstack/core';\nimport type {\n ACPToolDefinition,\n ACPToolList,\n ACPInputSchema,\n ACPToolResult,\n ContentBlock,\n} from '../types/acp-messages.js';\n\nexport class ACPToolsRegistry {\n private tools = new Map<string, Tool>();\n private readonly owner: string;\n\n constructor(owner = 'wrongstack') {\n this.owner = owner;\n }\n\n /**\n * Register one or more tools.\n * Throws on duplicate name unless force=true.\n */\n register(tools: Tool[]): void {\n for (const tool of tools) {\n this.tools.set(tool.name, tool);\n }\n }\n\n /**\n * Replace the current tool set.\n */\n setTools(tools: Tool[]): void {\n this.tools.clear();\n for (const tool of tools) this.tools.set(tool.name, tool);\n }\n\n get(name: string): Tool | undefined {\n return this.tools.get(name);\n }\n\n has(name: string): boolean {\n return this.tools.has(name);\n }\n\n list(): Tool[] {\n return Array.from(this.tools.values());\n }\n\n /** Build the ACP tools/list payload from registered tools. */\n buildToolList(): ACPToolList {\n return {\n tools: Array.from(this.tools.values()).map((t) =>\n toACPToolDefinition(t, this.owner),\n ),\n };\n }\n\n /**\n * Execute a tool by name and return ACP-formatted result.\n * Returns null if the tool is not found.\n */\n async execute(\n name: string,\n args: Record<string, unknown>,\n ctx: unknown,\n signal: AbortSignal,\n ): Promise<ACPToolResult | null> {\n const tool = this.tools.get(name);\n if (!tool) return null;\n\n try {\n const result = await tool.execute(args, ctx as Parameters<Tool['execute']>[1], {\n signal,\n });\n return toACPToolResult(result);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {content: [{type: 'text', text: msg}], isError: true} satisfies ACPToolResult;\n }\n }\n}\n\n/** Convert a WrongStack Tool → ACP ACPToolDefinition */\nfunction toACPToolDefinition(tool: Tool, _owner: string): ACPToolDefinition {\n return {\n name: tool.name,\n description: tool.description,\n inputSchema: toACPInputSchema(tool.inputSchema),\n annotations: {\n title: tool.name,\n description: tool.usageHint ?? tool.description,\n priority: toolToPriority(tool),\n alwaysAccept: tool.permission === 'auto',\n },\n };\n}\n\n/** Minimal JSON Schema → ACP input schema. ACP uses JSON Schema draft-07. */\nfunction toACPInputSchema(src: unknown): ACPInputSchema {\n if (!src || typeof src !== 'object') {\n return {};\n }\n const s = src as Record<string, unknown>;\n\n // Recursively convert properties\n if (s.properties && typeof s.properties === 'object') {\n const props: Record<string, ACPInputSchema> = {};\n for (const [k, v] of Object.entries(s.properties as Record<string, unknown>)) {\n props[k] = toACPInputSchema(v);\n }\n return {\n type: typeof s.type === 'string' ? s.type : undefined,\n properties: props,\n required: Array.isArray(s.required) ? (s.required as string[]) : undefined,\n items: s.items ? toACPInputSchema(s.items) : undefined,\n enum: Array.isArray(s.enum) ? s.enum : undefined,\n description: typeof s.description === 'string' ? s.description : undefined,\n default: s.default,\n minimum: typeof s.minimum === 'number' ? s.minimum : undefined,\n maximum: typeof s.maximum === 'number' ? s.maximum : undefined,\n };\n }\n\n return {\n type: typeof s.type === 'string' ? s.type : undefined,\n items: s.items ? toACPInputSchema(s.items) : undefined,\n enum: Array.isArray(s.enum) ? s.enum : undefined,\n description: typeof s.description === 'string' ? s.description : undefined,\n default: s.default,\n minimum: typeof s.minimum === 'number' ? s.minimum : undefined,\n maximum: typeof s.maximum === 'number' ? s.maximum : undefined,\n };\n}\n\n/** Convert a WrongStack ToolResult → ACP ContentBlock[] */\nfunction toACPToolResult(result: unknown): ACPToolResult {\n const blocks: ContentBlock[] = [];\n\n if (result === undefined || result === null) {\n return {content: [{type: 'text', text: 'ok'}]};\n }\n\n if (typeof result === 'string') {\n blocks.push({type: 'text', text: result});\n } else if (typeof result === 'object') {\n blocks.push({type: 'text', text: JSON.stringify(result, null, 2)});\n } else {\n blocks.push({type: 'text', text: String(result)});\n }\n\n return {content: blocks};\n}\n\nfunction toolToPriority(tool: Tool): 'high' | 'medium' | 'low' {\n if (tool.riskTier === 'destructive') return 'high';\n if (tool.riskTier === 'standard' || tool.permission === 'confirm') return 'medium';\n return 'low';\n}\n","/**\n * ACPProtocolHandler — state machine for ACP server-side message handling.\n *\n * ACP turn lifecycle:\n * idle → [initialize] → await-turn → [tools/call] → executing\n * → [tool result sent] → idle\n *\n * We implement this as a simple switch on the method name, since the ACP\n * protocol is request/response based (not streaming) on the wire.\n *\n * Concurrency: ACP allows Cancellations and multiple concurrent tool calls\n * within a turn. We handle each tools/call in its own Promise.all.\n */\nimport type {\n ACPMessage,\n ACPRequest,\n ACPNotification,\n ACPInitializeParams,\n ACPToolCallRequest,\n ACPToolResult,\n ACPToolCallResponse,\n} from '../types/acp-messages.js';\nimport type {AgentServerTransport} from './stdio-transport.js';\n\nexport const WRONGSTACK_VERSION = '0.1.0';\nconst WRONGSTACK_CAPABILITIES = [\n 'code-generation',\n 'async-tools',\n 'streaming',\n 'progress',\n];\n\nexport class ACPProtocolHandler {\n private initialized = false;\n private readonly signal = new AbortController();\n private pendingCalls = new Map<string | number, Promise<unknown>>();\n\n constructor(\n private readonly transport: AgentServerTransport,\n private readonly registry: import('./tools-registry.js').ACPToolsRegistry,\n private readonly context: unknown,\n ) {}\n\n /** Wire an external abort signal from the ACP client */\n wireAbortController(abortController: AbortController): void {\n abortController.signal.addEventListener('abort', () => {\n for (const id of this.pendingCalls.keys()) {\n this.transport.send({id, method: 'cancel', result: {ok: true}}).catch(() => {});\n }\n });\n }\n\n /** Process one inbound message. Returns true if this was a terminal message. */\n async handleMessage(msg: ACPMessage): Promise<boolean> {\n if (msg.id !== undefined) {\n return this.handleRequest(msg as ACPRequest);\n }\n return this.handleNotification(msg as ACPNotification);\n }\n\n private async handleRequest(req: ACPRequest): Promise<boolean> {\n if (req.method !== 'initialize' && !this.initialized) {\n await this.sendError(req.id ?? null, -32000, 'Not initialized');\n return false;\n }\n\n // All requests after initialization check have a guaranteed id\n const id = req.id as string | number;\n\n switch (req.method) {\n case 'initialize':\n return this.handleInitialize(req as ACPRequest & {params: ACPInitializeParams}, id);\n case 'ping':\n await this.transport.send({id, method: 'ping', result: {pong: true}});\n return false;\n case 'tools/call':\n return this.handleToolCall(req as ACPRequest & {params: ACPToolCallRequest['params']}, id);\n case 'tools/list':\n return this.handleToolsList(id);\n case 'cancel':\n return this.handleCancel(id);\n case 'session/list':\n return this.handleSessionList(id);\n case 'sessionInfoUpdate':\n await this.transport.send({id, method: 'sessionInfoUpdate', result: {ok: true}});\n return false;\n default:\n await this.sendError(id, -32601, `Unknown method: ${req.method}`);\n return false;\n }\n }\n\n private async handleNotification(n: ACPNotification): Promise<boolean> {\n if (n.method === 'cancel') {\n this.handleCancelNotification(n as ACPNotification & {params?: {reason?: string}});\n }\n return false;\n }\n\n private async handleInitialize(\n req: ACPRequest & {params: ACPInitializeParams},\n id: string | number,\n ): Promise<boolean> {\n this.initialized = true;\n\n const result = {\n capabilities: WRONGSTACK_CAPABILITIES,\n agentName: 'WrongStack',\n agentVersion: WRONGSTACK_VERSION,\n protocolVersion: req.params?.protocolVersion ?? '2024-11',\n ...this.registry.buildToolList(),\n };\n\n await this.transport.send({id, method: 'initialize', result});\n return false;\n }\n\n private async handleToolsList(id: string | number): Promise<boolean> {\n await this.transport.send({\n id,\n method: 'tools/list',\n result: this.registry.buildToolList(),\n });\n return false;\n }\n\n private async handleToolCall(\n req: ACPRequest & {params: {name: string; arguments: Record<string, unknown>}},\n id: string | number,\n ): Promise<boolean> {\n const {name, arguments: args} = req.params;\n\n const runPromise = (async () => {\n if (!this.registry.has(name)) {\n return {\n content: [{type: 'text', text: `Tool not found: ${name}`}],\n isError: true,\n } satisfies ACPToolResult;\n }\n\n const result = await this.registry.execute(\n name,\n args,\n this.context,\n this.signal.signal,\n );\n return result ?? {content: [{type: 'text', text: 'Tool returned null'}], isError: false};\n })();\n\n this.pendingCalls.set(id, runPromise);\n\n try {\n const toolResult = (await runPromise) as ACPToolResult;\n this.pendingCalls.delete(id);\n\n const response: ACPToolCallResponse = {method: 'tools/call', id, result: toolResult};\n await this.transport.send(response);\n } catch (err) {\n this.pendingCalls.delete(id);\n const msg = err instanceof Error ? err.message : String(err);\n await this.transport.send({\n id,\n method: 'tools/call',\n result: {content: [{type: 'text', text: msg}], isError: true},\n });\n }\n\n return false;\n }\n\n private async handleCancel(id: string | number): Promise<boolean> {\n this.pendingCalls.delete(id);\n await this.transport.send({id, method: 'cancel', result: {ok: true}});\n return false;\n }\n\n private handleCancelNotification(\n _n: ACPNotification & {params?: {reason?: string}},\n ): void {\n // Broadcast cancellation to all pending — best-effort\n }\n\n private async handleSessionList(id: string | number): Promise<boolean> {\n await this.transport.send({\n id,\n method: 'session/list',\n result: {sessions: []},\n });\n return false;\n }\n\n private async sendError(id: string | number | null, code: number, message: string): Promise<void> {\n if (id === null) return;\n await this.transport.send({id, method: '', error: {code, message}});\n }\n}\n","/**\n * WrongStackACPServer — ACP server-side entry point.\n *\n * Exposes WrongStack as an ACP-compatible agent. ACP clients (Zed, JetBrains,\n * VS Code ACP extension) spawn this as a subprocess, send JSON-RPC messages\n * over stdio, and receive tool responses.\n *\n * Usage:\n * node dist/agent/wrongstack-acp-agent.js\n *\n * Or via the CLI:\n * wstack acp-server\n *\n * Startup: sends `[wstack-acp]\\n` to stdout so the client knows which process\n * is the ACP server before protocol messages begin.\n */\nimport { fileURLToPath } from 'node:url';\nimport { writeErr } from '@wrongstack/core';\nimport type { Tool } from '@wrongstack/core';\nimport { ACPProtocolHandler } from './protocol-handler.js';\nimport { StdioTransport } from './stdio-transport.js';\nimport { ACPToolsRegistry } from './tools-registry.js';\n\nexport interface WrongStackACPServerOptions {\n /**\n * Initial tool set. Typically loaded from the WrongStack tool registry\n * via `api.tools.list()` so the ACP server exposes exactly the tools the\n * CLI has configured.\n */\n tools: Tool[];\n /**\n * Owner label for tool metadata. Passed to ACPToolsRegistry.\n * @default 'wrongstack'\n */\n owner?: string;\n}\n\nexport class WrongStackACPServer {\n private readonly transport: StdioTransport;\n private readonly registry: ACPToolsRegistry;\n private readonly handler: ACPProtocolHandler;\n private running = false;\n\n constructor(opts: WrongStackACPServerOptions) {\n this.transport = new StdioTransport();\n this.registry = new ACPToolsRegistry(opts.owner);\n this.registry.register(opts.tools);\n this.handler = new ACPProtocolHandler(\n this.transport,\n this.registry,\n /* TODO: load WrongStack Context */ {},\n );\n }\n\n /**\n * Start the server. Blocks until the client disconnects.\n *\n * 1. Send the startup marker `[wstack-acp]` so the client\n * knows which stdout line is the protocol boundary.\n * 2. Loop: read messages, dispatch to handler, until EOF or error.\n *\n * Single dispatch path: every inbound message is read exactly once\n * from the transport and passed to the protocol handler exactly once.\n * An earlier version combined a `transport.onMessage` callback with\n * this read loop, which caused every message to be processed twice\n * (once by the callback, once by the loop) — duplicate tool calls\n * and duplicate responses to the client. See the ACP double-dispatch\n * fix in the security audit (P1-001).\n */\n async start(): Promise<void> {\n this.transport.sendStartupMarker();\n this.running = true;\n\n while (this.running) {\n const msg = await this.transport.read();\n if (!msg) break; // EOF\n const terminal = await this.handler.handleMessage(msg);\n if (terminal) break;\n }\n\n this.transport.close();\n }\n\n /** Stop the server. */\n stop(): void {\n this.running = false;\n this.transport.close();\n }\n}\n\n/**\n * Bootstrap function for `node dist/agent/wrongstack-acp-agent.js`.\n * Instantiates the server with the default tool set.\n *\n * Tool loading: the ACP agent is a subprocess without the full CLI context,\n * so it needs to receive its tools from the parent via environment or a\n * pre-main bootstrap. For now, it uses an empty tool set unless tools are\n * explicitly passed via constructor options.\n *\n * In practice the CLI will instantiate and run WrongStackACPServer directly,\n * passing `api.tools.list()` as the tool set.\n */\nasync function main(): Promise<void> {\n const server = new WrongStackACPServer({ tools: [] });\n await server.start();\n}\n\n// Only auto-start when this file is the process entrypoint (e.g.\n// `node dist/agent/wrongstack-acp-agent.js`). Importing the module — which the\n// CLI does to reuse `WrongStackACPServer` — must stay side-effect-free, or\n// every launch would start an ACP server and hijack stdin.\nconst isEntrypoint =\n process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1];\nif (isEntrypoint) {\n main().catch((err) => {\n writeErr(`[wstack-acp fatal] ${err}\\n`);\n process.exit(1);\n });\n}\n","/**\n * ToolTranslator — bidirectional translation between WrongStack tools and\n * ACP tool representations.\n *\n * Used by DIR-1 (WrongStack as ACP client) to:\n * - Map WrongStack TaskSpec → ACP task payload\n * - Map ACP tool responses → TaskResult\n *\n * Used by DIR-2 (WrongStack as ACP server) to:\n * - Convert the WrongStack Tool.inputSchema → ACPToolDefinition.inputSchema\n * - (handled by tools-registry.ts — same logic lives there)\n *\n * For DIR-1 async tool calls: ACP agents send progress notifications while\n * a tool is running, then send a final result. The translator handles this\n * by polling for the final [result] notification on the transport.\n */\nimport type {ACPMessage, ACPToolDefinition, ACPToolCallResponse, ContentBlock} from '../types/acp-messages.js';\nimport type {TaskSpec, TaskResult} from '@wrongstack/core';\n\nexport interface ToolTranslatorOptions {\n /**\n * If true (default), wrap tool calls in an async poll loop that waits\n * for progress notifications until a final result arrives.\n */\n asyncTools?: boolean;\n pollIntervalMs?: number;\n totalTimeoutMs?: number;\n}\n\nconst DEFAULT_OPTIONS: Required<ToolTranslatorOptions> = {\n asyncTools: true,\n pollIntervalMs: 500,\n totalTimeoutMs: 120_000,\n};\n\n/** Convert an ACP ACPToolDefinition → a JSON schema object recognisable by WrongStack */\nexport function acpToolToSchema(def: ACPToolDefinition): Record<string, unknown> {\n if (!def.inputSchema) return {type: 'object', properties: {}};\n return def.inputSchema as Record<string, unknown>;\n}\n\n/** Extract tool result text from ACP ContentBlock[] */\nexport function extractTextFromContent(blocks: ContentBlock[]): string {\n const parts: string[] = [];\n for (const b of blocks) {\n if (b.type === 'text') parts.push(b.text);\n else if (b.type === 'resource') parts.push(`[resource: ${b.resource.uri}]`);\n else if (b.type === 'image') parts.push(`[image: ${b.data.slice(0, 20)}...]`);\n else if (b.type === 'progress') {\n if (b.messages?.length) parts.push(b.messages.join('\\n'));\n }\n }\n return parts.join('\\n');\n}\n\n/** Build a TaskSpec from an ACP task payload */\nexport function buildTaskSpec(payload: {\n taskId: string;\n task: string;\n subagentId?: string;\n}): TaskSpec {\n return {\n id: payload.taskId,\n description: payload.task,\n subagentId: payload.subagentId,\n };\n}\n\n/** Parse an ACP tools/call response → TaskResult */\nexport function parseToolResponse(\n taskId: string,\n subagentId: string,\n response: ACPToolCallResponse,\n): TaskResult {\n const blocks = response.result.content;\n const text = extractTextFromContent(blocks);\n\n // Detect error state from isError flag or error-like text\n const isError =\n response.result.isError || text.toLowerCase().includes('error') ||\n text.toLowerCase().includes('failed');\n\n return {\n taskId,\n subagentId,\n status: isError ? 'failed' : 'success',\n result: text,\n iterations: 1,\n toolCalls: 1,\n durationMs: 0,\n };\n}\n\n/** ToolTranslator for DIR-1 — wraps ACP client transport, adds task semantics */\nexport class ToolTranslator {\n private readonly opts: Required<ToolTranslatorOptions>;\n private readonly pending = new Map<string | number, {\n resolve: (v: ACPToolCallResponse) => void;\n reject: (e: Error) => void;\n timeout: ReturnType<typeof setTimeout>;\n }>();\n\n constructor(opts: ToolTranslatorOptions = {}) {\n this.opts = {...DEFAULT_OPTIONS, ...opts};\n }\n\n /**\n * Start listening to a transport for tool responses and cancellations.\n * Call this once after constructing the translator and before sending tasks.\n */\n attachToTransport(\n transport: {onMessage: (h: (msg: ACPMessage) => void) => () => void; send: (msg: ACPMessage) => Promise<void>},\n ): void {\n transport.onMessage((msg) => {\n if (msg.method === 'tools/call' && msg.id !== undefined) {\n const pending = this.pending.get(msg.id);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(msg.id!);\n pending.resolve(msg as unknown as ACPToolCallResponse);\n }\n }\n\n // Handle cancellation notifications\n if (msg.method === 'cancel' && msg.id !== undefined) {\n const pending = this.pending.get(msg.id);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(msg.id!);\n pending.reject(new Error('Call cancelled by client'));\n }\n }\n });\n }\n\n /**\n * Send a tool call over the transport and wait for a response.\n * If asyncTools is true, polls for progress and resolves when the final\n * response arrives.\n */\n async callTool(\n transport: {send: (msg: ACPMessage) => Promise<void>},\n name: string,\n args: Record<string, unknown>,\n callId: string | number = crypto.randomUUID(),\n ): Promise<ACPToolCallResponse> {\n await transport.send({\n method: 'tools/call',\n id: callId,\n params: {name, arguments: args},\n });\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.pending.delete(callId);\n reject(new Error(`Tool call ${name} timed out after ${this.opts.totalTimeoutMs}ms`));\n }, this.opts.totalTimeoutMs);\n\n this.pending.set(callId, {resolve, reject, timeout});\n });\n }\n\n cancelAll(): void {\n for (const [, p] of this.pending) {\n clearTimeout(p.timeout);\n }\n this.pending.clear();\n }\n}\n","/**\n * ACPSubagentRunner — SubagentRunner implementation for DIR-1.\n *\n * Wraps an external ACP agent (Cline, Gemini CLI, Codex CLI, Copilot, etc.)\n * as a WrongStack subagent. The external agent runs its own agent loop;\n * we send it a task via ACP and return the result.\n *\n * Connected to Director / MultiAgentCoordinator via the SubagentRunner\n * interface (same as AgentSubagentRunner).\n */\nimport type {SubagentRunContext, SubagentRunner, TaskSpec} from '@wrongstack/core';\nimport {ClientTransport} from '../agent/stdio-transport.js';\nimport type {ACPToolCallResponse} from '../types/acp-messages.js';\nimport {ToolTranslator, parseToolResponse} from '../client/tool-translator.js';\nimport type {ToolTranslatorOptions} from '../client/tool-translator.js';\n\nexport interface ACPSubagentRunnerOptions {\n /** ACP agent command or npm package (e.g. 'npx', 'gemini', 'gh') */\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n /** Subagent role — used for protocol negotiation and prompt overrides */\n role?: string;\n toolTranslatorOpts?: ToolTranslatorOptions;\n}\n\n/** Map WrongStack ACP agent role → how to spawn it. */\nexport const ACP_AGENT_COMMANDS: Record<string, ACPSubagentRunnerOptions> = {\n cline: {\n command: 'npx',\n args: ['-y', '@agentify/cline'],\n role: 'cline',\n },\n 'gemini-cli': {\n command: 'gemini',\n role: 'gemini-cli',\n },\n copilot: {\n command: 'gh',\n args: ['copilot', 'agent'],\n role: 'copilot',\n },\n openhands: {\n command: 'openhands',\n role: 'openhands',\n },\n goose: {\n command: 'goose',\n role: 'goose',\n },\n};\n\n/**\n * Build an ACPSubagentRunner for a given role, or a generic one from explicit options.\n */\nexport async function makeACPSubagentRunner(\n options: ACPSubagentRunnerOptions,\n): Promise<SubagentRunner> {\n const transport = new ClientTransport({\n command: options.command,\n args: options.args,\n env: options.env,\n cwd: options.cwd,\n handshakeTimeoutMs: 30_000,\n });\n\n const translator = new ToolTranslator(options.toolTranslatorOpts);\n const activeAbort = new AbortController();\n\n let sessionStarted = false;\n\n const startSession = async (): Promise<void> => {\n if (sessionStarted) return;\n await transport.start();\n\n await transport.send({\n method: 'initialize',\n id: '1',\n params: {\n capabilities: ['code-generation', 'async-tools', 'streaming', 'progress'],\n protocolVersion: '2024-11',\n sessionId: options.role ?? 'wrongstack-subagent',\n },\n });\n\n const initResp = await transport.read();\n if (!initResp || initResp.error) {\n throw new Error(`ACP initialize failed: ${initResp?.error?.message ?? 'no response'}`);\n }\n\n translator.attachToTransport({\n onMessage: (h) => transport.onMessage(h),\n send: (m) => transport.send(m),\n });\n\n sessionStarted = true;\n };\n\n const runner: SubagentRunner = async (\n task: TaskSpec,\n ctx: SubagentRunContext,\n ): Promise<{result?: unknown; iterations: number; toolCalls: number}> => {\n ctx.signal.addEventListener('abort', () => {\n activeAbort.abort();\n transport.stop();\n });\n\n await startSession();\n\n const callId = crypto.randomUUID();\n let toolResult: ACPToolCallResponse | null = null;\n\n const resultPromise = new Promise<ACPToolCallResponse>((resolve, reject) => {\n const budgetMs = ctx.budget.limits.timeoutMs ?? 300_000;\n\n const timeout = setTimeout(() => {\n reject(new Error(`ACP task timed out for subagent ${ctx.subagentId} (${budgetMs}ms budget)`));\n }, budgetMs);\n\n transport.onMessage((msg) => {\n if (msg.method === 'tools/call' && msg.id !== undefined) {\n clearTimeout(timeout);\n resolve(msg as unknown as ACPToolCallResponse);\n }\n });\n\n ctx.signal.addEventListener('abort', () => {\n clearTimeout(timeout);\n reject(new Error('Task aborted by parent'));\n });\n });\n\n try {\n // Most ACP agents accept a free-form task string as their primary input.\n // Use the tools/call protocol with a special 'task' pseudo-tool if the\n // agent advertises it; otherwise send it as an initialize session detail\n // or a custom agent/run message. The agent will respond on stdout.\n await transport.send({\n method: 'agent/run',\n id: callId,\n params: {\n task: task.description,\n sessionId: ctx.subagentId,\n },\n });\n\n toolResult = await resultPromise;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n result: `ACP subagent error: ${msg}`,\n iterations: 0,\n toolCalls: 0,\n };\n }\n\n if (!toolResult) {\n return {result: 'ACP subagent returned no result', iterations: 1, toolCalls: 1};\n }\n\n const parsed = parseToolResponse(task.id, ctx.subagentId, toolResult);\n return {\n result: parsed.result ?? parsed.error,\n iterations: parsed.iterations,\n toolCalls: parsed.toolCalls,\n };\n };\n\n return runner;\n}\n\n/** Returns the runner and a stop function to clean up the transport. */\nexport async function makeACPSubagentRunnerWithStop(\n options: ACPSubagentRunnerOptions,\n): Promise<{runner: SubagentRunner; stop: () => void}> {\n const transport = new ClientTransport({\n command: options.command,\n args: options.args,\n env: options.env,\n cwd: options.cwd,\n handshakeTimeoutMs: 30_000,\n });\n\n const translator = new ToolTranslator(options.toolTranslatorOpts);\n const activeAbort = new AbortController();\n\n let sessionStarted = false;\n\n const startSession = async (): Promise<void> => {\n if (sessionStarted) return;\n await transport.start();\n\n await transport.send({\n method: 'initialize',\n id: '1',\n params: {\n capabilities: ['code-generation', 'async-tools', 'streaming', 'progress'],\n protocolVersion: '2024-11',\n sessionId: options.role ?? 'wrongstack-subagent',\n },\n });\n\n const initResp = await transport.read();\n if (!initResp || initResp.error) {\n throw new Error(`ACP initialize failed: ${initResp?.error?.message ?? 'no response'}`);\n }\n\n translator.attachToTransport({\n onMessage: (h) => transport.onMessage(h),\n send: (m) => transport.send(m),\n });\n\n sessionStarted = true;\n };\n\n const stop = () => {\n activeAbort.abort();\n transport.stop();\n };\n\n const runner: SubagentRunner = async (\n task: TaskSpec,\n ctx: SubagentRunContext,\n ): Promise<{result?: unknown; iterations: number; toolCalls: number}> => {\n ctx.signal.addEventListener('abort', () => {\n activeAbort.abort();\n transport.stop();\n });\n\n await startSession();\n\n const callId = crypto.randomUUID();\n let toolResult: ACPToolCallResponse | null = null;\n\n const resultPromise = new Promise<ACPToolCallResponse>((resolve, reject) => {\n const budgetMs = ctx.budget.limits.timeoutMs ?? 300_000;\n\n const timeout = setTimeout(() => {\n reject(new Error(`ACP task timed out for subagent ${ctx.subagentId} (${budgetMs}ms budget)`));\n }, budgetMs);\n\n transport.onMessage((msg) => {\n if (msg.method === 'tools/call' && msg.id !== undefined) {\n clearTimeout(timeout);\n resolve(msg as unknown as ACPToolCallResponse);\n }\n });\n\n ctx.signal.addEventListener('abort', () => {\n clearTimeout(timeout);\n reject(new Error('Task aborted by parent'));\n });\n });\n\n try {\n await transport.send({\n method: 'agent/run',\n id: callId,\n params: {\n task: task.description,\n sessionId: ctx.subagentId,\n },\n });\n\n toolResult = await resultPromise;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n result: `ACP subagent error: ${msg}`,\n iterations: 0,\n toolCalls: 0,\n };\n }\n\n if (!toolResult) {\n return {result: 'ACP subagent returned no result', iterations: 1, toolCalls: 1};\n }\n\n const parsed = parseToolResponse(task.id, ctx.subagentId, toolResult);\n return {\n result: parsed.result ?? parsed.error,\n iterations: parsed.iterations,\n toolCalls: parsed.toolCalls,\n };\n };\n\n return {runner, stop};\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/acp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.0",
|
|
4
|
+
"license": "MIT",
|
|
4
5
|
"description": "ACP (Agent Client Protocol) integration for WrongStack — client + agent support",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"ai",
|
|
8
|
+
"agent",
|
|
9
|
+
"acp",
|
|
10
|
+
"agent-client-protocol",
|
|
11
|
+
"coding-agent"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/WrongStack/WrongStack.git",
|
|
16
|
+
"directory": "packages/acp"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://github.com/WrongStack/WrongStack#readme",
|
|
19
|
+
"bugs": "https://github.com/WrongStack/WrongStack/issues",
|
|
20
|
+
"author": "ECOSTACK TECHNOLOGY OÜ",
|
|
5
21
|
"type": "module",
|
|
22
|
+
"sideEffects": false,
|
|
6
23
|
"exports": {
|
|
7
24
|
".": {
|
|
8
25
|
"import": "./dist/index.js",
|
|
@@ -21,13 +38,16 @@
|
|
|
21
38
|
"dist"
|
|
22
39
|
],
|
|
23
40
|
"dependencies": {
|
|
24
|
-
"@wrongstack/core": "0.
|
|
41
|
+
"@wrongstack/core": "0.41.0"
|
|
25
42
|
},
|
|
26
43
|
"devDependencies": {
|
|
27
44
|
"@types/node": "^22",
|
|
28
45
|
"typescript": "^5",
|
|
29
46
|
"vitest": "^4.1.6"
|
|
30
47
|
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
},
|
|
31
51
|
"scripts": {
|
|
32
52
|
"build": "tsup",
|
|
33
53
|
"typecheck": "tsc --noEmit",
|