import { Log } from "@/util/log" import { bootstrap } from "../bootstrap" import { cmd } from "./cmd" import { AgentSideConnection, ndJsonStream } from "@agentclientprotocol/sdk" import { ACP } from "@/acp/agent" import { Server } from "@/server/server" import { createOpencodeClient } from "@opencode-ai/sdk/v2" const log = Log.create({ service: "acp-command" }) process.on("unhandledRejection", (reason, promise) => { log.error("Unhandled rejection", { promise, reason, }) }) export const AcpCommand = cmd({ command: "acp", describe: "start ACP (Agent Client Protocol) server", builder: (yargs) => { return yargs .option("cwd", { describe: "working directory", type: "string", default: process.cwd(), }) .option("port", { type: "number", describe: "port to listen on", default: 0, }) .option("hostname", { type: "string", describe: "hostname to listen on", default: "127.0.0.1", }) }, handler: async (args) => { await bootstrap(process.cwd(), async () => { const server = Server.listen({ port: args.port, hostname: args.hostname, }) const sdk = createOpencodeClient({ baseUrl: `http://${server.hostname}:${server.port}`, }) const input = new WritableStream({ write(chunk) { return new Promise((resolve, reject) => { process.stdout.write(chunk, (err) => { if (err) { reject(err) } else { resolve() } }) }) }, }) const output = new ReadableStream({ start(controller) { process.stdin.on("data", (chunk: Buffer) => { controller.enqueue(new Uint8Array(chunk)) }) process.stdin.on("end", () => controller.close()) process.stdin.on("error", (err) => controller.error(err)) }, }) const stream = ndJsonStream(input, output) const agent = await ACP.init({ sdk }) new AgentSideConnection((conn) => { return agent.create(conn, { sdk }) }, stream) log.info("setup connection") process.stdin.resume() await new Promise((resolve, reject) => { process.stdin.on("end", resolve) process.stdin.on("error", reject) }) }) }, })