Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "Bug Fix",
"description": "Amazon Q: In browser-only VS Code (vscode.dev, github.dev), a clear message now guides you to desktop VS Code or a remote environment where Amazon Q is fully supported."
}
10 changes: 8 additions & 2 deletions packages/amazonq/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,11 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is
// This contains every lsp agnostic things (auth, security scan, code scan)
await activateCodeWhisperer(extContext as ExtContext)

if (!isAmazonLinux2() || hasGlibcPatch()) {
if (isWeb) {
// The language server runs as a child process, which the browser-only extension host cannot spawn.
// Skip it instead of surfacing a confusing "Failed to launch Amazon Q language server" error.
getLogger('amazonqLsp').info('skipping language server activation: not supported in the web extension host')
} else if (!isAmazonLinux2() || hasGlibcPatch()) {
// Activate Amazon Q LSP for everyone unless they're using AL2 without the glibc patch
await activateAmazonqLsp(context)
}
Expand Down Expand Up @@ -169,7 +173,9 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is
// reload webviews
await vscode.commands.executeCommand('workbench.action.webview.reloadWebviewAction')

if (AuthUtils.ExtensionUse.instance.isFirstUse()) {
// The chat panel is not available in the web extension host (see `!aws.isWebExtHost` in package.json),
// so there is nothing to focus there.
if (!isWeb && AuthUtils.ExtensionUse.instance.isFirstUse()) {
// Give time for the extension to finish initializing.
globals.clock.setTimeout(async () => {
CommonAuthWebview.authSource = ExtStartUpSources.firstStartUp
Expand Down
5 changes: 5 additions & 0 deletions packages/amazonq/src/extensionWeb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@

import type { ExtensionContext } from 'vscode'
import { activateWebShared } from 'aws-core-vscode/webShared'
import { showWebModeUnsupportedMessageOnce } from 'aws-core-vscode/amazonq'
import { activateAmazonQCommon, deactivateCommon } from './extension'

export async function activate(context: ExtensionContext) {
await activateWebShared(context)
await activateAmazonQCommon(context, true)
// Amazon Q needs a Node.js extension host (desktop VS Code, or a browser editor connected to a
// remote environment). In the browser-only extension host the language server cannot start, so
// tell the user up front instead of letting them click "Sign in" and see nothing happen.
showWebModeUnsupportedMessageOnce()
}

export async function deactivate() {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/amazonq/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export { MessagePublisher } from './messages/messagePublisher'
export { MessageListener } from './messages/messageListener'
export { AuthController } from './auth/controller'
export { showAmazonQWalkthroughOnce } from './onboardingPage/walkthrough'
export { showWebModeUnsupportedMessage, showWebModeUnsupportedMessageOnce, webModeUnsupportedMessage } from './webMode'
export {
focusAmazonQChatWalkthrough,
openAmazonQWalkthrough,
Expand Down
34 changes: 34 additions & 0 deletions packages/core/src/amazonq/webMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

import { showMessage } from '../shared/utilities/messages'
import { once } from '../shared/utilities/functionUtils'

/**
* Amazon Q depends on the Amazon Q language server, which runs as a Node.js child process.
* The browser-only VS Code extension host (for example vscode.dev or github.dev opened without
* a remote/backend environment) cannot spawn processes, so Amazon Q features cannot work there.
*
* Users end up with an extension that appears installed but does nothing when they click "Sign in".
* This message tells them why, and what to do instead.
*/
export const webModeUnsupportedMessage =
'Amazon Q is not available in the browser-only version of VS Code (for example vscode.dev or github.dev without a remote environment). ' +
'Use VS Code on your desktop, or connect the browser editor to a remote environment such as a codespace or a remote host, to use Amazon Q.'

/**
* Shows a non-modal notification explaining that Amazon Q does not work in the browser-only extension host.
*/
export function showWebModeUnsupportedMessage(): Thenable<string | undefined> {
return showMessage('info', webModeUnsupportedMessage, [], {}, { id: 'amazonqWebModeUnsupported' })
}

/**
* Same as {@link showWebModeUnsupportedMessage}, but only shows the notification once per session.
* Intended for extension activation so the notification is not repeated.
*/
export const showWebModeUnsupportedMessageOnce = once(() => {
void showWebModeUnsupportedMessage()
})
6 changes: 4 additions & 2 deletions packages/core/src/codewhisperer/ui/codeWhispererNodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { submitFeedback } from '../../feedback/vue/submitFeedback'
import { focusAmazonQPanel } from '../../codewhispererChat/commands/registerCommands'
import { isWeb } from '../../shared/extensionGlobals'
import { getLogger } from '../../shared/logger/logger'
import { showWebModeUnsupportedMessage } from '../../amazonq/webMode'

export function createAutoSuggestions(running: boolean): DataQuickPickItem<'autoSuggestions'> {
const labelResume = localize('AWS.codewhisperer.resumeCodeWhispererNode.label', 'Resume Auto-Suggestions')
Expand Down Expand Up @@ -249,9 +250,10 @@ export function createSignIn(): DataQuickPickItem<'signIn'> {
})
}
if (isWeb()) {
// TODO: nkomonen, call a Command instead
// Amazon Q cannot run in the browser-only extension host (no language server), so signing in
// would not lead anywhere. Explain why instead of starting an auth flow that appears to do nothing.
onClick = () => {
void AuthUtil.instance.connectToAwsBuilderId()
void showWebModeUnsupportedMessage()
}
}

Expand Down
56 changes: 56 additions & 0 deletions packages/core/src/test/amazonq/webMode.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*!
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

import assert from 'assert'
import sinon from 'sinon'
import globals from '../../shared/extensionGlobals'
import { showWebModeUnsupportedMessage, webModeUnsupportedMessage } from '../../amazonq/webMode'
import { createSignIn } from '../../codewhisperer/ui/codeWhispererNodes'
import { getTestWindow } from '../shared/vscode/window'

/** `waitForMessage` treats strings as regex patterns, so match on a prefix without special characters. */
const webModeMessagePattern = /^Amazon Q is not available in the browser-only version of VS Code/

describe('amazonq webMode', function () {
let sandbox: sinon.SinonSandbox

beforeEach(function () {
sandbox = sinon.createSandbox()
})

afterEach(function () {
sandbox.restore()
})

describe('showWebModeUnsupportedMessage', function () {
it('shows an informational notification', async function () {
const shown = getTestWindow().waitForMessage(webModeMessagePattern)
void showWebModeUnsupportedMessage()
const message = await shown
message.assertInfo(webModeUnsupportedMessage)
})
})

describe('createSignIn', function () {
it('explains that Amazon Q is unavailable when running in the web extension host', async function () {
sandbox.stub(globals, 'isWeb').value(true)

const shown = getTestWindow().waitForMessage(webModeMessagePattern)
createSignIn().onClick?.()
const message = await shown
message.assertInfo(webModeUnsupportedMessage)
})

it('does not show the web notice outside of the web extension host', function () {
sandbox.stub(globals, 'isWeb').value(false)

createSignIn().onClick?.()
assert.strictEqual(
getTestWindow().shownMessages.some((m) => m.message === webModeUnsupportedMessage),
false
)
})
})
})
Loading