diff --git a/packages/vscode-ide-companion/src/acp/acpConnection.ts b/packages/vscode-ide-companion/src/acp/acpConnection.ts index 38b48fc4..0047e63d 100644 --- a/packages/vscode-ide-companion/src/acp/acpConnection.ts +++ b/packages/vscode-ide-companion/src/acp/acpConnection.ts @@ -26,29 +26,15 @@ import { determineNodePathForCli } from '../cli/cliPathDetector.js'; * ACP Connection Handler for VSCode Extension * * This class implements the client side of the ACP (Agent Communication Protocol). - * - * Implementation Status: - * - * Client Methods (Methods this class implements, called by CLI): - * ✅ session/update - Handle session updates via onSessionUpdate callback - * ✅ session/request_permission - Request user permission for tool execution - * ✅ fs/read_text_file - Read file from workspace - * ✅ fs/write_text_file - Write file to workspace - * - * Agent Methods (Methods CLI implements, called by this class): - * ✅ initialize - Initialize ACP protocol connection - * ✅ authenticate - Authenticate with selected auth method - * ✅ session/new - Create new chat session - * ✅ session/prompt - Send user message to agent - * ✅ session/cancel - Cancel current generation - * ✅ session/load - Load previous session - * ✅ session/save - Save current session */ export class AcpConnection { private child: ChildProcess | null = null; private pendingRequests = new Map>(); private nextRequestId = { value: 0 }; private backend: AcpBackend | null = null; + // Remember the working dir provided at connect() so later ACP calls + // that require cwd (e.g. session/list) can include it. + private workingDir: string = process.cwd(); private messageHandler: AcpMessageHandler; private sessionManager: AcpSessionManager; @@ -83,6 +69,7 @@ export class AcpConnection { } this.backend = backend; + this.workingDir = workingDir; const isWindows = process.platform === 'win32'; const env = { ...process.env }; @@ -327,12 +314,16 @@ export class AcpConnection { * @param sessionId - Session ID * @returns Load response */ - async loadSession(sessionId: string): Promise { + async loadSession( + sessionId: string, + cwdOverride?: string, + ): Promise { return this.sessionManager.loadSession( sessionId, this.child, this.pendingRequests, this.nextRequestId, + cwdOverride || this.workingDir, ); } @@ -341,11 +332,16 @@ export class AcpConnection { * * @returns Session list response */ - async listSessions(): Promise { + async listSessions(options?: { + cursor?: number; + size?: number; + }): Promise { return this.sessionManager.listSessions( this.child, this.pendingRequests, this.nextRequestId, + this.workingDir, + options, ); } diff --git a/packages/vscode-ide-companion/src/acp/acpMessageHandler.ts b/packages/vscode-ide-companion/src/acp/acpMessageHandler.ts index ccf43abf..e0af2ba9 100644 --- a/packages/vscode-ide-companion/src/acp/acpMessageHandler.ts +++ b/packages/vscode-ide-companion/src/acp/acpMessageHandler.ts @@ -107,7 +107,8 @@ export class AcpMessageHandler { if ('result' in message) { console.log( `[ACP] Response for ${method}:`, - JSON.stringify(message.result).substring(0, 200), + // JSON.stringify(message.result).substring(0, 200), + message.result, ); if ( message.result && @@ -204,11 +205,11 @@ export class AcpMessageHandler { }> { try { const response = await callbacks.onPermissionRequest(params); - const optionId = response.optionId; + const optionId = response?.optionId; console.log('[ACP] Permission request:', optionId); // Handle cancel, deny, or allow let outcome: string; - if (optionId.includes('reject') || optionId === 'cancel') { + if (optionId && (optionId.includes('reject') || optionId === 'cancel')) { outcome = 'cancelled'; } else { outcome = 'selected'; diff --git a/packages/vscode-ide-companion/src/acp/acpSessionManager.ts b/packages/vscode-ide-companion/src/acp/acpSessionManager.ts index efe82331..00836012 100644 --- a/packages/vscode-ide-companion/src/acp/acpSessionManager.ts +++ b/packages/vscode-ide-companion/src/acp/acpSessionManager.ts @@ -196,7 +196,7 @@ export class AcpSessionManager { nextRequestId, ); - this.sessionId = response.sessionId || null; + this.sessionId = (response && response.sessionId) || null; console.log('[ACP] Session created with ID:', this.sessionId); return response; } @@ -247,11 +247,12 @@ export class AcpSessionManager { child: ChildProcess | null, pendingRequests: Map>, nextRequestId: { value: number }, + cwd: string = process.cwd(), ): Promise { console.log('[ACP] Sending session/load request for session:', sessionId); console.log('[ACP] Request parameters:', { sessionId, - cwd: process.cwd(), + cwd, mcpServers: [], }); @@ -260,7 +261,7 @@ export class AcpSessionManager { AGENT_METHODS.session_load, { sessionId, - cwd: process.cwd(), + cwd, mcpServers: [], }, child, @@ -274,10 +275,13 @@ export class AcpSessionManager { ); // Check if response contains an error - if (response.error) { + if (response && response.error) { console.error('[ACP] Session load returned error:', response.error); } else { console.log('[ACP] Session load succeeded'); + // session/load returns null on success per schema; update local sessionId + // so subsequent prompts use the loaded session. + this.sessionId = sessionId; } return response; @@ -302,12 +306,19 @@ export class AcpSessionManager { child: ChildProcess | null, pendingRequests: Map>, nextRequestId: { value: number }, + cwd: string = process.cwd(), + options?: { cursor?: number; size?: number }, ): Promise { console.log('[ACP] Requesting session list...'); try { + // session/list requires cwd in params per ACP schema + const params: Record = { cwd }; + if (options?.cursor !== undefined) params.cursor = options.cursor; + if (options?.size !== undefined) params.size = options.size; + const response = await this.sendRequest( AGENT_METHODS.session_list, - {}, + params, child, pendingRequests, nextRequestId,