Skip to content

Commit 99ec961

Browse files
committed
Merge remote-tracking branch 'upstream/master' into chat-custom
2 parents 2e15dac + cc8686f commit 99ec961

File tree

74 files changed

+1195
-1015
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+1195
-1015
lines changed

.github/workflows/node.js.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ jobs:
2121
env:
2222
VSCODE_TEST_VERSION: ${{ matrix.vscode-version }}
2323
NODE_OPTIONS: '--max-old-space-size=8192'
24+
AWS_TOOLKIT_TEST_CACHE_DIR: '/tmp/.vscode-test/'
25+
AWS_TOOLKIT_TEST_USER_DIR: '/tmp/.vscode-test/user-data/'
2426
steps:
2527
- uses: actions/checkout@v4
2628
- name: Use Node.js ${{ matrix.node-version }}
@@ -88,6 +90,8 @@ jobs:
8890
env:
8991
VSCODE_TEST_VERSION: ${{ matrix.vscode-version }}
9092
NODE_OPTIONS: '--max-old-space-size=8192'
93+
AWS_TOOLKIT_TEST_CACHE_DIR: '/tmp/.vscode-test/'
94+
AWS_TOOLKIT_TEST_USER_DIR: '/tmp/.vscode-test/user-data/'
9195
steps:
9296
- uses: actions/checkout@v4
9397
- name: Use Node.js ${{ matrix.node-version }}

docs/arch_develop.md

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -71,39 +71,35 @@ Some components of the core library depend on the `package.json`s of the extensi
7171
- Does not restore, it is a superset of what exists in `packages/core` for `configuration.properties`.
7272
- To develop for the Amazon Q extension: add all changes to `packages/amazonq/package.json`, EXCEPT for settings that are references by code in the core library, or settings that already exist in the core `package.json`
7373

74-
## Shared vs Common names
74+
## `web`, `node`, `common`, `shared` naming conventions
7575

76-
In this repo, the keywords **"shared"** and **"common"** have specific meanings in the context of file/folder names.
76+
This project can run in different environments, eg Web mode (in the browser with no compute backend), or in Node.js on your desktop (the most common way).
77+
A problem arises when we use code that is exclusive to one environment, an example being Node.js' Filesystem module which will fail in Web mode.
7778

78-
### "common"
79+
To ensure developers use compatible code for their environment we have subfolders in each topic which contains environment specific code in a single place.
7980

80-
Code within a folder/file that has the "common" keyword implies that it can run in any environment. Examples of environments are: Web mode, or Node.js (local desktop)
81+
Using this file tree as reference, here are the rules:
8182

82-
We need this distinction since not all code can run in any environment. A common example is filesystem code, where the actual implementation used could work in Node.js but not in Web mode.
83-
84-
### "shared"
85-
86-
Code within a folder/file that has the "shared" keyword implies that it is intended to be reused wherever it can be. This is generalized code that "Feature A" or "Feature B" could use if it works for their use case.
87-
88-
An example is the `waitUntil()` function which continuously invokes an arbitrary callback function until it succeeds.
89-
90-
> NOTE: Something that is "shared" does not mean it is "common", as it could be reused in different places but only work in Node.js for example.
83+
```
84+
src/
85+
├── myTopic/
86+
│ ├── {file}.ts
87+
│ ├── node/
88+
│ │ └── {file}.ts
89+
│ └── web/
90+
│ └── {file}.ts
91+
└── shared/
92+
```
9193

92-
### How to apply this
94+
- `myTopic/` is the general name of the folder, eg `request` for http requests.
95+
- `myTopic/{file}.ts` is for code that works in any environment, we refer to this as `"common"` code.
96+
- `node/{file}.ts` is for code that works exclusively in Node.js.
97+
- `web/{file}.ts` is for code that works exclusively in Web mode.
98+
- `shared/` is for code that is intended to be reused, i.e general purpose utils.
99+
- Note environment specific code should be place in to a `web/` or `node/` subfolder.
100+
- If the code is not in a subfolder then it is considered `shared common` code.
93101

94-
- Aim to make code compatible with "common" from the beginning.
95-
- In a "topic" folder, if you have common code, create a subfolder named "common" and add your common code to there.
96-
```
97-
src/
98-
|
99-
myTopic/
100-
|
101-
common/
102-
nonCommon.ts
103-
```
104-
- See if yours, or existing code can be moved in to a "shared" folder. Maybe it can be easily modified to become "shared".
105-
- If there is no "shared" or "common" naming used for the file/folder, then assume it only works in Node.js.
106-
- In the rare case your code only works in Web mode, create a `web` subfolder for that code.
102+
> IMPORTANT: The current codebase does not fully follow this convention yet, the transition is being done incrementally. Due to this, code that is `"common"` may not actually be common yet. If you run in to this, please move that code to the appropriate subfolder.
107103
108104
## Commands
109105

