in packages/core/src/codewhisperer/activation.ts [102:532]
export async function activate(context: ExtContext): Promise<void> {
localize = nls.loadMessageBundle()
// Import old CodeWhisperer settings into Amazon Q
await CodeWhispererSettings.instance.importSettings()
// initialize AuthUtil earlier to make sure it can listen to connection change events.
const auth = AuthUtil.instance
auth.initCodeWhispererHooks()
// TODO: is this indirection useful?
registerDeclaredCommands(
context.extensionContext.subscriptions,
CodeWhispererCommandDeclarations.instance,
new CodeWhispererCommandBackend(context.extensionContext)
)
/**
* CodeWhisperer security panel
*/
const securityPanelViewProvider = new SecurityPanelViewProvider(context.extensionContext)
context.extensionContext.subscriptions.push(
vscode.window.registerWebviewViewProvider(SecurityPanelViewProvider.viewType, securityPanelViewProvider)
)
// TODO: this is already done in packages/core/src/extensionCommon.ts, why doesn't amazonq use that?
registerCommandErrorHandler((info, error) => {
const defaultMessage = localize('AWS.generic.message.error', 'Failed to run command: {0}', info.id)
void logAndShowError(localize, error, info.id, defaultMessage)
})
// TODO: this is already done in packages/core/src/extensionCommon.ts, why doesn't amazonq use that?
registerWebviewErrorHandler((error: unknown, webviewId: string, command: string) => {
return logAndShowWebviewError(localize, error, webviewId, command)
})
/**
* Service control
*/
const client = new codewhispererClient.DefaultCodeWhispererClient()
// Service initialization
const container = Container.instance
ReferenceInlineProvider.instance
ImportAdderProvider.instance
context.extensionContext.subscriptions.push(
// register toolkit api callback
registerToolkitApiCallback.register(),
signoutCodeWhisperer.register(auth),
/**
* Configuration change
*/
vscode.workspace.onDidChangeConfiguration(async (configurationChangeEvent) => {
if (configurationChangeEvent.affectsConfiguration('editor.tabSize')) {
EditorContext.updateTabSize(getTabSizeSetting())
}
if (configurationChangeEvent.affectsConfiguration('amazonQ.showCodeWithReferences')) {
ReferenceLogViewProvider.instance.update()
if (auth.isEnterpriseSsoInUse()) {
await vscode.window
.showInformationMessage(
CodeWhispererConstants.ssoConfigAlertMessage,
CodeWhispererConstants.settingsLearnMore
)
.then(async (resp) => {
if (resp === CodeWhispererConstants.settingsLearnMore) {
void openUrl(vscode.Uri.parse(CodeWhispererConstants.learnMoreUri))
}
})
}
}
if (configurationChangeEvent.affectsConfiguration('amazonQ.shareContentWithAWS')) {
if (auth.isEnterpriseSsoInUse()) {
await vscode.window
.showInformationMessage(
CodeWhispererConstants.ssoConfigAlertMessageShareData,
CodeWhispererConstants.settingsLearnMore
)
.then(async (resp) => {
if (resp === CodeWhispererConstants.settingsLearnMore) {
void openUrl(vscode.Uri.parse(CodeWhispererConstants.learnMoreUri))
}
})
}
}
if (configurationChangeEvent.affectsConfiguration('editor.inlineSuggest.enabled')) {
await vscode.window
.showInformationMessage(
CodeWhispererConstants.reloadWindowPrompt,
CodeWhispererConstants.reloadWindow
)
.then((selected) => {
if (selected === CodeWhispererConstants.reloadWindow) {
void vscode.commands.executeCommand('workbench.action.reloadWindow')
}
})
}
if (configurationChangeEvent.affectsConfiguration('amazonQ.ignoredSecurityIssues')) {
const ignoredIssues = CodeWhispererSettings.instance.getIgnoredSecurityIssues()
toggleIssuesVisibility((issue) => !ignoredIssues.includes(issue.title))
}
}),
/**
* Open Configuration
*/
Commands.register('aws.amazonq.configure', async (id) => {
if (id === 'codewhisperer') {
await vscode.commands.executeCommand(
'workbench.action.openSettings',
`@id:amazonQ.showCodeWithReferences`
)
} else {
await openSettings('amazonQ')
}
}),
Commands.register('aws.amazonq.refreshAnnotation', async (forceProceed: boolean) => {
telemetry.record({
traceId: TelemetryHelper.instance.traceId,
})
const editor = vscode.window.activeTextEditor
if (editor) {
if (forceProceed) {
await container.lineAnnotationController.refresh(editor, 'codewhisperer', true)
} else {
await container.lineAnnotationController.refresh(editor, 'codewhisperer')
}
}
}),
// show introduction
showIntroduction.register(),
// toggle code suggestions
toggleCodeSuggestions.register(CodeSuggestionsState.instance),
// toggle code scans
toggleCodeScans.register(CodeScansState.instance),
// enable code suggestions
enableCodeSuggestions.register(context),
// project scan
showSecurityScan.register(context, securityPanelViewProvider, client),
// on demand file scan
showFileScan.register(context, securityPanelViewProvider, client),
// show security issue webview panel
openSecurityIssuePanel.register(context),
// sign in with sso or AWS ID
showSsoSignIn.register(),
// show reconnect prompt
reconnect.register(),
// learn more about CodeWhisperer
showLearnMore.register(),
// show free tier limit
showFreeTierLimit.register(),
// update reference log instance
updateReferenceLog.register(),
// refresh codewhisperer status bar
refreshStatusBar.register(),
// generate code fix
generateFix.register(client, context),
// regenerate code fix
regenerateFix.register(),
// apply suggested fix
applySecurityFix.register(),
// reject suggested fix
rejectFix.register(context.extensionContext),
// ignore issues by title
ignoreAllIssues.register(),
// ignore single issue
ignoreIssue.register(),
// explain issue
explainIssue.register(),
// quick pick with codewhisperer options
listCodeWhispererCommands.register(),
// quick pick with security issues tree filters
showSecurityIssueFilters.register(),
// quick pick code issue grouping strategy
showCodeIssueGroupingQuickPick.register(),
// reset security issue filters
clearFilters.register(),
// handle security issues tree item clicked
focusIssue.register(),
// refresh the treeview on every change
SecurityTreeViewFilterState.instance.onDidChangeState((e) => {
SecurityIssueTreeViewProvider.instance.refresh()
}),
// refresh treeview when grouping strategy changes
CodeIssueGroupingStrategyState.instance.onDidChangeState((e) => {
SecurityIssueTreeViewProvider.instance.refresh()
}),
// show a no match state
SecurityIssueTreeViewProvider.instance.onDidChangeTreeData((e) => {
const noMatches =
Array.isArray(e) &&
e.length === 0 &&
SecurityIssueProvider.instance.issues.some((group) => group.issues.some((issue) => issue.visible))
void setContext('aws.amazonq.security.noMatches', noMatches)
}),
// select customization
selectCustomizationPrompt.register(),
// notify new customizations
notifyNewCustomizationsCmd.register(),
selectRegionProfileCommand.register(),
/**
* On recommendation acceptance
*/
acceptSuggestion.register(context),
// direct CodeWhisperer connection setup with customization
connectWithCustomization.register(),
// on text document close.
vscode.workspace.onDidCloseTextDocument((e) => {
if (isInlineCompletionEnabled() && e.uri.fsPath !== InlineCompletionService.instance.filePath()) {
return
}
RecommendationHandler.instance.reportUserDecisions(-1)
}),
vscode.languages.registerHoverProvider(
[...CodeWhispererConstants.platformLanguageIds],
ReferenceHoverProvider.instance
),
vscode.window.registerWebviewViewProvider(ReferenceLogViewProvider.viewType, ReferenceLogViewProvider.instance),
showReferenceLog.register(),
showExploreAgentsView.register(),
vscode.languages.registerCodeLensProvider(
[...CodeWhispererConstants.platformLanguageIds],
ReferenceInlineProvider.instance
),
vscode.languages.registerCodeLensProvider(
[...CodeWhispererConstants.platformLanguageIds, { scheme: 'untitled' }],
ImportAdderProvider.instance
),
vscode.languages.registerHoverProvider(
[...CodeWhispererConstants.securityScanLanguageIds],
SecurityIssueHoverProvider.instance
),
vscode.languages.registerCodeActionsProvider(
[...CodeWhispererConstants.securityScanLanguageIds],
SecurityIssueCodeActionProvider.instance
),
vscode.commands.registerCommand('aws.amazonq.openEditorAtRange', openEditorAtRange),
auth.regionProfileManager.onDidChangeRegionProfile(() => {
// Validate user still has access to the selected customization.
const selectedCustomization = getSelectedCustomization()
// No need to validate base customization which has empty arn.
if (selectedCustomization.arn.length > 0) {
getAvailableCustomizationsList()
.then(async (customizations) => {
const r = customizations.find((it) => it.arn === selectedCustomization.arn)
if (!r) {
await switchToBaseCustomizationAndNotify()
}
})
.catch((e) => {
getLogger().error(
`encounter error while validating selected customization on profile change: %s`,
(e as Error).message
)
})
}
})
)
// run the auth startup code with context for telemetry
await telemetry.function_call.run(
async () => {
await auth.restore()
await auth.clearExtraConnections()
if (auth.isConnectionExpired()) {
auth.showReauthenticatePrompt().catch((e) => {
const defaulMsg = localize('AWS.generic.message.error', 'Failed to reauth:')
void logAndShowError(localize, e, 'showReauthenticatePrompt', defaulMsg)
})
if (auth.isEnterpriseSsoInUse()) {
await auth.notifySessionConfiguration()
}
}
if (auth.requireProfileSelection()) {
await notifySelectDeveloperProfile()
}
},
{ emit: false, functionId: { name: 'activateCwCore' } }
)
if (auth.isValidEnterpriseSsoInUse()) {
await notifyNewCustomizations()
}
if (auth.isBuilderIdInUse()) {
await CodeScansState.instance.setScansEnabled(false)
}
/**
* CodeWhisperer auto scans
*/
setSubscriptionsForAutoScans()
setSubscriptionsForCodeIssues()
function shouldRunAutoScan(editor: vscode.TextEditor | undefined, isScansEnabled?: boolean) {
return (
(isScansEnabled ?? CodeScansState.instance.isScansEnabled()) &&
!CodeScansState.instance.isMonthlyQuotaExceeded() &&
auth.isConnectionValid() &&
!auth.isBuilderIdInUse() &&
editor &&
editor.document.uri.scheme === 'file' &&
securityScanLanguageContext.isLanguageSupported(editor.document.languageId)
)
}
function setSubscriptionsForAutoScans() {
// Initial scan when the editor opens for the first time
const editor = vscode.window.activeTextEditor
if (editor && shouldRunAutoScan(editor) && editor.document.getText().length > 0) {
void debounceStartSecurityScan(
securityPanelViewProvider,
editor,
client,
context.extensionContext,
CodeWhispererConstants.CodeAnalysisScope.FILE_AUTO,
false
)
}
context.extensionContext.subscriptions.push(
// Trigger scan if focus switches to a different file
vscode.window.onDidChangeActiveTextEditor((editor) => {
const codewhispererDiagnostics = editor
? securityScanRender.securityDiagnosticCollection
?.get(editor.document.uri)
?.filter(({ source }) => source === CodeWhispererConstants.codewhispererDiagnosticSourceLabel)
: undefined
if (
editor &&
shouldRunAutoScan(editor) &&
editor.document.getText().length > 0 &&
(!codewhispererDiagnostics || codewhispererDiagnostics?.length === 0)
) {
void debounceStartSecurityScan(
securityPanelViewProvider,
editor,
client,
context.extensionContext,
CodeWhispererConstants.CodeAnalysisScope.FILE_AUTO,
false
)
}
}),
// Trigger scan if the file contents change
vscode.workspace.onDidChangeTextDocument(async (event) => {
const editor = vscode.window.activeTextEditor
if (
editor &&
shouldRunAutoScan(editor) &&
event.document === editor.document &&
event.contentChanges.length > 0
) {
void debounceStartSecurityScan(
securityPanelViewProvider,
editor,
client,
context.extensionContext,
CodeWhispererConstants.CodeAnalysisScope.FILE_AUTO,
false
)
}
})
)
// Trigger scan if the toggle has just been enabled
CodeScansState.instance.onDidChangeState((isScansEnabled) => {
const editor = vscode.window.activeTextEditor
if (editor && shouldRunAutoScan(editor, isScansEnabled) && editor.document.getText().length > 0) {
void debounceStartSecurityScan(
securityPanelViewProvider,
editor,
client,
context.extensionContext,
CodeWhispererConstants.CodeAnalysisScope.FILE_AUTO,
false
)
}
})
}
void FeatureConfigProvider.instance.fetchFeatureConfigs().catch((error) => {
getLogger().error('Failed to fetch feature configs - %s', error)
})
await Commands.tryExecute('aws.amazonq.refreshConnectionCallback')
container.ready()
function setSubscriptionsForCodeIssues() {
context.extensionContext.subscriptions.push(
vscode.workspace.onDidChangeTextDocument(async (e) => {
if (e.document.uri.scheme !== 'file') {
return
}
const diagnostics = securityScanRender.securityDiagnosticCollection?.get(e.document.uri)
if (!diagnostics || diagnostics.length === 0) {
return
}
disposeSecurityDiagnostic(e)
SecurityIssueProvider.instance.handleDocumentChange(e)
SecurityIssueTreeViewProvider.instance.refresh()
await syncSecurityIssueWebview(context)
toggleIssuesVisibility((issue, filePath) =>
filePath !== e.document.uri.fsPath
? issue.visible
: !detectCommentAboveLine(
e.document,
issue.startLine,
CodeWhispererConstants.amazonqIgnoreNextLine
)
)
}),
vscode.window.createTreeView(SecurityIssueTreeViewProvider.viewType, {
treeDataProvider: SecurityIssueTreeViewProvider.instance,
})
)
}
}