diff --git a/packages/amazonq/.changes/next-release/Feature-57661731-6180-4157-a04b-d3a8b50aa1a8.json b/packages/amazonq/.changes/next-release/Feature-57661731-6180-4157-a04b-d3a8b50aa1a8.json new file mode 100644 index 00000000000..c2e164f773f --- /dev/null +++ b/packages/amazonq/.changes/next-release/Feature-57661731-6180-4157-a04b-d3a8b50aa1a8.json @@ -0,0 +1,4 @@ +{ + "type": "Feature", + "description": "Add MCP Server Support" +} diff --git a/packages/amazonq/package.json b/packages/amazonq/package.json index 09c26af6b06..c7557807a6d 100644 --- a/packages/amazonq/package.json +++ b/packages/amazonq/package.json @@ -387,16 +387,21 @@ "when": "view == aws.amazonq.AmazonQChatView", "group": "0_topAmazonQ@1" }, - { - "command": "aws.amazonq.learnMore", - "when": "view =~ /^aws\\.amazonq/", - "group": "1_amazonQ@1" - }, { "command": "aws.amazonq.selectRegionProfile", "when": "view == aws.amazonq.AmazonQChatView && aws.amazonq.connectedSsoIdc == true", "group": "1_amazonQ@1" }, + { + "command": "aws.amazonq.manageSubscription", + "when": "(view == aws.amazonq.AmazonQChatView) && aws.codewhisperer.connected", + "group": "1_amazonQ@2" + }, + { + "command": "aws.amazonq.learnMore", + "when": "view =~ /^aws\\.amazonq/", + "group": "1_amazonQ@3" + }, { "command": "aws.amazonq.signout", "when": "(view == aws.amazonq.AmazonQChatView) && aws.codewhisperer.connected && !aws.isSageMakerUnifiedStudio", @@ -678,6 +683,13 @@ "category": "%AWS.amazonq.title%", "icon": "$(question)" }, + { + "command": "aws.amazonq.manageSubscription", + "title": "%AWS.command.manageSubscription%", + "category": "%AWS.amazonq.title%", + "icon": "$(gear)", + "enablement": "aws.codewhisperer.connected && !aws.amazonq.connectedSsoIdc" + }, { "command": "aws.amazonq.signout", "title": "%AWS.command.codewhisperer.signout%", diff --git a/packages/amazonq/src/lsp/chat/activation.ts b/packages/amazonq/src/lsp/chat/activation.ts index f6277068734..2ef8810ca60 100644 --- a/packages/amazonq/src/lsp/chat/activation.ts +++ b/packages/amazonq/src/lsp/chat/activation.ts @@ -6,7 +6,7 @@ import { window } from 'vscode' import { LanguageClient } from 'vscode-languageclient' import { AmazonQChatViewProvider } from './webviewProvider' -import { registerCommands } from './commands' +import { focusAmazonQPanel, registerCommands } from './commands' import { registerLanguageServerEventListener, registerMessageListeners } from './messages' import { Commands, getLogger, globals, undefinedIfEmpty } from 'aws-core-vscode/shared' import { activate as registerLegacyChatListeners } from '../../app/chat/activation' @@ -78,6 +78,18 @@ export async function activate(languageClient: LanguageClient, encryptionKey: Bu Commands.register('aws.amazonq.updateCustomizations', () => { pushCustomizationToServer(languageClient) }), + Commands.register('aws.amazonq.manageSubscription', () => { + focusAmazonQPanel().catch((e) => languageClient.error(`[VSCode Client] focusAmazonQPanel() failed`)) + + languageClient + .sendRequest('workspace/executeCommand', { + command: 'aws/chat/manageSubscription', + // arguments: [], + }) + .catch((e) => { + getLogger('amazonqLsp').error('failed request: aws/chat/manageSubscription: %O', e) + }) + }), globals.logOutputChannel.onDidChangeLogLevel((logLevel) => { getLogger('amazonqLsp').info(`Local log level changed to ${logLevel}, notifying LSP`) void pushConfigUpdate(languageClient, { diff --git a/packages/amazonq/src/lsp/chat/commands.ts b/packages/amazonq/src/lsp/chat/commands.ts index 74c63592a4f..115118a4ad2 100644 --- a/packages/amazonq/src/lsp/chat/commands.ts +++ b/packages/amazonq/src/lsp/chat/commands.ts @@ -125,7 +125,7 @@ function registerGenericCommand(commandName: string, genericCommand: string, pro * * Instead, we just create our own as a temporary solution */ -async function focusAmazonQPanel() { +export async function focusAmazonQPanel() { await Commands.tryExecute('aws.amazonq.AmazonQChatView.focus') await Commands.tryExecute('aws.amazonq.AmazonCommonAuth.focus') } diff --git a/packages/amazonq/src/lsp/chat/messages.ts b/packages/amazonq/src/lsp/chat/messages.ts index ac3f1836521..c55086fd3fc 100644 --- a/packages/amazonq/src/lsp/chat/messages.ts +++ b/packages/amazonq/src/lsp/chat/messages.ts @@ -316,7 +316,7 @@ export function registerMessageListeners( ) if (!buttonResult.success) { languageClient.error( - `[VSCode Client] Failed to execute action associated with button with reason: ${buttonResult.failureReason}` + `[VSCode Client] Failed to execute button action: ${buttonResult.failureReason}` ) } break diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index 2460af9260c..4395ade9a2c 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -150,6 +150,7 @@ export async function startLanguageServer( awsClientCapabilities: { q: { developerProfiles: true, + mcp: true, }, window: { notifications: true, diff --git a/packages/core/package.nls.json b/packages/core/package.nls.json index 609eeb5cd08..aa1ac167917 100644 --- a/packages/core/package.nls.json +++ b/packages/core/package.nls.json @@ -137,6 +137,7 @@ "AWS.command.codecatalyst.login": "Connect to CodeCatalyst", "AWS.command.codecatalyst.logout": "Sign out of CodeCatalyst", "AWS.command.codecatalyst.signout": "Sign Out", + "AWS.command.manageSubscription": "Manage Q Developer Pro Subscription", "AWS.command.amazonq.explainCode": "Explain", "AWS.command.amazonq.refactorCode": "Refactor", "AWS.command.amazonq.fixCode": "Fix", diff --git a/packages/core/src/auth/index.ts b/packages/core/src/auth/index.ts index 87a6877844e..2dd361f9804 100644 --- a/packages/core/src/auth/index.ts +++ b/packages/core/src/auth/index.ts @@ -28,3 +28,5 @@ export * as cache from './sso/cache' export * as authUtils from './utils' export * as auth2 from './auth2' export * as SsoAccessTokenProvider from './sso/ssoAccessTokenProvider' +export * as AuthUtils from './utils' +export * as credentialsValidation from './credentials/validation' diff --git a/packages/core/src/codewhisperer/ui/codeWhispererNodes.ts b/packages/core/src/codewhisperer/ui/codeWhispererNodes.ts index 0e3090538fb..1d7d6278d79 100644 --- a/packages/core/src/codewhisperer/ui/codeWhispererNodes.ts +++ b/packages/core/src/codewhisperer/ui/codeWhispererNodes.ts @@ -177,6 +177,18 @@ export function createGettingStarted(): DataQuickPickItem<'gettingStarted'> { } as DataQuickPickItem<'gettingStarted'> } +export function createManageSubscription(): DataQuickPickItem<'manageSubscription'> { + const label = localize('AWS.command.manageSubscription', 'Manage Q Developer Pro Subscription') + // const kind = AuthUtil.instance.isBuilderIdInUse() ? 'AWS Builder ID' : 'IAM Identity Center' + + return { + data: 'manageSubscription', + label: label, + iconPath: getIcon('vscode-link-external'), + onClick: () => Commands.tryExecute('aws.amazonq.manageSubscription'), + } as DataQuickPickItem<'manageSubscription'> +} + export function createSignout(): DataQuickPickItem<'signout'> { const label = localize('AWS.codewhisperer.signoutNode.label', 'Sign Out') const icon = getIcon('vscode-export') diff --git a/packages/core/src/codewhisperer/ui/statusBarMenu.ts b/packages/core/src/codewhisperer/ui/statusBarMenu.ts index d8c05270073..f9c4b70e960 100644 --- a/packages/core/src/codewhisperer/ui/statusBarMenu.ts +++ b/packages/core/src/codewhisperer/ui/statusBarMenu.ts @@ -11,6 +11,7 @@ import { createSelectCustomization, createReconnect, createGettingStarted, + createManageSubscription, createSignout, createSeparator, createSettingsNode, @@ -106,7 +107,7 @@ export function getQuickPickItems(): DataQuickPickItem[] { createSettingsNode(), ...(AuthUtil.instance.isIdcConnection() && regionProfile ? [createSelectRegionProfileNode(regionProfile)] : []), ...(AuthUtil.instance.isConnected() && !hasVendedIamCredentials() && !hasVendedCredentialsFromMetadata() - ? [createSignout()] + ? [createManageSubscription(), createSignout()] : []), ] diff --git a/packages/core/src/login/webview/vue/login.vue b/packages/core/src/login/webview/vue/login.vue index ddcd1d91c28..312aa18029b 100644 --- a/packages/core/src/login/webview/vue/login.vue +++ b/packages/core/src/login/webview/vue/login.vue @@ -108,8 +108,8 @@ @toggle="toggleItemSelection" :isSelected="selectedLoginOption === LoginOption.BUILDER_ID" :itemId="LoginOption.BUILDER_ID" - :itemText="'with Builder ID, a personal profile from AWS'" - :itemTitle="'Use for Free'" + :itemText="'Free to start with a Builder ID.'" + :itemTitle="'Personal account'" :itemType="LoginOption.BUILDER_ID" class="selectable-item bottomMargin" > @@ -118,8 +118,8 @@ @toggle="toggleItemSelection" :isSelected="selectedLoginOption === LoginOption.ENTERPRISE_SSO" :itemId="LoginOption.ENTERPRISE_SSO" - :itemText="''" - :itemTitle="'Use with Pro license'" + :itemText="'Best for individual teams or organizations.'" + :itemTitle="'Company account'" :itemType="LoginOption.ENTERPRISE_SSO" class="selectable-item bottomMargin" > diff --git a/packages/core/src/test/codewhisperer/commands/basicCommands.test.ts b/packages/core/src/test/codewhisperer/commands/basicCommands.test.ts index 7fb7107af47..4d18401a242 100644 --- a/packages/core/src/test/codewhisperer/commands/basicCommands.test.ts +++ b/packages/core/src/test/codewhisperer/commands/basicCommands.test.ts @@ -42,6 +42,7 @@ import { createGettingStarted, createGitHubNode, createLearnMore, + createManageSubscription, createOpenReferenceLog, createReconnect, createSecurityScan, @@ -445,7 +446,13 @@ describe('CodeWhisperer-basicCommands', function () { sinon.stub(AuthUtil.instance, 'isConnected').returns(true) getTestWindow().onDidShowQuickPick((e) => { - e.assertContainsItems(createReconnect(), createLearnMore(), ...genericItems(), createSignout()) + e.assertContainsItems( + createReconnect(), + createLearnMore(), + ...genericItems(), + createManageSubscription(), + createSignout() + ) e.dispose() // skip needing to select an item to continue }) @@ -465,6 +472,7 @@ describe('CodeWhisperer-basicCommands', function () { switchToAmazonQNode(), ...genericItems(), createSettingsNode(), + createManageSubscription(), createSignout() ) e.dispose() // skip needing to select an item to continue @@ -490,6 +498,7 @@ describe('CodeWhisperer-basicCommands', function () { switchToAmazonQNode(), ...genericItems(), createSettingsNode(), + createManageSubscription(), createSignout() ) e.dispose() // skip needing to select an item to continue @@ -516,6 +525,7 @@ describe('CodeWhisperer-basicCommands', function () { ...genericItems(), createSeparator(), createSettingsNode(), + createManageSubscription(), createSignout(), ]) e.dispose() // skip needing to select an item to continue @@ -538,6 +548,7 @@ describe('CodeWhisperer-basicCommands', function () { switchToAmazonQNode(), ...genericItems(), createSettingsNode(), + createManageSubscription(), createSignout() ) e.dispose()