Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/acp-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,11 @@ export class ClaudeAcpAgent implements Agent {
delete this.sessions[sessionId];
}

/** Tear down all active sessions. Called when the ACP connection closes. */
async dispose(): Promise<void> {
await Promise.all(Object.keys(this.sessions).map((id) => this.teardownSession(id)));
}

async unstable_closeSession(params: CloseSessionRequest): Promise<CloseSessionResponse> {
if (!this.sessions[params.sessionId]) {
throw new Error("Session not found");
Expand Down Expand Up @@ -2239,7 +2244,12 @@ export function runAcp() {
const output = nodeToWebReadable(process.stdin);

const stream = ndJsonStream(input, output);
new AgentSideConnection((client) => new ClaudeAcpAgent(client), stream);
let agent!: ClaudeAcpAgent;
const connection = new AgentSideConnection((client) => {
agent = new ClaudeAcpAgent(client);
return agent;
}, stream);
return { connection, agent };
}

function commonPrefixLength(a: string, b: string) {
Expand Down
14 changes: 12 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,18 @@ if (process.argv.includes("--cli")) {
console.error("Unhandled Rejection at:", promise, "reason:", reason);
});

runAcp();
const { connection, agent } = runAcp();

// Keep process alive
// Exit cleanly when the ACP connection closes (e.g. stdin EOF, transport
// error). Without this, `process.stdin.resume()` keeps the event loop
// alive indefinitely, causing orphan process accumulation in oneshot mode.
connection.closed.then(async () => {
await agent.dispose().catch((err) => {
console.error("Error during cleanup:", err);
});
process.exit(0);
});

// Keep process alive while connection is open
process.stdin.resume();
}