@@ -292,22 +288,22 @@ Commands and events are defined on the backend via sub-classes of `VueWebview`.
292288
```ts
293289
client
294290
.foo()
295-
.then(response => console.log(response))
296-
.catch(err => console.log(err))
291+
.then((response) => console.log(response))
292+
.catch((err) => console.log(err))
297293
```
298294

299295
The backend protocol is allowed to throw errors. These result in rejected Promises on the frontend.
300296

301297
- Registering for events:
302298

303299
```ts
304-
client.onBar(num => console.log(num))
300+
client.onBar((num) => console.log(num))
305301
```
306302

307303
- Methods called `init` will only return data on the initial webview load:
308304

309305
```ts
310-
client.init(data => (this.data = data ?? this.data))
306+
client.init((data) => (this.data = data ?? this.data))
311307
```
312308

313309
## Webviews (non Vue)
@@ -493,8 +489,8 @@ class ExampleWizard extends Wizard<ExampleState> {
493489
{ label: '1', data: 1 },
494490
{ label: '2', data: 2 },
495491
]
496-
this.form.bar.bindPrompter(state => createQuickPick(items, { title: `Select a number (${state.foo})` }), {
497-
showWhen: state => state.foo?.length > 5,
492+
this.form.bar.bindPrompter((state) => createQuickPick(items, { title: `Select a number (${state.foo})` }), {
493+
showWhen: (state) => state.foo?.length > 5,
498494
})
499495
}
500496
}

docs/web.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ VS Code window, in the background it is running in a Browser context.
8585

8686
## Adding Web mode specific npm modules
8787

