diff --git a/packages/amazonq/src/extension.ts b/packages/amazonq/src/extension.ts index 53d7cd88037..9b83695205c 100644 --- a/packages/amazonq/src/extension.ts +++ b/packages/amazonq/src/extension.ts @@ -45,6 +45,7 @@ import { registerCommands } from './commands' import { focusAmazonQPanel } from 'aws-core-vscode/codewhispererChat' import { activate as activateAmazonqLsp } from './lsp/activation' import { hasGlibcPatch } from './lsp/client' +import { activateAutoDebug } from './lsp/chat/autoDebug/activation' export const amazonQContextPrefix = 'amazonq' @@ -131,6 +132,14 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is await activateAmazonqLsp(context) } + // Activate AutoDebug feature at extension level + try { + const autoDebugFeature = await activateAutoDebug(context) + context.subscriptions.push(autoDebugFeature) + } catch (error) { + getLogger().error('Failed to activate AutoDebug feature at extension level: %s', error) + } + // Generic extension commands registerGenericCommands(context, amazonQContextPrefix) diff --git a/packages/amazonq/src/lsp/chat/activation.ts b/packages/amazonq/src/lsp/chat/activation.ts index 90a0adbc61f..1f443bed875 100644 --- a/packages/amazonq/src/lsp/chat/activation.ts +++ b/packages/amazonq/src/lsp/chat/activation.ts @@ -17,12 +17,16 @@ import { activate as registerLegacyChatListeners } from '../../app/chat/activati import { DefaultAmazonQAppInitContext } from 'aws-core-vscode/amazonq' import { AuthUtil, getSelectedCustomization } from 'aws-core-vscode/codewhisperer' import { pushConfigUpdate } from '../config' +import { AutoDebugLspClient } from './autoDebug/lsp/autoDebugLspClient' export async function activate(languageClient: LanguageClient, encryptionKey: Buffer, mynahUIPath: string) { const disposables = globals.context.subscriptions const provider = new AmazonQChatViewProvider(mynahUIPath, languageClient) + // Set the chat view provider for AutoDebug to use + AutoDebugLspClient.setChatViewProvider(provider) + disposables.push( window.registerWebviewViewProvider(AmazonQChatViewProvider.viewType, provider, { webviewOptions: { diff --git a/packages/amazonq/src/lsp/chat/autoDebug/activation.ts b/packages/amazonq/src/lsp/chat/autoDebug/activation.ts new file mode 100644 index 00000000000..f18c82c237a --- /dev/null +++ b/packages/amazonq/src/lsp/chat/autoDebug/activation.ts @@ -0,0 +1,78 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as vscode from 'vscode' +import { getLogger } from 'aws-core-vscode/shared' +import { AutoDebugCommands } from './commands' +import { AutoDebugCodeActionsProvider } from './codeActionsProvider' +import { AutoDebugController } from './controller' + +/** + * Auto Debug feature activation for Amazon Q + * This handles the complete lifecycle of the auto debug feature + */ +export class AutoDebugFeature implements vscode.Disposable { + private readonly logger = getLogger() + private readonly disposables: vscode.Disposable[] = [] + + private autoDebugCommands?: AutoDebugCommands + private codeActionsProvider?: AutoDebugCodeActionsProvider + private controller?: AutoDebugController + + constructor(private readonly context: vscode.ExtensionContext) {} + + /** + * Activate the auto debug feature + */ + async activate(): Promise { + try { + // Initialize the controller first + this.controller = new AutoDebugController() + + // Initialize commands and register them with the controller + this.autoDebugCommands = new AutoDebugCommands() + this.autoDebugCommands.registerCommands(this.context, this.controller) + + // Initialize code actions provider + this.codeActionsProvider = new AutoDebugCodeActionsProvider() + this.context.subscriptions.push(this.codeActionsProvider) + + // Add all to disposables + this.disposables.push(this.controller, this.autoDebugCommands, this.codeActionsProvider) + } catch (error) { + this.logger.error('AutoDebugFeature: Failed to activate auto debug feature: %s', error) + throw error + } + } + + /** + * Get the auto debug controller instance + */ + getController(): AutoDebugController | undefined { + return this.controller + } + + /** + * Dispose of all resources + */ + dispose(): void { + vscode.Disposable.from(...this.disposables).dispose() + } +} + +/** + * Factory function to activate auto debug feature with LSP client + * This is the main entry point for activating auto debug + */ +export async function activateAutoDebug( + context: vscode.ExtensionContext, + client?: any, + encryptionKey?: Buffer +): Promise { + const feature = new AutoDebugFeature(context) + await feature.activate() + + return feature +} diff --git a/packages/amazonq/src/lsp/chat/autoDebug/codeActionsProvider.ts b/packages/amazonq/src/lsp/chat/autoDebug/codeActionsProvider.ts new file mode 100644 index 00000000000..aed926eaacf --- /dev/null +++ b/packages/amazonq/src/lsp/chat/autoDebug/codeActionsProvider.ts @@ -0,0 +1,119 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as vscode from 'vscode' + +/** + * Provides code actions for Amazon Q Auto Debug features. + * Integrates with VS Code's quick fix system to offer debugging assistance. + */ +export class AutoDebugCodeActionsProvider implements vscode.CodeActionProvider, vscode.Disposable { + private readonly disposables: vscode.Disposable[] = [] + + public static readonly providedCodeActionKinds = [vscode.CodeActionKind.QuickFix, vscode.CodeActionKind.Refactor] + + constructor() { + this.registerProvider() + } + + private registerProvider(): void { + // Register for all file types + const selector: vscode.DocumentSelector = [{ scheme: 'file' }] + + this.disposables.push( + vscode.languages.registerCodeActionsProvider(selector, this, { + providedCodeActionKinds: AutoDebugCodeActionsProvider.providedCodeActionKinds, + }) + ) + } + + /** + * Provides code actions for the given document and range + */ + public provideCodeActions( + document: vscode.TextDocument, + range: vscode.Range | vscode.Selection, + context: vscode.CodeActionContext, + token: vscode.CancellationToken + ): vscode.ProviderResult<(vscode.CodeAction | vscode.Command)[]> { + if (token.isCancellationRequested) { + return [] + } + + const actions: vscode.CodeAction[] = [] + + // Get diagnostics for the current range + const diagnostics = context.diagnostics.filter( + (diagnostic) => diagnostic.range.intersection(range) !== undefined + ) + + if (diagnostics.length > 0) { + // Add "Fix with Amazon Q" action + actions.push(this.createFixWithQAction(document, range, diagnostics)) + + // Add "Fix All with Amazon Q" action + actions.push(this.createFixAllWithQAction(document)) + + // Add "Explain Problem" action + actions.push(this.createExplainProblemAction(document, range, diagnostics)) + } + return actions + } + + private createFixWithQAction( + document: vscode.TextDocument, + range: vscode.Range, + diagnostics: vscode.Diagnostic[] + ): vscode.CodeAction { + const action = new vscode.CodeAction( + `Amazon Q: Fix Problem (${diagnostics.length} issue${diagnostics.length !== 1 ? 's' : ''})`, + vscode.CodeActionKind.QuickFix + ) + + action.command = { + command: 'amazonq.01.fixWithQ', + title: 'Amazon Q: Fix Problem', + arguments: [range, diagnostics], + } + + action.diagnostics = diagnostics + action.isPreferred = true // Make this the preferred quick fix + + return action + } + + private createFixAllWithQAction(document: vscode.TextDocument): vscode.CodeAction { + const action = new vscode.CodeAction('Amazon Q: Fix All Errors', vscode.CodeActionKind.QuickFix) + + action.command = { + command: 'amazonq.02.fixAllWithQ', + title: 'Amazon Q: Fix All Errors', + } + + return action + } + + private createExplainProblemAction( + document: vscode.TextDocument, + range: vscode.Range, + diagnostics: vscode.Diagnostic[] + ): vscode.CodeAction { + const action = new vscode.CodeAction('Amazon Q: Explain Problem', vscode.CodeActionKind.QuickFix) + + action.command = { + command: 'amazonq.03.explainProblem', + title: 'Amazon Q: Explain Problem', + arguments: [range, diagnostics], + } + + action.diagnostics = diagnostics + + return action + } + + public dispose(): void { + vscode.Disposable.from(...this.disposables).dispose() + } +} diff --git a/packages/amazonq/src/lsp/chat/autoDebug/commands.ts b/packages/amazonq/src/lsp/chat/autoDebug/commands.ts new file mode 100644 index 00000000000..54dfd06a1dc --- /dev/null +++ b/packages/amazonq/src/lsp/chat/autoDebug/commands.ts @@ -0,0 +1,147 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as vscode from 'vscode' +import { Commands, getLogger, messages } from 'aws-core-vscode/shared' +import { AutoDebugController } from './controller' + +/** + * Auto Debug commands for Amazon Q + * Handles all command registrations and implementations + */ +export class AutoDebugCommands implements vscode.Disposable { + private readonly logger = getLogger() + private readonly disposables: vscode.Disposable[] = [] + private controller!: AutoDebugController + + /** + * Register all auto debug commands + */ + registerCommands(context: vscode.ExtensionContext, controller: AutoDebugController): void { + this.controller = controller + this.disposables.push( + // Fix with Amazon Q command + Commands.register( + { + id: 'amazonq.01.fixWithQ', + name: 'Amazon Q: Fix Problem', + }, + async (range?: vscode.Range, diagnostics?: vscode.Diagnostic[]) => { + await this.fixWithAmazonQ(range, diagnostics) + } + ), + + // Fix All with Amazon Q command + Commands.register( + { + id: 'amazonq.02.fixAllWithQ', + name: 'Amazon Q: Fix All Errors', + }, + async () => { + await this.fixAllWithAmazonQ() + } + ), + + // Explain Problem with Amazon Q command + Commands.register( + { + id: 'amazonq.03.explainProblem', + name: 'Amazon Q: Explain Problem', + }, + async (range?: vscode.Range, diagnostics?: vscode.Diagnostic[]) => { + await this.explainProblem(range, diagnostics) + } + ) + ) + + // Add all disposables to context + context.subscriptions.push(...this.disposables) + } + + /** + * Generic error handling wrapper for command execution + */ + private async executeWithErrorHandling( + action: () => Promise, + errorMessage: string, + logContext: string + ): Promise { + try { + return await action() + } catch (error) { + this.logger.error(`AutoDebugCommands: Error in ${logContext}: %s`, error) + void messages.showMessage('error', 'Amazon Q was not able to fix or explain the problem. Try again shortly') + } + } + + /** + * Check if there's an active editor and log warning if not + */ + private checkActiveEditor(): vscode.TextEditor | undefined { + const editor = vscode.window.activeTextEditor + if (!editor) { + this.logger.warn('AutoDebugCommands: No active editor found') + } + return editor + } + + /** + * Fix with Amazon Q - fixes only the specific issues the user selected + */ + private async fixWithAmazonQ(range?: vscode.Range, diagnostics?: vscode.Diagnostic[]): Promise { + await this.executeWithErrorHandling( + async () => { + const editor = this.checkActiveEditor() + if (!editor) { + return + } + await this.controller.fixSpecificProblems(range, diagnostics) + }, + 'Fix with Amazon Q', + 'fixWithAmazonQ' + ) + } + + /** + * Fix All with Amazon Q - processes all errors in the current file + */ + private async fixAllWithAmazonQ(): Promise { + await this.executeWithErrorHandling( + async () => { + const editor = this.checkActiveEditor() + if (!editor) { + return + } + await this.controller.fixAllProblemsInFile(10) // 10 errors per batch + }, + 'Fix All with Amazon Q', + 'fixAllWithAmazonQ' + ) + } + + /** + * Explains the problem using Amazon Q + */ + private async explainProblem(range?: vscode.Range, diagnostics?: vscode.Diagnostic[]): Promise { + await this.executeWithErrorHandling( + async () => { + const editor = this.checkActiveEditor() + if (!editor) { + return + } + await this.controller.explainProblems(range, diagnostics) + }, + 'Explain Problem', + 'explainProblem' + ) + } + + /** + * Dispose of all resources + */ + dispose(): void { + vscode.Disposable.from(...this.disposables).dispose() + } +} diff --git a/packages/amazonq/src/lsp/chat/autoDebug/controller.ts b/packages/amazonq/src/lsp/chat/autoDebug/controller.ts new file mode 100644 index 00000000000..0a0f8e10622 --- /dev/null +++ b/packages/amazonq/src/lsp/chat/autoDebug/controller.ts @@ -0,0 +1,204 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as vscode from 'vscode' +import { getLogger, randomUUID, messages } from 'aws-core-vscode/shared' +import { AutoDebugLspClient } from './lsp/autoDebugLspClient' +import { mapDiagnosticSeverity } from './shared/diagnosticUtils' +import { ErrorContextFormatter } from './diagnostics/errorContext' +import { Problem } from './diagnostics/problemDetector' +export interface AutoDebugConfig { + readonly enabled: boolean + readonly excludedSources: string[] + readonly severityFilter: ('error' | 'warning' | 'info' | 'hint')[] +} + +/** + * Simplified controller for Amazon Q Auto Debug system. + * Focuses on context menu and quick fix functionality without workspace-wide monitoring. + */ +export class AutoDebugController implements vscode.Disposable { + private readonly logger = getLogger() + private readonly lspClient: AutoDebugLspClient + private readonly errorFormatter: ErrorContextFormatter + private readonly disposables: vscode.Disposable[] = [] + + private config: AutoDebugConfig + + constructor(config?: Partial) { + this.config = { + enabled: true, + excludedSources: [], // No default exclusions - let users configure as needed + severityFilter: ['error'], // Only auto-fix errors, not warnings + ...config, + } + + this.lspClient = new AutoDebugLspClient() + this.errorFormatter = new ErrorContextFormatter() + } + + /** + * Extract common logic for getting problems from diagnostics + */ + private async getProblemsFromDiagnostics( + range?: vscode.Range, + diagnostics?: vscode.Diagnostic[] + ): Promise<{ editor: vscode.TextEditor; problems: Problem[] } | undefined> { + const editor = vscode.window.activeTextEditor + if (!editor) { + throw new Error('No active editor found') + } + + // Use provided diagnostics or get diagnostics for the range + let targetDiagnostics = diagnostics + if (!targetDiagnostics && range) { + const allDiagnostics = vscode.languages.getDiagnostics(editor.document.uri) + targetDiagnostics = allDiagnostics.filter((d) => d.range.intersection(range) !== undefined) + } + + if (!targetDiagnostics || targetDiagnostics.length === 0) { + return undefined + } + + // Convert diagnostics to problems + const problems = targetDiagnostics.map((diagnostic) => ({ + uri: editor.document.uri, + diagnostic, + severity: mapDiagnosticSeverity(diagnostic.severity), + source: diagnostic.source || 'unknown', + isNew: false, + })) + + return { editor, problems } + } + + /** + * Filter diagnostics to only errors and apply source filtering + */ + private filterErrorDiagnostics(diagnostics: vscode.Diagnostic[]): vscode.Diagnostic[] { + return diagnostics.filter((d) => { + if (d.severity !== vscode.DiagnosticSeverity.Error) { + return false + } + // Apply source filtering + if (this.config.excludedSources.length > 0 && d.source) { + return !this.config.excludedSources.includes(d.source) + } + return true + }) + } + + /** + * Fix specific problems in the code + */ + async fixSpecificProblems(range?: vscode.Range, diagnostics?: vscode.Diagnostic[]): Promise { + try { + const result = await this.getProblemsFromDiagnostics(range, diagnostics) + if (!result) { + return + } + const fixMessage = this.createFixMessage(result.editor.document.uri.fsPath, result.problems) + await this.sendMessageToChat(fixMessage) + } catch (error) { + this.logger.error('AutoDebugController: Error fixing specific problems: %s', error) + throw error + } + } + + /** + * Fix with Amazon Q - sends up to 15 error messages one time when user clicks the button + */ + public async fixAllProblemsInFile(maxProblems: number = 15): Promise { + try { + const editor = vscode.window.activeTextEditor + if (!editor) { + void messages.showMessage('warn', 'No active editor found') + return + } + + // Get all diagnostics for the current file + const allDiagnostics = vscode.languages.getDiagnostics(editor.document.uri) + const errorDiagnostics = this.filterErrorDiagnostics(allDiagnostics) + if (errorDiagnostics.length === 0) { + return + } + + // Take up to maxProblems errors (15 by default) + const diagnosticsToFix = errorDiagnostics.slice(0, maxProblems) + const result = await this.getProblemsFromDiagnostics(undefined, diagnosticsToFix) + if (!result) { + return + } + + const fixMessage = this.createFixMessage(result.editor.document.uri.fsPath, result.problems) + await this.sendMessageToChat(fixMessage) + } catch (error) { + this.logger.error('AutoDebugController: Error in fix process: %s', error) + } + } + + /** + * Explain problems using Amazon Q + */ + async explainProblems(range?: vscode.Range, diagnostics?: vscode.Diagnostic[]): Promise { + try { + const result = await this.getProblemsFromDiagnostics(range, diagnostics) + if (!result) { + return + } + const explainMessage = this.createExplainMessage(result.editor.document.uri.fsPath, result.problems) + await this.sendMessageToChat(explainMessage) + } catch (error) { + this.logger.error('AutoDebugController: Error explaining problems: %s', error) + throw error + } + } + + private createFixMessage(filePath: string, problems: Problem[]): string { + const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || '' + const formattedProblems = this.errorFormatter.formatProblemsString(problems, workspaceRoot) + + return `Please help me fix the following errors in ${filePath}:${formattedProblems}` + } + + private createExplainMessage(filePath: string, problems: Problem[]): string { + const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || '' + const formattedProblems = this.errorFormatter.formatProblemsString(problems, workspaceRoot) + + return `Please explain the following problems in ${filePath}. DO NOT edit files. ONLY provide explanation:${formattedProblems}` + } + + /** + * Sends message directly to language server bypassing webview connectors + * This ensures messages go through the proper LSP chat system + */ + private async sendMessageToChat(message: string): Promise { + const triggerID = randomUUID() + try { + const success = await this.lspClient.sendChatMessage({ + message: message, + triggerType: 'autoDebug', + eventId: triggerID, + }) + + if (success) { + this.logger.debug('AutoDebugController: Chat message sent successfully through LSP client') + } else { + this.logger.error('AutoDebugController: Failed to send chat message through LSP client') + throw new Error('Failed to send message through LSP client') + } + } catch (error) { + this.logger.error( + 'AutoDebugController: Error sending message through LSP client with triggerID %s: %s', + triggerID, + error + ) + } + } + + public dispose(): void { + vscode.Disposable.from(...this.disposables).dispose() + } +} diff --git a/packages/amazonq/src/lsp/chat/autoDebug/diagnostics/diagnosticsMonitor.ts b/packages/amazonq/src/lsp/chat/autoDebug/diagnostics/diagnosticsMonitor.ts new file mode 100644 index 00000000000..8f4000bf217 --- /dev/null +++ b/packages/amazonq/src/lsp/chat/autoDebug/diagnostics/diagnosticsMonitor.ts @@ -0,0 +1,22 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as vscode from 'vscode' + +export interface DiagnosticCollection { + readonly diagnostics: [vscode.Uri, vscode.Diagnostic[]][] + readonly timestamp: number +} + +export interface DiagnosticSnapshot { + readonly diagnostics: DiagnosticCollection + readonly captureTime: number + readonly id: string +} + +export interface FileDiagnostics { + readonly uri: vscode.Uri + readonly diagnostics: vscode.Diagnostic[] +} diff --git a/packages/amazonq/src/lsp/chat/autoDebug/diagnostics/errorContext.ts b/packages/amazonq/src/lsp/chat/autoDebug/diagnostics/errorContext.ts new file mode 100644 index 00000000000..dee7bc0565a --- /dev/null +++ b/packages/amazonq/src/lsp/chat/autoDebug/diagnostics/errorContext.ts @@ -0,0 +1,75 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as vscode from 'vscode' +import * as path from 'path' +import { Problem } from './problemDetector' + +export interface ErrorContext { + readonly source: string + readonly severity: 'error' | 'warning' | 'info' | 'hint' + readonly location: { + readonly file: string + readonly line: number + readonly column: number + readonly range?: vscode.Range + } + readonly message: string + readonly code?: string | number + readonly relatedInformation?: vscode.DiagnosticRelatedInformation[] + readonly suggestedFixes?: vscode.CodeAction[] + readonly surroundingCode?: string +} + +export interface FormattedErrorReport { + readonly summary: string + readonly details: string + readonly contextualCode: string + readonly suggestions: string +} + +/** + * Formats diagnostic errors into contextual information for AI debugging assistance. + */ +export class ErrorContextFormatter { + /** + * Creates a problems string with Markdown formatting for better readability + */ + public formatProblemsString(problems: Problem[], cwd: string): string { + let result = '' + const fileGroups = this.groupProblemsByFile(problems) + + for (const [filePath, fileProblems] of fileGroups.entries()) { + if (fileProblems.length > 0) { + result += `\n\n**${path.relative(cwd, filePath)}**\n\n` + + // Group problems into a code block for better formatting + result += '```\n' + for (const problem of fileProblems) { + const line = problem.diagnostic.range.start.line + 1 + const source = problem.source ? `${problem.source}` : 'Unknown' + result += `[${source}] Line ${line}: ${problem.diagnostic.message}\n` + } + result += '```' + } + } + + return result.trim() + } + + private groupProblemsByFile(problems: Problem[]): Map { + const groups = new Map() + + for (const problem of problems) { + const filePath = problem.uri.fsPath + if (!groups.has(filePath)) { + groups.set(filePath, []) + } + groups.get(filePath)!.push(problem) + } + + return groups + } +} diff --git a/packages/amazonq/src/lsp/chat/autoDebug/diagnostics/problemDetector.ts b/packages/amazonq/src/lsp/chat/autoDebug/diagnostics/problemDetector.ts new file mode 100644 index 00000000000..44d00b55ca1 --- /dev/null +++ b/packages/amazonq/src/lsp/chat/autoDebug/diagnostics/problemDetector.ts @@ -0,0 +1,21 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as vscode from 'vscode' + +export interface Problem { + readonly uri: vscode.Uri + readonly diagnostic: vscode.Diagnostic + readonly severity: 'error' | 'warning' | 'info' | 'hint' + readonly source: string + readonly isNew: boolean +} + +export interface CategorizedProblems { + readonly errors: Problem[] + readonly warnings: Problem[] + readonly info: Problem[] + readonly hints: Problem[] +} diff --git a/packages/amazonq/src/lsp/chat/autoDebug/index.ts b/packages/amazonq/src/lsp/chat/autoDebug/index.ts new file mode 100644 index 00000000000..4819835066b --- /dev/null +++ b/packages/amazonq/src/lsp/chat/autoDebug/index.ts @@ -0,0 +1,18 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Auto Debug feature for Amazon Q + * + * This module provides auto debug functionality including: + * - Command registration for fixing problems with Amazon Q + * - Code actions provider for quick fixes + * - Integration with VSCode's diagnostic system + */ + +export { AutoDebugFeature, activateAutoDebug } from './activation' +export { AutoDebugCommands } from './commands' +export { AutoDebugCodeActionsProvider } from './codeActionsProvider' +export { AutoDebugController } from './controller' diff --git a/packages/amazonq/src/lsp/chat/autoDebug/lsp/autoDebugLspClient.ts b/packages/amazonq/src/lsp/chat/autoDebug/lsp/autoDebugLspClient.ts new file mode 100644 index 00000000000..2d2d0ca3664 --- /dev/null +++ b/packages/amazonq/src/lsp/chat/autoDebug/lsp/autoDebugLspClient.ts @@ -0,0 +1,75 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +import { getLogger, placeholder } from 'aws-core-vscode/shared' +import { focusAmazonQPanel } from 'aws-core-vscode/codewhispererChat' + +export class AutoDebugLspClient { + private readonly logger = getLogger() + private static chatViewProvider: any // AmazonQChatViewProvider instance + + /** + * Sets the chat view provider instance + */ + public static setChatViewProvider(provider: any): void { + AutoDebugLspClient.chatViewProvider = provider + } + + public async sendChatMessage(params: { message: string; triggerType: string; eventId: string }): Promise { + try { + // Ensure the chat view provider and webview are available + await this.ensureWebviewReady() + + // Get the webview provider from the static reference + const amazonQChatViewProvider = AutoDebugLspClient.chatViewProvider + + if (!amazonQChatViewProvider?.webview) { + this.logger.error( + 'AutoDebugLspClient: Amazon Q Chat View Provider webview not available after initialization' + ) + return false + } + + // Focus Amazon Q panel first using the imported function + await focusAmazonQPanel.execute(placeholder, 'autoDebug') + + // Wait for panel to focus + await new Promise((resolve) => setTimeout(resolve, 200)) + await amazonQChatViewProvider.webview.postMessage({ + command: 'sendToPrompt', + params: { + selection: '', + triggerType: 'autoDebug', + prompt: { + prompt: params.message, // what gets sent to the user + escapedPrompt: params.message, // what gets sent to the backend + }, + autoSubmit: true, // Automatically submit the message + }, + }) + return true + } catch (error) { + this.logger.error('AutoDebugLspClient: Error sending message via webview: %s', error) + return false + } + } + + /** + * Ensures that the chat view provider and its webview are ready for use + */ + private async ensureWebviewReady(): Promise { + if (!AutoDebugLspClient.chatViewProvider) { + await focusAmazonQPanel.execute(placeholder, 'autoDebug') + // wait 1 second for focusAmazonQPanel to finish + await new Promise((resolve) => setTimeout(resolve, 500)) + } + + // Now ensure the webview is created + if (!AutoDebugLspClient.chatViewProvider.webview) { + await focusAmazonQPanel.execute(placeholder, 'autoDebug') + // wait 1 second for webview to be created + await new Promise((resolve) => setTimeout(resolve, 500)) + } + } +} diff --git a/packages/amazonq/src/lsp/chat/autoDebug/shared/diagnosticUtils.ts b/packages/amazonq/src/lsp/chat/autoDebug/shared/diagnosticUtils.ts new file mode 100644 index 00000000000..bf466168347 --- /dev/null +++ b/packages/amazonq/src/lsp/chat/autoDebug/shared/diagnosticUtils.ts @@ -0,0 +1,35 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as vscode from 'vscode' +import { toIdeDiagnostics } from 'aws-core-vscode/codewhisperer' + +/** + * Maps VSCode DiagnosticSeverity to string representation + * Reuses the existing toIdeDiagnostics logic but returns lowercase format expected by Problem interface + */ +export function mapDiagnosticSeverity(severity: vscode.DiagnosticSeverity): 'error' | 'warning' | 'info' | 'hint' { + // Create a minimal diagnostic to use with toIdeDiagnostics + const tempDiagnostic: vscode.Diagnostic = { + range: new vscode.Range(0, 0, 0, 0), + message: '', + severity: severity, + } + + const ideDiagnostic = toIdeDiagnostics(tempDiagnostic) + // Convert uppercase severity to lowercase format expected by Problem interface + switch (ideDiagnostic.severity) { + case 'ERROR': + return 'error' + case 'WARNING': + return 'warning' + case 'INFORMATION': + return 'info' + case 'HINT': + return 'hint' + default: + return 'error' + } +}