Repository navigation
Conversation
Fixes the ACP half of CodebuffAI#319. `freebuff --acp` serves ACP v1 (stdio JSON-RPC, newline-delimited) using the official \@agentclientprotocol/sdk, so editors such as Zed can drive the CLI as an agent subprocess. The ACP surface is a second front end over the same conversation machinery the TUI uses: `getCodebuffClient()` + the SDK's `run()` with PrintModeEvent handlers. Free mode's session admission, instance metadata and device signing are unchanged, so the server's client allowlist still sees an official Freebuff CLI - the third-party-refusal gate that keeps an external SDK wrapper from driving free mode (seen while prototyping) never trips. Mapping: text -> agent_message_chunk, reasoning_delta -> agent_thought_chunk, tool_call -> tool_call (pending), tool_result -> tool_call_update (completed), error -> notice, finish -> the session/prompt response (end_turn). session/cancel aborts the in-flight SDK run; tool calls left open by a turn end failed/completed so clients never spin forever. Tests cover the event mapping, the protocol lifecycle in-process, and the real stdio transport (spawn the CLI, initialize, session/new).
|
Good instinct and a genuinely useful feature — reusing The blocking bug: Other things to flag before porting:
None of this touches forbidden paths, and the overall shape is portable — fix the constructor bug and clarify the hardcoded agent/costMode choice and this is in good shape. |
Summary
Adds
--acp: the CLI serves the Agent Client Protocol v1 over stdio (newline-delimited JSON-RPC, via the official@agentclientprotocol/sdk), so editors like Zed can drive Freebuff as an agent subprocess. This is the in-tree answer to #319.Why in-tree, not a wrapper
While prototyping this as an external SDK wrapper, a run with the user's device token through a non-CLI harness was refused by the backend:
So the ACP surface has to live inside the official binary. That is also the minimal-diff path: the adapter reuses the exact run plumbing the TUI uses (
getCodebuffClient()→ SDKrun()withPrintModeEventhandlers), so free mode's session admission,freebuff_instance_idmetadata and device signing are byte-identical and the allowlist still sees an official Freebuff CLI.What it does
freebuff --acp(andcodebuff --acp) skips renderer setup and serves the protocol on stdin/stdout instead of the TUI.previousRunstate.PrintModeEvent→session/update):text→agent_message_chunkreasoning_delta→agent_thought_chunktool_call→tool_call(pending, with kind from a name table)tool_result→tool_call_update(completed, output as content)error→noticefinish→ thesession/promptresponse resolves withend_turnsession/cancelaborts the in-flight SDK run. Tool calls a turn leaves open are closed (failedon cancel,completedotherwise) so clients never spin forever.What it deliberately does not do
authMethods: []): the CLI's own keychain/credentials login is the auth path;session/promptreturnsauth_requiredwhen signed out.session/load/session/list(in-memory sessions die with the process;agentCapabilities.loadSession: false).overrideToolstosession/request_permission.usage_update.Tests
PrintModeEventvariant, unknown tools, media outputs).initialize→session/new→session/promptand asserts the streamed updates.--acpand completes the handshake over actual stdio.One drive-by:
picocolorswas imported bycli/src/index.tsxbut missing fromcli/package.json(resolved transitively in the private tree; fails to run from a fresh clone of this mirror).Related
--acpgives editors a standard protocol instead of a bespoke NDJSON format.cli/src/acp/is ~20 lines (--acpflag + early return inmain()).