diff --git a/src/acp-agent.ts b/src/acp-agent.ts index b21de4de..8703baf5 100644 --- a/src/acp-agent.ts +++ b/src/acp-agent.ts @@ -227,6 +227,10 @@ function shouldHideClaudeAuth(): boolean { const IS_ROOT = (process.geteuid?.() ?? process.getuid?.()) === 0; const ALLOW_BYPASS = !IS_ROOT || !!process.env.IS_SANDBOX; +// Slash commands that the SDK handles locally without replaying the user +// message and without invoking the model. +const LOCAL_ONLY_COMMANDS = new Set(["/context", "/heapdump", "/extra-usage"]); + const PERMISSION_MODE_ALIASES: Record = { default: "default", acceptedits: "acceptEdits", @@ -471,6 +475,16 @@ export class ClaudeAcpAgent implements Agent { let promptReplayed = false; + // These local-only commands return a result without replaying the user + // message. Mark promptReplayed=true so their result isn't consumed as a + // background task result. + const firstText = params.prompt[0]?.type === "text" ? params.prompt[0].text : ""; + const isLocalOnlyCommand = + firstText.startsWith("/") && LOCAL_ONLY_COMMANDS.has(firstText.split(" ", 1)[0]); + if (isLocalOnlyCommand) { + promptReplayed = true; + } + if (session.promptRunning) { session.input.push(userMessage); const order = session.nextPendingOrder++; @@ -626,6 +640,20 @@ export class ClaudeAcpAgent implements Agent { if (message.is_error) { throw RequestError.internalError(undefined, message.result); } + // For local-only commands (no model invocation), the result + // text is the command output — forward it to the client. + if (isLocalOnlyCommand) { + for (const notification of toAcpNotifications( + message.result, + "assistant", + params.sessionId, + this.toolUseCache, + this.client, + this.logger, + )) { + await this.client.sessionUpdate(notification); + } + } return { stopReason: "end_turn", usage }; } case "error_during_execution": @@ -716,22 +744,6 @@ export class ClaudeAcpAgent implements Agent { typeof message.message.content === "string" && message.message.content.includes("") ) { - // Handle /context by sending its reply as regular agent message. - if (message.message.content.includes("Context Usage")) { - for (const notification of toAcpNotifications( - message.message.content - .replace("", "") - .replace("", ""), - "assistant", - params.sessionId, - this.toolUseCache, - this.client, - this.logger, - { clientCapabilities: this.clientCapabilities }, - )) { - await this.client.sessionUpdate(notification); - } - } this.logger.log(message.message.content); break; }