diff --git a/packages/vscode-ide-companion/src/extension.ts b/packages/vscode-ide-companion/src/extension.ts index 08979099..2adfaef1 100644 --- a/packages/vscode-ide-companion/src/extension.ts +++ b/packages/vscode-ide-companion/src/extension.ts @@ -8,11 +8,7 @@ import * as vscode from 'vscode'; import { IDEServer } from './ide-server.js'; import semver from 'semver'; import { DiffContentProvider, DiffManager } from './diff-manager.js'; -import { - createLogger, - getConsoleLogger, - initSharedConsoleLogger, -} from './utils/logger.js'; +import { createLogger } from './utils/logger.js'; import { detectIdeFromEnv, IDE_DEFINITIONS, @@ -109,8 +105,6 @@ async function checkForUpdates( export async function activate(context: vscode.ExtensionContext) { logger = vscode.window.createOutputChannel('Qwen Code Companion'); - initSharedConsoleLogger(context); - const consoleLog = getConsoleLogger(); log = createLogger(context, logger); log('Extension activated'); @@ -148,18 +142,18 @@ export async function activate(context: vscode.ExtensionContext) { webviewPanel: vscode.WebviewPanel, state: unknown, ) { - consoleLog( + console.log( '[Extension] Deserializing WebView panel with state:', state, ); // Create a new provider for the restored panel const provider = createWebViewProvider(); - consoleLog('[Extension] Provider created for deserialization'); + console.log('[Extension] Provider created for deserialization'); // Restore state if available BEFORE restoring the panel if (state && typeof state === 'object') { - consoleLog('[Extension] Restoring state:', state); + console.log('[Extension] Restoring state:', state); provider.restoreState( state as { conversationId: string | null; @@ -167,11 +161,11 @@ export async function activate(context: vscode.ExtensionContext) { }, ); } else { - consoleLog('[Extension] No state to restore or invalid state'); + console.log('[Extension] No state to restore or invalid state'); } await provider.restorePanel(webviewPanel); - consoleLog('[Extension] Panel restore completed'); + console.log('[Extension] Panel restore completed'); log('WebView panel restored from serialization'); }, @@ -212,6 +206,7 @@ export async function activate(context: vscode.ExtensionContext) { } catch (err) { console.warn('[Extension] Auto-allow on diff.accept failed:', err); } + console.log('[Extension] Diff accepted'); }), vscode.commands.registerCommand('qwen.diff.cancel', (uri?: vscode.Uri) => { const docUri = uri ?? vscode.window.activeTextEditor?.document.uri; @@ -228,6 +223,7 @@ export async function activate(context: vscode.ExtensionContext) { } catch (err) { console.warn('[Extension] Auto-reject on diff.cancel failed:', err); } + console.log('[Extension] Diff cancelled'); })), vscode.commands.registerCommand('qwen.diff.closeAll', async () => { try { diff --git a/packages/vscode-ide-companion/src/services/acpConnection.ts b/packages/vscode-ide-companion/src/services/acpConnection.ts index 4dd35b71..a9992de4 100644 --- a/packages/vscode-ide-companion/src/services/acpConnection.ts +++ b/packages/vscode-ide-companion/src/services/acpConnection.ts @@ -31,6 +31,7 @@ export class AcpConnection { private child: ChildProcess | null = null; private pendingRequests = new Map>(); private nextRequestId = { value: 0 }; + // Deduplicate concurrent authenticate calls (across retry paths) private static authInFlight: Promise | null = null; // Remember the working dir provided at connect() so later ACP calls diff --git a/packages/vscode-ide-companion/src/services/authStateManager.ts b/packages/vscode-ide-companion/src/services/authStateManager.ts index aa75fe36..824a642c 100644 --- a/packages/vscode-ide-companion/src/services/authStateManager.ts +++ b/packages/vscode-ide-companion/src/services/authStateManager.ts @@ -5,7 +5,6 @@ */ import type * as vscode from 'vscode'; -import { createConsoleLogger, getConsoleLogger } from '../utils/logger.js'; interface AuthState { isAuthenticated: boolean; @@ -22,7 +21,6 @@ export class AuthStateManager { private static context: vscode.ExtensionContext | null = null; private static readonly AUTH_STATE_KEY = 'qwen.authState'; private static readonly AUTH_CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 hours - private static consoleLog: (...args: unknown[]) => void = getConsoleLogger(); // Deduplicate concurrent auth flows (e.g., multiple tabs prompting login) private static authFlowInFlight: Promise | null = null; private constructor() {} @@ -38,10 +36,6 @@ export class AuthStateManager { // If a context is provided, update the static context if (context) { AuthStateManager.context = context; - AuthStateManager.consoleLog = createConsoleLogger( - context, - 'AuthStateManager', - ); } return AuthStateManager.instance; @@ -76,19 +70,17 @@ export class AuthStateManager { const state = await this.getAuthState(); if (!state) { - AuthStateManager.consoleLog( - '[AuthStateManager] No cached auth state found', - ); + console.log('[AuthStateManager] No cached auth state found'); return false; } - AuthStateManager.consoleLog('[AuthStateManager] Found cached auth state:', { + console.log('[AuthStateManager] Found cached auth state:', { workingDir: state.workingDir, authMethod: state.authMethod, timestamp: new Date(state.timestamp).toISOString(), isAuthenticated: state.isAuthenticated, }); - AuthStateManager.consoleLog('[AuthStateManager] Checking against:', { + console.log('[AuthStateManager] Checking against:', { workingDir, authMethod, }); @@ -99,8 +91,8 @@ export class AuthStateManager { now - state.timestamp > AuthStateManager.AUTH_CACHE_DURATION; if (isExpired) { - AuthStateManager.consoleLog('[AuthStateManager] Cached auth expired'); - AuthStateManager.consoleLog( + console.log('[AuthStateManager] Cached auth expired'); + console.log( '[AuthStateManager] Cache age:', Math.floor((now - state.timestamp) / 1000 / 60), 'minutes', @@ -114,29 +106,15 @@ export class AuthStateManager { state.workingDir === workingDir && state.authMethod === authMethod; if (!isSameContext) { - AuthStateManager.consoleLog( - '[AuthStateManager] Working dir or auth method changed', - ); - AuthStateManager.consoleLog( - '[AuthStateManager] Cached workingDir:', - state.workingDir, - ); - AuthStateManager.consoleLog( - '[AuthStateManager] Current workingDir:', - workingDir, - ); - AuthStateManager.consoleLog( - '[AuthStateManager] Cached authMethod:', - state.authMethod, - ); - AuthStateManager.consoleLog( - '[AuthStateManager] Current authMethod:', - authMethod, - ); + console.log('[AuthStateManager] Working dir or auth method changed'); + console.log('[AuthStateManager] Cached workingDir:', state.workingDir); + console.log('[AuthStateManager] Current workingDir:', workingDir); + console.log('[AuthStateManager] Cached authMethod:', state.authMethod); + console.log('[AuthStateManager] Current authMethod:', authMethod); return false; } - AuthStateManager.consoleLog('[AuthStateManager] Valid cached auth found'); + console.log('[AuthStateManager] Valid cached auth found'); return state.isAuthenticated; } @@ -146,10 +124,7 @@ export class AuthStateManager { */ async debugAuthState(): Promise { const state = await this.getAuthState(); - AuthStateManager.consoleLog( - '[AuthStateManager] DEBUG - Current auth state:', - state, - ); + console.log('[AuthStateManager] DEBUG - Current auth state:', state); if (state) { const now = Date.now(); @@ -157,16 +132,9 @@ export class AuthStateManager { const isExpired = now - state.timestamp > AuthStateManager.AUTH_CACHE_DURATION; - AuthStateManager.consoleLog( - '[AuthStateManager] DEBUG - Auth state age:', - age, - 'minutes', - ); - AuthStateManager.consoleLog( - '[AuthStateManager] DEBUG - Auth state expired:', - isExpired, - ); - AuthStateManager.consoleLog( + console.log('[AuthStateManager] DEBUG - Auth state age:', age, 'minutes'); + console.log('[AuthStateManager] DEBUG - Auth state expired:', isExpired); + console.log( '[AuthStateManager] DEBUG - Auth state valid:', state.isAuthenticated, ); @@ -191,7 +159,7 @@ export class AuthStateManager { timestamp: Date.now(), }; - AuthStateManager.consoleLog('[AuthStateManager] Saving auth state:', { + console.log('[AuthStateManager] Saving auth state:', { workingDir, authMethod, timestamp: new Date(state.timestamp).toISOString(), @@ -201,14 +169,11 @@ export class AuthStateManager { AuthStateManager.AUTH_STATE_KEY, state, ); - AuthStateManager.consoleLog('[AuthStateManager] Auth state saved'); + console.log('[AuthStateManager] Auth state saved'); // Verify the state was saved correctly const savedState = await this.getAuthState(); - AuthStateManager.consoleLog( - '[AuthStateManager] Verified saved state:', - savedState, - ); + console.log('[AuthStateManager] Verified saved state:', savedState); } /** @@ -222,9 +187,9 @@ export class AuthStateManager { ); } - AuthStateManager.consoleLog('[AuthStateManager] Clearing auth state'); + console.log('[AuthStateManager] Clearing auth state'); const currentState = await this.getAuthState(); - AuthStateManager.consoleLog( + console.log( '[AuthStateManager] Current state before clearing:', currentState, ); @@ -233,14 +198,11 @@ export class AuthStateManager { AuthStateManager.AUTH_STATE_KEY, undefined, ); - AuthStateManager.consoleLog('[AuthStateManager] Auth state cleared'); + console.log('[AuthStateManager] Auth state cleared'); // Verify the state was cleared const newState = await this.getAuthState(); - AuthStateManager.consoleLog( - '[AuthStateManager] State after clearing:', - newState, - ); + console.log('[AuthStateManager] State after clearing:', newState); } /** @@ -249,15 +211,17 @@ export class AuthStateManager { private async getAuthState(): Promise { // Ensure we have a valid context if (!AuthStateManager.context) { - AuthStateManager.consoleLog( + console.log( '[AuthStateManager] No context available for getting auth state', ); return undefined; } - return AuthStateManager.context.globalState.get( + const a = AuthStateManager.context.globalState.get( AuthStateManager.AUTH_STATE_KEY, ); + console.log('[AuthStateManager] Auth state:', a); + return a; } /** diff --git a/packages/vscode-ide-companion/src/services/qwenAgentManager.ts b/packages/vscode-ide-companion/src/services/qwenAgentManager.ts index b954aed8..89214139 100644 --- a/packages/vscode-ide-companion/src/services/qwenAgentManager.ts +++ b/packages/vscode-ide-companion/src/services/qwenAgentManager.ts @@ -23,7 +23,6 @@ import { QwenSessionUpdateHandler } from './qwenSessionUpdateHandler.js'; import { CliContextManager } from '../cli/cliContextManager.js'; import { authMethod } from '../types/acpTypes.js'; import { MIN_CLI_VERSION_FOR_SESSION_METHODS } from '../cli/cliVersionManager.js'; -import { getConsoleLogger } from '../utils/logger.js'; export type { ChatMessage, PlanEntry, ToolCallUpdateData }; @@ -51,10 +50,8 @@ export class QwenAgentManager { // Callback storage private callbacks: QwenAgentCallbacks = {}; - private consoleLog: (...args: unknown[]) => void; - constructor(consoleLogger = getConsoleLogger()) { - this.consoleLog = consoleLogger; + constructor() { this.connection = new AcpConnection(); this.sessionReader = new QwenSessionReader(); this.sessionManager = new QwenSessionManager(); @@ -81,7 +78,7 @@ export class QwenAgentManager { ).update; const text = update?.content?.text || ''; if (update?.sessionUpdate === 'user_message_chunk' && text) { - this.consoleLog( + console.log( '[QwenAgentManager] Rehydration: routing user message chunk', ); this.callbacks.onMessage?.({ @@ -92,7 +89,7 @@ export class QwenAgentManager { return; } if (update?.sessionUpdate === 'agent_message_chunk' && text) { - this.consoleLog( + console.log( '[QwenAgentManager] Rehydration: routing agent message chunk', ); this.callbacks.onMessage?.({ @@ -103,7 +100,7 @@ export class QwenAgentManager { return; } // For other types during rehydration, fall through to normal handler - this.consoleLog( + console.log( '[QwenAgentManager] Rehydration: non-text update, forwarding to handler', ); } @@ -262,7 +259,7 @@ export class QwenAgentManager { * @returns Session list */ async getSessionList(): Promise>> { - this.consoleLog( + console.log( '[QwenAgentManager] Getting session list with version-aware strategy', ); @@ -270,7 +267,7 @@ export class QwenAgentManager { const cliContextManager = CliContextManager.getInstance(); const supportsSessionList = cliContextManager.supportsSessionList(); - this.consoleLog( + console.log( '[QwenAgentManager] CLI supports session/list:', supportsSessionList, ); @@ -278,14 +275,11 @@ export class QwenAgentManager { // Try ACP method first if supported if (supportsSessionList) { try { - this.consoleLog( + console.log( '[QwenAgentManager] Attempting to get session list via ACP method', ); const response = await this.connection.listSessions(); - this.consoleLog( - '[QwenAgentManager] ACP session list response:', - response, - ); + console.log('[QwenAgentManager] ACP session list response:', response); // sendRequest resolves with the JSON-RPC "result" directly // Newer CLI returns an object: { items: [...], nextCursor?, hasMore } @@ -303,7 +297,7 @@ export class QwenAgentManager { : []; } - this.consoleLog( + console.log( '[QwenAgentManager] Sessions retrieved via ACP:', res, items.length, @@ -322,7 +316,7 @@ export class QwenAgentManager { cwd: item.cwd, })); - this.consoleLog( + console.log( '[QwenAgentManager] Sessions retrieved via ACP:', sessions.length, ); @@ -338,11 +332,9 @@ export class QwenAgentManager { // Always fall back to file system method try { - this.consoleLog( - '[QwenAgentManager] Getting session list from file system', - ); + console.log('[QwenAgentManager] Getting session list from file system'); const sessions = await this.sessionReader.getAllSessions(undefined, true); - this.consoleLog( + console.log( '[QwenAgentManager] Session list from file system (all projects):', sessions.length, ); @@ -360,7 +352,7 @@ export class QwenAgentManager { }), ); - this.consoleLog( + console.log( '[QwenAgentManager] Sessions retrieved from file system:', result.length, ); @@ -500,7 +492,7 @@ export class QwenAgentManager { const item = list.find( (s) => s.sessionId === sessionId || s.id === sessionId, ); - this.consoleLog( + console.log( '[QwenAgentManager] Session list item for filePath lookup:', item, ); @@ -571,7 +563,7 @@ export class QwenAgentManager { } } // Simple linear reconstruction: filter user/assistant and sort by timestamp - this.consoleLog( + console.log( '[QwenAgentManager] JSONL records read:', records.length, filePath, @@ -728,7 +720,7 @@ export class QwenAgentManager { // Handle other types if needed } - this.consoleLog( + console.log( '[QwenAgentManager] JSONL messages reconstructed:', msgs.length, ); @@ -866,7 +858,7 @@ export class QwenAgentManager { tag: string, ): Promise<{ success: boolean; message?: string }> { try { - this.consoleLog( + console.log( '[QwenAgentManager] Saving session via /chat save command:', sessionId, 'with tag:', @@ -877,9 +869,7 @@ export class QwenAgentManager { // The CLI will handle this as a special command await this.connection.sendPrompt(`/chat save "${tag}"`); - this.consoleLog( - '[QwenAgentManager] /chat save command sent successfully', - ); + console.log('[QwenAgentManager] /chat save command sent successfully'); return { success: true, message: `Session saved with tag: ${tag}`, @@ -926,14 +916,14 @@ export class QwenAgentManager { conversationId: string, ): Promise<{ success: boolean; tag?: string; message?: string }> { try { - this.consoleLog('[QwenAgentManager] ===== CHECKPOINT SAVE START ====='); - this.consoleLog('[QwenAgentManager] Conversation ID:', conversationId); - this.consoleLog('[QwenAgentManager] Message count:', messages.length); - this.consoleLog( + console.log('[QwenAgentManager] ===== CHECKPOINT SAVE START ====='); + console.log('[QwenAgentManager] Conversation ID:', conversationId); + console.log('[QwenAgentManager] Message count:', messages.length); + console.log( '[QwenAgentManager] Current working dir:', this.currentWorkingDir, ); - this.consoleLog( + console.log( '[QwenAgentManager] Current session ID (from CLI):', this.currentSessionId, ); @@ -1010,11 +1000,11 @@ export class QwenAgentManager { try { // Route upcoming session/update messages as discrete messages for replay this.rehydratingSessionId = sessionId; - this.consoleLog( + console.log( '[QwenAgentManager] Rehydration start for session:', sessionId, ); - this.consoleLog( + console.log( '[QwenAgentManager] Attempting session/load via ACP for session:', sessionId, ); @@ -1022,7 +1012,7 @@ export class QwenAgentManager { sessionId, cwdOverride, ); - this.consoleLog( + console.log( '[QwenAgentManager] Session load succeeded. Response:', JSON.stringify(response).substring(0, 200), ); @@ -1062,10 +1052,7 @@ export class QwenAgentManager { throw error; } finally { // End rehydration routing regardless of outcome - this.consoleLog( - '[QwenAgentManager] Rehydration end for session:', - sessionId, - ); + console.log('[QwenAgentManager] Rehydration end for session:', sessionId); this.rehydratingSessionId = null; } } @@ -1078,7 +1065,7 @@ export class QwenAgentManager { * @returns Loaded session messages or null */ async loadSession(sessionId: string): Promise { - this.consoleLog( + console.log( '[QwenAgentManager] Loading session with version-aware strategy:', sessionId, ); @@ -1087,7 +1074,7 @@ export class QwenAgentManager { const cliContextManager = CliContextManager.getInstance(); const supportsSessionLoad = cliContextManager.supportsSessionLoad(); - this.consoleLog( + console.log( '[QwenAgentManager] CLI supports session/load:', supportsSessionLoad, ); @@ -1095,13 +1082,11 @@ export class QwenAgentManager { // Try ACP method first if supported if (supportsSessionLoad) { try { - this.consoleLog( + console.log( '[QwenAgentManager] Attempting to load session via ACP method', ); await this.loadSessionViaAcp(sessionId); - this.consoleLog( - '[QwenAgentManager] Session loaded successfully via ACP', - ); + console.log('[QwenAgentManager] Session loaded successfully via ACP'); // After loading via ACP, we still need to get messages from file system // In future, we might get them directly from the ACP response @@ -1115,11 +1100,11 @@ export class QwenAgentManager { // Always fall back to file system method try { - this.consoleLog( + console.log( '[QwenAgentManager] Loading session messages from file system', ); const messages = await this.loadSessionMessagesFromFile(sessionId); - this.consoleLog( + console.log( '[QwenAgentManager] Session messages loaded successfully from file system', ); return messages; @@ -1142,7 +1127,7 @@ export class QwenAgentManager { sessionId: string, ): Promise { try { - this.consoleLog( + console.log( '[QwenAgentManager] Loading session from file system:', sessionId, ); @@ -1154,7 +1139,7 @@ export class QwenAgentManager { ); if (!session) { - this.consoleLog( + console.log( '[QwenAgentManager] Session not found in file system:', sessionId, ); @@ -1209,7 +1194,7 @@ export class QwenAgentManager { return this.sessionCreateInFlight; } - this.consoleLog('[QwenAgentManager] Creating new session...'); + console.log('[QwenAgentManager] Creating new session...'); // Prefer the provided authStateManager, otherwise fall back to the one // remembered during connect(). This prevents accidental re-auth in // fallback paths (e.g. session switching) when the handler didn't pass it. @@ -1250,7 +1235,7 @@ export class QwenAgentManager { } } const newSessionId = this.connection.currentSessionId; - this.consoleLog( + console.log( '[QwenAgentManager] New session created with ID:', newSessionId, ); @@ -1276,7 +1261,7 @@ export class QwenAgentManager { * Cancel current prompt */ async cancelCurrentPrompt(): Promise { - this.consoleLog('[QwenAgentManager] Cancelling current prompt'); + console.log('[QwenAgentManager] Cancelling current prompt'); await this.connection.cancelSession(); } diff --git a/packages/vscode-ide-companion/src/utils/logger.ts b/packages/vscode-ide-companion/src/utils/logger.ts index f92cfe8c..b3f8ad1e 100644 --- a/packages/vscode-ide-companion/src/utils/logger.ts +++ b/packages/vscode-ide-companion/src/utils/logger.ts @@ -6,11 +6,6 @@ import * as vscode from 'vscode'; -type ConsoleLogger = (...args: unknown[]) => void; - -// Shared console logger instance, initialized during extension activation. -let sharedConsoleLogger: ConsoleLogger = () => {}; - export function createLogger( context: vscode.ExtensionContext, logger: vscode.OutputChannel, @@ -21,40 +16,3 @@ export function createLogger( } }; } - -/** - * Creates a dev-only logger that writes to the VS Code console (Developer Tools). - */ -export function createConsoleLogger( - context: vscode.ExtensionContext, - scope?: string, -): ConsoleLogger { - return (...args: unknown[]) => { - if (context.extensionMode !== vscode.ExtensionMode.Development) { - return; - } - if (scope) { - console.log(`[${scope}]`, ...args); - return; - } - console.log(...args); - }; -} - -/** - * Initialize the shared console logger so other modules can import it without - * threading the extension context everywhere. - */ -export function initSharedConsoleLogger( - context: vscode.ExtensionContext, - scope?: string, -) { - sharedConsoleLogger = createConsoleLogger(context, scope); -} - -/** - * Get the shared console logger (no-op until initialized). - */ -export function getConsoleLogger(): ConsoleLogger { - return sharedConsoleLogger; -} diff --git a/packages/vscode-ide-companion/src/webview/App.tsx b/packages/vscode-ide-companion/src/webview/App.tsx index 65d978fd..4bdf6622 100644 --- a/packages/vscode-ide-companion/src/webview/App.tsx +++ b/packages/vscode-ide-companion/src/webview/App.tsx @@ -45,11 +45,9 @@ import { FileIcon, UserIcon } from './components/icons/index.js'; import { ApprovalMode, NEXT_APPROVAL_MODE } from '../types/acpTypes.js'; import type { ApprovalModeValue } from '../types/acpTypes.js'; import type { PlanEntry } from '../types/chatTypes.js'; -import { createWebviewConsoleLogger } from './utils/logger.js'; export const App: React.FC = () => { const vscode = useVSCode(); - const consoleLog = useMemo(() => createWebviewConsoleLogger('App'), []); // Core hooks const sessionManagement = useSessionManagement(vscode); @@ -542,7 +540,7 @@ export const App: React.FC = () => { ); }, [messageHandling.messages, inProgressToolCalls, completedToolCalls]); - consoleLog('[App] Rendering messages:', allMessages); + console.log('[App] Rendering messages:', allMessages); // Render all messages and tool calls const renderMessages = useCallback<() => React.ReactNode>( diff --git a/packages/vscode-ide-companion/src/webview/WebViewProvider.ts b/packages/vscode-ide-companion/src/webview/WebViewProvider.ts index 11054259..faa81226 100644 --- a/packages/vscode-ide-companion/src/webview/WebViewProvider.ts +++ b/packages/vscode-ide-companion/src/webview/WebViewProvider.ts @@ -16,7 +16,6 @@ import { WebViewContent } from '../webview/WebViewContent.js'; import { CliInstaller } from '../cli/cliInstaller.js'; import { getFileName } from './utils/webviewUtils.js'; import { authMethod, type ApprovalModeValue } from '../types/acpTypes.js'; -import { createConsoleLogger } from '../utils/logger.js'; export class WebViewProvider { private panelManager: PanelManager; @@ -33,15 +32,12 @@ export class WebViewProvider { private pendingPermissionResolve: ((optionId: string) => void) | null = null; // Track current ACP mode id to influence permission/diff behavior private currentModeId: ApprovalModeValue | null = null; - private consoleLog: (...args: unknown[]) => void; constructor( context: vscode.ExtensionContext, private extensionUri: vscode.Uri, ) { - const agentConsoleLogger = createConsoleLogger(context, 'QwenAgentManager'); - this.consoleLog = createConsoleLogger(context, 'WebViewProvider'); - this.agentManager = new QwenAgentManager(agentConsoleLogger); + this.agentManager = new QwenAgentManager(); this.conversationStore = new ConversationStore(context); this.authStateManager = AuthStateManager.getInstance(context); this.panelManager = new PanelManager(extensionUri, () => { @@ -384,7 +380,7 @@ export class WebViewProvider { // Set up state serialization newPanel.onDidChangeViewState(() => { - this.consoleLog( + console.log( '[WebViewProvider] Panel view state changed, triggering serialization check', ); }); @@ -514,7 +510,7 @@ export class WebViewProvider { } // Attempt to restore authentication state and initialize connection - this.consoleLog( + console.log( '[WebViewProvider] Attempting to restore auth state and connection...', ); await this.attemptAuthStateRestoration(); @@ -536,26 +532,23 @@ export class WebViewProvider { workingDir, authMethod, ); - this.consoleLog( - '[WebViewProvider] Has valid cached auth:', - hasValidAuth, - ); + console.log('[WebViewProvider] Has valid cached auth:', hasValidAuth); if (hasValidAuth) { - this.consoleLog( + console.log( '[WebViewProvider] Valid auth found, attempting connection...', ); // Try to connect with cached auth await this.initializeAgentConnection(); } else { - this.consoleLog( + console.log( '[WebViewProvider] No valid auth found, rendering empty conversation', ); // Render the chat UI immediately without connecting await this.initializeEmptyConversation(); } } else { - this.consoleLog( + console.log( '[WebViewProvider] No auth state manager, rendering empty conversation', ); await this.initializeEmptyConversation(); @@ -585,11 +578,11 @@ export class WebViewProvider { const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; const workingDir = workspaceFolder?.uri.fsPath || process.cwd(); - this.consoleLog( + console.log( '[WebViewProvider] Starting initialization, workingDir:', workingDir, ); - this.consoleLog( + console.log( '[WebViewProvider] AuthStateManager available:', !!this.authStateManager, ); @@ -598,10 +591,10 @@ export class WebViewProvider { const cliDetection = await CliDetector.detectQwenCli(); if (!cliDetection.isInstalled) { - this.consoleLog( + console.log( '[WebViewProvider] Qwen CLI not detected, skipping agent connection', ); - this.consoleLog( + console.log( '[WebViewProvider] CLI detection error:', cliDetection.error, ); @@ -612,20 +605,20 @@ export class WebViewProvider { // Initialize empty conversation (can still browse history) await this.initializeEmptyConversation(); } else { - this.consoleLog( + console.log( '[WebViewProvider] Qwen CLI detected, attempting connection...', ); - this.consoleLog('[WebViewProvider] CLI path:', cliDetection.cliPath); - this.consoleLog('[WebViewProvider] CLI version:', cliDetection.version); + console.log('[WebViewProvider] CLI path:', cliDetection.cliPath); + console.log('[WebViewProvider] CLI version:', cliDetection.version); try { - this.consoleLog('[WebViewProvider] Connecting to agent...'); - this.consoleLog( + console.log('[WebViewProvider] Connecting to agent...'); + console.log( '[WebViewProvider] Using authStateManager:', !!this.authStateManager, ); const authInfo = await this.authStateManager.getAuthInfo(); - this.consoleLog('[WebViewProvider] Auth cache status:', authInfo); + console.log('[WebViewProvider] Auth cache status:', authInfo); // Pass the detected CLI path to ensure we use the correct installation await this.agentManager.connect( @@ -633,7 +626,7 @@ export class WebViewProvider { this.authStateManager, cliDetection.cliPath, ); - this.consoleLog('[WebViewProvider] Agent connected successfully'); + console.log('[WebViewProvider] Agent connected successfully'); this.agentInitialized = true; // Load messages from the current Qwen session @@ -674,8 +667,8 @@ export class WebViewProvider { * Called when user explicitly uses /login command */ async forceReLogin(): Promise { - this.consoleLog('[WebViewProvider] Force re-login requested'); - this.consoleLog( + console.log('[WebViewProvider] Force re-login requested'); + console.log( '[WebViewProvider] Current authStateManager:', !!this.authStateManager, ); @@ -694,23 +687,20 @@ export class WebViewProvider { // Clear existing auth cache if (this.authStateManager) { await this.authStateManager.clearAuthState(); - this.consoleLog('[WebViewProvider] Auth cache cleared'); + console.log('[WebViewProvider] Auth cache cleared'); } else { - this.consoleLog('[WebViewProvider] No authStateManager to clear'); + console.log('[WebViewProvider] No authStateManager to clear'); } // Disconnect existing connection if any if (this.agentInitialized) { try { this.agentManager.disconnect(); - this.consoleLog( + console.log( '[WebViewProvider] Existing connection disconnected', ); } catch (_error) { - this.consoleLog( - '[WebViewProvider] Error disconnecting:', - _error, - ); + console.log('[WebViewProvider] Error disconnecting:', _error); } this.agentInitialized = false; } @@ -724,7 +714,7 @@ export class WebViewProvider { // Reinitialize connection (will trigger fresh authentication) await this.doInitializeAgentConnection(); - this.consoleLog( + console.log( '[WebViewProvider] Force re-login completed successfully', ); @@ -733,9 +723,7 @@ export class WebViewProvider { const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; const workingDir = workspaceFolder?.uri.fsPath || process.cwd(); await this.authStateManager.saveAuthState(workingDir, authMethod); - this.consoleLog( - '[WebViewProvider] Auth state saved after re-login', - ); + console.log('[WebViewProvider] Auth state saved after re-login'); } // Send success notification to WebView @@ -772,15 +760,15 @@ export class WebViewProvider { * Called when restoring WebView after VSCode restart */ async refreshConnection(): Promise { - this.consoleLog('[WebViewProvider] Refresh connection requested'); + console.log('[WebViewProvider] Refresh connection requested'); // Disconnect existing connection if any if (this.agentInitialized) { try { this.agentManager.disconnect(); - this.consoleLog('[WebViewProvider] Existing connection disconnected'); + console.log('[WebViewProvider] Existing connection disconnected'); } catch (_error) { - this.consoleLog('[WebViewProvider] Error disconnecting:', _error); + console.log('[WebViewProvider] Error disconnecting:', _error); } this.agentInitialized = false; } @@ -791,7 +779,7 @@ export class WebViewProvider { // Reinitialize connection (will use cached auth if available) try { await this.initializeAgentConnection(); - this.consoleLog( + console.log( '[WebViewProvider] Connection refresh completed successfully', ); @@ -821,7 +809,7 @@ export class WebViewProvider { */ private async loadCurrentSessionMessages(): Promise { try { - this.consoleLog( + console.log( '[WebViewProvider] Initializing with new session (skipping restoration)', ); @@ -835,12 +823,12 @@ export class WebViewProvider { workingDir, this.authStateManager, ); - this.consoleLog('[WebViewProvider] ACP session created successfully'); + console.log('[WebViewProvider] ACP session created successfully'); // Ensure auth state is saved after successful session creation if (this.authStateManager) { await this.authStateManager.saveAuthState(workingDir, authMethod); - this.consoleLog( + console.log( '[WebViewProvider] Auth state saved after session creation', ); } @@ -854,7 +842,7 @@ export class WebViewProvider { ); } } else { - this.consoleLog( + console.log( '[WebViewProvider] Existing ACP session detected, skipping new session creation', ); } @@ -878,14 +866,14 @@ export class WebViewProvider { */ private async initializeEmptyConversation(): Promise { try { - this.consoleLog('[WebViewProvider] Initializing empty conversation'); + console.log('[WebViewProvider] Initializing empty conversation'); const newConv = await this.conversationStore.createConversation(); this.messageHandler.setCurrentConversationId(newConv.id); this.sendMessageToWebView({ type: 'conversationLoaded', data: newConv, }); - this.consoleLog( + console.log( '[WebViewProvider] Empty conversation initialized:', this.messageHandler.getCurrentConversationId(), ); @@ -1009,7 +997,7 @@ export class WebViewProvider { * Call this when auth cache is cleared to force re-authentication */ resetAgentState(): void { - this.consoleLog('[WebViewProvider] Resetting agent state'); + console.log('[WebViewProvider] Resetting agent state'); this.agentInitialized = false; // Disconnect existing connection this.agentManager.disconnect(); @@ -1019,7 +1007,7 @@ export class WebViewProvider { * Clear authentication cache for this WebViewProvider instance */ async clearAuthCache(): Promise { - this.consoleLog('[WebViewProvider] Clearing auth cache for this instance'); + console.log('[WebViewProvider] Clearing auth cache for this instance'); if (this.authStateManager) { await this.authStateManager.clearAuthState(); this.resetAgentState(); @@ -1031,8 +1019,8 @@ export class WebViewProvider { * This sets up the panel with all event listeners */ async restorePanel(panel: vscode.WebviewPanel): Promise { - this.consoleLog('[WebViewProvider] Restoring WebView panel'); - this.consoleLog( + console.log('[WebViewProvider] Restoring WebView panel'); + console.log( '[WebViewProvider] Current authStateManager in restore:', !!this.authStateManager, ); @@ -1163,10 +1151,10 @@ export class WebViewProvider { // Capture the tab reference on restore this.panelManager.captureTab(); - this.consoleLog('[WebViewProvider] Panel restored successfully'); + console.log('[WebViewProvider] Panel restored successfully'); // Attempt to restore authentication state and initialize connection - this.consoleLog( + console.log( '[WebViewProvider] Attempting to restore auth state and connection after restore...', ); await this.attemptAuthStateRestoration(); @@ -1180,12 +1168,12 @@ export class WebViewProvider { conversationId: string | null; agentInitialized: boolean; } { - this.consoleLog('[WebViewProvider] Getting state for serialization'); - this.consoleLog( + console.log('[WebViewProvider] Getting state for serialization'); + console.log( '[WebViewProvider] Current conversationId:', this.messageHandler.getCurrentConversationId(), ); - this.consoleLog( + console.log( '[WebViewProvider] Current agentInitialized:', this.agentInitialized, ); @@ -1193,7 +1181,7 @@ export class WebViewProvider { conversationId: this.messageHandler.getCurrentConversationId(), agentInitialized: this.agentInitialized, }; - this.consoleLog('[WebViewProvider] Returning state:', state); + console.log('[WebViewProvider] Returning state:', state); return state; } @@ -1211,10 +1199,10 @@ export class WebViewProvider { conversationId: string | null; agentInitialized: boolean; }): void { - this.consoleLog('[WebViewProvider] Restoring state:', state); + console.log('[WebViewProvider] Restoring state:', state); this.messageHandler.setCurrentConversationId(state.conversationId); this.agentInitialized = state.agentInitialized; - this.consoleLog( + console.log( '[WebViewProvider] State restored. agentInitialized:', this.agentInitialized, ); diff --git a/packages/vscode-ide-companion/src/webview/components/messages/toolcalls/shared/utils.ts b/packages/vscode-ide-companion/src/webview/components/messages/toolcalls/shared/utils.ts index 4ae9efd6..ceb2cb2b 100644 --- a/packages/vscode-ide-companion/src/webview/components/messages/toolcalls/shared/utils.ts +++ b/packages/vscode-ide-companion/src/webview/components/messages/toolcalls/shared/utils.ts @@ -61,25 +61,6 @@ export const safeTitle = (title: unknown): string => { return ''; }; -/** - * Get icon emoji for a given tool kind - */ -export const getKindIcon = (kind: string): string => { - const kindMap: Record = { - edit: '✏️', - write: '✏️', - read: '📖', - execute: '⚡', - fetch: '🌐', - delete: '🗑️', - move: '📦', - search: '🔍', - think: '💭', - diff: '📝', - }; - return kindMap[kind.toLowerCase()] || '🔧'; -}; - /** * Check if a tool call should be displayed * Hides internal tool calls diff --git a/packages/vscode-ide-companion/src/webview/hooks/useWebViewMessages.ts b/packages/vscode-ide-companion/src/webview/hooks/useWebViewMessages.ts index a00fa0e5..7a3f7e06 100644 --- a/packages/vscode-ide-companion/src/webview/hooks/useWebViewMessages.ts +++ b/packages/vscode-ide-companion/src/webview/hooks/useWebViewMessages.ts @@ -14,7 +14,6 @@ import type { import type { ToolCallUpdate } from '../../types/chatTypes.js'; import type { ApprovalModeValue } from '../../types/acpTypes.js'; import type { PlanEntry } from '../../types/chatTypes.js'; -import { createWebviewConsoleLogger } from '../utils/logger.js'; interface UseWebViewMessagesProps { // Session management @@ -130,7 +129,6 @@ export const useWebViewMessages = ({ }: UseWebViewMessagesProps) => { // VS Code API for posting messages back to the extension host const vscode = useVSCode(); - const consoleLog = useRef(createWebviewConsoleLogger('WebViewMessages')); // Track active long-running tool calls (execute/bash/command) so we can // keep the bottom "waiting" message visible until all of them complete. const activeExecToolCallsRef = useRef>(new Set()); @@ -753,10 +751,7 @@ export const useWebViewMessages = ({ path: string; }>; if (files) { - consoleLog.current( - '[WebView] Received workspaceFiles:', - files.length, - ); + console.log('[WebView] Received workspaceFiles:', files.length); handlers.fileContext.setWorkspaceFiles(files); } break; diff --git a/packages/vscode-ide-companion/src/webview/utils/logger.ts b/packages/vscode-ide-companion/src/webview/utils/logger.ts deleted file mode 100644 index 40d1793e..00000000 --- a/packages/vscode-ide-companion/src/webview/utils/logger.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @license - * Copyright 2025 Qwen Team - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * Creates a dev-only console logger for the WebView bundle. - * In production builds it becomes a no-op to avoid noisy logs. - */ -export function createWebviewConsoleLogger(scope?: string) { - return (...args: unknown[]) => { - const env = (globalThis as { process?: { env?: Record } }) - .process?.env; - const isProduction = env?.NODE_ENV === 'production'; - if (isProduction) { - return; - } - if (scope) { - console.log(`[${scope}]`, ...args); - return; - } - console.log(...args); - }; -}