diff --git a/packages/amazonq/src/app/amazonqScan/app.ts b/packages/amazonq/src/app/amazonqScan/app.ts index 21857163bd2..2b237ab534e 100644 --- a/packages/amazonq/src/app/amazonqScan/app.ts +++ b/packages/amazonq/src/app/amazonqScan/app.ts @@ -19,6 +19,7 @@ import { Messenger } from './chat/controller/messenger/messenger' import { UIMessageListener } from './chat/views/actions/uiMessageListener' import { debounce } from 'lodash' import { Commands, placeholder } from 'aws-core-vscode/shared' +import { codeReviewInChat } from './models/constants' export function init(appContext: AmazonQAppInitContext) { const scanChatControllerEventEmitters: ScanChatControllerEventEmitters = { @@ -74,17 +75,19 @@ export function init(appContext: AmazonQAppInitContext) { return debouncedEvent() }) - Commands.register('aws.amazonq.security.scan-statusbar', async () => { - if (AuthUtil.instance.isConnectionExpired()) { - await AuthUtil.instance.notifyReauthenticate() - } - return focusAmazonQPanel.execute(placeholder, 'amazonq.security.scan').then(() => { - DefaultAmazonQAppInitContext.instance.getAppsToWebViewMessagePublisher().publish({ - sender: 'amazonqCore', - command: 'review', + if (!codeReviewInChat) { + Commands.register('aws.amazonq.security.scan-statusbar', async () => { + if (AuthUtil.instance.isConnectionExpired()) { + await AuthUtil.instance.notifyReauthenticate() + } + return focusAmazonQPanel.execute(placeholder, 'amazonq.security.scan').then(() => { + DefaultAmazonQAppInitContext.instance.getAppsToWebViewMessagePublisher().publish({ + sender: 'amazonqCore', + command: 'review', + }) }) }) - }) + } codeScanState.setChatControllers(scanChatControllerEventEmitters) onDemandFileScanState.setChatControllers(scanChatControllerEventEmitters) diff --git a/packages/amazonq/src/app/amazonqScan/models/constants.ts b/packages/amazonq/src/app/amazonqScan/models/constants.ts index 93e815884e1..4180b130b78 100644 --- a/packages/amazonq/src/app/amazonqScan/models/constants.ts +++ b/packages/amazonq/src/app/amazonqScan/models/constants.ts @@ -97,3 +97,5 @@ const getIconForStep = (targetStep: number, currentStep: number) => { ? checkIcons.done : checkIcons.wait } + +export const codeReviewInChat = true diff --git a/packages/amazonq/src/lsp/chat/commands.ts b/packages/amazonq/src/lsp/chat/commands.ts index 83e70b7bae3..fca3a132f90 100644 --- a/packages/amazonq/src/lsp/chat/commands.ts +++ b/packages/amazonq/src/lsp/chat/commands.ts @@ -6,10 +6,12 @@ import { Commands, globals } from 'aws-core-vscode/shared' import { window } from 'vscode' import { AmazonQChatViewProvider } from './webviewProvider' -import { CodeScanIssue } from 'aws-core-vscode/codewhisperer' +import { CodeScanIssue, AuthUtil } from 'aws-core-vscode/codewhisperer' import { getLogger } from 'aws-core-vscode/shared' import * as vscode from 'vscode' import * as path from 'path' +import { codeReviewInChat } from '../../app/amazonqScan/models/constants' +import { telemetry, AmazonqCodeReviewTool } from 'aws-core-vscode/telemetry' /** * TODO: Re-enable these once we can figure out which path they're going to live in @@ -29,7 +31,8 @@ export function registerCommands(provider: AmazonQChatViewProvider) { filePath, 'Explain', 'Provide a small description of the issue. You must not attempt to fix the issue. You should only give a small summary of it to the user.', - provider + provider, + 'explainIssue' ) ), Commands.register('aws.amazonq.generateFix', (issue: CodeScanIssue, filePath: string) => @@ -38,7 +41,8 @@ export function registerCommands(provider: AmazonQChatViewProvider) { filePath, 'Fix', 'Generate a fix for the following code issue. You must not explain the issue, just generate and explain the fix. The user should have the option to accept or reject the fix before any code is changed.', - provider + provider, + 'applyFix' ) ), Commands.register('aws.amazonq.sendToPrompt', (data) => { @@ -64,6 +68,11 @@ export function registerCommands(provider: AmazonQChatViewProvider) { registerShellCommandShortCut('aws.amazonq.rejectCmdExecution', 'reject-shell-command', provider), registerShellCommandShortCut('aws.amazonq.stopCmdExecution', 'stop-shell-command', provider) ) + if (codeReviewInChat) { + globals.context.subscriptions.push( + registerGenericCommand('aws.amazonq.security.scan-statusbar', 'Review', provider) + ) + } } async function handleIssueCommand( @@ -71,7 +80,8 @@ async function handleIssueCommand( filePath: string, action: string, contextPrompt: string, - provider: AmazonQChatViewProvider + provider: AmazonQChatViewProvider, + metricName: string ) { await focusAmazonQPanel() @@ -95,6 +105,16 @@ async function handleIssueCommand( autoSubmit: true, }, }) + + telemetry.amazonq_codeReviewTool.emit({ + findingId: issue.findingId, + detectorId: issue.detectorId, + ruleId: issue.ruleId, + credentialStartUrl: AuthUtil.instance.startUrl, + autoDetected: issue.autoDetected, + result: 'Succeeded', + reason: metricName, + } as AmazonqCodeReviewTool) } async function openFileWithSelection(issue: CodeScanIssue, filePath: string) { diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index d335dae40ef..7f265946af9 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -51,6 +51,7 @@ import { SessionManager } from '../app/inline/sessionManager' import { LineTracker } from '../app/inline/stateTracker/lineTracker' import { InlineTutorialAnnotation } from '../app/inline/tutorials/inlineTutorialAnnotation' import { InlineChatTutorialAnnotation } from '../app/inline/tutorials/inlineChatTutorialAnnotation' +import { codeReviewInChat } from '../app/amazonqScan/models/constants' const localize = nls.loadMessageBundle() const logger = getLogger('amazonqLsp.lspClient') @@ -179,7 +180,7 @@ export async function startLanguageServer( reroute: true, modelSelection: true, workspaceFilePath: vscode.workspace.workspaceFile?.fsPath, - codeReviewInChat: false, + codeReviewInChat: codeReviewInChat, }, window: { notifications: true,