88-
If you need to manage npm modules required for Web mode, such as a [browserfied module](https://www.npmjs.com/package/os-browserify), see [the documentation here](../packages/core/src/web/README.md).
88+
If you need to manage npm modules required for Web mode, such as a [browserfied module](https://www.npmjs.com/package/os-browserify), see [the documentation here](../packages/core/src/web/README.md#packagejson).
8989

9090
## Finding incompatible transitive dependencies
9191

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "Amazon Q Dev and Transform introduction text formatted incorrectly"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "Amazon Q /dev: update error message for code gen timeout and include backfill for error name"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "Sign-in page may fail to render in rare circumstances."
4+
}

packages/amazonq/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"onCommand:aws.amazonq.accept",
4343
"onView:aws.codeWhisperer.securityPanel"
4444
],
45-
"main": "./dist/src/extension",
45+
"main": "./dist/src/extensionNode",
4646
"browser": "./dist/src/extensionWeb",
4747
"scripts": {
4848
"vscode:prepublish": "npm run clean && npm run buildScripts && webpack --mode production",

packages/amazonq/src/extension.ts

Lines changed: 143 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -3,90 +3,160 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6+
import { AuthUtils, CredentialsStore, LoginManager, SsoConnection, initializeAuth } from 'aws-core-vscode/auth'
7+
import {
8+
AuthUtil,
9+
activate as activateCodeWhisperer,
10+
shutdown as shutdownCodeWhisperer,
11+
} from 'aws-core-vscode/codewhisperer'
12+
import { makeEndpointsProvider, registerGenericCommands } from 'aws-core-vscode'
13+
import { CommonAuthWebview } from 'aws-core-vscode/login'
14+
import {
15+
DefaultAWSClientBuilder,
16+
DefaultAwsContext,
17+
ExtContext,
18+
RegionProvider,
19+
Settings,
20+
activateLogger,
21+
activateTelemetry,
22+
env,
23+
errors,
24+
fs,
25+
getLogger,
26+
getMachineId,
27+
globals,
28+
initialize,
29+
initializeComputeRegion,
30+
messages,
31+
placeholder,
32+
setContext,
33+
} from 'aws-core-vscode/shared'
34+
import { ExtStartUpSources, telemetry } from 'aws-core-vscode/telemetry'
35+
import { VSCODE_EXTENSION_ID } from 'aws-core-vscode/utils'
36+
import { join } from 'path'
37+
import * as semver from 'semver'
638
import * as vscode from 'vscode'
7-
import { activateAmazonQCommon, amazonQContextPrefix, deactivateCommon } from './extensionCommon'
8-
import { DefaultAmazonQAppInitContext } from 'aws-core-vscode/amazonq'
9-
import { activate as activateQGumby } from 'aws-core-vscode/amazonqGumby'
10-
import { ExtContext } from 'aws-core-vscode/shared'
11-
import { updateDevMode } from 'aws-core-vscode/dev'
12-
import { CommonAuthViewProvider } from 'aws-core-vscode/login'
13-
import { isExtensionActive, VSCODE_EXTENSION_ID } from 'aws-core-vscode/utils'
14-
import { registerSubmitFeedback } from 'aws-core-vscode/feedback'
15-
import { DevOptions } from 'aws-core-vscode/dev'
16-
import { Auth } from 'aws-core-vscode/auth'
17-
import api from './api'
18-
import { activate as activateCWChat } from './app/chat/activation'
19-
20-
export async function activate(context: vscode.ExtensionContext) {
21-
// IMPORTANT: No other code should be added to this function. Place it in one of the following 2 functions where appropriate.
22-
await activateAmazonQCommon(context, false)
23-
await activateAmazonQNonCommon(context)
24-
25-
return api
26-
}
39+
import { registerCommands } from './commands'
40+
import { focusAmazonQPanel } from 'aws-core-vscode/codewhispererChat'
41+
42+
export const amazonQContextPrefix = 'amazonq'
2743

2844
/**
29-
* The code in this function is not common, implying it only works in Node.js and not web.
30-
* The goal should be for this to not exist and that all code is "common". So if possible make
31-
* the code compatible with web and move it to {@link activateAmazonQCommon}.
45+
* Activation code for Amazon Q that will we want in all environments (eg Node.js, web mode)
3246
*/
33-
async function activateAmazonQNonCommon(context: vscode.ExtensionContext) {
47+
export async function activateAmazonQCommon(context: vscode.ExtensionContext, isWeb: boolean) {
48+
initialize(context, isWeb)
49+
const homeDirLogs = await fs.init(context, (homeDir) => {
50+
void messages.showViewLogsMessage(`Invalid home directory (check $HOME): "${homeDir}"`)
51+
})
52+
errors.init(fs.getUsername(), env.isAutomation())
53+
await initializeComputeRegion()
54+
55+
globals.contextPrefix = 'amazonq.' //todo: disconnect from above line
56+
57+
// Avoid activation if older toolkit is installed
58+
// Amazon Q is only compatible with AWS Toolkit >= 3.0.0
59+
// Or AWS Toolkit with a development version. Example: 2.19.0-3413gv
60+
const toolkit = vscode.extensions.getExtension(VSCODE_EXTENSION_ID.awstoolkit)
61+
if (toolkit) {
62+
const toolkitVersion = semver.coerce(toolkit.packageJSON.version)
63+
// XXX: can't use `SemVer.prerelease` because Toolkit "prerelease" (git sha) is not a valid
64+
// semver prerelease: it may start with a number.
65+
const isDevVersion = toolkit.packageJSON.version.toString().includes('-')
66+
if (toolkitVersion && toolkitVersion.major < 3 && !isDevVersion) {
67+
await vscode.commands
68+
.executeCommand('workbench.extensions.installExtension', VSCODE_EXTENSION_ID.awstoolkit)
69+
.then(
70+
() =>
71+
vscode.window
72+
.showInformationMessage(
73+
`The Amazon Q extension is incompatible with AWS Toolkit ${
74+
toolkitVersion as any
75+
} and older. Your AWS Toolkit was updated to version 3.0 or later.`,
76+
'Reload Now'
77+
)
78+
.then(async (resp) => {
79+
if (resp === 'Reload Now') {
80+
await vscode.commands.executeCommand('workbench.action.reloadWindow')
81+
}
82+
}),
83+
(reason) => {
84+
getLogger().error('workbench.extensions.installExtension failed: %O', reason)
85+
}
86+
)
87+
return
88+
}
89+
}
90+
91+
globals.machineId = await getMachineId()
92+
globals.awsContext = new DefaultAwsContext()
93+
globals.sdkClientBuilder = new DefaultAWSClientBuilder(globals.awsContext)
94+
globals.manifestPaths.endpoints = context.asAbsolutePath(join('resources', 'endpoints.json'))
95+
globals.regionProvider = RegionProvider.fromEndpointsProvider(makeEndpointsProvider())
96+
97+
const qOutputChannel = vscode.window.createOutputChannel('Amazon Q', { log: true })
98+
const qLogChannel = vscode.window.createOutputChannel('Amazon Q Logs', { log: true })
99+
await activateLogger(context, amazonQContextPrefix, qOutputChannel, qLogChannel)
100+
globals.outputChannel = qOutputChannel
101+
globals.logOutputChannel = qLogChannel
102+
globals.loginManager = new LoginManager(globals.awsContext, new CredentialsStore())
103+
104+
if (homeDirLogs.length > 0) {
105+
getLogger().error('fs.init: invalid env vars found: %O', homeDirLogs)
106+
}
107+
108+
await activateTelemetry(context, globals.awsContext, Settings.instance, 'Amazon Q For VS Code')
109+
110+
await initializeAuth(globals.loginManager)
111+
34112
const extContext = {
35113
extensionContext: context,
36114
}
37-
await activateCWChat(context)
38-
await activateQGumby(extContext as ExtContext)
39-
40-
const authProvider = new CommonAuthViewProvider(
41-
context,
42-
amazonQContextPrefix,
43-
DefaultAmazonQAppInitContext.instance.onDidChangeAmazonQVisibility
44-
)
45-
context.subscriptions.push(
46-
vscode.window.registerWebviewViewProvider(authProvider.viewType, authProvider, {
47-
webviewOptions: {
48-
retainContextWhenHidden: true,
49-
},
50-
}),
51-
registerSubmitFeedback(context, 'Amazon Q', amazonQContextPrefix)
52-
)
53-
54-
await setupDevMode(context)
55-
}
115+
await activateCodeWhisperer(extContext as ExtContext)
56116

57-
/**
58-
* Some parts of this do not work in Web mode so we need to set Dev Mode up here.
59-
*
60-
* TODO: Get the following working in web mode as well and then move this function.
61-
*/
62-
async function setupDevMode(context: vscode.ExtensionContext) {
63-
// At some point this imports CodeCatalyst code which breaks in web mode.
64-
// TODO: Make this work in web mode and move it to extensionCommon.ts
65-
await updateDevMode()
66-
67-
const devOptions: DevOptions = {
68-
context,
69-
auth: Auth.instance,
70-
menuOptions: [
71-
'editStorage',
72-
'showEnvVars',
73-
'deleteSsoConnections',
74-
'expireSsoConnections',
75-
'editAuthConnections',
76-
],
117+
// Generic extension commands
118+
registerGenericCommands(context, amazonQContextPrefix)
119+
120+
// Amazon Q specific commands
121+
registerCommands(context)
122+
123+
// Hide the Amazon Q tree in toolkit explorer
124+
await setContext('aws.toolkit.amazonq.dismissed', true)
125+
126+
// reload webviews
127+
await vscode.commands.executeCommand('workbench.action.webview.reloadWebviewAction')
128+
129+
if (AuthUtils.ExtensionUse.instance.isFirstUse()) {
130+
// Give time for the extension to finish initializing.
131+
globals.clock.setTimeout(async () => {
132+
CommonAuthWebview.authSource = ExtStartUpSources.firstStartUp
133+
void focusAmazonQPanel.execute(placeholder, 'firstStartUp')
134+
}, 1000)
77135
}
78136

79-
context.subscriptions.push(
80-
vscode.commands.registerCommand('amazonq.dev.openMenu', async () => {
81-
if (!isExtensionActive(VSCODE_EXTENSION_ID.awstoolkit)) {
82-
void vscode.window.showErrorMessage('AWS Toolkit must be installed to access the Developer Menu.')
83-
return
84-
}
85-
await vscode.commands.executeCommand('_aws.dev.invokeMenu', devOptions)
137+
await telemetry.auth_userState.run(async () => {
138+
telemetry.record({ passive: true })
139+
140+
const firstUse = AuthUtils.ExtensionUse.instance.isFirstUse()
141+
const wasUpdated = AuthUtils.ExtensionUse.instance.wasUpdated()
142+
143+
if (firstUse) {
144+
telemetry.record({ source: ExtStartUpSources.firstStartUp })
145+
} else if (wasUpdated) {
146+
telemetry.record({ source: ExtStartUpSources.update })
147+
} else {
148+
telemetry.record({ source: ExtStartUpSources.reload })
149+
}
150+
151+
const authState = (await AuthUtil.instance.getChatAuthState()).codewhispererChat
152+
telemetry.record({
153+
authStatus: authState === 'connected' || authState === 'expired' ? authState : 'notConnected',
154+
authEnabledConnections: AuthUtils.getAuthFormIdsFromConnection(AuthUtil.instance.conn).join(','),
155+
authScopes: ((AuthUtil.instance.conn as SsoConnection)?.scopes ?? []).join(','),
86156
})
87-
)
157+
})
88158
}
89159

90-
export async function deactivate() {
91-
await deactivateCommon()
160+
export async function deactivateCommon() {
161+
await shutdownCodeWhisperer()
92162
}

0 commit comments

Comments
 (0)