Files
opencode/packages/opencode/src/cli/cmd/acp.ts
2025-12-26 10:29:48 -06:00

79 lines
2.3 KiB
TypeScript

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 { Config } from "@/config/config"
import { Server } from "@/server/server"
import { createOpencodeClient } from "@opencode-ai/sdk/v2"
import { withNetworkOptions, resolveNetworkOptions } from "../network"
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 withNetworkOptions(yargs).option("cwd", {
describe: "working directory",
type: "string",
default: process.cwd(),
})
},
handler: async (args) => {
await bootstrap(process.cwd(), async () => {
const config = await Config.get()
const opts = resolveNetworkOptions(args, config)
const server = Server.listen(opts)
const sdk = createOpencodeClient({
baseUrl: `http://${server.hostname}:${server.port}`,
})
const input = new WritableStream<Uint8Array>({
write(chunk) {
return new Promise<void>((resolve, reject) => {
process.stdout.write(chunk, (err) => {
if (err) {
reject(err)
} else {
resolve()
}
})
})
},
})
const output = new ReadableStream<Uint8Array>({
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)
})
})
},
})