Skip to content

Commit eedcd61

Browse files
ccdclaude
andcommitted
feat: a2a-bridge acp -p "prompt" one-shot mode
New flag for quick smoke-testing the bridge from the command line: a2a-bridge acp -p "hello" A2A_BRIDGE_CONTROL_URL=ws://1.2.3.4:4512/ws a2a-bridge acp -p "hi" Connects to daemon, sends one prompt, prints the reply to stdout, exits. No ACP SDK handshake, no stdin — just gateway round-trip. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent f96cc4f commit eedcd61

2 files changed

Lines changed: 39 additions & 3 deletions

File tree

src/cli/acp-cli.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ describe("E2E: a2a-bridge acp CLI subcommand", () => {
131131
ensureDaemon: false,
132132
controlWsUrl: `ws://127.0.0.1:${port}/ws`,
133133
});
134-
register(() => service.stop());
134+
register(() => service && "stop" in service ? service.stop() : undefined);
135135

136136
const updates: CapturedUpdate[] = [];
137137
const recordingClient = makeRecordingClient(updates);

src/cli/acp.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,17 @@ export interface RunAcpOptions {
4444
export async function runAcp(
4545
args: string[],
4646
options: RunAcpOptions = {},
47-
): Promise<AcpInboundService> {
48-
void args;
47+
): Promise<AcpInboundService | void> {
48+
// One-shot prompt mode: a2a-bridge acp -p "hello" / --prompt "hello"
49+
const promptIdx = args.findIndex((a) => a === "-p" || a === "--prompt");
50+
if (promptIdx !== -1) {
51+
const text = args[promptIdx + 1];
52+
if (!text) {
53+
console.error("Usage: a2a-bridge acp -p <prompt>");
54+
process.exit(1);
55+
}
56+
return runOneShotPrompt(text, options);
57+
}
4958

5059
const stdio = options.stdio ?? defaultStdio();
5160
const gateway = await resolveGateway(options);
@@ -55,6 +64,33 @@ export async function runAcp(
5564
return service;
5665
}
5766

67+
/**
68+
* One-shot mode: connect to daemon, send one prompt, print the reply,
69+
* exit. Useful for smoke-testing the bridge from the command line.
70+
*/
71+
async function runOneShotPrompt(
72+
text: string,
73+
options: RunAcpOptions,
74+
): Promise<void> {
75+
const gateway = await resolveGateway(options);
76+
const turn = gateway.startTurn(text);
77+
78+
const chunks: string[] = [];
79+
await new Promise<void>((resolve, reject) => {
80+
turn.on("chunk", (c: string) => chunks.push(c));
81+
turn.on("complete", () => resolve());
82+
turn.on("error", (err: Error) => reject(err));
83+
});
84+
85+
const reply = chunks.join("");
86+
console.log(reply);
87+
88+
// Clean shutdown
89+
if ("disconnect" in gateway && typeof gateway.disconnect === "function") {
90+
await (gateway as { disconnect: () => Promise<void> }).disconnect();
91+
}
92+
}
93+
5894
async function resolveGateway(options: RunAcpOptions): Promise<ClaudeCodeGateway> {
5995
if (options.gateway) return options.gateway;
6096

0 commit comments

Comments
 (0)