From 9f44fa6bb8dfad737df4f33240a0131e0275f4d1 Mon Sep 17 00:00:00 2001 From: aws-toolkit-automation <> Date: Tue, 6 May 2025 18:40:07 +0000 Subject: [PATCH 01/36] Release 3.60.0 --- package-lock.json | 4 ++-- packages/toolkit/.changes/3.60.0.json | 5 +++++ packages/toolkit/CHANGELOG.md | 4 ++++ packages/toolkit/package.json | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 packages/toolkit/.changes/3.60.0.json diff --git a/package-lock.json b/package-lock.json index 50e66f18b6c..c91bf2b987f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "prettier": "^3.3.3", "prettier-plugin-sh": "^0.14.0", "pretty-quick": "^4.0.0", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "^5.0.4", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", @@ -28098,7 +28098,7 @@ }, "packages/toolkit": { "name": "aws-toolkit-vscode", - "version": "3.60.0-SNAPSHOT", + "version": "3.60.0", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" diff --git a/packages/toolkit/.changes/3.60.0.json b/packages/toolkit/.changes/3.60.0.json new file mode 100644 index 00000000000..2464e57a4b0 --- /dev/null +++ b/packages/toolkit/.changes/3.60.0.json @@ -0,0 +1,5 @@ +{ + "date": "2025-05-06", + "version": "3.60.0", + "entries": [] +} \ No newline at end of file diff --git a/packages/toolkit/CHANGELOG.md b/packages/toolkit/CHANGELOG.md index 215c7c68cba..e21988fcd50 100644 --- a/packages/toolkit/CHANGELOG.md +++ b/packages/toolkit/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.60.0 2025-05-06 + +- Miscellaneous non-user-facing changes + ## 3.59.0 2025-05-05 - Miscellaneous non-user-facing changes diff --git a/packages/toolkit/package.json b/packages/toolkit/package.json index cffb69d0c1a..107245f54f2 100644 --- a/packages/toolkit/package.json +++ b/packages/toolkit/package.json @@ -2,7 +2,7 @@ "name": "aws-toolkit-vscode", "displayName": "AWS Toolkit", "description": "Including CodeCatalyst, Infrastructure Composer, and support for Lambda, S3, CloudWatch Logs, CloudFormation, and many other services.", - "version": "3.60.0-SNAPSHOT", + "version": "3.60.0", "extensionKind": [ "workspace" ], From 8a02d60b5c0ba292bcf2c8026b2417a034086be5 Mon Sep 17 00:00:00 2001 From: Tai Lai Date: Thu, 8 May 2025 14:09:21 -0700 Subject: [PATCH 02/36] fix(amazonq): agent tabs open with prompt options (#7265) ## Problem Inconsistent behavior when opening agent tabs (/review, /doc, etc). When the tab is reused it keeps the prompt input options visible, but when a new tab is created it doesn't. https://github.com/user-attachments/assets/2ff7264f-f7a3-46f6-9a34-e29835768833 ## Solution Set `promptInputOptions` to empty when an existing tab is reused. --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --- .../Bug Fix-b873a959-2742-4440-badc-c90c6ac754c3.json | 4 ++++ packages/core/src/amazonq/webview/ui/quickActions/handler.ts | 2 ++ 2 files changed, 6 insertions(+) create mode 100644 packages/amazonq/.changes/next-release/Bug Fix-b873a959-2742-4440-badc-c90c6ac754c3.json diff --git a/packages/amazonq/.changes/next-release/Bug Fix-b873a959-2742-4440-badc-c90c6ac754c3.json b/packages/amazonq/.changes/next-release/Bug Fix-b873a959-2742-4440-badc-c90c6ac754c3.json new file mode 100644 index 00000000000..02c9a67d136 --- /dev/null +++ b/packages/amazonq/.changes/next-release/Bug Fix-b873a959-2742-4440-badc-c90c6ac754c3.json @@ -0,0 +1,4 @@ +{ + "type": "Bug Fix", + "description": "Named agent tabs sometimes open with unnecessary input options" +} diff --git a/packages/core/src/amazonq/webview/ui/quickActions/handler.ts b/packages/core/src/amazonq/webview/ui/quickActions/handler.ts index fe124d1fc0c..f0d707247e9 100644 --- a/packages/core/src/amazonq/webview/ui/quickActions/handler.ts +++ b/packages/core/src/amazonq/webview/ui/quickActions/handler.ts @@ -355,6 +355,8 @@ export class QuickActionHandler { loadingChat: true, cancelButtonWhenLoading: false, }) + } else { + this.mynahUI.updateStore(affectedTabId, { promptInputOptions: [] }) } if (affectedTabId && this.isHybridChatEnabled) { From 4369fb507fa79f2f6a56b8c5f3dd5b34f272733e Mon Sep 17 00:00:00 2001 From: Josh Pinkney <103940141+jpinkney-aws@users.noreply.github.com> Date: Thu, 8 May 2025 21:09:13 -0400 Subject: [PATCH 03/36] fix(amazonq): flare clientId changes on every instance (#7273) ## Problem clientId from `clientParams.initializationOptions?.aws?.clientInfo?.clientId` is random on every restart ## Solution use the client id from telemetry utils --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --- packages/amazonq/src/lsp/client.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index 5cbf174e577..e3b58455d77 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -5,7 +5,6 @@ import vscode, { env, version } from 'vscode' import * as nls from 'vscode-nls' -import * as crypto from 'crypto' import { LanguageClient, LanguageClientOptions, RequestType, State } from 'vscode-languageclient' import { InlineCompletionManager } from '../app/inline/completion' import { AmazonQLspAuth, encryptionKey, notificationTypes } from './auth' @@ -34,6 +33,7 @@ import { getOptOutPreference, isAmazonInternalOs, fs, + getClientId, } from 'aws-core-vscode/shared' import { processUtils } from 'aws-core-vscode/shared' import { activate } from './chat/activation' @@ -120,7 +120,7 @@ export async function startLanguageServer( name: 'AmazonQ-For-VSCode', version: '0.0.1', }, - clientId: crypto.randomUUID(), + clientId: getClientId(globals.globalState), }, awsClientCapabilities: { q: { From 0d97988720489dfecd59991c449988ab760b6824 Mon Sep 17 00:00:00 2001 From: aws-toolkit-automation <> Date: Fri, 9 May 2025 01:16:29 +0000 Subject: [PATCH 04/36] Release 1.66.0 --- package-lock.json | 4 ++-- packages/amazonq/.changes/1.66.0.json | 14 ++++++++++++++ ...g Fix-75375702-36b5-4e89-af57-4afe983a7238.json | 4 ---- ...g Fix-b873a959-2742-4440-badc-c90c6ac754c3.json | 4 ---- packages/amazonq/CHANGELOG.md | 5 +++++ packages/amazonq/package.json | 2 +- 6 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 packages/amazonq/.changes/1.66.0.json delete mode 100644 packages/amazonq/.changes/next-release/Bug Fix-75375702-36b5-4e89-af57-4afe983a7238.json delete mode 100644 packages/amazonq/.changes/next-release/Bug Fix-b873a959-2742-4440-badc-c90c6ac754c3.json diff --git a/package-lock.json b/package-lock.json index c5a890c2260..5c66ecf29e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "prettier": "^3.3.3", "prettier-plugin-sh": "^0.14.0", "pretty-quick": "^4.0.0", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "^5.0.4", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", @@ -26384,7 +26384,7 @@ }, "packages/amazonq": { "name": "amazon-q-vscode", - "version": "1.66.0-SNAPSHOT", + "version": "1.66.0", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" diff --git a/packages/amazonq/.changes/1.66.0.json b/packages/amazonq/.changes/1.66.0.json new file mode 100644 index 00000000000..ab4a819b85a --- /dev/null +++ b/packages/amazonq/.changes/1.66.0.json @@ -0,0 +1,14 @@ +{ + "date": "2025-05-09", + "version": "1.66.0", + "entries": [ + { + "type": "Bug Fix", + "description": "Avoid inline completion 'Improperly formed request' errors when file is too large" + }, + { + "type": "Bug Fix", + "description": "Named agent tabs sometimes open with unnecessary input options" + } + ] +} \ No newline at end of file diff --git a/packages/amazonq/.changes/next-release/Bug Fix-75375702-36b5-4e89-af57-4afe983a7238.json b/packages/amazonq/.changes/next-release/Bug Fix-75375702-36b5-4e89-af57-4afe983a7238.json deleted file mode 100644 index 83796afaa55..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-75375702-36b5-4e89-af57-4afe983a7238.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "Avoid inline completion 'Improperly formed request' errors when file is too large" -} diff --git a/packages/amazonq/.changes/next-release/Bug Fix-b873a959-2742-4440-badc-c90c6ac754c3.json b/packages/amazonq/.changes/next-release/Bug Fix-b873a959-2742-4440-badc-c90c6ac754c3.json deleted file mode 100644 index 02c9a67d136..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-b873a959-2742-4440-badc-c90c6ac754c3.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "Named agent tabs sometimes open with unnecessary input options" -} diff --git a/packages/amazonq/CHANGELOG.md b/packages/amazonq/CHANGELOG.md index b5ceba33c7c..197aecdfdf6 100644 --- a/packages/amazonq/CHANGELOG.md +++ b/packages/amazonq/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.66.0 2025-05-09 + +- **Bug Fix** Avoid inline completion 'Improperly formed request' errors when file is too large +- **Bug Fix** Named agent tabs sometimes open with unnecessary input options + ## 1.65.0 2025-05-05 - **Feature** Support selecting customizations across all Q profiles with automatic profile switching for enterprise users diff --git a/packages/amazonq/package.json b/packages/amazonq/package.json index 0553b16a973..4197556075d 100644 --- a/packages/amazonq/package.json +++ b/packages/amazonq/package.json @@ -2,7 +2,7 @@ "name": "amazon-q-vscode", "displayName": "Amazon Q", "description": "The most capable generative AI-powered assistant for building, operating, and transforming software, with advanced capabilities for managing data and AI", - "version": "1.66.0-SNAPSHOT", + "version": "1.66.0", "extensionKind": [ "workspace" ], From dcaeb535747bb694a4637d155823aa8e800aab72 Mon Sep 17 00:00:00 2001 From: aws-toolkit-automation <> Date: Fri, 9 May 2025 13:56:54 +0000 Subject: [PATCH 05/36] Update version to snapshot version: 3.61.0-SNAPSHOT --- package-lock.json | 4 ++-- packages/toolkit/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index c91bf2b987f..dcdfcc8b0d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "prettier": "^3.3.3", "prettier-plugin-sh": "^0.14.0", "pretty-quick": "^4.0.0", - "ts-node": "^10.9.2", + "ts-node": "^10.9.1", "typescript": "^5.0.4", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", @@ -28098,7 +28098,7 @@ }, "packages/toolkit": { "name": "aws-toolkit-vscode", - "version": "3.60.0", + "version": "3.61.0-SNAPSHOT", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" diff --git a/packages/toolkit/package.json b/packages/toolkit/package.json index 107245f54f2..077030c66cb 100644 --- a/packages/toolkit/package.json +++ b/packages/toolkit/package.json @@ -2,7 +2,7 @@ "name": "aws-toolkit-vscode", "displayName": "AWS Toolkit", "description": "Including CodeCatalyst, Infrastructure Composer, and support for Lambda, S3, CloudWatch Logs, CloudFormation, and many other services.", - "version": "3.60.0", + "version": "3.61.0-SNAPSHOT", "extensionKind": [ "workspace" ], From 91e5039d2d2127fedfbdafc9b212e1984c64326b Mon Sep 17 00:00:00 2001 From: aws-toolkit-automation <> Date: Fri, 9 May 2025 13:58:47 +0000 Subject: [PATCH 06/36] Update version to snapshot version: 1.67.0-SNAPSHOT --- package-lock.json | 4 ++-- packages/amazonq/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5c66ecf29e7..4c9375c6b7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "prettier": "^3.3.3", "prettier-plugin-sh": "^0.14.0", "pretty-quick": "^4.0.0", - "ts-node": "^10.9.2", + "ts-node": "^10.9.1", "typescript": "^5.0.4", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", @@ -26384,7 +26384,7 @@ }, "packages/amazonq": { "name": "amazon-q-vscode", - "version": "1.66.0", + "version": "1.67.0-SNAPSHOT", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" diff --git a/packages/amazonq/package.json b/packages/amazonq/package.json index 4197556075d..f9d466f5767 100644 --- a/packages/amazonq/package.json +++ b/packages/amazonq/package.json @@ -2,7 +2,7 @@ "name": "amazon-q-vscode", "displayName": "Amazon Q", "description": "The most capable generative AI-powered assistant for building, operating, and transforming software, with advanced capabilities for managing data and AI", - "version": "1.66.0", + "version": "1.67.0-SNAPSHOT", "extensionKind": [ "workspace" ], From 1085a8de0d19e2989693fa4616cb265f9705ecc6 Mon Sep 17 00:00:00 2001 From: Nikolas Komonen <118216176+nkomonen-amazon@users.noreply.github.com> Date: Fri, 9 May 2025 12:22:46 -0400 Subject: [PATCH 07/36] telemetry(amazonq): Emit metric on server crash (#7278) When the server crashes and then restarts again, we will emit a metric to indicate it crashed. When querying look for: `metadata.metricName: languageServer_crash` & `metadata.id: AmazonQ` --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. Signed-off-by: nkomonen-amazon --- packages/amazonq/src/lsp/client.ts | 7 +++++++ packages/core/src/shared/telemetry/vscodeTelemetry.json | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index e3b58455d77..4735d9cbc8c 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -39,6 +39,7 @@ import { processUtils } from 'aws-core-vscode/shared' import { activate } from './chat/activation' import { AmazonQResourcePaths } from './lspInstaller' import { ConfigSection, isValidConfigSection, toAmazonQLSPLogLevel } from './config' +import { telemetry } from 'aws-core-vscode/telemetry' const localize = nls.loadMessageBundle() const logger = getLogger('amazonqLsp.lspClient') @@ -288,6 +289,12 @@ function onServerRestartHandler(client: LanguageClient, auth: AmazonQLspAuth) { return } + // Emit telemetry that a crash was detected. + // It is not guaranteed to 100% be a crash since somehow the server may have been intentionally restarted, + // but most of the time it probably will have been due to a crash. + // TODO: Port this metric override to common definitions + telemetry.languageServer_crash.emit({ id: 'AmazonQ' }) + // Need to set the auth token in the again await auth.refreshConnection(true) }) diff --git a/packages/core/src/shared/telemetry/vscodeTelemetry.json b/packages/core/src/shared/telemetry/vscodeTelemetry.json index 4a5117ee252..b28aeec4847 100644 --- a/packages/core/src/shared/telemetry/vscodeTelemetry.json +++ b/packages/core/src/shared/telemetry/vscodeTelemetry.json @@ -1019,6 +1019,15 @@ } ] }, + { + "name": "languageServer_crash", + "description": "Called when a language server crash is detected. TODO: Port this to common", + "metadata": [ + { + "type": "id" + } + ] + }, { "name": "ide_heartbeat", "description": "A heartbeat sent by the extension", From a14b9a215b63144f63745299fd0f6c74bbe68150 Mon Sep 17 00:00:00 2001 From: Adam Khamis <110852798+akhamis-amzn@users.noreply.github.com> Date: Fri, 9 May 2025 15:52:44 -0400 Subject: [PATCH 08/36] telemetry(amazonq): expose FileCreationFailed exceptions #7260 ## Problem FileCreationFailed exceptions are displayed as UnknownException in telemetry. This exception is new and we want to separate this out from other unknown exceptions. ## Solution Return API service error with `FileCreationFailedException` --- .../core/src/amazonqFeatureDev/session/sessionState.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/core/src/amazonqFeatureDev/session/sessionState.ts b/packages/core/src/amazonqFeatureDev/session/sessionState.ts index 5890539409f..5879c16493f 100644 --- a/packages/core/src/amazonqFeatureDev/session/sessionState.ts +++ b/packages/core/src/amazonqFeatureDev/session/sessionState.ts @@ -205,6 +205,14 @@ export class FeatureDevCodeGenState extends BaseCodeGenState { 429 ) } + case codegenResult.codeGenerationStatusDetail?.includes('FileCreationFailed'): { + return new ApiServiceError( + i18n('AWS.amazonq.featureDev.error.codeGen.default'), + 'GetTaskAssistCodeGeneration', + 'FileCreationFailedException', + 500 + ) + } default: { return new ApiServiceError( i18n('AWS.amazonq.featureDev.error.codeGen.default'), From 05cde57b3d526d3b69727b3f7a40c1ca585fb6ba Mon Sep 17 00:00:00 2001 From: Na Yue Date: Fri, 9 May 2025 15:15:14 -0700 Subject: [PATCH 09/36] fix(lsp): send extension version to Q LSP #7279 ## Problem Extension version sent to Q LSP is hardcoded. ## Solution Ssend the actual extension version BEFORE: aws-sdk-nodejs/2.1692.0 darwin/v23.10.0 AWS-Language-Servers AWS-CodeWhisperer/0.1.0 AmazonQ-For-VSCode/0.0.1 Visual-Studio-Code---Insiders/1.100.0-insider ClientId/c342ab45-6aba-4118-b48c-44dcedb10a78 promise AFTER aws-sdk-nodejs/2.1692.0 darwin/v23.10.0 AWS-Language-Servers AWS-CodeWhisperer/0.1.0 AmazonQ-For-VSCode/testPluginVersion Visual-Studio-Code---Insiders/1.100.0-insider ClientId/c342ab45-6aba-4118-b48c-44dcedb10a78 promise --- packages/amazonq/src/lsp/client.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index 4735d9cbc8c..d20f8067103 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -34,6 +34,7 @@ import { isAmazonInternalOs, fs, getClientId, + extensionVersion, } from 'aws-core-vscode/shared' import { processUtils } from 'aws-core-vscode/shared' import { activate } from './chat/activation' @@ -119,7 +120,7 @@ export async function startLanguageServer( version: version, extension: { name: 'AmazonQ-For-VSCode', - version: '0.0.1', + version: extensionVersion, }, clientId: getClientId(globals.globalState), }, From 4b091678205c84954735a2a1ff1f5c087c4f7116 Mon Sep 17 00:00:00 2001 From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> Date: Fri, 9 May 2025 16:00:28 -0700 Subject: [PATCH 10/36] fix(amazonq): adding logs for the agentic chat telemetry events (#7276) ## Problem - No logs is being emitted for telemetry events. ## Solution - Adding logs if telemetry events are emitted. --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --- packages/amazonq/src/lsp/chat/messages.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/amazonq/src/lsp/chat/messages.ts b/packages/amazonq/src/lsp/chat/messages.ts index 9578858b708..38a52f72f9c 100644 --- a/packages/amazonq/src/lsp/chat/messages.ts +++ b/packages/amazonq/src/lsp/chat/messages.ts @@ -94,6 +94,7 @@ export function registerLanguageServerEventListener(languageClient: LanguageClie const telemetryName: string = e.name if (telemetryName in telemetry) { + languageClient.info(`[Telemetry] Emitting ${telemetryName} telemetry: ${JSON.stringify(e.data)}`) telemetry[telemetryName as keyof TelemetryBase].emit(e.data) } }) From ffc0cb47cfd017a6ec033613a6d453f4cd433eb3 Mon Sep 17 00:00:00 2001 From: Jiatong Li Date: Mon, 12 May 2025 14:34:05 -0700 Subject: [PATCH 11/36] fix(amazonq): pass uri.path as workspaceIdentifier when initializing #7291 ## Problem `workspaceIdentifier` should be a string: - https://github.com/aws/language-server-runtimes/pull/497 ## Solution Pass `extensionContext.storageUri?.path`. --- packages/amazonq/src/lsp/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index d20f8067103..4af113b13c4 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -134,7 +134,7 @@ export async function startLanguageServer( }, }, contextConfiguration: { - workspaceIdentifier: extensionContext.storageUri, + workspaceIdentifier: extensionContext.storageUri?.path, }, logLevel: toAmazonQLSPLogLevel(globals.logOutputChannel.logLevel), }, From 2d898fbac0bb0418ffc51b22d38202617bff2bfa Mon Sep 17 00:00:00 2001 From: Avi Alpert <131792194+avi-alpert@users.noreply.github.com> Date: Mon, 12 May 2025 17:36:08 -0400 Subject: [PATCH 12/36] deps: bump @aws-toolkits/telemetry to 1.0.318 #7290 ## Problem New telemetry metrics were [added](https://github.com/aws/aws-toolkit-common/pull/1023) to aws-toolkit-common ## Solution Consume latest version of aws-toolkit-common package --- package-lock.json | 9 ++++----- package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0a36cb6df6a..e5f1e7e7a70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "vscode-nls-dev": "^4.0.4" }, "devDependencies": { - "@aws-toolkits/telemetry": "^1.0.317", + "@aws-toolkits/telemetry": "^1.0.318", "@playwright/browser-chromium": "^1.43.1", "@stylistic/eslint-plugin": "^2.11.0", "@types/he": "^1.2.3", @@ -10760,11 +10760,10 @@ } }, "node_modules/@aws-toolkits/telemetry": { - "version": "1.0.317", - "resolved": "https://registry.npmjs.org/@aws-toolkits/telemetry/-/telemetry-1.0.317.tgz", - "integrity": "sha512-QFLBFfHZjuB2pBd1p0Tn/GMKTYYQu3/nrlj0Co7EkqozvDNDG0nTjxtkXxotbwjrqVD5Sv8i46gEdgsyQ7at3w==", + "version": "1.0.318", + "resolved": "https://registry.npmjs.org/@aws-toolkits/telemetry/-/telemetry-1.0.318.tgz", + "integrity": "sha512-L64GJ+KRN0fdTIx1CPIbbgBeFcg9DilsIxfjeZyod7ld0mw6he70rPopBtK4jP+pTEkfUE4wTRsaco1nWXz3+w==", "dev": true, - "license": "Apache-2.0", "dependencies": { "ajv": "^6.12.6", "cross-spawn": "^7.0.6", diff --git a/package.json b/package.json index 30f0497cdb2..f4b31c22d83 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "skippedTestReport": "ts-node ./scripts/skippedTestReport.ts ./packages/amazonq/test/e2e/" }, "devDependencies": { - "@aws-toolkits/telemetry": "^1.0.317", + "@aws-toolkits/telemetry": "^1.0.318", "@playwright/browser-chromium": "^1.43.1", "@stylistic/eslint-plugin": "^2.11.0", "@types/he": "^1.2.3", From 8e85476708e0d2e9467cc7afe13a42661de78f1d Mon Sep 17 00:00:00 2001 From: Brad Skaggs <126105424+brdskggs@users.noreply.github.com> Date: Tue, 13 May 2025 11:54:16 -0400 Subject: [PATCH 13/36] fix(amazonq): use neighbor cells as completion context in Notebook #7086 ## Problem VS Code treats each cell in a notebook as a separate editor. As a result, when building the left- and right-contexts for the completion from the current editor, we were limited to just the current cell, which might be very small and/or reference variables and functions defined in other cells. That meant that completions never used the context of other cells when making suggestions, and were often _very_ generic. https://github.com/aws/aws-toolkit-vscode/issues/7031 ## Solution The `extractContextForCodeWhisperer` function now checks if it is being called in a cell in a Jupyter notebook. If so, it collects the surrounding cells to use as context, respecting the maximum context length. During this process, Markdown cells have each line prefixed with a language-specific comment character. --- ...-9b0e6490-39a8-445f-9d67-9d762de7421c.json | 4 + .../codewhisperer/util/editorContext.test.ts | 219 ++++++++++++++++++ .../util/runtimeLanguageContext.test.ts | 34 +++ .../src/codewhisperer/util/editorContext.ts | 125 +++++++++- .../util/runtimeLanguageContext.ts | 50 ++++ 5 files changed, 429 insertions(+), 3 deletions(-) create mode 100644 packages/amazonq/.changes/next-release/Bug Fix-9b0e6490-39a8-445f-9d67-9d762de7421c.json diff --git a/packages/amazonq/.changes/next-release/Bug Fix-9b0e6490-39a8-445f-9d67-9d762de7421c.json b/packages/amazonq/.changes/next-release/Bug Fix-9b0e6490-39a8-445f-9d67-9d762de7421c.json new file mode 100644 index 00000000000..f17516bb8f4 --- /dev/null +++ b/packages/amazonq/.changes/next-release/Bug Fix-9b0e6490-39a8-445f-9d67-9d762de7421c.json @@ -0,0 +1,4 @@ +{ + "type": "Bug Fix", + "description": "Previous and subsequent cells are used as context for completion in a Jupyter notebook" +} diff --git a/packages/amazonq/test/unit/codewhisperer/util/editorContext.test.ts b/packages/amazonq/test/unit/codewhisperer/util/editorContext.test.ts index d5085e4db0c..f8265a4fa86 100644 --- a/packages/amazonq/test/unit/codewhisperer/util/editorContext.test.ts +++ b/packages/amazonq/test/unit/codewhisperer/util/editorContext.test.ts @@ -6,6 +6,7 @@ import assert from 'assert' import * as codewhispererClient from 'aws-core-vscode/codewhisperer' import * as EditorContext from 'aws-core-vscode/codewhisperer' import { + createMockDocument, createMockTextEditor, createMockClientRequest, resetCodeWhispererGlobalVariables, @@ -15,6 +16,27 @@ import { } from 'aws-core-vscode/test' import { globals } from 'aws-core-vscode/shared' import { GenerateCompletionsRequest } from 'aws-core-vscode/codewhisperer' +import * as vscode from 'vscode' + +export function createNotebookCell( + document: vscode.TextDocument = createMockDocument('def example():\n return "test"'), + kind: vscode.NotebookCellKind = vscode.NotebookCellKind.Code, + notebook: vscode.NotebookDocument = {} as any, + index: number = 0, + outputs: vscode.NotebookCellOutput[] = [], + metadata: { readonly [key: string]: any } = {}, + executionSummary?: vscode.NotebookCellExecutionSummary +): vscode.NotebookCell { + return { + document, + kind, + notebook, + index, + outputs, + metadata, + executionSummary, + } +} describe('editorContext', function () { let telemetryEnabledDefault: boolean @@ -63,6 +85,44 @@ describe('editorContext', function () { } assert.deepStrictEqual(actual, expected) }) + + it('in a notebook, includes context from other cells', async function () { + const cells: vscode.NotebookCellData[] = [ + new vscode.NotebookCellData(vscode.NotebookCellKind.Markup, 'Previous cell', 'python'), + new vscode.NotebookCellData( + vscode.NotebookCellKind.Code, + 'import numpy as np\nimport pandas as pd\n\ndef analyze_data(df):\n # Current cell with cursor here', + 'python' + ), + new vscode.NotebookCellData( + vscode.NotebookCellKind.Code, + '# Process the data\nresult = analyze_data(df)\nprint(result)', + 'python' + ), + ] + + const document = await vscode.workspace.openNotebookDocument( + 'jupyter-notebook', + new vscode.NotebookData(cells) + ) + const editor: any = { + document: document.cellAt(1).document, + selection: { active: new vscode.Position(4, 13) }, + } + + const actual = EditorContext.extractContextForCodeWhisperer(editor) + const expected: codewhispererClient.FileContext = { + filename: 'Untitled-1.py', + programmingLanguage: { + languageName: 'python', + }, + leftFileContent: + '# Previous cell\nimport numpy as np\nimport pandas as pd\n\ndef analyze_data(df):\n # Current', + rightFileContent: + ' cell with cursor here\n# Process the data\nresult = analyze_data(df)\nprint(result)\n', + } + assert.deepStrictEqual(actual, expected) + }) }) describe('getFileName', function () { @@ -115,6 +175,165 @@ describe('editorContext', function () { }) }) + describe('getNotebookCellContext', function () { + it('Should return cell text for python code cells when language is python', function () { + const mockCodeCell = createNotebookCell(createMockDocument('def example():\n return "test"')) + const result = EditorContext.getNotebookCellContext(mockCodeCell, 'python') + assert.strictEqual(result, 'def example():\n return "test"') + }) + + it('Should return java comments for python code cells when language is java', function () { + const mockCodeCell = createNotebookCell(createMockDocument('def example():\n return "test"')) + const result = EditorContext.getNotebookCellContext(mockCodeCell, 'java') + assert.strictEqual(result, '// def example():\n// return "test"') + }) + + it('Should return python comments for java code cells when language is python', function () { + const mockCodeCell = createNotebookCell(createMockDocument('println(1 + 1);', 'somefile.ipynb', 'java')) + const result = EditorContext.getNotebookCellContext(mockCodeCell, 'python') + assert.strictEqual(result, '# println(1 + 1);') + }) + + it('Should add python comment prefixes for markdown cells when language is python', function () { + const mockMarkdownCell = createNotebookCell( + createMockDocument('# Heading\nThis is a markdown cell'), + vscode.NotebookCellKind.Markup + ) + const result = EditorContext.getNotebookCellContext(mockMarkdownCell, 'python') + assert.strictEqual(result, '# # Heading\n# This is a markdown cell') + }) + + it('Should add java comment prefixes for markdown cells when language is java', function () { + const mockMarkdownCell = createNotebookCell( + createMockDocument('# Heading\nThis is a markdown cell'), + vscode.NotebookCellKind.Markup + ) + const result = EditorContext.getNotebookCellContext(mockMarkdownCell, 'java') + assert.strictEqual(result, '// # Heading\n// This is a markdown cell') + }) + }) + + describe('getNotebookCellsSliceContext', function () { + it('Should extract content from cells in reverse order up to maxLength from prefix cells', function () { + const mockCells = [ + createNotebookCell(createMockDocument('First cell content')), + createNotebookCell(createMockDocument('Second cell content')), + createNotebookCell(createMockDocument('Third cell content')), + ] + + const result = EditorContext.getNotebookCellsSliceContext(mockCells, 100, 'python', false) + assert.strictEqual(result, 'First cell content\nSecond cell content\nThird cell content\n') + }) + + it('Should extract content from cells in reverse order up to maxLength from suffix cells', function () { + const mockCells = [ + createNotebookCell(createMockDocument('First cell content')), + createNotebookCell(createMockDocument('Second cell content')), + createNotebookCell(createMockDocument('Third cell content')), + ] + + const result = EditorContext.getNotebookCellsSliceContext(mockCells, 100, 'python', true) + assert.strictEqual(result, 'First cell content\nSecond cell content\nThird cell content\n') + }) + + it('Should respect maxLength parameter from prefix cells', function () { + const mockCells = [ + createNotebookCell(createMockDocument('First')), + createNotebookCell(createMockDocument('Second')), + createNotebookCell(createMockDocument('Third')), + createNotebookCell(createMockDocument('Fourth')), + ] + // Should only include part of second cell and the last two cells + const result = EditorContext.getNotebookCellsSliceContext(mockCells, 15, 'python', false) + assert.strictEqual(result, 'd\nThird\nFourth\n') + }) + + it('Should respect maxLength parameter from suffix cells', function () { + const mockCells = [ + createNotebookCell(createMockDocument('First')), + createNotebookCell(createMockDocument('Second')), + createNotebookCell(createMockDocument('Third')), + createNotebookCell(createMockDocument('Fourth')), + ] + + // Should only include first cell and part of second cell + const result = EditorContext.getNotebookCellsSliceContext(mockCells, 15, 'python', true) + assert.strictEqual(result, 'First\nSecond\nTh') + }) + + it('Should handle empty cells array from prefix cells', function () { + const result = EditorContext.getNotebookCellsSliceContext([], 100, 'python', false) + assert.strictEqual(result, '') + }) + + it('Should handle empty cells array from suffix cells', function () { + const result = EditorContext.getNotebookCellsSliceContext([], 100, 'python', true) + assert.strictEqual(result, '') + }) + + it('Should add python comments to markdown prefix cells', function () { + const mockCells = [ + createNotebookCell(createMockDocument('# Heading\nThis is markdown'), vscode.NotebookCellKind.Markup), + createNotebookCell(createMockDocument('def example():\n return "test"')), + ] + const result = EditorContext.getNotebookCellsSliceContext(mockCells, 100, 'python', false) + assert.strictEqual(result, '# # Heading\n# This is markdown\ndef example():\n return "test"\n') + }) + + it('Should add python comments to markdown suffix cells', function () { + const mockCells = [ + createNotebookCell(createMockDocument('# Heading\nThis is markdown'), vscode.NotebookCellKind.Markup), + createNotebookCell(createMockDocument('def example():\n return "test"')), + ] + + const result = EditorContext.getNotebookCellsSliceContext(mockCells, 100, 'python', true) + assert.strictEqual(result, '# # Heading\n# This is markdown\ndef example():\n return "test"\n') + }) + + it('Should add java comments to markdown and python prefix cells when language is java', function () { + const mockCells = [ + createNotebookCell(createMockDocument('# Heading\nThis is markdown'), vscode.NotebookCellKind.Markup), + createNotebookCell(createMockDocument('def example():\n return "test"')), + ] + const result = EditorContext.getNotebookCellsSliceContext(mockCells, 100, 'java', false) + assert.strictEqual(result, '// # Heading\n// This is markdown\n// def example():\n// return "test"\n') + }) + + it('Should add java comments to markdown and python suffix cells when language is java', function () { + const mockCells = [ + createNotebookCell(createMockDocument('# Heading\nThis is markdown'), vscode.NotebookCellKind.Markup), + createNotebookCell(createMockDocument('println(1 + 1);', 'somefile.ipynb', 'java')), + ] + + const result = EditorContext.getNotebookCellsSliceContext(mockCells, 100, 'java', true) + assert.strictEqual(result, '// # Heading\n// This is markdown\nprintln(1 + 1);\n') + }) + + it('Should handle code prefix cells with different languages', function () { + const mockCells = [ + createNotebookCell( + createMockDocument('println(1 + 1);', 'somefile.ipynb', 'java'), + vscode.NotebookCellKind.Code + ), + createNotebookCell(createMockDocument('def example():\n return "test"')), + ] + const result = EditorContext.getNotebookCellsSliceContext(mockCells, 100, 'python', false) + assert.strictEqual(result, '# println(1 + 1);\ndef example():\n return "test"\n') + }) + + it('Should handle code suffix cells with different languages', function () { + const mockCells = [ + createNotebookCell( + createMockDocument('println(1 + 1);', 'somefile.ipynb', 'java'), + vscode.NotebookCellKind.Code + ), + createNotebookCell(createMockDocument('def example():\n return "test"')), + ] + const result = EditorContext.getNotebookCellsSliceContext(mockCells, 100, 'python', true) + assert.strictEqual(result, '# println(1 + 1);\ndef example():\n return "test"\n') + }) + }) + describe('validateRequest', function () { it('Should return false if request filename.length is invalid', function () { const req = createMockClientRequest() diff --git a/packages/amazonq/test/unit/codewhisperer/util/runtimeLanguageContext.test.ts b/packages/amazonq/test/unit/codewhisperer/util/runtimeLanguageContext.test.ts index 59c3771abb4..a5cc430a5a9 100644 --- a/packages/amazonq/test/unit/codewhisperer/util/runtimeLanguageContext.test.ts +++ b/packages/amazonq/test/unit/codewhisperer/util/runtimeLanguageContext.test.ts @@ -333,6 +333,40 @@ describe('runtimeLanguageContext', function () { } }) + describe('getSingleLineCommentPrefix', function () { + it('should return the correct comment prefix for supported languages', function () { + assert.strictEqual(languageContext.getSingleLineCommentPrefix('java'), '// ') + assert.strictEqual(languageContext.getSingleLineCommentPrefix('javascript'), '// ') + assert.strictEqual(languageContext.getSingleLineCommentPrefix('jsonc'), '// ') + assert.strictEqual(languageContext.getSingleLineCommentPrefix('kotlin'), '// ') + assert.strictEqual(languageContext.getSingleLineCommentPrefix('lua'), '-- ') + assert.strictEqual(languageContext.getSingleLineCommentPrefix('python'), '# ') + assert.strictEqual(languageContext.getSingleLineCommentPrefix('ruby'), '# ') + assert.strictEqual(languageContext.getSingleLineCommentPrefix('sql'), '-- ') + assert.strictEqual(languageContext.getSingleLineCommentPrefix('tf'), '# ') + assert.strictEqual(languageContext.getSingleLineCommentPrefix('typescript'), '// ') + assert.strictEqual(languageContext.getSingleLineCommentPrefix('vue'), '') + assert.strictEqual(languageContext.getSingleLineCommentPrefix('yaml'), '# ') + }) + + it('should normalize language ID before getting comment prefix', function () { + assert.strictEqual(languageContext.getSingleLineCommentPrefix('hcl'), '# ') + assert.strictEqual(languageContext.getSingleLineCommentPrefix('javascriptreact'), '// ') + assert.strictEqual(languageContext.getSingleLineCommentPrefix('shellscript'), '# ') + assert.strictEqual(languageContext.getSingleLineCommentPrefix('typescriptreact'), '// ') + assert.strictEqual(languageContext.getSingleLineCommentPrefix('yml'), '# ') + }) + + it('should return empty string for unsupported languages', function () { + assert.strictEqual(languageContext.getSingleLineCommentPrefix('nonexistent'), '') + assert.strictEqual(languageContext.getSingleLineCommentPrefix(undefined), '') + }) + + it('should return empty string for plaintext', function () { + assert.strictEqual(languageContext.getSingleLineCommentPrefix('plaintext'), '') + }) + }) + // for now we will only jsx mapped to javascript, tsx mapped to typescript, all other language should remain the same describe('test covertCwsprRequest', function () { const leftFileContent = 'left' diff --git a/packages/core/src/codewhisperer/util/editorContext.ts b/packages/core/src/codewhisperer/util/editorContext.ts index 58301e176f6..a3f787af6c6 100644 --- a/packages/core/src/codewhisperer/util/editorContext.ts +++ b/packages/core/src/codewhisperer/util/editorContext.ts @@ -25,19 +25,125 @@ import { predictionTracker } from '../nextEditPrediction/activation' let tabSize: number = getTabSizeSetting() +function getEnclosingNotebook(editor: vscode.TextEditor): vscode.NotebookDocument | undefined { + // For notebook cells, find the existing notebook with a cell that matches the current editor. + return vscode.workspace.notebookDocuments.find( + (nb) => + nb.notebookType === 'jupyter-notebook' && nb.getCells().some((cell) => cell.document === editor.document) + ) +} + +export function getNotebookContext( + notebook: vscode.NotebookDocument, + editor: vscode.TextEditor, + languageName: string, + caretLeftFileContext: string, + caretRightFileContext: string +) { + // Expand the context for a cell inside of a noteboo with whatever text fits from the preceding and subsequent cells + const allCells = notebook.getCells() + const cellIndex = allCells.findIndex((cell) => cell.document === editor.document) + // Extract text from prior cells if there is enough room in left file context + if (caretLeftFileContext.length < CodeWhispererConstants.charactersLimit - 1) { + const leftCellsText = getNotebookCellsSliceContext( + allCells.slice(0, cellIndex), + CodeWhispererConstants.charactersLimit - (caretLeftFileContext.length + 1), + languageName, + true + ) + if (leftCellsText.length > 0) { + caretLeftFileContext = addNewlineIfMissing(leftCellsText) + caretLeftFileContext + } + } + // Extract text from subsequent cells if there is enough room in right file context + if (caretRightFileContext.length < CodeWhispererConstants.charactersLimit - 1) { + const rightCellsText = getNotebookCellsSliceContext( + allCells.slice(cellIndex + 1), + CodeWhispererConstants.charactersLimit - (caretRightFileContext.length + 1), + languageName, + false + ) + if (rightCellsText.length > 0) { + caretRightFileContext = addNewlineIfMissing(caretRightFileContext) + rightCellsText + } + } + return { caretLeftFileContext, caretRightFileContext } +} + +export function getNotebookCellContext(cell: vscode.NotebookCell, referenceLanguage?: string): string { + // Extract the text verbatim if the cell is code and the cell has the same language. + // Otherwise, add the correct comment string for the reference language + const cellText = cell.document.getText() + if ( + cell.kind === vscode.NotebookCellKind.Markup || + (runtimeLanguageContext.normalizeLanguage(cell.document.languageId) ?? cell.document.languageId) !== + referenceLanguage + ) { + const commentPrefix = runtimeLanguageContext.getSingleLineCommentPrefix(referenceLanguage) + if (commentPrefix === '') { + return cellText + } + return cell.document + .getText() + .split('\n') + .map((line) => `${commentPrefix}${line}`) + .join('\n') + } + return cellText +} + +export function getNotebookCellsSliceContext( + cells: vscode.NotebookCell[], + maxLength: number, + referenceLanguage: string, + fromStart: boolean +): string { + // Extract context from array of notebook cells that fits inside `maxLength` characters, + // from either the start or the end of the array. + let output: string[] = [] + if (!fromStart) { + cells = cells.reverse() + } + cells.some((cell) => { + const cellText = addNewlineIfMissing(getNotebookCellContext(cell, referenceLanguage)) + if (cellText.length > 0) { + if (cellText.length >= maxLength) { + if (fromStart) { + output.push(cellText.substring(0, maxLength)) + } else { + output.push(cellText.substring(cellText.length - maxLength)) + } + return true + } + output.push(cellText) + maxLength -= cellText.length + } + }) + if (!fromStart) { + output = output.reverse() + } + return output.join('') +} + +export function addNewlineIfMissing(text: string): string { + if (text.length > 0 && !text.endsWith('\n')) { + text += '\n' + } + return text +} + export function extractContextForCodeWhisperer(editor: vscode.TextEditor): codewhispererClient.FileContext { const document = editor.document const curPos = editor.selection.active const offset = document.offsetAt(curPos) - const caretLeftFileContext = editor.document.getText( + let caretLeftFileContext = editor.document.getText( new vscode.Range( document.positionAt(offset - CodeWhispererConstants.charactersLimit), document.positionAt(offset) ) ) - - const caretRightFileContext = editor.document.getText( + let caretRightFileContext = editor.document.getText( new vscode.Range( document.positionAt(offset), document.positionAt(offset + CodeWhispererConstants.charactersLimit) @@ -48,6 +154,19 @@ export function extractContextForCodeWhisperer(editor: vscode.TextEditor): codew languageName = runtimeLanguageContext.normalizeLanguage(editor.document.languageId) ?? editor.document.languageId } + if (editor.document.uri.scheme === 'vscode-notebook-cell') { + const notebook = getEnclosingNotebook(editor) + if (notebook) { + ;({ caretLeftFileContext, caretRightFileContext } = getNotebookContext( + notebook, + editor, + languageName, + caretLeftFileContext, + caretRightFileContext + )) + } + } + return { filename: getFileRelativePath(editor), programmingLanguage: { diff --git a/packages/core/src/codewhisperer/util/runtimeLanguageContext.ts b/packages/core/src/codewhisperer/util/runtimeLanguageContext.ts index 9a495cf5356..3a1403b453e 100644 --- a/packages/core/src/codewhisperer/util/runtimeLanguageContext.ts +++ b/packages/core/src/codewhisperer/util/runtimeLanguageContext.ts @@ -58,6 +58,13 @@ export class RuntimeLanguageContext { */ private supportedLanguageExtensionMap: ConstantMap + /** + * A map storing single-line comment prefixes for different languages + * Key: CodewhispererLanguage + * Value: Comment prefix string + */ + private languageSingleLineCommentPrefixMap: ConstantMap + constructor() { this.supportedLanguageMap = createConstantMap< CodeWhispererConstants.PlatformLanguageId | CodewhispererLanguage, @@ -146,6 +153,39 @@ export class RuntimeLanguageContext { psm1: 'powershell', r: 'r', }) + this.languageSingleLineCommentPrefixMap = createConstantMap({ + c: '// ', + cpp: '// ', + csharp: '// ', + dart: '// ', + go: '// ', + hcl: '# ', + java: '// ', + javascript: '// ', + json: '// ', + jsonc: '// ', + jsx: '// ', + kotlin: '// ', + lua: '-- ', + php: '// ', + plaintext: '', + powershell: '# ', + python: '# ', + r: '# ', + ruby: '# ', + rust: '// ', + scala: '// ', + shell: '# ', + sql: '-- ', + swift: '// ', + systemVerilog: '// ', + tf: '# ', + tsx: '// ', + typescript: '// ', + vue: '', // vue lacks a single-line comment prefix + yaml: '# ', + yml: '# ', + }) } /** @@ -159,6 +199,16 @@ export class RuntimeLanguageContext { return this.supportedLanguageMap.get(languageId) } + /** + * Get the comment prefix for a given language + * @param language The language to get comment prefix for + * @returns The comment prefix string, or empty string if not found + */ + public getSingleLineCommentPrefix(language?: string): string { + const normalizedLanguage = this.normalizeLanguage(language) + return normalizedLanguage ? (this.languageSingleLineCommentPrefixMap.get(normalizedLanguage) ?? '') : '' + } + /** * Normalize client side language id to service aware language id (service is not aware of jsx/tsx) * Only used when invoking CodeWhisperer service API, for client usage please use normalizeLanguage From c97740e8ea85be21a42067566cf33ed30a82708c Mon Sep 17 00:00:00 2001 From: Zoe Lin <60411978+zixlin7@users.noreply.github.com> Date: Tue, 13 May 2025 10:21:34 -0700 Subject: [PATCH 14/36] feat(amazonq): import userWrittenCode configuration for inline with lsp (#7281) ## Problem Add importAdder and userWrittenCode configuration to inline with LSP ## Solution --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --- packages/amazonq/src/lsp/client.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index 4af113b13c4..0b32a6b57ae 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -333,6 +333,8 @@ function getConfigSection(section: ConfigSection) { includeSuggestionsWithCodeReferences: CodeWhispererSettings.instance.isSuggestionsWithCodeReferencesEnabled(), shareCodeWhispererContentWithAWS: !CodeWhispererSettings.instance.isOptoutEnabled(), + includeImportsWithSuggestions: CodeWhispererSettings.instance.isImportRecommendationEnabled(), + sendUserWrittenCodeMetrics: true, }, ] case 'aws.logLevel': From 143e35ced83bbe2caa96817ff0a70db7b24217fc Mon Sep 17 00:00:00 2001 From: Nikolas Komonen <118216176+nkomonen-amazon@users.noreply.github.com> Date: Tue, 13 May 2025 18:30:23 -0400 Subject: [PATCH 15/36] fix(amazonq): push customizations on startup (#7297) ## Problem At the startup of the extension, the customization that a user already decided previously was not being pushed to flare. The only time we would push the customization to flare was if the customization was changed. Otherwise everything else works as expected. ## Solution On startup, push the customization to flare (if it already exists) --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. Signed-off-by: nkomonen-amazon --- packages/amazonq/src/lsp/chat/activation.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/amazonq/src/lsp/chat/activation.ts b/packages/amazonq/src/lsp/chat/activation.ts index 9dd1d31c3de..3a36377b9b5 100644 --- a/packages/amazonq/src/lsp/chat/activation.ts +++ b/packages/amazonq/src/lsp/chat/activation.ts @@ -25,6 +25,11 @@ export async function activate(languageClient: LanguageClient, encryptionKey: Bu type: 'profile', profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn, }) + // We need to push the cached customization on startup explicitly + await pushConfigUpdate(languageClient, { + type: 'customization', + customization: getSelectedCustomization(), + }) const provider = new AmazonQChatViewProvider(mynahUIPath) From 3f5fa1783297d5cd13b25b1243ec65dd5142664b Mon Sep 17 00:00:00 2001 From: chungjac Date: Tue, 13 May 2025 17:05:25 -0700 Subject: [PATCH 16/36] deps: bump @aws-toolkits/telemetry to 1.0.319 (#7300) ## Problem - Added new metrics in aws-toolkit-common package: https://github.com/aws/aws-toolkit-common/pull/1024 ## Solution - Consume latest version of aws-toolkit-common package --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index e5f1e7e7a70..f2e583508b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "vscode-nls-dev": "^4.0.4" }, "devDependencies": { - "@aws-toolkits/telemetry": "^1.0.318", + "@aws-toolkits/telemetry": "^1.0.319", "@playwright/browser-chromium": "^1.43.1", "@stylistic/eslint-plugin": "^2.11.0", "@types/he": "^1.2.3", @@ -10760,10 +10760,11 @@ } }, "node_modules/@aws-toolkits/telemetry": { - "version": "1.0.318", - "resolved": "https://registry.npmjs.org/@aws-toolkits/telemetry/-/telemetry-1.0.318.tgz", - "integrity": "sha512-L64GJ+KRN0fdTIx1CPIbbgBeFcg9DilsIxfjeZyod7ld0mw6he70rPopBtK4jP+pTEkfUE4wTRsaco1nWXz3+w==", + "version": "1.0.319", + "resolved": "https://registry.npmjs.org/@aws-toolkits/telemetry/-/telemetry-1.0.319.tgz", + "integrity": "sha512-NMydYKj2evnYGQuVFoR1pHkyjimu/f5NYiMT4BJBUaKWsaUyxuFoYs497PXtg4ZlJx/sxj11rLLgjZR/ciIVQw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "ajv": "^6.12.6", "cross-spawn": "^7.0.6", diff --git a/package.json b/package.json index f4b31c22d83..493327237eb 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "skippedTestReport": "ts-node ./scripts/skippedTestReport.ts ./packages/amazonq/test/e2e/" }, "devDependencies": { - "@aws-toolkits/telemetry": "^1.0.318", + "@aws-toolkits/telemetry": "^1.0.319", "@playwright/browser-chromium": "^1.43.1", "@stylistic/eslint-plugin": "^2.11.0", "@types/he": "^1.2.3", From 6081f890bdbb91fcd8b60c4cc0abb65b15d4a38d Mon Sep 17 00:00:00 2001 From: Lei Gao <97199248+leigaol@users.noreply.github.com> Date: Tue, 13 May 2025 18:22:39 -0700 Subject: [PATCH 17/36] fix(amazonq):support chat in al2 aarch64 and CDM (#7270) ## Problem LSP cannot start without GLIBC>=2.28 in AL2 aarch64 and CloudDevMachine ## Solution --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --- ...-bb976b5f-7697-42d8-89a9-8e96310a23f4.json | 4 ++++ packages/amazonq/src/extension.ts | 4 ++-- packages/amazonq/src/lsp/client.ts | 19 ++++++++----------- .../core/src/amazonq/lsp/lspController.ts | 4 ++-- packages/core/src/shared/index.ts | 2 +- packages/core/src/shared/telemetry/util.ts | 4 ++-- packages/core/src/shared/vscode/env.ts | 14 ++++++-------- .../core/src/test/shared/vscode/env.test.ts | 17 +++++++---------- 8 files changed, 32 insertions(+), 36 deletions(-) create mode 100644 packages/amazonq/.changes/next-release/Bug Fix-bb976b5f-7697-42d8-89a9-8e96310a23f4.json diff --git a/packages/amazonq/.changes/next-release/Bug Fix-bb976b5f-7697-42d8-89a9-8e96310a23f4.json b/packages/amazonq/.changes/next-release/Bug Fix-bb976b5f-7697-42d8-89a9-8e96310a23f4.json new file mode 100644 index 00000000000..988fb2bcc7b --- /dev/null +++ b/packages/amazonq/.changes/next-release/Bug Fix-bb976b5f-7697-42d8-89a9-8e96310a23f4.json @@ -0,0 +1,4 @@ +{ + "type": "Bug Fix", + "description": "Support chat in AL2 aarch64" +} diff --git a/packages/amazonq/src/extension.ts b/packages/amazonq/src/extension.ts index 5ae9e397119..45641b37440 100644 --- a/packages/amazonq/src/extension.ts +++ b/packages/amazonq/src/extension.ts @@ -33,7 +33,7 @@ import { maybeShowMinVscodeWarning, Experiments, isSageMaker, - isAmazonInternalOs, + isAmazonLinux2, } from 'aws-core-vscode/shared' import { ExtStartUpSources } from 'aws-core-vscode/telemetry' import { VSCODE_EXTENSION_ID } from 'aws-core-vscode/utils' @@ -123,7 +123,7 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is await activateCodeWhisperer(extContext as ExtContext) if ( (Experiments.instance.get('amazonqLSP', true) || Auth.instance.isInternalAmazonUser()) && - (!isAmazonInternalOs() || (await hasGlibcPatch())) + (!isAmazonLinux2() || hasGlibcPatch()) ) { // start the Amazon Q LSP for internal users first // for AL2, start LSP if glibc patch is found diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index 0b32a6b57ae..5559afb9f1d 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -31,8 +31,7 @@ import { getLogger, undefinedIfEmpty, getOptOutPreference, - isAmazonInternalOs, - fs, + isAmazonLinux2, getClientId, extensionVersion, } from 'aws-core-vscode/shared' @@ -45,8 +44,11 @@ import { telemetry } from 'aws-core-vscode/telemetry' const localize = nls.loadMessageBundle() const logger = getLogger('amazonqLsp.lspClient') -export async function hasGlibcPatch(): Promise { - return await fs.exists('/opt/vsc-sysroot/lib64/ld-linux-x86-64.so.2') +export const glibcLinker: string = process.env.VSCODE_SERVER_CUSTOM_GLIBC_LINKER || '' +export const glibcPath: string = process.env.VSCODE_SERVER_CUSTOM_GLIBC_PATH || '' + +export function hasGlibcPatch(): boolean { + return glibcLinker.length > 0 && glibcPath.length > 0 } export async function startLanguageServer( @@ -71,13 +73,8 @@ export async function startLanguageServer( const traceServerEnabled = Settings.instance.isSet(`${clientId}.trace.server`) let executable: string[] = [] // apply the GLIBC 2.28 path to node js runtime binary - if (isAmazonInternalOs() && (await hasGlibcPatch())) { - executable = [ - '/opt/vsc-sysroot/lib64/ld-linux-x86-64.so.2', - '--library-path', - '/opt/vsc-sysroot/lib64', - resourcePaths.node, - ] + if (isAmazonLinux2() && hasGlibcPatch()) { + executable = [glibcLinker, '--library-path', glibcPath, resourcePaths.node] getLogger('amazonqLsp').info(`Patched node runtime with GLIBC to ${executable}`) } else { executable = [resourcePaths.node] diff --git a/packages/core/src/amazonq/lsp/lspController.ts b/packages/core/src/amazonq/lsp/lspController.ts index 3b7bd98a61d..5a1b84b7c49 100644 --- a/packages/core/src/amazonq/lsp/lspController.ts +++ b/packages/core/src/amazonq/lsp/lspController.ts @@ -11,7 +11,7 @@ import { activate as activateLsp, LspClient } from './lspClient' import { telemetry } from '../../shared/telemetry/telemetry' import { isCloud9 } from '../../shared/extensionUtilities' import globals, { isWeb } from '../../shared/extensionGlobals' -import { isAmazonInternalOs } from '../../shared/vscode/env' +import { isAmazonLinux2 } from '../../shared/vscode/env' import { WorkspaceLspInstaller } from './workspaceInstaller' import { lspSetupStage } from '../../shared/lsp/utils/setupStage' import { RelevantTextDocumentAddition } from '../../codewhispererChat/controllers/chat/model' @@ -165,7 +165,7 @@ export class LspController { } async trySetupLsp(context: vscode.ExtensionContext, buildIndexConfig: BuildIndexConfig) { - if (isCloud9() || isWeb() || isAmazonInternalOs()) { + if (isCloud9() || isWeb() || isAmazonLinux2()) { this.logger.warn('Skipping LSP setup. LSP is not compatible with the current environment. ') // do not do anything if in Cloud9 or Web mode or in AL2 (AL2 does not support node v18+) return diff --git a/packages/core/src/shared/index.ts b/packages/core/src/shared/index.ts index 4cda5285f69..f4c78e2093c 100644 --- a/packages/core/src/shared/index.ts +++ b/packages/core/src/shared/index.ts @@ -18,7 +18,7 @@ export * from './extensionUtilities' export * from './extensionStartup' export { RegionProvider } from './regions/regionProvider' export { Commands } from './vscode/commands2' -export { getMachineId, getServiceEnvVarConfig, isAmazonInternalOs } from './vscode/env' +export { getMachineId, getServiceEnvVarConfig, isAmazonLinux2 } from './vscode/env' export { getLogger } from './logger/logger' export { activateExtension, openUrl } from './utilities/vsCodeUtils' export { waitUntil, sleep, Timeout } from './utilities/timeoutUtils' diff --git a/packages/core/src/shared/telemetry/util.ts b/packages/core/src/shared/telemetry/util.ts index 4d136bc96f0..310c36b82d6 100644 --- a/packages/core/src/shared/telemetry/util.ts +++ b/packages/core/src/shared/telemetry/util.ts @@ -15,7 +15,7 @@ import { isAutomation, isRemoteWorkspace, isCloudDesktop, - isAmazonInternalOs, + isAmazonLinux2, } from '../vscode/env' import { addTypeName } from '../utilities/typeConstructors' import globals, { isWeb } from '../extensionGlobals' @@ -290,7 +290,7 @@ export async function getComputeEnvType(): Promise { } else if (isSageMaker()) { return web ? 'sagemaker-web' : 'sagemaker' } else if (isRemoteWorkspace()) { - if (isAmazonInternalOs()) { + if (isAmazonLinux2()) { if (await isCloudDesktop()) { return 'cloudDesktop-amzn' } diff --git a/packages/core/src/shared/vscode/env.ts b/packages/core/src/shared/vscode/env.ts index 004db0efc27..02d46ae6695 100644 --- a/packages/core/src/shared/vscode/env.ts +++ b/packages/core/src/shared/vscode/env.ts @@ -125,23 +125,21 @@ export function isRemoteWorkspace(): boolean { } /** - * There is Amazon Linux 2, but additionally an Amazon Linux 2 Internal. - * The internal version is for Amazon employees only. And this version can - * be used by either EC2 OR CloudDesktop. It is not exclusive to either. + * There is Amazon Linux 2. * - * Use {@link isCloudDesktop()} to know if we are specifically using it. + * Use {@link isCloudDesktop()} to know if we are specifically using internal Amazon Linux 2. * - * Example: `5.10.220-188.869.amzn2int.x86_64` + * Example: `5.10.220-188.869.amzn2int.x86_64` or `5.10.236-227.928.amzn2.x86_64` (Cloud Dev Machine) */ -export function isAmazonInternalOs() { - return os.release().includes('amzn2int') && process.platform === 'linux' +export function isAmazonLinux2() { + return (os.release().includes('.amzn2int.') || os.release().includes('.amzn2.')) && process.platform === 'linux' } /** * Returns true if we are in an internal Amazon Cloud Desktop */ export async function isCloudDesktop() { - if (!isAmazonInternalOs()) { + if (!isAmazonLinux2()) { return false } diff --git a/packages/core/src/test/shared/vscode/env.test.ts b/packages/core/src/test/shared/vscode/env.test.ts index ef81bdf05ab..cf09d085e68 100644 --- a/packages/core/src/test/shared/vscode/env.test.ts +++ b/packages/core/src/test/shared/vscode/env.test.ts @@ -5,13 +5,7 @@ import assert from 'assert' import path from 'path' -import { - isCloudDesktop, - getEnvVars, - getServiceEnvVarConfig, - isAmazonInternalOs as isAmazonInternalOS, - isBeta, -} from '../../../shared/vscode/env' +import { isCloudDesktop, getEnvVars, getServiceEnvVarConfig, isAmazonLinux2, isBeta } from '../../../shared/vscode/env' import { ChildProcess } from '../../../shared/utilities/processUtils' import * as sinon from 'sinon' import os from 'os' @@ -103,13 +97,16 @@ describe('env', function () { assert.strictEqual(isBeta(), expected) }) - it('isAmazonInternalOS', function () { + it('isAmazonLinux2', function () { sandbox.stub(process, 'platform').value('linux') const versionStub = stubOsVersion('5.10.220-188.869.amzn2int.x86_64') - assert.strictEqual(isAmazonInternalOS(), true) + assert.strictEqual(isAmazonLinux2(), true) + + versionStub.returns('5.10.236-227.928.amzn2.x86_64') + assert.strictEqual(isAmazonLinux2(), true) versionStub.returns('5.10.220-188.869.NOT_INTERNAL.x86_64') - assert.strictEqual(isAmazonInternalOS(), false) + assert.strictEqual(isAmazonLinux2(), false) }) it('isCloudDesktop', async function () { From 229126e33dee62e99632b7c865c36a7459d1db34 Mon Sep 17 00:00:00 2001 From: Nikolas Komonen <118216176+nkomonen-amazon@users.noreply.github.com> Date: Wed, 14 May 2025 12:58:00 -0400 Subject: [PATCH 18/36] docs(amazonq): How to export logs (#7308) Add doc how to export logs --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. Signed-off-by: nkomonen-amazon --- CONTRIBUTING.md | 3 +++ docs/images/exportAmazonQLogs.png | Bin 0 -> 117008 bytes docs/images/openExportLogs.png | Bin 0 -> 110167 bytes 3 files changed, 3 insertions(+) create mode 100644 docs/images/exportAmazonQLogs.png create mode 100644 docs/images/openExportLogs.png diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6c9bcba59f5..04dbdd11a26 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -387,6 +387,9 @@ If you need to report an issue attach these to give the most detailed informatio 4. Open the Command Palette again and select `Reload Window`. 5. Now you should see additional `[debug]` prefixed logs in the output. - ![](./docs/images/logsDebugLog.png) +6. To export logs, click the kebab (`...`), select `Export Logs`, and then select the appropriate channel (`Amazon Q Logs` for Amazon Q) + - ![](./docs/images/openExportLogs.png) + - ![](./docs/images/exportAmazonQLogs.png) ### Telemetry diff --git a/docs/images/exportAmazonQLogs.png b/docs/images/exportAmazonQLogs.png new file mode 100644 index 0000000000000000000000000000000000000000..ae74b3c7df135ed1c3f47c4913dec8922e3e5d14 GIT binary patch literal 117008 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 literal 0 HcmV?d00001 diff --git a/docs/images/openExportLogs.png b/docs/images/openExportLogs.png new file mode 100644 index 0000000000000000000000000000000000000000..4a9902f8c284b4079ea016912dfc2af07ae58734 GIT binary patch literal 110167 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
  • S@ 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¥$=5$ zovuyx&7df7Y(gK-1@-eLFN~Im^!ZfSUD{QO2};(er(9FQ>{S_VxSSCOb50YtrEe6Y z$?r?+f%;*}B_%4P=>5S+;GkZi-QXYI1KQF18@sR>G4x&WrISfx#99+{(oL4#nNF@X zN)VCdi+2Ez!C z^`E|T%lcj}o+A{yeEAHYQdf7&tx-bU(@2$(VtK*j{ z?As(2Mi-Oocf{7Du7>)5UHPk=k{NUh17x@H&pH7pSa+fKI@wA`=Z%Bv22@~uCp3{b$cXeFuQ|glcklue2 zRC@WMGq5J%lt0|Ozf0gi#50jBDo`N0war)J3;;4EKw}O_1z2IMY$>|3e+WtZ$Y%hd z7bCpa-aDG*K$}h7%(dI%aA#^{$h>hceg4G4=_Vs27O0hm!O5}pDE4t#-Q)KhAXk-&Ez6~^NqwFXmH?d z>VW5C?{(UwZF3i7J)(`2%qsrR#F7VRN~M=DMHvJ&Lh>nqU1tqklA>E@^QE%7+I}fj z@lW&L=rBP00SI#6k2-tg3xDWa_! zOxrWWOCwg>Lsa_@UGHwOhCdU0DHvTd5{4`*GYqT|)w8EVyViEw zJ^sP>IRP-eeiKWnI1c5<{lSNT-LsIcjxDsZ@)Qm2SQ&T*3t7IJadY4rtGeh zPFp+1C;_^Ho2~{9Wv;%dXg@_R5}^8G_*Fa0|Ep1^21>Mj^f$vx0~JEGU2Og9rn5(j zoF2%9vLsPcWS3XDPH81vVIkHvtl<^*@tpwnaO$fqRJTJ-dZoO%J3v;vm#+;NO~*H# zW54M-w?bc%1Gy&I@%`rExR+I3n(;W1c!>3H2-_BF`RX5(tjax#r^xS?f-`j<;CC_k z85>UgR(74gx*181q`0<``XEkwb5Y^EgoRyC07U!0hsD*!&wtTT>G$H0h~VDj{whG!Cp*K<%|N8*;AYH`S(s$*)Y+VPB%JQG8g!tjKz7N%6SQ z-l&5Cz{5*x9PVY2MM$eGTLc7cxtO_b%1uqJPWHKpD{MZU?MzZv+4b;10o!r%j#)b8 z#S^JD!0HC;-QDKwpPr)W{6P6{rM<+mC+;r--Kh5h{;jr_mX-nsGm>BF7hnnP?DwJx z%aITuJBcj0NZLuztDzs9Ht4M#d*64|R=+G@jr55?MzZa`tMW(;os>CH@`)Y&OCn{cd7rPiDewj2G8_w*#@D3zd zb-#@T7T|V`-7-Gc>BVWS7Hm<05CUDV4snO9Wzk#f0@iKkLl4<`{2)Bgm;w$Uunc0^^`6_7UfxdEX2Vzkv>YlfUB8{<`0W9F8fI;ELTTeNKq#oP>%7g^ z_DlKWD=G9Nl8R$D|6pL6s~zgl39;HG19j^C<}7ccyYe$*;kNw`OcInu4B}0!1M*H{ z$1rb(0aU{dij|k@p)NzIppd7tZ^lxO9v^NjM@wB&Uan1BtVBzNczT@UMZz}XnU_)0 zcM6@q3PkWp`P47q>qjJ5QC6nEtk6D`k+Ik%`9>B z6cL1Gt`#EDzQ07@;&GP{&GHWmdiweexAHAtypw}-GvJZ~vo#=)df?*l-|X99H!~xp z1z=&`u0IgTxtHP7rq3A_mKpY$?}55rCN8|YAPWp}IIS|A=w>{2JWAaUJXp)I`hdo??BYSx^@+$YzrdeRB@0%H=NLV^Eo z*AP1%w~Y9pvO25YGD7-S&HqVGa&hzhI{>cu+~HTzFj-AKaaJT~slvdpN`0$2&E-Ou zI>o~90+<6&4#Wf4;OVM$gP845aBL8IV-s;n+XEH^4a_i5-%Q*EXaQ@|HFN%O)vZKk zB2qz&M=sEN1^q1NfIh(7zRdyvIUoz ze7HiGhD`yONqj86&||on*Spm50x*m{+wm4HopMs5{(Z$4zd?wfnLBkeJWt#HXP_A` zWcv|t#XDOVzz$LW_VdDMb80mYxWskV(l@CeYpThFuzQef>2|GWa569&=p*s0q3P7o z>?L4nnBAnF!tod%``TiswCbd^vEnJ3HwG?3L+!4CdaTtJt6O->iGc)AJu=^nD7S}Q zFeo5>+3_NcyrG%m+1d_zE_^EFuiv`Haw@+(hi&6RFXgoITH!O^zEDc|$ z&O2lYUMi{c@;ImO;T#qKFwSm5P$VMKtL-KylPvN(%NovYr%FYwLb68f@h`DKACl_p zp^!1m0c^Dr5=_Si>lK69oB6;Aztnf;S<0JJozGOk6FSYqk?|BtQ?x?s)2`~Dm29G< z&4!Ucf@IBFJSaD>N*JNXj^BDxaXWkV=*Cl2E05pUCtbFb`-dq3T*5g%TU<$}IQx^! ze+MMw-W8@+x?TH+tl|s~0&diLYAFgL&hF`2XtCG)`w0xe3Pj5ri`(31PZMs00OZd* z_xg_B{0=bVATp4J^VbLe#gVygSl@ZJVQZlvteo$h&;3WkPt@BA33gdQ<2PTVya-`t z8-b#9pArHIzL=WXw%3{wO#g;r%zUc)rxN@0+1kHB_mGwx=T`*Zt$Z z|6G^qrZbIYS+*lC>ylGI$HDAZr~ZgPb@QP(yQ=zb&?roDcukBIe~gsH8>BmST5cUT zv|w~zDGCh#-at}?SGEJaW$5Ck!O`p8IVdH;M$0zp4yhWeMyU=$D#wU-$Z66 zjL8F)&xY!aCoy z!z(>678w99oH_)vhUg(5?J|;X!YnSLk8v5DN)T?WA3ey7V7^WS1MihO%q}Q;j+8Lw z4YTx1cuNd@6*6JYr}o*|@3t#BDr_=#$MbGgpA@n+)TWuKC4}7+X3>*pGEvdXwfzOzJ1?nYsteWN?F~8wb2{4VrLVP6ESRdQnro6A8La>>u8h&o=z4hq|eKw1pl# zdA!EuTT>&@Lu6oOKC)pN+CU7gpaJMpe6QK#V;zq-D>`C|Vj%w;#9as&0m>a;j0!O? z#1Qy^3K1Lig1wiZsj~Iash(EGg)g!WG3yKJYgCeL%-D!) zi{SOw_^9s$`jHvXStH|}m&A}3)unDd5?HVnp_^Q;)wY)hj1Jo4;;qv5cvm5->pbD| zlhR@f76hkn{8lP8#pAr@wmClYuT|rDH4L4AkHKX(mn!A)@>huV=Tg%*{qg z8Rj^9Pyoz8M_07J=^!w4UtFS+2-J(;3p!Ny*J73y{F1=@MabUBWXCY>BmS?BscIQi zY>W!A1E3$mib|G7Cxe#jFTt$5-(FQvV6He(QZwGnf9=B+`0$!@K=4clfAEh_hwQM! zex$V5BA%NE6ZYnCH#avM56MXG7y);hLsb{|NM+6Ez3%iVI*9_LuuC;4GwFIEtaXsy z3Tpy6WV3vkMro@hl<+Bb1n$_?ko-`#lv2d1jdSc%AdQkA02It8+ELIr7rVDM&rKbM^ zVY&q9Dn$9KBF-)rd;t=ojTtQ_8A1Q3te$Cnj&z`dp!dO-`s$?&y^!FXDG*Gna?O0$ z%Rv;esRkc?bXx)E&%veQ&())~_?=Bvj4x#6x<)qJt6$7Fhdw&%S%~1_+WEta-~+J)aH9o$XxaFpzax~pk+blqWWqH z`0iS7clX^nS>jiKr%+Ad-D~r-ykMFJxQJ$P9VJt=$`38}wCf@xUZ6$O(LrDEPTyoK z^CrL-r9bQz&`eHZ#j{^Yo~pI!%^maUc}e?z9pz2OHag{}OJpGAflC|DGASnMK)OD|?A#x7qKF zjQrMpGe{{DJgqSUn0nZ24jHJea`p&0{rcE80Cb`2ER#BA8rI4|;buci7dcOFYnw)i z+cCkbYZlhfQ+y>2Pkx3||5D!$bt#)RzG-JD8WIN3yaB>RIhr+c+-tdu96a?t0`IaE zG?ieWR+hsrj+z|_LT@P(g+zI=)oOlHBD?9{HgTL?h2lDI8!_T$577 zIQRcw&3$=1)ZOW%2tW7Q;MXJ z7-4Klma%3T8N=_sXUg`y^Xc{aJiq7r`u0y#?|bk2oO91P_iXpP&4a!;4?hRDyb9$r zkQ+E4ZUF3CX-*qjQd&i(o^0KepL851(gIX`J7-}*1t~sl-VG=(xfA9SG7{KQ7SyIo z7oNA;E7!WwVytn^-RmYOHHKW)YFFIpWoWkf64psskHa0`KXE>14+=Eje>foGRCaXf zU69g!al~dZep~h7t0sA}+wGf-tro_kRJsp5+J4uGOZ>i}u~W^7WGqIYXcy+V1;~Jh zF4*t4S!LD7?hC1<#GL+Y{o~GM_G4k?Dow5g47e}iJmP!B!qZ?h^9s-HUgs|lF@EM- zDrE8o3q2^M{IZ;>U|DJt4}LS^^@<3%PE0sdygwvQ;x!gLcCmD&A#x9e>sUL<{NZ!u zN-=dufeDbl!4zCM?JDnkSY%tr8o$-sAHUNGb;|l$rS&a>&>S)#Cm1>2VBStNr%4(~ ze&?`y7HK;ECS%Ip+8;$GuC1-rYu-D$MLE$bkcBNmys{RQoZK>fv=4YmGDuq0)}zzP zFyzaLBa@Q!ORYjA_2KZDo+R{NMz2i@svGQr{uX0-bc(hO%of?!6)HZ`h#|k`>=Smb zm&jasCau3u6>)hMi?eX(WZ`%Cgv@xzYSLz{Zt$?JaW#C>`k8fn)ilJ ztNL#KUFv6Z$xDMj1z*vuUnolc9RA8B_imX@giWK4%Fnwe8hZwob=_M=qu%hn5}PHk zA9Mz&e@VUyoTY^OUXx2Jg-FJrQAR~lEY~n<>Jh$pV|rW)J-T9v8%mjbn~|4;eL{|A z%wHMz<{aBdMydX3?*=PuEynyoCcBGEUQ~)>V?ma~bx>vRep##DI?Cfp`U@IapPHDO zY1ZV~pLe1(NGc^OV@u-az%~#ha0~E~(bfAXM9SyZurc4z00Lnbbmpa1I2^sa#G+_I z7tR$Kg(WB?e?}=$jrd8~i(C#jAH=zkq>`*{qU^dQuH7d}aSKZ--EpssegzWsJni?v z_trq0l@>NfPC?A0tDv!tTZ$LnAo$0vQoTDhqsB((b0Vc8dx6Pe<*W;x->p{rL^+}fQ9G^9s z%yBlTF#k=19T7Ms;Wg(jy8~|na9LlMsg{;6X{Uu7E(}zvTmv_bx>ac*)_Bj4HhBZ! z28Ez2CBo%fqf4_Bj~qty&>^XJno_B2RkR&DHKl4M9;^cJoR^D^+8WYQ{$igGxY~|+ zQhc^Rmm2F_Ed#E^=6$)mVGblL-a5P>&@8dHB>njh6<`M0Z4f|c6n%;H&>r$?68PG= zw949D5Wkc*4Z`WMjSxc}5L9gb%Oy9wamlveWZ9}q= z^J>9FyjTh?Kj>7t>^&r5NVs&sjO}%QAiZM?D|;3D@K7wl)P>rzH73r4(*~6#JZYw# zv#z@VsoT<-U$?b_mAXFaZW6b-k;xje7Pzph6Smav)i%*!9g0m z;DFesOj>!`WKhjvM{2L4jv(VwdzCrQ`q?)_S-j0SKvlObF{sMzg89IR!ud33d>AgA zSjQ&@GCc%J}X@4gCy>f2CGx9 zhW85$Hf9b{9ypZDi5;Lrmp_vm#J{f3?~KR9HWvrh*dM}0c{I7cC^oS!+Y@^01VcSU z>#@=<{G_0oZw*x_if;uiU{2rn5uVH~t9o4J-s#f|&K}TrAaacRYvf#t@Ucrj6t3AQ zds291;u*U^lN60!yT!sA-921T#MXcXv1{poZ}c{xw0s3EiH~eL6u#N1@8lf~PLRd% zJfdaaaGd-iV}x2d1XKs41II%4uY5J2FFf;%%E#ul}O%=HBoya&L2_F503jHE%? za0MtVldy_(NZFD6?6S1qQTD&a%yS1Ax2EbW)s0igR?VMNk45B z?ZXR;M2jd4xD@LwwSLa>tn5k$3;Als7d8i^EnO*S-HsG6_^on^w*2db;{kf?pM~u< zn@GjagO=J6l7XmEqn@5#`#aTmW!l7#iVbqtUxP2zkkr@CKYkovqN_t)q|)9v*6)mc zYlAhAJ1f`Tx4~%;60jihYqk$<3#K#5SCnocOu>vhw<*BX>ih ziEdL4(lYs#TNmF3d7ur(ziwYo=gvCMvQq7B+l=%~DtgNbYQ%bJ&iL>U^4`K-B-~!b zv1di6-`STf=7}1%_|?QiR0GXlFQ+<{OH#DB4r-zddU~+EMQS-OHYLf(PPpE4RIN@2 z!O_O1t9iO196Ow-kN0VvuAGsbNu*dy_LC;%4rUbzKz<9h7wEIlpLrvp;o0= zD9z$&mLDZQkTTvl{#B`b@M+o>|K}Ac(t|{1Zkf_SbU}5A$3ueLMBLJd>f-KkO23?` zZC-lMNF(iZW%TYUf;sAEcVeoh&~+mOIPY+d&b=E^)E<4;)~t>z-$r}t()g`xq_jvK zCado^%XSTIO^#Bj1r4Y`r!acb^aYArxgvGxyc@;evX(rg38@n_* zogt`F?jAG1$Q-n%bbS^l^S+_Gw~jBoHeC_S?vUvGp`Wcz>mh7I?Qb}j1rjJ^83XFl z$xQQ0vPRF)O%s%Y_Q1f8cjKenH1o&4`o6wcuV#~$f9F(CeQ}L$q%7za(|D6(9*I{k z8Pm9_cRhWd`q4F@cG-({!8cQK(uS}L*-w!B7**9T_uT49NlmSlxcDPo%W?Q=+D6U( z46#FI%E?^fTP|BWEm+k4XeevP&xaZ-LKQyY&BCtL8^{xChhBf@#su!Zug0Qp?RM_< zwZXv-8ey|fX#wg`c6S9g<;wao%qUM`x9 z(oHFzl4}*o5mOJYTPRd)0?mI2VYwfd_Fa(U(w(dK@W9NW?0)^o&$Obx{Hvp_r=xvm}{e3^FN$XflIH-;`{4Cks@~Gg^`=T?g4rEh`Uw_aw8~qK9ANB@%$WI~T zC3!-xRir0}bXm56zsqeqM64sQy6vqm2C_10wl%IQ$Ve^7T0FMZv&%Y2O!l#B&Zz=9 z)eO|?&f0YA&XuSA)6`;`4C97dmqk#E7_}l4TX~kbnzx5-v>j#btM`>=G^Ic`(zR>F z@6dgCCWEl6)j>+m$=n9jp21~qo<+Oc5HRSw@V%2X0W;Y7)~6kZsZwksOsN|L8Jc0T z0+3M$kWsQWmwFEq1}aRXcnDfbf#>;;eW%+5Fk(*Lh5BxDl+X0rV{pDGq?4)+Ljc~xJU2A-qVpJ=GSZWJR(#{ z^GUC!e=Yg>F1KW7vu-E8W@w+SP`+n!)R5?RZgz1QQt4AK$TEV4oNN9 zBW}d5&BQg17N1VA`#O5AS1LJhP3?QBUQ}|PKYx?8a>GPaSgZXM>1$bCXw~5-&nGK9 zvDO{!X5v@@u3Ig~FT9!?T?I}(0CEz)XG8A~O`r7qB!96rNx9*9BXL;Tn;Riinkh!1 z>FdOE+NuI`-w_I48QdCqz15(Df~~c3B8G~@oH6L9oWmyji^P}Ulgz>Ydl*fvjt>)w z>7YMIZ`$Si*#TuxkzC&2F#b%*|MSPdPY#I`DrnhY8}_y?k zGlGvI8j!JR3aS)~5mNU=elkzuXNAUzRjLHHg2UE{BN@iwk<{mIHct3v;*FYf;Wl`` zNYlLL`1BgL25FrNnvp6&slb+8)V)JT9<{$Bxd{|Hp3lPy#CPD6B26Qj2_q++7-+S+ z$s`sF$m5ST$Gs^|50s2gx&#iq_J&V<^Njcf?5{bO3BTrB61P;a=CB!6?^N6P=6JIb zf6Xs%g2}54tf+b=BS0SUD7$vQz=Aya3;hMQFV<3fCoBrEW{Ul&CeKM~?CO%yI=&GH zh2$x{`Y#GZD+w$p^0)}zIJm2No`>fcn*$Qwxcq*zx@g7#*5wtwZqiHZeNR++(8 z!td+HsnXb@wl5u;nJQZ5Z(bq>C%x!l=gytM6f$MBR)=$5CXr_ahj@t0?IV53*Qru* zA_dsETHW`VZ|H%uqnl2k(y*y{U3PJ%PdtvgPiUqVh-ZLEIK9|`@PfxdR;p57`yMNDrZ2QLupnRL;*`4Fx0Wg8zm>VC-1W3j24tFp zD)Hmj%XcJcXWG83GR{ulC1BkVH+&LXC;khRZ?%_A<{f*hyfZiIYF|8Mx09;5`dyH8 z2F0Rx^~Am#Z|jb?^(w5jZ6{idsgQ^wCEbqwp{61k1O@+3+fYq`gKd|i)jf^61u|3a+!pwi68~_}t*d*ZNWivO-Mn z_sW1aFTi>dY9r80w+p6y&g(zZzWX6n>QYL(fu*}|x>93a5=IBqeAoEd!bR z)8nXp_>TR07%_`+EHZb9+IiDL>w>9XcF@+RpALw%bvy*Qdr0pX|AjkBABKr>N_U-X zZ*MY5AD3{sRL?MFBE7_(7a5+2+S&Rese_o>9O%(>y7x+E74XnPzpL+<$I{}QMwbiu z8bbDM?yygi!>&=2jYrkf@pqJCr7j)h|5THIC7>s#zP3Js3ff&nn5(ADty_F|+bilO zu_0rhOFBmqO6%ZQhqGDo^UlR|r^A^oLej<7KaIFZoSeunDydl)7|QUR$Js(oa8oX{PpYle@5=J9F+z=I zEte&@jRqsU*lXXgF;mL3w3BtN7AriwFYLP5@}At))By$OzQ8jYTm{-C8SI)nQ?97d zrKp~3A8lf!tS8f>EI{h{*508lH=Vm&XaY{xa+cNl<=7GPpfmPd{C^4>Nyo$4ix8uazYbU%6@RBx0E!~yAsH>vhi_Nnv} z|NkokiaHFMjNP?tT!>??>j;c1+(XL#?sKnjKiv!(Csf)uWS_ThNRc});$q(V<$Q_p zR860}wWnY6rdu_M^>$-zscbcP^E17vF-@LC+XFqlLvIhCC)2vWhdRCaGF*2Y_=oQN zn)7sJwzpT53a7ZhgoAS5BElOnx)yh|V?||QqvSTGD^t`H>1j+QO1h=v9Nh+TDQE3p z9hL^1-qY{CmPMXk>{Iy{TgW?Nc~OapWt5ED2Vxd*?UZYyKFvFzo=WrTD0M2XVaQ?o zlB@ir){6V~)HsY2(nG>>SzmXqI3Q^4lw5GbM7=0#JN?4w=a39ZZO ztIN&+cUV$r<2a`|Ovb`?Y{j#y8Di2G7DWad+9m8U4B05LqI%40(0!$)Iq{y_DsImS z*U!^B%NBkOS{~x~;`H^m zKizXaBy7A%R1ZE7Y>cwQPK+mQwX^dRiKyJxwj)Zx(7L}rX8dnSE$g;gvYm;DfXGV0 zW0r%)R2_2BxbNS-l4%!khsa%{vjA_}6+T zP75!C4LTpO;n$M_ib7ZGNY-UVsg%|i2d3dCUYr-cLFJAjE9jo_GZ*%Lh8)Gj>#GjnY3nE1LYi^`-)f#8@7LA+I{F$z_E#~jUTZaG_cvK>%K;ulp4H!^6S;m2UjCL?0C;Ll|gwf zq~7~crssTn?$pJpI``d_R*FwvymYZ=f#aJ3)Ee_!eD3Sr zNZ;q5k;bl*Sul`QY+{_57Ytm&WOG$++tyK&e#&yEzR+t8RBSSEt@!VETZIXAWhwr= zZn92|Quex+W|WwQPsdzLTO~tKDBzLdiK3oq9mOZr7#Gyb<{JBjn1(ms2)R)~dx3LD z5xbMjv4Ty~`^#j?`}dX=b>P9ljIni$JlUSzwDo%#mxqjo+}Kg*7F) zIAX4Js%jPT$=PYF$!oy*1^>jply}31{6^bLu91s6>?}-C*_71AfMm>3 zProUr+s0oiQSv1T9$$zq>0>y*5UO44_(0YOe>zXeIL+je!u~Q^CeCAwH11P>!-9sF zQCl0+jyKCxyJSP#*IV=)Umze7@W~z}YbK&bz&{#oH3B{nPs!OV5y2FmC{vU!6_?bU z`u2v!OHv?L?Tw1$s00rMVt?(|qOAty`5l~y^~oou+D|JIo>v@TA}V<<$hoNfr4KnR zJpcWMt~hwd+YdjH6Kl?1_eV>Mc5-IDI}43?lKJY`SghmQVri(=l9KlOBguS$I- zkak1X+p_ai{mehlgD$~2qu>2*PJ7Ms^YsgXOL7by%QcrHXN(E&dfMdxkNGr}8sG7JAN6wRhPY+C0;A`kxVEj4sT|15R?-NuyO!)p-%qu*?(a3$l!XKlqS zpuEr>pszrmndknw7RC%vyqonI=9a{e`lGp*4rVb4+MRxj|50onN{q>yKwbm9N|rys zlIeg5DP+5}?mG5af9zy33LS{-M9gs=8+w1!>FDsxN%k%f2?Zs+iio1DbeWsWnZevK z6Kof^xFynR9kK=pxCZco_bh)p?89uwD_fBb4Zp|AWCajx-vfC5Kth%H+=G5*LG%qE zHhs8Li{LN-0qNvG2#a_HhWh%SYlZDLFbC+C9FWqVZh2XzOpuB$;Xs^$O}3y9V@a+< z=5l7^?kq%%E}tMB{Bt43orSrwicqXm<5x#V@jQo2LFOv~OXCMu;Q*8EWMOLu*T-Zl z{0*26h>!-_>5e(eb>=L37|_|(=H~8M9%SC48W0 z0BNfDxl;(_z2VFl%?Ah&-1&*_EW-Fb`ZHn@u2x+z_aL72#-r|&Ym4zLsHaTGqWop?JTZYHR8mLeMm zdMO{qi`&^U0SN66n*P+T3U7r|2N2}x28QZ6+Oac+DL|~^;Cl-MR%U3U2`iBF?9R-b zcGIiAa|@+rUYz|HXr7dx*|=j&fMsEm0E$K5D}mVxyqyogfSm8-*TNq^_=IdL)a2uonL; zjAwWg`Q@ku__OiHnYQ`8N@w;Gr1#g2P4zbBrI2>PH zU3lcKnV`3So>6kb@*66_p3dqY!%vQQxA2Lgy;xY;*g1G-|3GW9vbwx~F7e=hK0^Ly z{enKd_b-Sh@;&qB{T|+ugg#xEXVt*gm$qO?<$o+sAC}9xZxKlc*Wd(Sqf%RRTZ{AM zoVqX4`ydd4CD?4-;SbpLmT+Y12ORnYUs<#zWAR*ce}gR==jEl`{$<4>_`0`QT_nyJ zQ_LTbp7GD7*6-LXN9 z*NAdQAA>G`P(rjtM{$=r96gv*uzwEJiS z8T_PWR#p=81%loVXmuI491tvQnzsYT=Ud z1CVa0T&Eqn-}g+=g{mWCI}gKH);pJttuHrCUvc&>Pw&8E0bbl;Rs2UNtB9roUcqP@ z6HUk=p<3{Fi&pyn7W3naQn{h1pBAK}UY>7S4F@p*XcHUpOy$+Ndee~2{&5R~E{yQF z+$|2%Q-!erL5;^jhKeFZzR&K%H3 zK?%q~k^>vxUzg!UoxGh0+W=NJ3l5IVl6x_-vr(GHWJ?4?+`BSDuS0>v{Te|2e)bF$ zMQw4>mPng#t2a%rIqOH^Dxi%BQkunIwr9iG4kTp(`DBZuIiPFvDo7%HeTCZTcqs}> zCH8fIHASk%;Ha~^0S2R}2&Y4N-m7pgVEVnQMPQqQ_Ci+x&?4hwcELfrxLLFXf3R%< z{As5#(2}xo($>jNWTAansNjg++6x%VLg(qmSrnVW(pv;M<>+#c8l#HC_dj5Pu4Y0!SO8g1$YX!s_ci;kOBzYKSFVa<9SgRT}WFWUIJwEGpX4cXG*j=<+PyMSy-qr`Iugx(?`eRqfsISBv6| z(1jlNJ}iI&CR%yrmkOkXZX&E(ZMXnVsc*;@Q!bbmM!4rBL_*ns29yBx{x!`R^3G<4 z7B7YtSa4EPV^0Ap#9Zcr z2b?Z{da?IAubjItlG2I2-H(%?#}6x88$i7z>Nz(Q_${%>0VmSreA)dSCKi7BlSCOx z;5w_j7?imC8K?g`C&4bb1tJgF!xl}^gd?dSC)%QBdv+oGY36P~`vuvCa67)x70}*w zuheXIo6!b^%Yf{xsmu$4)4rT*+IZ?H%V2}z#_>TGV2>Pu?xV}%J)tnZr1iRz&Xg`f0dpiC`F zcR;`)LY~yRW17}2!^A%PyaZ6mJwpccB8@*64yC03LUxk>ZkYo!l%G9pE8~zpW!WtQ z1?1iyhVZX2)w}~8aC12?u0+9|3%)@+5cP!7t-5$IWCQG^EBpYM;C_6n3v}-`BC{J` zMO=*895EZ{X+ZLT&)^<*(+y7H774(A`r7$SX!oy9o)P{h?=Sg4foJE)-2m)}#U%%( z@tO0Z5;215;-Ax;9K8)np>GIxV|0V8Z4*MEFTo&Uq=R$GTe$+t0p4a{1I&i>WZ?UE zNst%Uuw)Kc)7y9pFmQzZg}SDDLU`~UY9&+}&`sE!-kv0= z8SniBh?{<(IXocrPD-?;Tv<67%1-}cWPlOPvQ9QVE(?FR7h3MOdG9Wis|2OZEesuX zWvY!X+(%Yo9R7W02Q>eJu@%}GobIEXPvH*c9pIyg3+HA)$^MTb0}LIPJyrEBMEDR5 zu3m8ki26sOnA8I)Y*6m<`wQ^BMF8BrE_7sw`{Rb=OdND4#(0T^Id=B&E19=dhtmIQ>ax%*;14?^wheyq9x3yW}~#=hN0 zIe7o%aia?xha9V+{Ljk90|bEQ+$9(T0Kip&3GN;lP|pO+hhARPzx;XNPou4-&-r94 zUM8UiG&f+f0L3Rv3|%~O;?Z@$R7-ypoEHWjF_eJdjc;3_oWMJV1Rb0&Q>{Fw_QEZ_ zKY84uE%~+04Nyivx2OY4$``i|YQwR3y8{AK#@&_SN-h_PmMkx~fTM<+3H3SKmN5$# zY(SU|v2)j*{M_jcWj9r1hz^dj#cn6m&_BV;IP-V!^4|sB&B`mlT)!ca0AHS+8}JFw z9alJU+1-E(Oxdy!{%WtnlYo9FxA8y$^Fkw0ir>L~x3f$_6{5FH!4@~AVOd@JdLOw# z*P;Ha3tKCcTU z9B(FwWP7AP8(~71KfU;OPKuBi_CgIV27Unbb)Lma(1>5*EwD8d{6%1s{^fG}F_b@X zNJI#vXVxt035F7P)iJsbaIeP1!mSY!2xjH8HcBx;G8d@2+=nZnFGsg50<>S&d0Yc7 z03Cq#9m|rT8^g->rx?SuAr&FV%-h(K^ZPiglMkPSVo<3`$3Lg0I*Ex6)B*%#CoF?{ zLab~bK``j!W@fJTZD4^O#KO%}7H>=N)bg$X)B${n# zws^32hqwOZgQNcMPM#M2c*!9#DDb?Z0|7v|gx88NVS$2a@y8P`zlTcTEiDFpQ}P~~ zKwsjBBm$LRHI5h@fpdU8h?Y2f)Jlgc577aT>cTRK)%_tO&rTYJ?l?O~>3gcx~}f9CQcYLT6QVJg-16knMC$31Yw|LctWe_H~;&~{E!aizeluc5Dl35R{o1D|$$%AZ4>gmO8wgz*`N;ryJfK&RTp_9j4K}{}`=E+5Eg2%BX*g zdm?lJa|C*3eXdaMV^g97vJ&}_$1Y(OtR_!-c-P2jC}Mi$;a?A0<@?OP>)u< zhu~aRc?6){#A6Et6z3cQJtqpQ8TQ%Zrt=S=`3kftqM-QRN* z8eaMrqXd8x8ATATS@3tWvgQ3Y@B7XSbVH+8XlDlMJvr)df4TD@!d91aVqQsIgDRss zV4>8BC*YyFQyWB(A{__np|Q+=6eVEjIC>c0dB+IUto16SA?hC~-02s|S_0?$>wxe5 z6uaTB_GhG;DP{A08~1Z?XT6p&Aj>Ae0E!|A7O?eo?N2!grH)cMX*1IaI(IgNhwwg+CpZ2B5hr zooC{@-T-*t*rCP*@W@|<7(^376ab&7X@7?km$wrnIva~tR6}3Q%60?L??$N#lc)5^1WgS@k zqL^?ZEAaAIrJ2pgBQyq9!*-Wos0$&Q2aXsT$4)3AycLnRyWlFaN*tjzj{j;l9^m!g zmjN*1wIC;zV)K3+%08l7@_~Y$5F+1#?#*7r9;3Em#WQb^)E~f4|78p%V6*BOJfD8z zC_@M6y4;3aAUF`fqAqewg+>@yyoUh)4_!Ba3I~h#8lc7GqnQ*DaD;-VetPkcyFydCA1R z-UovH8`7DWr0jnxPGu+Eu5W@G(nwfgrkZbOV$&Wb{FD4UzH!dwK`~tXLBUYts%m@q z0=ygOhxA6v$4z^n7QF;Rc(tF$?SKYxyjOu^)-Men9PmP0Ak<$e=6}OV5voBy00kQ9 zI_?JFyHm()VUmyh-&JtjK;klo;FE9zDn9IyeBg|K`%MdudgZ@5d0O}*pMD618fR#) zLS-Oa;48vRN)2e!;!kZ{A_+A`(6S8rW{qAy52p}45yb5EmoC-L!f=`2!4LKaR5$P1#iT~(zs|`2 zwmA1`-e9a008VzQ3Evy3|Vg%(1n*1j3bF1^Vi5@K8qm zW2}=Q>9_BU$U=c%DhuM^mkR5lix(yUInotRgvYP{G_{qL5(U1m&O95xO1~u#HECqP zO1W2511HRWfwAGP&oA(k6Lp+@x8sxGgKIvjD>Y literal 0 HcmV?d00001 From 04eb09a3b51b55eb01a61b32a3f2657018857aaa Mon Sep 17 00:00:00 2001 From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> Date: Wed, 14 May 2025 11:15:27 -0700 Subject: [PATCH 19/36] deps: bump @aws-toolkits/telemetry to 1.0.321 #7307 --- package-lock.json | 9 +++++---- package.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index f2e583508b3..da3a02fa37b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "vscode-nls-dev": "^4.0.4" }, "devDependencies": { - "@aws-toolkits/telemetry": "^1.0.319", + "@aws-toolkits/telemetry": "^1.0.321", "@playwright/browser-chromium": "^1.43.1", "@stylistic/eslint-plugin": "^2.11.0", "@types/he": "^1.2.3", @@ -10760,11 +10760,12 @@ } }, "node_modules/@aws-toolkits/telemetry": { - "version": "1.0.319", - "resolved": "https://registry.npmjs.org/@aws-toolkits/telemetry/-/telemetry-1.0.319.tgz", - "integrity": "sha512-NMydYKj2evnYGQuVFoR1pHkyjimu/f5NYiMT4BJBUaKWsaUyxuFoYs497PXtg4ZlJx/sxj11rLLgjZR/ciIVQw==", + "version": "1.0.321", + "resolved": "https://registry.npmjs.org/@aws-toolkits/telemetry/-/telemetry-1.0.321.tgz", + "integrity": "sha512-pL1TZOyREfEuZjvjhAPyb/6fOaPLlXMft4i1mbHJVs2rnJBKFAsJOl3osmCLKXuqiMT7jhmzOE8dRCkEuLleIw==", "dev": true, "license": "Apache-2.0", + "license": "Apache-2.0", "dependencies": { "ajv": "^6.12.6", "cross-spawn": "^7.0.6", diff --git a/package.json b/package.json index 493327237eb..f523a29bbff 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "skippedTestReport": "ts-node ./scripts/skippedTestReport.ts ./packages/amazonq/test/e2e/" }, "devDependencies": { - "@aws-toolkits/telemetry": "^1.0.319", + "@aws-toolkits/telemetry": "^1.0.321", "@playwright/browser-chromium": "^1.43.1", "@stylistic/eslint-plugin": "^2.11.0", "@types/he": "^1.2.3", From ab781b9a073dfc961ce133caa9d38fa722b9d48b Mon Sep 17 00:00:00 2001 From: aws-toolkit-automation <> Date: Wed, 14 May 2025 18:20:29 +0000 Subject: [PATCH 20/36] Release 3.61.0 --- package-lock.json | 5 ++--- packages/toolkit/.changes/3.61.0.json | 5 +++++ packages/toolkit/CHANGELOG.md | 4 ++++ packages/toolkit/package.json | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 packages/toolkit/.changes/3.61.0.json diff --git a/package-lock.json b/package-lock.json index da3a02fa37b..3fb59c0c52e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "prettier": "^3.3.3", "prettier-plugin-sh": "^0.14.0", "pretty-quick": "^4.0.0", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "^5.0.4", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", @@ -10765,7 +10765,6 @@ "integrity": "sha512-pL1TZOyREfEuZjvjhAPyb/6fOaPLlXMft4i1mbHJVs2rnJBKFAsJOl3osmCLKXuqiMT7jhmzOE8dRCkEuLleIw==", "dev": true, "license": "Apache-2.0", - "license": "Apache-2.0", "dependencies": { "ajv": "^6.12.6", "cross-spawn": "^7.0.6", @@ -28099,7 +28098,7 @@ }, "packages/toolkit": { "name": "aws-toolkit-vscode", - "version": "3.61.0-SNAPSHOT", + "version": "3.61.0", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" diff --git a/packages/toolkit/.changes/3.61.0.json b/packages/toolkit/.changes/3.61.0.json new file mode 100644 index 00000000000..8c9ca524a61 --- /dev/null +++ b/packages/toolkit/.changes/3.61.0.json @@ -0,0 +1,5 @@ +{ + "date": "2025-05-14", + "version": "3.61.0", + "entries": [] +} \ No newline at end of file diff --git a/packages/toolkit/CHANGELOG.md b/packages/toolkit/CHANGELOG.md index e21988fcd50..e830b391487 100644 --- a/packages/toolkit/CHANGELOG.md +++ b/packages/toolkit/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.61.0 2025-05-14 + +- Miscellaneous non-user-facing changes + ## 3.60.0 2025-05-06 - Miscellaneous non-user-facing changes diff --git a/packages/toolkit/package.json b/packages/toolkit/package.json index 077030c66cb..ac0ffc753a3 100644 --- a/packages/toolkit/package.json +++ b/packages/toolkit/package.json @@ -2,7 +2,7 @@ "name": "aws-toolkit-vscode", "displayName": "AWS Toolkit", "description": "Including CodeCatalyst, Infrastructure Composer, and support for Lambda, S3, CloudWatch Logs, CloudFormation, and many other services.", - "version": "3.61.0-SNAPSHOT", + "version": "3.61.0", "extensionKind": [ "workspace" ], From 2b44176ac0bd23fd6699889ca2b02ee1e331145c Mon Sep 17 00:00:00 2001 From: aws-toolkit-automation <> Date: Wed, 14 May 2025 18:20:33 +0000 Subject: [PATCH 21/36] Release 1.67.0 --- package-lock.json | 5 ++--- packages/amazonq/.changes/1.67.0.json | 14 ++++++++++++++ ...g Fix-9b0e6490-39a8-445f-9d67-9d762de7421c.json | 4 ---- ...g Fix-bb976b5f-7697-42d8-89a9-8e96310a23f4.json | 4 ---- packages/amazonq/CHANGELOG.md | 5 +++++ packages/amazonq/package.json | 2 +- 6 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 packages/amazonq/.changes/1.67.0.json delete mode 100644 packages/amazonq/.changes/next-release/Bug Fix-9b0e6490-39a8-445f-9d67-9d762de7421c.json delete mode 100644 packages/amazonq/.changes/next-release/Bug Fix-bb976b5f-7697-42d8-89a9-8e96310a23f4.json diff --git a/package-lock.json b/package-lock.json index da3a02fa37b..dd286ad32b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "prettier": "^3.3.3", "prettier-plugin-sh": "^0.14.0", "pretty-quick": "^4.0.0", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "^5.0.4", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", @@ -10765,7 +10765,6 @@ "integrity": "sha512-pL1TZOyREfEuZjvjhAPyb/6fOaPLlXMft4i1mbHJVs2rnJBKFAsJOl3osmCLKXuqiMT7jhmzOE8dRCkEuLleIw==", "dev": true, "license": "Apache-2.0", - "license": "Apache-2.0", "dependencies": { "ajv": "^6.12.6", "cross-spawn": "^7.0.6", @@ -26385,7 +26384,7 @@ }, "packages/amazonq": { "name": "amazon-q-vscode", - "version": "1.67.0-SNAPSHOT", + "version": "1.67.0", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" diff --git a/packages/amazonq/.changes/1.67.0.json b/packages/amazonq/.changes/1.67.0.json new file mode 100644 index 00000000000..59ff03eacdd --- /dev/null +++ b/packages/amazonq/.changes/1.67.0.json @@ -0,0 +1,14 @@ +{ + "date": "2025-05-14", + "version": "1.67.0", + "entries": [ + { + "type": "Bug Fix", + "description": "Previous and subsequent cells are used as context for completion in a Jupyter notebook" + }, + { + "type": "Bug Fix", + "description": "Support chat in AL2 aarch64" + } + ] +} \ No newline at end of file diff --git a/packages/amazonq/.changes/next-release/Bug Fix-9b0e6490-39a8-445f-9d67-9d762de7421c.json b/packages/amazonq/.changes/next-release/Bug Fix-9b0e6490-39a8-445f-9d67-9d762de7421c.json deleted file mode 100644 index f17516bb8f4..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-9b0e6490-39a8-445f-9d67-9d762de7421c.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "Previous and subsequent cells are used as context for completion in a Jupyter notebook" -} diff --git a/packages/amazonq/.changes/next-release/Bug Fix-bb976b5f-7697-42d8-89a9-8e96310a23f4.json b/packages/amazonq/.changes/next-release/Bug Fix-bb976b5f-7697-42d8-89a9-8e96310a23f4.json deleted file mode 100644 index 988fb2bcc7b..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-bb976b5f-7697-42d8-89a9-8e96310a23f4.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "Support chat in AL2 aarch64" -} diff --git a/packages/amazonq/CHANGELOG.md b/packages/amazonq/CHANGELOG.md index 197aecdfdf6..ceb42f25c55 100644 --- a/packages/amazonq/CHANGELOG.md +++ b/packages/amazonq/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.67.0 2025-05-14 + +- **Bug Fix** Previous and subsequent cells are used as context for completion in a Jupyter notebook +- **Bug Fix** Support chat in AL2 aarch64 + ## 1.66.0 2025-05-09 - **Bug Fix** Avoid inline completion 'Improperly formed request' errors when file is too large diff --git a/packages/amazonq/package.json b/packages/amazonq/package.json index f9d466f5767..451707760ce 100644 --- a/packages/amazonq/package.json +++ b/packages/amazonq/package.json @@ -2,7 +2,7 @@ "name": "amazon-q-vscode", "displayName": "Amazon Q", "description": "The most capable generative AI-powered assistant for building, operating, and transforming software, with advanced capabilities for managing data and AI", - "version": "1.67.0-SNAPSHOT", + "version": "1.67.0", "extensionKind": [ "workspace" ], From ae4dbcd5d69da582776596984dcbcfa5532e334b Mon Sep 17 00:00:00 2001 From: aws-toolkit-automation <> Date: Wed, 14 May 2025 21:27:08 +0000 Subject: [PATCH 22/36] Update version to snapshot version: 3.62.0-SNAPSHOT --- package-lock.json | 4 ++-- packages/toolkit/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3fb59c0c52e..bb3080d235e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "prettier": "^3.3.3", "prettier-plugin-sh": "^0.14.0", "pretty-quick": "^4.0.0", - "ts-node": "^10.9.2", + "ts-node": "^10.9.1", "typescript": "^5.0.4", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", @@ -28098,7 +28098,7 @@ }, "packages/toolkit": { "name": "aws-toolkit-vscode", - "version": "3.61.0", + "version": "3.62.0-SNAPSHOT", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" diff --git a/packages/toolkit/package.json b/packages/toolkit/package.json index ac0ffc753a3..491031f47af 100644 --- a/packages/toolkit/package.json +++ b/packages/toolkit/package.json @@ -2,7 +2,7 @@ "name": "aws-toolkit-vscode", "displayName": "AWS Toolkit", "description": "Including CodeCatalyst, Infrastructure Composer, and support for Lambda, S3, CloudWatch Logs, CloudFormation, and many other services.", - "version": "3.61.0", + "version": "3.62.0-SNAPSHOT", "extensionKind": [ "workspace" ], From 74bd712ac33a5643fba1ff976916511b4276ce2d Mon Sep 17 00:00:00 2001 From: aws-toolkit-automation <> Date: Wed, 14 May 2025 21:33:00 +0000 Subject: [PATCH 23/36] Update version to snapshot version: 1.68.0-SNAPSHOT --- package-lock.json | 4 ++-- packages/amazonq/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index dd286ad32b2..d7810cc62ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "prettier": "^3.3.3", "prettier-plugin-sh": "^0.14.0", "pretty-quick": "^4.0.0", - "ts-node": "^10.9.2", + "ts-node": "^10.9.1", "typescript": "^5.0.4", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", @@ -26384,7 +26384,7 @@ }, "packages/amazonq": { "name": "amazon-q-vscode", - "version": "1.67.0", + "version": "1.68.0-SNAPSHOT", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" diff --git a/packages/amazonq/package.json b/packages/amazonq/package.json index 451707760ce..06c6ce3d30c 100644 --- a/packages/amazonq/package.json +++ b/packages/amazonq/package.json @@ -2,7 +2,7 @@ "name": "amazon-q-vscode", "displayName": "Amazon Q", "description": "The most capable generative AI-powered assistant for building, operating, and transforming software, with advanced capabilities for managing data and AI", - "version": "1.67.0", + "version": "1.68.0-SNAPSHOT", "extensionKind": [ "workspace" ], From 6fead6e252b897f9921b7d992ebd487b8dfb3e51 Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Wed, 14 May 2025 15:45:07 -0700 Subject: [PATCH 24/36] feat(amazonq): add inline completion support for abap language (#7303) ## Problem ## Solution --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --- package-lock.json | 8 +++--- package.json | 2 +- ...-31d91f84-30cb-4acd-9e39-9dc153edf0a6.json | 4 +++ .../util/runtimeLanguageContext.test.ts | 2 -- .../src/codewhisperer/util/editorContext.ts | 3 +-- .../util/runtimeLanguageContext.ts | 25 ++++++++++++++++--- 6 files changed, 31 insertions(+), 13 deletions(-) create mode 100644 packages/amazonq/.changes/next-release/Feature-31d91f84-30cb-4acd-9e39-9dc153edf0a6.json diff --git a/package-lock.json b/package-lock.json index bc5c33db7f1..7f7f35e42fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "vscode-nls-dev": "^4.0.4" }, "devDependencies": { - "@aws-toolkits/telemetry": "^1.0.321", + "@aws-toolkits/telemetry": "^1.0.322", "@playwright/browser-chromium": "^1.43.1", "@stylistic/eslint-plugin": "^2.11.0", "@types/he": "^1.2.3", @@ -10760,9 +10760,9 @@ } }, "node_modules/@aws-toolkits/telemetry": { - "version": "1.0.321", - "resolved": "https://registry.npmjs.org/@aws-toolkits/telemetry/-/telemetry-1.0.321.tgz", - "integrity": "sha512-pL1TZOyREfEuZjvjhAPyb/6fOaPLlXMft4i1mbHJVs2rnJBKFAsJOl3osmCLKXuqiMT7jhmzOE8dRCkEuLleIw==", + "version": "1.0.322", + "resolved": "https://registry.npmjs.org/@aws-toolkits/telemetry/-/telemetry-1.0.322.tgz", + "integrity": "sha512-KtLabV3ycRH31EAZ0xoWrdpIBG3ym8CQAqgkHd9DSefndbepPRa07atfXw73Ok9J5aA81VHCFpx1dwrLg39EcQ==", "dev": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index f523a29bbff..525655b8c35 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "skippedTestReport": "ts-node ./scripts/skippedTestReport.ts ./packages/amazonq/test/e2e/" }, "devDependencies": { - "@aws-toolkits/telemetry": "^1.0.321", + "@aws-toolkits/telemetry": "^1.0.322", "@playwright/browser-chromium": "^1.43.1", "@stylistic/eslint-plugin": "^2.11.0", "@types/he": "^1.2.3", diff --git a/packages/amazonq/.changes/next-release/Feature-31d91f84-30cb-4acd-9e39-9dc153edf0a6.json b/packages/amazonq/.changes/next-release/Feature-31d91f84-30cb-4acd-9e39-9dc153edf0a6.json new file mode 100644 index 00000000000..da0d200410d --- /dev/null +++ b/packages/amazonq/.changes/next-release/Feature-31d91f84-30cb-4acd-9e39-9dc153edf0a6.json @@ -0,0 +1,4 @@ +{ + "type": "Feature", + "description": "Add inline completion support for abap language" +} diff --git a/packages/amazonq/test/unit/codewhisperer/util/runtimeLanguageContext.test.ts b/packages/amazonq/test/unit/codewhisperer/util/runtimeLanguageContext.test.ts index a5cc430a5a9..9d2dbf7954d 100644 --- a/packages/amazonq/test/unit/codewhisperer/util/runtimeLanguageContext.test.ts +++ b/packages/amazonq/test/unit/codewhisperer/util/runtimeLanguageContext.test.ts @@ -177,7 +177,6 @@ describe('runtimeLanguageContext', function () { 'jsx', 'kotlin', 'php', - 'plaintext', 'python', 'ruby', 'rust', @@ -288,7 +287,6 @@ describe('runtimeLanguageContext', function () { ['jsx', 'jsx'], ['kotlin', 'kt'], ['php', 'php'], - ['plaintext', 'txt'], ['python', 'py'], ['ruby', 'rb'], ['rust', 'rs'], diff --git a/packages/core/src/codewhisperer/util/editorContext.ts b/packages/core/src/codewhisperer/util/editorContext.ts index a3f787af6c6..756d9fb2a00 100644 --- a/packages/core/src/codewhisperer/util/editorContext.ts +++ b/packages/core/src/codewhisperer/util/editorContext.ts @@ -151,8 +151,7 @@ export function extractContextForCodeWhisperer(editor: vscode.TextEditor): codew ) let languageName = 'plaintext' if (!checkLeftContextKeywordsForJson(document.fileName, caretLeftFileContext, editor.document.languageId)) { - languageName = - runtimeLanguageContext.normalizeLanguage(editor.document.languageId) ?? editor.document.languageId + languageName = runtimeLanguageContext.resolveLang(editor.document) } if (editor.document.uri.scheme === 'vscode-notebook-cell') { const notebook = getEnclosingNotebook(editor) diff --git a/packages/core/src/codewhisperer/util/runtimeLanguageContext.ts b/packages/core/src/codewhisperer/util/runtimeLanguageContext.ts index 3a1403b453e..e1d4802b6f1 100644 --- a/packages/core/src/codewhisperer/util/runtimeLanguageContext.ts +++ b/packages/core/src/codewhisperer/util/runtimeLanguageContext.ts @@ -67,7 +67,7 @@ export class RuntimeLanguageContext { constructor() { this.supportedLanguageMap = createConstantMap< - CodeWhispererConstants.PlatformLanguageId | CodewhispererLanguage, + Exclude, CodewhispererLanguage >({ c: 'c', @@ -85,7 +85,6 @@ export class RuntimeLanguageContext { jsx: 'jsx', kotlin: 'kotlin', packer: 'tf', - plaintext: 'plaintext', php: 'php', python: 'python', ruby: 'ruby', @@ -112,6 +111,7 @@ export class RuntimeLanguageContext { systemverilog: 'systemVerilog', verilog: 'systemVerilog', vue: 'vue', + abap: 'abap', }) this.supportedLanguageExtensionMap = createConstantMap({ c: 'c', @@ -152,6 +152,8 @@ export class RuntimeLanguageContext { ps1: 'powershell', psm1: 'powershell', r: 'r', + abap: 'abap', + acds: 'abap', }) this.languageSingleLineCommentPrefixMap = createConstantMap({ c: '// ', @@ -185,9 +187,14 @@ export class RuntimeLanguageContext { vue: '', // vue lacks a single-line comment prefix yaml: '# ', yml: '# ', + abap: '', }) } + public resolveLang(doc: vscode.TextDocument): CodewhispererLanguage { + return this.normalizeLanguage(doc.languageId) || this.byFileExt(doc) || 'plaintext' + } + /** * To add a new platform language id: * 1. add new platform language ID constant in the file codewhisperer/constant.ts @@ -317,8 +324,7 @@ export class RuntimeLanguageContext { } else { const normalizedLanguageId = this.normalizeLanguage(arg.languageId) const byLanguageId = !normalizedLanguageId || normalizedLanguageId === 'plaintext' ? false : true - const extension = path.extname(arg.uri.fsPath) - const byFileExtension = this.isFileFormatSupported(extension.substring(1)) + const byFileExtension = this.byFileExt(arg) !== undefined return byLanguageId || byFileExtension } @@ -341,6 +347,17 @@ export class RuntimeLanguageContext { public getLanguageFromFileExtension(fileExtension: string) { return this.supportedLanguageExtensionMap.get(fileExtension) } + + private byFileExt(doc: vscode.TextDocument): CodewhispererLanguage | undefined { + const extension = path.extname(doc.uri.fsPath) + const byExt = this.supportedLanguageExtensionMap.get(extension.substring(1)) + + if (byExt === 'plaintext') { + return undefined + } + + return byExt + } } export const runtimeLanguageContext = new RuntimeLanguageContext() From 6898221117468901a0922ad9a7bf1aa5ca13cfdd Mon Sep 17 00:00:00 2001 From: Nikolas Komonen <118216176+nkomonen-amazon@users.noreply.github.com> Date: Thu, 15 May 2025 10:51:31 -0400 Subject: [PATCH 25/36] fix(amazonq): Profile needing to be selected on server restart (#7316) See individual commits for isolated changes ## Problem We were seeing the following errors from the Q Language Server on startup: - `Amazon Q Profile is not selected for IDC connection type` - `Amazon Q service is not signed in` ## Solution We needed to do 2 solutions, each is a separate commit (see their message). There were also some minor refactors. In short: - The Auth bearer token MUST be sent to the Q LSP before Profile is sent. We were not doing this and it was causing an error - When sending the Auth to the Q LSP, the startUrl MUST be included in the request or else it would fail. We thought we were sending it but based on the logs prefixed with `UpdateBearerToken` it showed`sso` did not contain the startUrl --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --------- Signed-off-by: nkomonen-amazon --- ...-2471c584-3904-4d90-bb7c-61efff219e43.json | 4 + ...-91d391d4-3777-4053-9e71-15b36dfa1f67.json | 4 + packages/amazonq/src/lsp/auth.ts | 7 +- packages/amazonq/src/lsp/chat/activation.ts | 62 +---- packages/amazonq/src/lsp/client.ts | 224 +++++++++--------- packages/amazonq/src/lsp/config.ts | 47 ++++ packages/core/src/auth/index.ts | 1 + 7 files changed, 179 insertions(+), 170 deletions(-) create mode 100644 packages/amazonq/.changes/next-release/Bug Fix-2471c584-3904-4d90-bb7c-61efff219e43.json create mode 100644 packages/amazonq/.changes/next-release/Bug Fix-91d391d4-3777-4053-9e71-15b36dfa1f67.json diff --git a/packages/amazonq/.changes/next-release/Bug Fix-2471c584-3904-4d90-bb7c-61efff219e43.json b/packages/amazonq/.changes/next-release/Bug Fix-2471c584-3904-4d90-bb7c-61efff219e43.json new file mode 100644 index 00000000000..f7af0fbb1a4 --- /dev/null +++ b/packages/amazonq/.changes/next-release/Bug Fix-2471c584-3904-4d90-bb7c-61efff219e43.json @@ -0,0 +1,4 @@ +{ + "type": "Bug Fix", + "description": "Fix Error: 'Amazon Q service is not signed in'" +} diff --git a/packages/amazonq/.changes/next-release/Bug Fix-91d391d4-3777-4053-9e71-15b36dfa1f67.json b/packages/amazonq/.changes/next-release/Bug Fix-91d391d4-3777-4053-9e71-15b36dfa1f67.json new file mode 100644 index 00000000000..e3a608296a0 --- /dev/null +++ b/packages/amazonq/.changes/next-release/Bug Fix-91d391d4-3777-4053-9e71-15b36dfa1f67.json @@ -0,0 +1,4 @@ +{ + "type": "Bug Fix", + "description": "Fix Error: 'Amazon Q Profile is not selected for IDC connection type'" +} diff --git a/packages/amazonq/src/lsp/auth.ts b/packages/amazonq/src/lsp/auth.ts index 816c4b09ab0..d81f464d6a3 100644 --- a/packages/amazonq/src/lsp/auth.ts +++ b/packages/amazonq/src/lsp/auth.ts @@ -18,6 +18,7 @@ import { AuthUtil } from 'aws-core-vscode/codewhisperer' import { Writable } from 'stream' import { onceChanged } from 'aws-core-vscode/utils' import { getLogger, oneMinute } from 'aws-core-vscode/shared' +import { isSsoConnection } from 'aws-core-vscode/auth' export const encryptionKey = crypto.randomBytes(32) @@ -76,8 +77,8 @@ export class AmazonQLspAuth { * @param force bypass memoization, and forcefully update the bearer token */ async refreshConnection(force: boolean = false) { - const activeConnection = this.authUtil.auth.activeConnection - if (activeConnection?.state === 'valid' && activeConnection?.type === 'sso') { + const activeConnection = this.authUtil.conn + if (this.authUtil.isConnectionValid() && isSsoConnection(activeConnection)) { // send the token to the language server const token = await this.authUtil.getBearerToken() await (force ? this._updateBearerToken(token) : this.updateBearerToken(token)) @@ -118,7 +119,7 @@ export class AmazonQLspAuth { data: jwt, metadata: { sso: { - startUrl: AuthUtil.instance.auth.startUrl, + startUrl: AuthUtil.instance.startUrl, }, }, encrypted: true, diff --git a/packages/amazonq/src/lsp/chat/activation.ts b/packages/amazonq/src/lsp/chat/activation.ts index 3a36377b9b5..f8e3ee16251 100644 --- a/packages/amazonq/src/lsp/chat/activation.ts +++ b/packages/amazonq/src/lsp/chat/activation.ts @@ -12,25 +12,11 @@ import { Commands, getLogger, globals, undefinedIfEmpty } from 'aws-core-vscode/ import { activate as registerLegacyChatListeners } from '../../app/chat/activation' import { DefaultAmazonQAppInitContext } from 'aws-core-vscode/amazonq' import { AuthUtil, getSelectedCustomization } from 'aws-core-vscode/codewhisperer' -import { - DidChangeConfigurationNotification, - updateConfigurationRequestType, -} from '@aws/language-server-runtimes/protocol' +import { pushConfigUpdate } from '../config' export async function activate(languageClient: LanguageClient, encryptionKey: Buffer, mynahUIPath: string) { const disposables = globals.context.subscriptions - // Make sure we've sent an auth profile to the language server before even initializing the UI - await pushConfigUpdate(languageClient, { - type: 'profile', - profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn, - }) - // We need to push the cached customization on startup explicitly - await pushConfigUpdate(languageClient, { - type: 'customization', - customization: getSelectedCustomization(), - }) - const provider = new AmazonQChatViewProvider(mynahUIPath) disposables.push( @@ -79,10 +65,6 @@ export async function activate(languageClient: LanguageClient, encryptionKey: Bu disposables.push( AuthUtil.instance.regionProfileManager.onDidChangeRegionProfile(async () => { - void pushConfigUpdate(languageClient, { - type: 'profile', - profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn, - }) await provider.refreshWebview() }), Commands.register('aws.amazonq.updateCustomizations', () => { @@ -99,45 +81,3 @@ export async function activate(languageClient: LanguageClient, encryptionKey: Bu }) ) } - -/** - * Push a config value to the language server, effectively updating it with the - * latest configuration from the client. - * - * The issue is we need to push certain configs to different places, since there are - * different handlers for specific configs. So this determines the correct place to - * push the given config. - */ -async function pushConfigUpdate(client: LanguageClient, config: QConfigs) { - switch (config.type) { - case 'profile': - await client.sendRequest(updateConfigurationRequestType.method, { - section: 'aws.q', - settings: { profileArn: config.profileArn }, - }) - break - case 'customization': - client.sendNotification(DidChangeConfigurationNotification.type.method, { - section: 'aws.q', - settings: { customization: config.customization }, - }) - break - case 'logLevel': - client.sendNotification(DidChangeConfigurationNotification.type.method, { - section: 'aws.logLevel', - }) - break - } -} -type ProfileConfig = { - type: 'profile' - profileArn: string | undefined -} -type CustomizationConfig = { - type: 'customization' - customization: string | undefined -} -type LogLevelConfig = { - type: 'logLevel' -} -type QConfigs = ProfileConfig | CustomizationConfig | LogLevelConfig diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index 5559afb9f1d..549b0ac7dad 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -16,7 +16,6 @@ import { GetConfigurationFromServerParams, RenameFilesParams, ResponseMessage, - updateConfigurationRequestType, WorkspaceFolder, } from '@aws/language-server-runtimes/protocol' import { AuthUtil, CodeWhispererSettings, getSelectedCustomization } from 'aws-core-vscode/codewhisperer' @@ -38,7 +37,7 @@ import { import { processUtils } from 'aws-core-vscode/shared' import { activate } from './chat/activation' import { AmazonQResourcePaths } from './lspInstaller' -import { ConfigSection, isValidConfigSection, toAmazonQLSPLogLevel } from './config' +import { ConfigSection, isValidConfigSection, pushConfigUpdate, toAmazonQLSPLogLevel } from './config' import { telemetry } from 'aws-core-vscode/telemetry' const localize = nls.loadMessageBundle() @@ -160,120 +159,133 @@ export async function startLanguageServer( const disposable = client.start() toDispose.push(disposable) + await client.onReady() - const auth = new AmazonQLspAuth(client) + const auth = await initializeAuth(client) - return client.onReady().then(async () => { - await auth.refreshConnection() + await onLanguageServerReady(auth, client, resourcePaths, toDispose) - if (Experiments.instance.get('amazonqLSPInline', false)) { - const inlineManager = new InlineCompletionManager(client) - inlineManager.registerInlineCompletion() - toDispose.push( - inlineManager, - Commands.register({ id: 'aws.amazonq.invokeInlineCompletion', autoconnect: true }, async () => { - await vscode.commands.executeCommand('editor.action.inlineSuggest.trigger') - }), - vscode.workspace.onDidCloseTextDocument(async () => { - await vscode.commands.executeCommand('aws.amazonq.rejectCodeSuggestion') - }) - ) - } + return client +} - if (Experiments.instance.get('amazonqChatLSP', true)) { - await activate(client, encryptionKey, resourcePaths.ui) - } +async function initializeAuth(client: LanguageClient): Promise { + const auth = new AmazonQLspAuth(client) + await auth.refreshConnection(true) + return auth +} - const refreshInterval = auth.startTokenRefreshInterval(10 * oneSecond) +async function onLanguageServerReady( + auth: AmazonQLspAuth, + client: LanguageClient, + resourcePaths: AmazonQResourcePaths, + toDispose: vscode.Disposable[] +) { + if (Experiments.instance.get('amazonqLSPInline', false)) { + const inlineManager = new InlineCompletionManager(client) + inlineManager.registerInlineCompletion() + toDispose.push( + inlineManager, + Commands.register({ id: 'aws.amazonq.invokeInlineCompletion', autoconnect: true }, async () => { + await vscode.commands.executeCommand('editor.action.inlineSuggest.trigger') + }), + vscode.workspace.onDidCloseTextDocument(async () => { + await vscode.commands.executeCommand('aws.amazonq.rejectCodeSuggestion') + }) + ) + } - const sendProfileToLsp = async () => { - try { - const result = await client.sendRequest(updateConfigurationRequestType.method, { - section: 'aws.q', - settings: { - profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn, - }, - }) - client.info( - `Client: Updated Amazon Q Profile ${AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn} to Amazon Q LSP`, - result - ) - } catch (err) { - client.error('Error when setting Q Developer Profile to Amazon Q LSP', err) - } - } + if (Experiments.instance.get('amazonqChatLSP', true)) { + await activate(client, encryptionKey, resourcePaths.ui) + } - // send profile to lsp once. - void sendProfileToLsp() + const refreshInterval = auth.startTokenRefreshInterval(10 * oneSecond) - toDispose.push( - AuthUtil.instance.auth.onDidChangeActiveConnection(async () => { - await auth.refreshConnection() - }), - AuthUtil.instance.auth.onDidDeleteConnection(async () => { - client.sendNotification(notificationTypes.deleteBearerToken.method) - }), - AuthUtil.instance.regionProfileManager.onDidChangeRegionProfile(sendProfileToLsp), - vscode.commands.registerCommand('aws.amazonq.getWorkspaceId', async () => { - const requestType = new RequestType( - 'aws/getConfigurationFromServer' - ) - const workspaceIdResp = await client.sendRequest(requestType.method, { - section: 'aws.q.workspaceContext', - }) - return workspaceIdResp - }), - vscode.workspace.onDidCreateFiles((e) => { - client.sendNotification('workspace/didCreateFiles', { - files: e.files.map((it) => { - return { uri: it.fsPath } - }), - } as CreateFilesParams) - }), - vscode.workspace.onDidDeleteFiles((e) => { - client.sendNotification('workspace/didDeleteFiles', { - files: e.files.map((it) => { - return { uri: it.fsPath } + // We manually push the cached values the first time since event handlers, which should push, may not have been setup yet. + // Execution order is weird and should be fixed in the flare implementation. + // TODO: Revisit if we need this if we setup the event handlers properly + if (AuthUtil.instance.isConnectionValid()) { + await sendProfileToLsp(client) + + await pushConfigUpdate(client, { + type: 'customization', + customization: getSelectedCustomization(), + }) + } + + toDispose.push( + AuthUtil.instance.auth.onDidChangeActiveConnection(async () => { + await auth.refreshConnection() + }), + AuthUtil.instance.auth.onDidDeleteConnection(async () => { + client.sendNotification(notificationTypes.deleteBearerToken.method) + }), + AuthUtil.instance.regionProfileManager.onDidChangeRegionProfile(() => sendProfileToLsp(client)), + vscode.commands.registerCommand('aws.amazonq.getWorkspaceId', async () => { + const requestType = new RequestType( + 'aws/getConfigurationFromServer' + ) + const workspaceIdResp = await client.sendRequest(requestType.method, { + section: 'aws.q.workspaceContext', + }) + return workspaceIdResp + }), + vscode.workspace.onDidCreateFiles((e) => { + client.sendNotification('workspace/didCreateFiles', { + files: e.files.map((it) => { + return { uri: it.fsPath } + }), + } as CreateFilesParams) + }), + vscode.workspace.onDidDeleteFiles((e) => { + client.sendNotification('workspace/didDeleteFiles', { + files: e.files.map((it) => { + return { uri: it.fsPath } + }), + } as DeleteFilesParams) + }), + vscode.workspace.onDidRenameFiles((e) => { + client.sendNotification('workspace/didRenameFiles', { + files: e.files.map((it) => { + return { oldUri: it.oldUri.fsPath, newUri: it.newUri.fsPath } + }), + } as RenameFilesParams) + }), + vscode.workspace.onDidSaveTextDocument((e) => { + client.sendNotification('workspace/didSaveTextDocument', { + textDocument: { + uri: e.uri.fsPath, + }, + } as DidSaveTextDocumentParams) + }), + vscode.workspace.onDidChangeWorkspaceFolders((e) => { + client.sendNotification('workspace/didChangeWorkspaceFolder', { + event: { + added: e.added.map((it) => { + return { + name: it.name, + uri: it.uri.fsPath, + } as WorkspaceFolder }), - } as DeleteFilesParams) - }), - vscode.workspace.onDidRenameFiles((e) => { - client.sendNotification('workspace/didRenameFiles', { - files: e.files.map((it) => { - return { oldUri: it.oldUri.fsPath, newUri: it.newUri.fsPath } + removed: e.removed.map((it) => { + return { + name: it.name, + uri: it.uri.fsPath, + } as WorkspaceFolder }), - } as RenameFilesParams) - }), - vscode.workspace.onDidSaveTextDocument((e) => { - client.sendNotification('workspace/didSaveTextDocument', { - textDocument: { - uri: e.uri.fsPath, - }, - } as DidSaveTextDocumentParams) - }), - vscode.workspace.onDidChangeWorkspaceFolders((e) => { - client.sendNotification('workspace/didChangeWorkspaceFolder', { - event: { - added: e.added.map((it) => { - return { - name: it.name, - uri: it.uri.fsPath, - } as WorkspaceFolder - }), - removed: e.removed.map((it) => { - return { - name: it.name, - uri: it.uri.fsPath, - } as WorkspaceFolder - }), - }, - } as DidChangeWorkspaceFoldersParams) - }), - { dispose: () => clearInterval(refreshInterval) }, - // Set this inside onReady so that it only triggers on subsequent language server starts (not the first) - onServerRestartHandler(client, auth) - ) - }) + }, + } as DidChangeWorkspaceFoldersParams) + }), + { dispose: () => clearInterval(refreshInterval) }, + // Set this inside onReady so that it only triggers on subsequent language server starts (not the first) + onServerRestartHandler(client, auth) + ) + + async function sendProfileToLsp(client: LanguageClient) { + await pushConfigUpdate(client, { + type: 'profile', + profileArn: AuthUtil.instance.regionProfileManager.activeRegionProfile?.arn, + }) + } } /** diff --git a/packages/amazonq/src/lsp/config.ts b/packages/amazonq/src/lsp/config.ts index bb6870cb561..1760fb51401 100644 --- a/packages/amazonq/src/lsp/config.ts +++ b/packages/amazonq/src/lsp/config.ts @@ -5,6 +5,11 @@ import * as vscode from 'vscode' import { DevSettings, getServiceEnvVarConfig } from 'aws-core-vscode/shared' import { LspConfig } from 'aws-core-vscode/amazonq' +import { LanguageClient } from 'vscode-languageclient' +import { + DidChangeConfigurationNotification, + updateConfigurationRequestType, +} from '@aws/language-server-runtimes/protocol' export interface ExtendedAmazonQLSPConfig extends LspConfig { ui?: string @@ -54,3 +59,45 @@ export function getAmazonQLspConfig(): ExtendedAmazonQLSPConfig { export function toAmazonQLSPLogLevel(logLevel: vscode.LogLevel): LspLogLevel { return lspLogLevelMapping.get(logLevel) ?? 'info' } + +/** + * Request/Notify a config value to the language server, effectively updating it with the + * latest configuration from the client. + * + * The issue is we need to push certain configs to different places, since there are + * different handlers for specific configs. So this determines the correct place to + * push the given config. + */ +export async function pushConfigUpdate(client: LanguageClient, config: QConfigs) { + switch (config.type) { + case 'profile': + await client.sendRequest(updateConfigurationRequestType.method, { + section: 'aws.q', + settings: { profileArn: config.profileArn }, + }) + break + case 'customization': + client.sendNotification(DidChangeConfigurationNotification.type.method, { + section: 'aws.q', + settings: { customization: config.customization }, + }) + break + case 'logLevel': + client.sendNotification(DidChangeConfigurationNotification.type.method, { + section: 'aws.logLevel', + }) + break + } +} +type ProfileConfig = { + type: 'profile' + profileArn: string | undefined +} +type CustomizationConfig = { + type: 'customization' + customization: string | undefined +} +type LogLevelConfig = { + type: 'logLevel' +} +type QConfigs = ProfileConfig | CustomizationConfig | LogLevelConfig diff --git a/packages/core/src/auth/index.ts b/packages/core/src/auth/index.ts index 54dd17d702b..02a0067be45 100644 --- a/packages/core/src/auth/index.ts +++ b/packages/core/src/auth/index.ts @@ -18,6 +18,7 @@ export { isBuilderIdConnection, getTelemetryMetadataForConn, isIamConnection, + isSsoConnection, } from './connection' export { Auth } from './auth' export { CredentialsStore } from './credentials/store' From 327fb5655ce4a76cbbc39089ea778f373c19e6d8 Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Thu, 15 May 2025 09:30:14 -0700 Subject: [PATCH 26/36] fix(chat): adding new events for list mcp server and click mcp events. (#7314) ## Problem We need to catch MCP server menu events on VSCode. ## Solution - Updated runtimes for new VSCode requests for mcp servers. - Added switch cases for mcp events. --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --- package-lock.json | 1803 ++++----------------- packages/amazonq/src/lsp/chat/messages.ts | 4 + packages/core/package.json | 4 +- 3 files changed, 361 insertions(+), 1450 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7f7f35e42fd..6337e22c1d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,22 +68,6 @@ "resolved": "src.gen/@amzn/codewhisperer-streaming", "link": true }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "11.9.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.15", - "js-yaml": "^4.1.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/philsturgeon" - } - }, "node_modules/@aws-crypto/crc32": { "version": "5.2.0", "license": "Apache-2.0", @@ -8113,6 +8097,7 @@ "node_modules/@aws-sdk/credential-provider-ini": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/credential-provider-env": "3.758.0", @@ -8135,6 +8120,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/client-sso": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", @@ -8182,6 +8168,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/core": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/core": "^3.1.5", @@ -8202,6 +8189,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/credential-provider-env": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", @@ -8216,6 +8204,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/credential-provider-http": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", @@ -8235,6 +8224,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/credential-provider-process": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", @@ -8250,6 +8240,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/credential-provider-sso": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/client-sso": "3.758.0", "@aws-sdk/core": "3.758.0", @@ -8267,6 +8258,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/middleware-host-header": { "version": "3.734.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/protocol-http": "^5.0.1", @@ -8280,6 +8272,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/middleware-logger": { "version": "3.734.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/types": "^4.1.0", @@ -8292,6 +8285,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/middleware-recursion-detection": { "version": "3.734.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/protocol-http": "^5.0.1", @@ -8305,6 +8299,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/middleware-user-agent": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", @@ -8321,6 +8316,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/region-config-resolver": { "version": "3.734.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/node-config-provider": "^4.0.1", @@ -8336,6 +8332,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/token-providers": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/nested-clients": "3.758.0", "@aws-sdk/types": "3.734.0", @@ -8351,6 +8348,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/types": { "version": "3.734.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -8362,6 +8360,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/util-endpoints": { "version": "3.743.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/types": "^4.1.0", @@ -8375,6 +8374,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/util-user-agent-browser": { "version": "3.734.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/types": "^4.1.0", @@ -8385,6 +8385,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@aws-sdk/util-user-agent-node": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/types": "3.734.0", @@ -8407,6 +8408,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/abort-controller": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -8418,6 +8420,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/config-resolver": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/types": "^4.1.0", @@ -8432,6 +8435,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/core": { "version": "3.1.5", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/middleware-serde": "^4.0.2", "@smithy/protocol-http": "^5.0.1", @@ -8449,6 +8453,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/credential-provider-imds": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/property-provider": "^4.0.1", @@ -8463,6 +8468,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/fetch-http-handler": { "version": "5.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", @@ -8477,6 +8483,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/hash-node": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-buffer-from": "^4.0.0", @@ -8490,6 +8497,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/invalid-dependency": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -8501,6 +8509,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/is-array-buffer": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -8511,6 +8520,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/middleware-content-length": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", @@ -8523,6 +8533,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/middleware-endpoint": { "version": "4.0.6", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-serde": "^4.0.2", @@ -8540,6 +8551,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/middleware-retry": { "version": "4.0.7", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", @@ -8558,6 +8570,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/middleware-serde": { "version": "4.0.2", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -8569,6 +8582,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/middleware-stack": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -8580,6 +8594,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/node-config-provider": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", @@ -8593,6 +8608,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/node-http-handler": { "version": "4.0.3", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", @@ -8607,6 +8623,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/property-provider": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -8618,6 +8635,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/protocol-http": { "version": "5.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -8629,6 +8647,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/querystring-builder": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", @@ -8641,6 +8660,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/querystring-parser": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -8652,6 +8672,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/service-error-classification": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0" }, @@ -8662,6 +8683,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/shared-ini-file-loader": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -8673,6 +8695,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/signature-v4": { "version": "5.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "@smithy/protocol-http": "^5.0.1", @@ -8690,6 +8713,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/smithy-client": { "version": "4.1.6", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-endpoint": "^4.0.6", @@ -8706,6 +8730,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/types": { "version": "4.1.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -8716,6 +8741,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/url-parser": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/querystring-parser": "^4.0.1", "@smithy/types": "^4.1.0", @@ -8728,6 +8754,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/util-base64": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", @@ -8740,6 +8767,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/util-body-length-browser": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -8750,6 +8778,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/util-body-length-node": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -8760,6 +8789,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/util-buffer-from": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" @@ -8771,6 +8801,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/util-config-provider": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -8781,6 +8812,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/util-defaults-mode-browser": { "version": "4.0.7", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/smithy-client": "^4.1.6", @@ -8795,6 +8827,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/util-defaults-mode-node": { "version": "4.0.7", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/config-resolver": "^4.0.1", "@smithy/credential-provider-imds": "^4.0.1", @@ -8811,6 +8844,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/util-endpoints": { "version": "3.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/types": "^4.1.0", @@ -8823,6 +8857,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/util-hex-encoding": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -8833,6 +8868,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/util-middleware": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -8844,6 +8880,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/util-retry": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/service-error-classification": "^4.0.1", "@smithy/types": "^4.1.0", @@ -8856,6 +8893,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/util-stream": { "version": "4.1.2", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/fetch-http-handler": "^5.0.1", "@smithy/node-http-handler": "^4.0.3", @@ -8873,6 +8911,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/util-uri-escape": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -8883,6 +8922,7 @@ "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/util-utf8": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" @@ -9054,6 +9094,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/nested-clients": "3.758.0", @@ -9069,6 +9110,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@aws-sdk/core": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/core": "^3.1.5", @@ -9089,6 +9131,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@aws-sdk/types": { "version": "3.734.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -9100,6 +9143,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/abort-controller": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -9111,6 +9155,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/core": { "version": "3.1.5", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/middleware-serde": "^4.0.2", "@smithy/protocol-http": "^5.0.1", @@ -9128,6 +9173,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/fetch-http-handler": { "version": "5.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", @@ -9142,6 +9188,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/is-array-buffer": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -9152,6 +9199,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/middleware-endpoint": { "version": "4.0.6", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-serde": "^4.0.2", @@ -9169,6 +9217,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/middleware-serde": { "version": "4.0.2", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -9180,6 +9229,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/middleware-stack": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -9191,6 +9241,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/node-config-provider": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", @@ -9204,6 +9255,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/node-http-handler": { "version": "4.0.3", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", @@ -9218,6 +9270,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/property-provider": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -9229,6 +9282,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/protocol-http": { "version": "5.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -9240,6 +9294,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/querystring-builder": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", @@ -9252,6 +9307,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/querystring-parser": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -9263,6 +9319,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/shared-ini-file-loader": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -9274,6 +9331,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/signature-v4": { "version": "5.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "@smithy/protocol-http": "^5.0.1", @@ -9291,6 +9349,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/smithy-client": { "version": "4.1.6", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-endpoint": "^4.0.6", @@ -9307,6 +9366,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/types": { "version": "4.1.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -9317,6 +9377,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/url-parser": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/querystring-parser": "^4.0.1", "@smithy/types": "^4.1.0", @@ -9329,6 +9390,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/util-base64": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", @@ -9341,6 +9403,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/util-body-length-browser": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -9351,6 +9414,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/util-buffer-from": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" @@ -9362,6 +9426,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/util-hex-encoding": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -9372,6 +9437,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/util-middleware": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -9383,6 +9449,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/util-stream": { "version": "4.1.2", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/fetch-http-handler": "^5.0.1", "@smithy/node-http-handler": "^4.0.3", @@ -9400,6 +9467,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/util-uri-escape": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -9410,6 +9478,7 @@ "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/util-utf8": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" @@ -9793,6 +9862,7 @@ "node_modules/@aws-sdk/nested-clients": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", @@ -9840,6 +9910,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/core": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/core": "^3.1.5", @@ -9860,6 +9931,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/middleware-host-header": { "version": "3.734.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/protocol-http": "^5.0.1", @@ -9873,6 +9945,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/middleware-logger": { "version": "3.734.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/types": "^4.1.0", @@ -9885,6 +9958,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/middleware-recursion-detection": { "version": "3.734.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/protocol-http": "^5.0.1", @@ -9898,6 +9972,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/middleware-user-agent": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/core": "3.758.0", "@aws-sdk/types": "3.734.0", @@ -9914,6 +9989,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/region-config-resolver": { "version": "3.734.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/node-config-provider": "^4.0.1", @@ -9929,6 +10005,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/types": { "version": "3.734.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -9940,6 +10017,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/util-endpoints": { "version": "3.743.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/types": "^4.1.0", @@ -9953,6 +10031,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/util-user-agent-browser": { "version": "3.734.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/types": "3.734.0", "@smithy/types": "^4.1.0", @@ -9963,6 +10042,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/util-user-agent-node": { "version": "3.758.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@aws-sdk/middleware-user-agent": "3.758.0", "@aws-sdk/types": "3.734.0", @@ -9985,6 +10065,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/abort-controller": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -9996,6 +10077,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/config-resolver": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/types": "^4.1.0", @@ -10010,6 +10092,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/core": { "version": "3.1.5", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/middleware-serde": "^4.0.2", "@smithy/protocol-http": "^5.0.1", @@ -10027,6 +10110,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/credential-provider-imds": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/property-provider": "^4.0.1", @@ -10041,6 +10125,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/fetch-http-handler": { "version": "5.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/querystring-builder": "^4.0.1", @@ -10055,6 +10140,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/hash-node": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-buffer-from": "^4.0.0", @@ -10068,6 +10154,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/invalid-dependency": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -10079,6 +10166,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/is-array-buffer": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -10089,6 +10177,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-content-length": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/protocol-http": "^5.0.1", "@smithy/types": "^4.1.0", @@ -10101,6 +10190,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-endpoint": { "version": "4.0.6", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-serde": "^4.0.2", @@ -10118,6 +10208,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-retry": { "version": "4.0.7", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/protocol-http": "^5.0.1", @@ -10136,6 +10227,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-serde": { "version": "4.0.2", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -10147,6 +10239,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/middleware-stack": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -10158,6 +10251,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-config-provider": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/shared-ini-file-loader": "^4.0.1", @@ -10171,6 +10265,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler": { "version": "4.0.3", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/protocol-http": "^5.0.1", @@ -10185,6 +10280,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/property-provider": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -10196,6 +10292,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/protocol-http": { "version": "5.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -10207,6 +10304,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/querystring-builder": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", @@ -10219,6 +10317,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/querystring-parser": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -10230,6 +10329,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/service-error-classification": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0" }, @@ -10240,6 +10340,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/shared-ini-file-loader": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -10251,6 +10352,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/signature-v4": { "version": "5.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "@smithy/protocol-http": "^5.0.1", @@ -10268,6 +10370,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/smithy-client": { "version": "4.1.6", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/core": "^3.1.5", "@smithy/middleware-endpoint": "^4.0.6", @@ -10284,6 +10387,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/types": { "version": "4.1.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -10294,6 +10398,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/url-parser": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/querystring-parser": "^4.0.1", "@smithy/types": "^4.1.0", @@ -10306,6 +10411,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-base64": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "@smithy/util-utf8": "^4.0.0", @@ -10318,6 +10424,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-body-length-browser": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -10328,6 +10435,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-body-length-node": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -10338,6 +10446,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-buffer-from": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/is-array-buffer": "^4.0.0", "tslib": "^2.6.2" @@ -10349,6 +10458,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-config-provider": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -10359,6 +10469,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-defaults-mode-browser": { "version": "4.0.7", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/property-provider": "^4.0.1", "@smithy/smithy-client": "^4.1.6", @@ -10373,6 +10484,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-defaults-mode-node": { "version": "4.0.7", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/config-resolver": "^4.0.1", "@smithy/credential-provider-imds": "^4.0.1", @@ -10389,6 +10501,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-endpoints": { "version": "3.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/node-config-provider": "^4.0.1", "@smithy/types": "^4.1.0", @@ -10401,6 +10514,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-hex-encoding": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -10411,6 +10525,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-middleware": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" @@ -10422,6 +10537,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-retry": { "version": "4.0.1", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/service-error-classification": "^4.0.1", "@smithy/types": "^4.1.0", @@ -10434,6 +10550,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-stream": { "version": "4.1.2", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/fetch-http-handler": "^5.0.1", "@smithy/node-http-handler": "^4.0.3", @@ -10451,6 +10568,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-uri-escape": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.6.2" }, @@ -10461,6 +10579,7 @@ "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-utf8": { "version": "4.0.0", "license": "Apache-2.0", + "peer": true, "dependencies": { "@smithy/util-buffer-from": "^4.0.0", "tslib": "^2.6.2" @@ -10796,26 +10915,23 @@ } }, "node_modules/@aws/language-server-runtimes": { - "version": "0.2.70", + "version": "0.2.81", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.2.81.tgz", + "integrity": "sha512-wnwa8ctVCAckIpfWSblHyLVzl6UKX5G7ft+yetH1pI0mZvseSNzHUhclxNl4WGaDgGnEbBjLD0XRNEy2yRrSYg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@apidevtools/json-schema-ref-parser": "^11.9.3", - "@aws-crypto/sha256-js": "^5.2.0", - "@aws-sdk/client-cognito-identity": "^3.758.0", - "@aws/language-server-runtimes-types": "^0.1.21", + "@aws/language-server-runtimes-types": "^0.1.28", "@opentelemetry/api": "^1.9.0", - "@opentelemetry/resources": "^1.30.1", - "@opentelemetry/sdk-metrics": "^1.30.1", - "@opentelemetry/sdk-node": "^0.57.2", - "@opentelemetry/sdk-trace-base": "^1.30.1", - "@opentelemetry/semantic-conventions": "^1.30.0", - "@smithy/node-http-handler": "^4.0.2", - "@smithy/protocol-http": "^5.0.1", - "@smithy/signature-v4": "^5.0.1", + "@opentelemetry/api-logs": "^0.200.0", + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/exporter-logs-otlp-http": "^0.200.0", + "@opentelemetry/exporter-metrics-otlp-http": "^0.200.0", + "@opentelemetry/resources": "^2.0.0", + "@opentelemetry/sdk-logs": "^0.200.0", + "@opentelemetry/sdk-metrics": "^2.0.0", + "@smithy/node-http-handler": "^4.0.4", "ajv": "^8.17.1", - "aws-sdk": "^2.1692.0", - "axios": "^1.8.4", "hpagent": "^1.2.0", "jose": "^5.9.6", "mac-ca": "^3.1.1", @@ -10829,9 +10945,9 @@ } }, "node_modules/@aws/language-server-runtimes-types": { - "version": "0.1.26", - "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.26.tgz", - "integrity": "sha512-c63rpUbcrtLqaC33t6elRApQqLbQvFgKzIQ2z/VCavE5F7HSLBfzhHkhgUFd775fBpsF4MHrIzwNitYLhDGobw==", + "version": "0.1.28", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.28.tgz", + "integrity": "sha512-eDNcEXGAyD4rzl+eVJ6Ngfbm4iaR8MkoMk1wVcnV+VGqu63TyvV1aVWnZdl9tR4pmC0rIH3tj8FSCjhSU6eJlA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -10839,862 +10955,73 @@ "vscode-languageserver-types": "^3.17.5" } }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.768.0", + "node_modules/@aws/language-server-runtimes/node_modules/@smithy/abort-controller": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.2.tgz", + "integrity": "sha512-Sl/78VDtgqKxN2+1qduaVE140XF+Xg+TafkncspwM4jFP/LHr76ZHmIY/y3V1M0mMLNk+Je6IGbzxy23RSToMw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.758.0", - "@aws-sdk/credential-provider-node": "3.758.0", - "@aws-sdk/middleware-host-header": "3.734.0", - "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", - "@aws-sdk/middleware-user-agent": "3.758.0", - "@aws-sdk/region-config-resolver": "3.734.0", - "@aws-sdk/types": "3.734.0", - "@aws-sdk/util-endpoints": "3.743.0", - "@aws-sdk/util-user-agent-browser": "3.734.0", - "@aws-sdk/util-user-agent-node": "3.758.0", - "@smithy/config-resolver": "^4.0.1", - "@smithy/core": "^3.1.5", - "@smithy/fetch-http-handler": "^5.0.1", - "@smithy/hash-node": "^4.0.1", - "@smithy/invalid-dependency": "^4.0.1", - "@smithy/middleware-content-length": "^4.0.1", - "@smithy/middleware-endpoint": "^4.0.6", - "@smithy/middleware-retry": "^4.0.7", - "@smithy/middleware-serde": "^4.0.2", - "@smithy/middleware-stack": "^4.0.1", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/node-http-handler": "^4.0.3", - "@smithy/protocol-http": "^5.0.1", - "@smithy/smithy-client": "^4.1.6", - "@smithy/types": "^4.1.0", - "@smithy/url-parser": "^4.0.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.7", - "@smithy/util-defaults-mode-node": "^4.0.7", - "@smithy/util-endpoints": "^3.0.1", - "@smithy/util-middleware": "^4.0.1", - "@smithy/util-retry": "^4.0.1", - "@smithy/util-utf8": "^4.0.0", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/client-sso": { - "version": "3.758.0", + "node_modules/@aws/language-server-runtimes/node_modules/@smithy/node-http-handler": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.4.tgz", + "integrity": "sha512-/mdqabuAT3o/ihBGjL94PUbTSPSRJ0eeVTdgADzow0wRJ0rN4A27EOrtlK56MYiO1fDvlO3jVTCxQtQmK9dZ1g==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.758.0", - "@aws-sdk/middleware-host-header": "3.734.0", - "@aws-sdk/middleware-logger": "3.734.0", - "@aws-sdk/middleware-recursion-detection": "3.734.0", - "@aws-sdk/middleware-user-agent": "3.758.0", - "@aws-sdk/region-config-resolver": "3.734.0", - "@aws-sdk/types": "3.734.0", - "@aws-sdk/util-endpoints": "3.743.0", - "@aws-sdk/util-user-agent-browser": "3.734.0", - "@aws-sdk/util-user-agent-node": "3.758.0", - "@smithy/config-resolver": "^4.0.1", - "@smithy/core": "^3.1.5", - "@smithy/fetch-http-handler": "^5.0.1", - "@smithy/hash-node": "^4.0.1", - "@smithy/invalid-dependency": "^4.0.1", - "@smithy/middleware-content-length": "^4.0.1", - "@smithy/middleware-endpoint": "^4.0.6", - "@smithy/middleware-retry": "^4.0.7", - "@smithy/middleware-serde": "^4.0.2", - "@smithy/middleware-stack": "^4.0.1", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/node-http-handler": "^4.0.3", - "@smithy/protocol-http": "^5.0.1", - "@smithy/smithy-client": "^4.1.6", - "@smithy/types": "^4.1.0", - "@smithy/url-parser": "^4.0.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-body-length-node": "^4.0.0", - "@smithy/util-defaults-mode-browser": "^4.0.7", - "@smithy/util-defaults-mode-node": "^4.0.7", - "@smithy/util-endpoints": "^3.0.1", - "@smithy/util-middleware": "^4.0.1", - "@smithy/util-retry": "^4.0.1", - "@smithy/util-utf8": "^4.0.0", + "@smithy/abort-controller": "^4.0.2", + "@smithy/protocol-http": "^5.1.0", + "@smithy/querystring-builder": "^4.0.2", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/core": { - "version": "3.758.0", + "node_modules/@aws/language-server-runtimes/node_modules/@smithy/protocol-http": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.1.0.tgz", + "integrity": "sha512-KxAOL1nUNw2JTYrtviRRjEnykIDhxc84qMBzxvu1MUfQfHTuBlCG7PA6EdVwqpJjH7glw7FqQoFxUJSyBQgu7g==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "3.734.0", - "@smithy/core": "^3.1.5", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/property-provider": "^4.0.1", - "@smithy/protocol-http": "^5.0.1", - "@smithy/signature-v4": "^5.0.1", - "@smithy/smithy-client": "^4.1.6", - "@smithy/types": "^4.1.0", - "@smithy/util-middleware": "^4.0.1", - "fast-xml-parser": "4.4.1", + "@smithy/types": "^4.2.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.758.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.758.0", - "@aws-sdk/types": "3.734.0", - "@smithy/property-provider": "^4.0.1", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.758.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.758.0", - "@aws-sdk/types": "3.734.0", - "@smithy/fetch-http-handler": "^5.0.1", - "@smithy/node-http-handler": "^4.0.3", - "@smithy/property-provider": "^4.0.1", - "@smithy/protocol-http": "^5.0.1", - "@smithy/smithy-client": "^4.1.6", - "@smithy/types": "^4.1.0", - "@smithy/util-stream": "^4.1.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.758.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.758.0", - "@aws-sdk/credential-provider-http": "3.758.0", - "@aws-sdk/credential-provider-ini": "3.758.0", - "@aws-sdk/credential-provider-process": "3.758.0", - "@aws-sdk/credential-provider-sso": "3.758.0", - "@aws-sdk/credential-provider-web-identity": "3.758.0", - "@aws-sdk/types": "3.734.0", - "@smithy/credential-provider-imds": "^4.0.1", - "@smithy/property-provider": "^4.0.1", - "@smithy/shared-ini-file-loader": "^4.0.1", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.758.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.758.0", - "@aws-sdk/types": "3.734.0", - "@smithy/property-provider": "^4.0.1", - "@smithy/shared-ini-file-loader": "^4.0.1", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.758.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-sso": "3.758.0", - "@aws-sdk/core": "3.758.0", - "@aws-sdk/token-providers": "3.758.0", - "@aws-sdk/types": "3.734.0", - "@smithy/property-provider": "^4.0.1", - "@smithy/shared-ini-file-loader": "^4.0.1", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.734.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.734.0", - "@smithy/protocol-http": "^5.0.1", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/middleware-logger": { - "version": "3.734.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.734.0", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.734.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.734.0", - "@smithy/protocol-http": "^5.0.1", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.758.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.758.0", - "@aws-sdk/types": "3.734.0", - "@aws-sdk/util-endpoints": "3.743.0", - "@smithy/core": "^3.1.5", - "@smithy/protocol-http": "^5.0.1", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.734.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.734.0", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/types": "^4.1.0", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/token-providers": { - "version": "3.758.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/nested-clients": "3.758.0", - "@aws-sdk/types": "3.734.0", - "@smithy/property-provider": "^4.0.1", - "@smithy/shared-ini-file-loader": "^4.0.1", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/types": { - "version": "3.734.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/util-endpoints": { - "version": "3.743.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.734.0", - "@smithy/types": "^4.1.0", - "@smithy/util-endpoints": "^3.0.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.734.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.734.0", - "@smithy/types": "^4.1.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.758.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/middleware-user-agent": "3.758.0", - "@aws-sdk/types": "3.734.0", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/abort-controller": { - "version": "4.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/config-resolver": { - "version": "4.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.0.1", - "@smithy/types": "^4.1.0", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/core": { - "version": "3.1.5", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/middleware-serde": "^4.0.2", - "@smithy/protocol-http": "^5.0.1", - "@smithy/types": "^4.1.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-middleware": "^4.0.1", - "@smithy/util-stream": "^4.1.2", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/credential-provider-imds": { - "version": "4.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.0.1", - "@smithy/property-provider": "^4.0.1", - "@smithy/types": "^4.1.0", - "@smithy/url-parser": "^4.0.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/fetch-http-handler": { - "version": "5.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.0.1", - "@smithy/querystring-builder": "^4.0.1", - "@smithy/types": "^4.1.0", - "@smithy/util-base64": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/hash-node": { - "version": "4.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.1.0", - "@smithy/util-buffer-from": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/invalid-dependency": { - "version": "4.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/is-array-buffer": { - "version": "4.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/middleware-content-length": { - "version": "4.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.0.1", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/middleware-endpoint": { - "version": "4.0.6", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.1.5", - "@smithy/middleware-serde": "^4.0.2", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/shared-ini-file-loader": "^4.0.1", - "@smithy/types": "^4.1.0", - "@smithy/url-parser": "^4.0.1", - "@smithy/util-middleware": "^4.0.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/middleware-retry": { - "version": "4.0.7", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.0.1", - "@smithy/protocol-http": "^5.0.1", - "@smithy/service-error-classification": "^4.0.1", - "@smithy/smithy-client": "^4.1.6", - "@smithy/types": "^4.1.0", - "@smithy/util-middleware": "^4.0.1", - "@smithy/util-retry": "^4.0.1", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/middleware-serde": { - "version": "4.0.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/middleware-stack": { - "version": "4.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/node-config-provider": { - "version": "4.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/property-provider": "^4.0.1", - "@smithy/shared-ini-file-loader": "^4.0.1", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/node-http-handler": { - "version": "4.0.3", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/abort-controller": "^4.0.1", - "@smithy/protocol-http": "^5.0.1", - "@smithy/querystring-builder": "^4.0.1", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/property-provider": { - "version": "4.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/protocol-http": { - "version": "5.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/querystring-builder": { - "version": "4.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.1.0", - "@smithy/util-uri-escape": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/querystring-parser": { - "version": "4.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/service-error-classification": { - "version": "4.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.1.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/shared-ini-file-loader": { - "version": "4.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/signature-v4": { - "version": "5.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^4.0.0", - "@smithy/protocol-http": "^5.0.1", - "@smithy/types": "^4.1.0", - "@smithy/util-hex-encoding": "^4.0.0", - "@smithy/util-middleware": "^4.0.1", - "@smithy/util-uri-escape": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/smithy-client": { - "version": "4.1.6", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.1.5", - "@smithy/middleware-endpoint": "^4.0.6", - "@smithy/middleware-stack": "^4.0.1", - "@smithy/protocol-http": "^5.0.1", - "@smithy/types": "^4.1.0", - "@smithy/util-stream": "^4.1.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/types": { - "version": "4.1.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/url-parser": { - "version": "4.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/querystring-parser": "^4.0.1", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/util-base64": { - "version": "4.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/util-body-length-browser": { - "version": "4.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/util-body-length-node": { - "version": "4.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/util-buffer-from": { - "version": "4.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/util-config-provider": { - "version": "4.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.0.7", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/property-provider": "^4.0.1", - "@smithy/smithy-client": "^4.1.6", - "@smithy/types": "^4.1.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/util-defaults-mode-node": { - "version": "4.0.7", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/config-resolver": "^4.0.1", - "@smithy/credential-provider-imds": "^4.0.1", - "@smithy/node-config-provider": "^4.0.1", - "@smithy/property-provider": "^4.0.1", - "@smithy/smithy-client": "^4.1.6", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/util-endpoints": { - "version": "3.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.0.1", - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/util-hex-encoding": { - "version": "4.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/util-middleware": { - "version": "4.0.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/util-retry": { - "version": "4.0.1", + "node_modules/@aws/language-server-runtimes/node_modules/@smithy/querystring-builder": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.2.tgz", + "integrity": "sha512-NTOs0FwHw1vimmQM4ebh+wFQvOwkEf/kQL6bSM1Lock+Bv4I89B3hGYoUEPkmvYPkDKyp5UdXJYu+PoTQ3T31Q==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^4.0.1", - "@smithy/types": "^4.1.0", + "@smithy/types": "^4.2.0", + "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/util-stream": { - "version": "4.1.2", + "node_modules/@aws/language-server-runtimes/node_modules/@smithy/types": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", + "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@smithy/fetch-http-handler": "^5.0.1", - "@smithy/node-http-handler": "^4.0.3", - "@smithy/types": "^4.1.0", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-buffer-from": "^4.0.0", - "@smithy/util-hex-encoding": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", "tslib": "^2.6.2" }, "engines": { @@ -11703,6 +11030,8 @@ }, "node_modules/@aws/language-server-runtimes/node_modules/@smithy/util-uri-escape": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -11712,18 +11041,6 @@ "node": ">=18.0.0" } }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/util-utf8": { - "version": "4.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@aws/language-server-runtimes/node_modules/ajv": { "version": "8.17.1", "dev": true, @@ -12109,35 +11426,6 @@ "node": ">=10" } }, - "node_modules/@grpc/grpc-js": { - "version": "1.13.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@grpc/proto-loader": "^0.7.13", - "@js-sdsl/ordered-map": "^4.4.2" - }, - "engines": { - "node": ">=12.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.13", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.5", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "dev": true, @@ -12288,614 +11576,294 @@ "dev": true, "license": "MIT", "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@js-sdsl/ordered-map": { - "version": "4.4.2", - "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/@jsdevtools/ono": { - "version": "7.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/@koa/cors": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@koa/router": { - "version": "13.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "http-errors": "^2.0.0", - "koa-compose": "^4.1.0", - "path-to-regexp": "^6.3.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@koa/router/node_modules/path-to-regexp": { - "version": "6.3.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.4", - "dev": true, - "license": "MIT" - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/api-logs": { - "version": "0.57.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@opentelemetry/context-async-hooks": { - "version": "1.30.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/core": { - "version": "1.30.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "1.28.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/core/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.28.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-grpc": { - "version": "0.57.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "1.30.1", - "@opentelemetry/otlp-exporter-base": "0.57.2", - "@opentelemetry/otlp-grpc-exporter-base": "0.57.2", - "@opentelemetry/otlp-transformer": "0.57.2", - "@opentelemetry/sdk-logs": "0.57.2" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-http": { - "version": "0.57.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.57.2", - "@opentelemetry/core": "1.30.1", - "@opentelemetry/otlp-exporter-base": "0.57.2", - "@opentelemetry/otlp-transformer": "0.57.2", - "@opentelemetry/sdk-logs": "0.57.2" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-proto": { - "version": "0.57.2", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.57.2", - "@opentelemetry/core": "1.30.1", - "@opentelemetry/otlp-exporter-base": "0.57.2", - "@opentelemetry/otlp-transformer": "0.57.2", - "@opentelemetry/resources": "1.30.1", - "@opentelemetry/sdk-logs": "0.57.2", - "@opentelemetry/sdk-trace-base": "1.30.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "node": ">=6.0.0" } }, - "node_modules/@opentelemetry/exporter-metrics-otlp-grpc": { - "version": "0.57.2", + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "1.30.1", - "@opentelemetry/exporter-metrics-otlp-http": "0.57.2", - "@opentelemetry/otlp-exporter-base": "0.57.2", - "@opentelemetry/otlp-grpc-exporter-base": "0.57.2", - "@opentelemetry/otlp-transformer": "0.57.2", - "@opentelemetry/resources": "1.30.1", - "@opentelemetry/sdk-metrics": "1.30.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, - "node_modules/@opentelemetry/exporter-metrics-otlp-http": { - "version": "0.57.2", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/otlp-exporter-base": "0.57.2", - "@opentelemetry/otlp-transformer": "0.57.2", - "@opentelemetry/resources": "1.30.1", - "@opentelemetry/sdk-metrics": "1.30.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@opentelemetry/exporter-metrics-otlp-proto": { - "version": "0.57.2", + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/exporter-metrics-otlp-http": "0.57.2", - "@opentelemetry/otlp-exporter-base": "0.57.2", - "@opentelemetry/otlp-transformer": "0.57.2", - "@opentelemetry/resources": "1.30.1", - "@opentelemetry/sdk-metrics": "1.30.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } + "license": "MIT" }, - "node_modules/@opentelemetry/exporter-prometheus": { - "version": "0.57.2", + "node_modules/@koa/cors": { + "version": "5.0.0", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/resources": "1.30.1", - "@opentelemetry/sdk-metrics": "1.30.1" + "vary": "^1.1.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "node": ">= 14.0.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-grpc": { - "version": "0.57.2", + "node_modules/@koa/router": { + "version": "13.1.0", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "1.30.1", - "@opentelemetry/otlp-exporter-base": "0.57.2", - "@opentelemetry/otlp-grpc-exporter-base": "0.57.2", - "@opentelemetry/otlp-transformer": "0.57.2", - "@opentelemetry/resources": "1.30.1", - "@opentelemetry/sdk-trace-base": "1.30.1" + "http-errors": "^2.0.0", + "koa-compose": "^4.1.0", + "path-to-regexp": "^6.3.0" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "node": ">= 18" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-http": { - "version": "0.57.2", + "node_modules/@koa/router/node_modules/path-to-regexp": { + "version": "6.3.0", "dev": true, - "license": "Apache-2.0", + "license": "MIT" + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/otlp-exporter-base": "0.57.2", - "@opentelemetry/otlp-transformer": "0.57.2", - "@opentelemetry/resources": "1.30.1", - "@opentelemetry/sdk-trace-base": "1.30.1" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "node": ">= 8" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto": { - "version": "0.57.2", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/otlp-exporter-base": "0.57.2", - "@opentelemetry/otlp-transformer": "0.57.2", - "@opentelemetry/resources": "1.30.1", - "@opentelemetry/sdk-trace-base": "1.30.1" - }, + "license": "MIT", "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "node": ">= 8" } }, - "node_modules/@opentelemetry/exporter-zipkin": { - "version": "1.30.1", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/resources": "1.30.1", - "@opentelemetry/sdk-trace-base": "1.30.1", - "@opentelemetry/semantic-conventions": "1.28.0" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "node": ">= 8" } }, - "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.28.0", + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "dev": true, "license": "Apache-2.0", "engines": { - "node": ">=14" + "node": ">=8.0.0" } }, - "node_modules/@opentelemetry/instrumentation": { - "version": "0.57.2", + "node_modules/@opentelemetry/api-logs": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.200.0.tgz", + "integrity": "sha512-IKJBQxh91qJ+3ssRly5hYEJ8NDHu9oY/B1PXVSCWf7zytmYO9RNLB0Ox9XQ/fJ8m6gY6Q6NtBWlmXfaXt5Uc4Q==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "0.57.2", - "@types/shimmer": "^1.2.0", - "import-in-the-middle": "^1.8.1", - "require-in-the-middle": "^7.1.1", - "semver": "^7.5.2", - "shimmer": "^1.2.1" + "@opentelemetry/api": "^1.3.0" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "node": ">=8.0.0" } }, - "node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.57.2", + "node_modules/@opentelemetry/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.0.tgz", + "integrity": "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/otlp-transformer": "0.57.2" + "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { - "node": ">=14" + "node": "^18.19.0 || >=20.6.0" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, - "node_modules/@opentelemetry/otlp-grpc-exporter-base": { - "version": "0.57.2", + "node_modules/@opentelemetry/exporter-logs-otlp-http": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.200.0.tgz", + "integrity": "sha512-KfWw49htbGGp9s8N4KI8EQ9XuqKJ0VG+yVYVYFiCYSjEV32qpQ5qZ9UZBzOZ6xRb+E16SXOSCT3RkqBVSABZ+g==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "1.30.1", - "@opentelemetry/otlp-exporter-base": "0.57.2", - "@opentelemetry/otlp-transformer": "0.57.2" + "@opentelemetry/api-logs": "0.200.0", + "@opentelemetry/core": "2.0.0", + "@opentelemetry/otlp-exporter-base": "0.200.0", + "@opentelemetry/otlp-transformer": "0.200.0", + "@opentelemetry/sdk-logs": "0.200.0" }, "engines": { - "node": ">=14" + "node": "^18.19.0 || >=20.6.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/otlp-transformer": { - "version": "0.57.2", + "node_modules/@opentelemetry/exporter-metrics-otlp-http": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.200.0.tgz", + "integrity": "sha512-5BiR6i8yHc9+qW7F6LqkuUnIzVNA7lt0qRxIKcKT+gq3eGUPHZ3DY29sfxI3tkvnwMgtnHDMNze5DdxW39HsAw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "0.57.2", - "@opentelemetry/core": "1.30.1", - "@opentelemetry/resources": "1.30.1", - "@opentelemetry/sdk-logs": "0.57.2", - "@opentelemetry/sdk-metrics": "1.30.1", - "@opentelemetry/sdk-trace-base": "1.30.1", - "protobufjs": "^7.3.0" + "@opentelemetry/core": "2.0.0", + "@opentelemetry/otlp-exporter-base": "0.200.0", + "@opentelemetry/otlp-transformer": "0.200.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/sdk-metrics": "2.0.0" }, "engines": { - "node": ">=14" + "node": "^18.19.0 || >=20.6.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/propagator-b3": { - "version": "1.30.1", + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.200.0.tgz", + "integrity": "sha512-IxJgA3FD7q4V6gGq4bnmQM5nTIyMDkoGFGrBrrDjB6onEiq1pafma55V+bHvGYLWvcqbBbRfezr1GED88lacEQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.30.1" + "@opentelemetry/core": "2.0.0", + "@opentelemetry/otlp-transformer": "0.200.0" }, "engines": { - "node": ">=14" + "node": "^18.19.0 || >=20.6.0" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/propagator-jaeger": { - "version": "1.30.1", + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.200.0.tgz", + "integrity": "sha512-+9YDZbYybOnv7sWzebWOeK6gKyt2XE7iarSyBFkwwnP559pEevKOUD8NyDHhRjCSp13ybh9iVXlMfcj/DwF/yw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.30.1" + "@opentelemetry/api-logs": "0.200.0", + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/sdk-logs": "0.200.0", + "@opentelemetry/sdk-metrics": "2.0.0", + "@opentelemetry/sdk-trace-base": "2.0.0", + "protobufjs": "^7.3.0" }, "engines": { - "node": ">=14" + "node": "^18.19.0 || >=20.6.0" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "@opentelemetry/api": "^1.3.0" } }, "node_modules/@opentelemetry/resources": { - "version": "1.30.1", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.0.tgz", + "integrity": "sha512-rnZr6dML2z4IARI4zPGQV4arDikF/9OXZQzrC01dLmn0CZxU5U5OLd/m1T7YkGRj5UitjeoCtg/zorlgMQcdTg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/semantic-conventions": "1.28.0" + "@opentelemetry/core": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { - "node": ">=14" + "node": "^18.19.0 || >=20.6.0" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.28.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=14" + "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "node_modules/@opentelemetry/sdk-logs": { - "version": "0.57.2", + "version": "0.200.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.200.0.tgz", + "integrity": "sha512-VZG870063NLfObmQQNtCVcdXXLzI3vOjjrRENmU37HYiPFa0ZXpXVDsTD02Nh3AT3xYJzQaWKl2X2lQ2l7TWJA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "0.57.2", - "@opentelemetry/core": "1.30.1", - "@opentelemetry/resources": "1.30.1" + "@opentelemetry/api-logs": "0.200.0", + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0" }, "engines": { - "node": ">=14" + "node": "^18.19.0 || >=20.6.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "node_modules/@opentelemetry/sdk-metrics": { - "version": "1.30.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/resources": "1.30.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-node": { - "version": "0.57.2", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.0.tgz", + "integrity": "sha512-Bvy8QDjO05umd0+j+gDeWcTaVa1/R2lDj/eOvjzpm8VQj1K1vVZJuyjThpV5/lSHyYW2JaHF2IQ7Z8twJFAhjA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "0.57.2", - "@opentelemetry/core": "1.30.1", - "@opentelemetry/exporter-logs-otlp-grpc": "0.57.2", - "@opentelemetry/exporter-logs-otlp-http": "0.57.2", - "@opentelemetry/exporter-logs-otlp-proto": "0.57.2", - "@opentelemetry/exporter-metrics-otlp-grpc": "0.57.2", - "@opentelemetry/exporter-metrics-otlp-http": "0.57.2", - "@opentelemetry/exporter-metrics-otlp-proto": "0.57.2", - "@opentelemetry/exporter-prometheus": "0.57.2", - "@opentelemetry/exporter-trace-otlp-grpc": "0.57.2", - "@opentelemetry/exporter-trace-otlp-http": "0.57.2", - "@opentelemetry/exporter-trace-otlp-proto": "0.57.2", - "@opentelemetry/exporter-zipkin": "1.30.1", - "@opentelemetry/instrumentation": "0.57.2", - "@opentelemetry/resources": "1.30.1", - "@opentelemetry/sdk-logs": "0.57.2", - "@opentelemetry/sdk-metrics": "1.30.1", - "@opentelemetry/sdk-trace-base": "1.30.1", - "@opentelemetry/sdk-trace-node": "1.30.1", - "@opentelemetry/semantic-conventions": "1.28.0" + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0" }, "engines": { - "node": ">=14" + "node": "^18.19.0 || >=20.6.0" }, "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.28.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=14" + "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "node_modules/@opentelemetry/sdk-trace-base": { - "version": "1.30.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/resources": "1.30.1", - "@opentelemetry/semantic-conventions": "1.28.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.28.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@opentelemetry/sdk-trace-node": { - "version": "1.30.1", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.0.tgz", + "integrity": "sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@opentelemetry/context-async-hooks": "1.30.1", - "@opentelemetry/core": "1.30.1", - "@opentelemetry/propagator-b3": "1.30.1", - "@opentelemetry/propagator-jaeger": "1.30.1", - "@opentelemetry/sdk-trace-base": "1.30.1", - "semver": "^7.5.2" + "@opentelemetry/core": "2.0.0", + "@opentelemetry/resources": "2.0.0", + "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { - "node": ">=14" + "node": "^18.19.0 || >=20.6.0" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.30.0", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.33.0.tgz", + "integrity": "sha512-TIpZvE8fiEILFfTlfPnltpBaD3d9/+uQHVCyC3vfdh6WfCXKhNFzoP5RyDDIndfvZC5GrA4pyEDNyjPloJud+w==", "dev": true, "license": "Apache-2.0", "engines": { @@ -12935,26 +11903,36 @@ }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/base64": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/codegen": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/fetch": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -12964,26 +11942,36 @@ }, "node_modules/@protobufjs/float": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/inquire": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/path": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/pool": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/utf8": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", "dev": true, "license": "BSD-3-Clause" }, @@ -14444,11 +13432,6 @@ "@types/node": "*" } }, - "node_modules/@types/shimmer": { - "version": "1.2.0", - "dev": true, - "license": "MIT" - }, "node_modules/@types/sinon": { "version": "10.0.5", "dev": true, @@ -15880,16 +14863,6 @@ "resolved": "packages/toolkit", "link": true }, - "node_modules/axios": { - "version": "1.8.4", - "dev": true, - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, "node_modules/azure-devops-node-api": { "version": "11.2.0", "dev": true, @@ -16601,11 +15574,6 @@ "webpack": ">=4.0.1" } }, - "node_modules/cjs-module-lexer": { - "version": "1.4.3", - "dev": true, - "license": "MIT" - }, "node_modules/clean-regexp": { "version": "1.0.0", "dev": true, @@ -19635,17 +18603,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-in-the-middle": { - "version": "1.13.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "acorn": "^8.14.0", - "acorn-import-attributes": "^1.9.5", - "cjs-module-lexer": "^1.2.2", - "module-details-from-path": "^1.0.3" - } - }, "node_modules/import-local": { "version": "3.0.3", "dev": true, @@ -20827,11 +19784,6 @@ "version": "4.17.21", "license": "MIT" }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.get": { "version": "4.4.2", "dev": true, @@ -20873,7 +19825,9 @@ "license": "MIT" }, "node_modules/long": { - "version": "5.3.1", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", "dev": true, "license": "Apache-2.0" }, @@ -21485,11 +20439,6 @@ "node": ">=10" } }, - "node_modules/module-details-from-path": { - "version": "1.0.3", - "dev": true, - "license": "MIT" - }, "node_modules/morgan": { "version": "1.10.0", "dev": true, @@ -22608,7 +21557,9 @@ "license": "MIT" }, "node_modules/protobufjs": { - "version": "7.4.0", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.1.tgz", + "integrity": "sha512-3qx3IRjR9WPQKagdwrKjO3Gu8RgQR2qqw+1KnigWhoVjFqegIj1K3bP11sGqhxrO46/XL7lekuG4jmjL+4cLsw==", "dev": true, "hasInstallScript": true, "license": "BSD-3-Clause", @@ -22650,11 +21601,6 @@ "node": ">= 0.10" } }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "dev": true, - "license": "MIT" - }, "node_modules/psl": { "version": "1.9.0", "dev": true, @@ -23170,40 +22116,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-in-the-middle": { - "version": "7.5.2", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "module-details-from-path": "^1.0.3", - "resolve": "^1.22.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/require-in-the-middle/node_modules/debug": { - "version": "4.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/require-in-the-middle/node_modules/ms": { - "version": "2.1.3", - "dev": true, - "license": "MIT" - }, "node_modules/requires-port": { "version": "1.0.0", "dev": true, @@ -23783,11 +22695,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/shimmer": { - "version": "1.2.1", - "dev": true, - "license": "BSD-2-Clause" - }, "node_modules/side-channel": { "version": "1.0.6", "license": "MIT", @@ -26484,8 +25391,8 @@ "@aws-sdk/types": "^3.13.1", "@aws/chat-client": "^0.1.4", "@aws/chat-client-ui-types": "^0.1.24", - "@aws/language-server-runtimes": "^0.2.70", - "@aws/language-server-runtimes-types": "^0.1.26", + "@aws/language-server-runtimes": "^0.2.81", + "@aws/language-server-runtimes-types": "^0.1.28", "@cspotcode/source-map-support": "^0.8.1", "@sinonjs/fake-timers": "^10.0.2", "@types/adm-zip": "^0.4.34", diff --git a/packages/amazonq/src/lsp/chat/messages.ts b/packages/amazonq/src/lsp/chat/messages.ts index 38a52f72f9c..89d221e9442 100644 --- a/packages/amazonq/src/lsp/chat/messages.ts +++ b/packages/amazonq/src/lsp/chat/messages.ts @@ -32,6 +32,8 @@ import { getSerializedChatRequestType, listConversationsRequestType, conversationClickRequestType, + listMcpServersRequestType, + mcpServerClickRequestType, ShowSaveFileDialogRequestType, ShowSaveFileDialogParams, LSPErrorCodes, @@ -313,6 +315,8 @@ export function registerMessageListeners( } case listConversationsRequestType.method: case conversationClickRequestType.method: + case listMcpServersRequestType.method: + case mcpServerClickRequestType.method: case tabBarActionRequestType.method: await resolveChatResponse(message.command, message.params, languageClient, webview) break diff --git a/packages/core/package.json b/packages/core/package.json index 0ed5e368121..f35369cc5b9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -443,8 +443,8 @@ "@aws-sdk/types": "^3.13.1", "@aws/chat-client": "^0.1.4", "@aws/chat-client-ui-types": "^0.1.24", - "@aws/language-server-runtimes": "^0.2.70", - "@aws/language-server-runtimes-types": "^0.1.26", + "@aws/language-server-runtimes": "^0.2.81", + "@aws/language-server-runtimes-types": "^0.1.28", "@cspotcode/source-map-support": "^0.8.1", "@sinonjs/fake-timers": "^10.0.2", "@types/adm-zip": "^0.4.34", From dbb24b77916314ea9a55dbe928668ef5eb9afb6b Mon Sep 17 00:00:00 2001 From: aws-toolkit-automation <> Date: Thu, 15 May 2025 16:33:56 +0000 Subject: [PATCH 27/36] Release 3.62.0 --- package-lock.json | 4 ++-- packages/toolkit/.changes/3.62.0.json | 5 +++++ packages/toolkit/CHANGELOG.md | 4 ++++ packages/toolkit/package.json | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 packages/toolkit/.changes/3.62.0.json diff --git a/package-lock.json b/package-lock.json index 6337e22c1d7..081e144778d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "prettier": "^3.3.3", "prettier-plugin-sh": "^0.14.0", "pretty-quick": "^4.0.0", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "^5.0.4", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", @@ -27005,7 +27005,7 @@ }, "packages/toolkit": { "name": "aws-toolkit-vscode", - "version": "3.62.0-SNAPSHOT", + "version": "3.62.0", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" diff --git a/packages/toolkit/.changes/3.62.0.json b/packages/toolkit/.changes/3.62.0.json new file mode 100644 index 00000000000..7c2d15933be --- /dev/null +++ b/packages/toolkit/.changes/3.62.0.json @@ -0,0 +1,5 @@ +{ + "date": "2025-05-15", + "version": "3.62.0", + "entries": [] +} \ No newline at end of file diff --git a/packages/toolkit/CHANGELOG.md b/packages/toolkit/CHANGELOG.md index e830b391487..7d36b0551ef 100644 --- a/packages/toolkit/CHANGELOG.md +++ b/packages/toolkit/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.62.0 2025-05-15 + +- Miscellaneous non-user-facing changes + ## 3.61.0 2025-05-14 - Miscellaneous non-user-facing changes diff --git a/packages/toolkit/package.json b/packages/toolkit/package.json index 491031f47af..b48309d98b8 100644 --- a/packages/toolkit/package.json +++ b/packages/toolkit/package.json @@ -2,7 +2,7 @@ "name": "aws-toolkit-vscode", "displayName": "AWS Toolkit", "description": "Including CodeCatalyst, Infrastructure Composer, and support for Lambda, S3, CloudWatch Logs, CloudFormation, and many other services.", - "version": "3.62.0-SNAPSHOT", + "version": "3.62.0", "extensionKind": [ "workspace" ], From 9881fae3f9114729e2c62295fb1ad3a536ce9167 Mon Sep 17 00:00:00 2001 From: aws-toolkit-automation <> Date: Thu, 15 May 2025 16:37:46 +0000 Subject: [PATCH 28/36] Release 1.68.0 --- package-lock.json | 4 ++-- packages/amazonq/.changes/1.68.0.json | 18 ++++++++++++++++++ ...x-2471c584-3904-4d90-bb7c-61efff219e43.json | 4 ---- ...x-91d391d4-3777-4053-9e71-15b36dfa1f67.json | 4 ---- ...e-31d91f84-30cb-4acd-9e39-9dc153edf0a6.json | 4 ---- packages/amazonq/CHANGELOG.md | 6 ++++++ packages/amazonq/package.json | 2 +- 7 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 packages/amazonq/.changes/1.68.0.json delete mode 100644 packages/amazonq/.changes/next-release/Bug Fix-2471c584-3904-4d90-bb7c-61efff219e43.json delete mode 100644 packages/amazonq/.changes/next-release/Bug Fix-91d391d4-3777-4053-9e71-15b36dfa1f67.json delete mode 100644 packages/amazonq/.changes/next-release/Feature-31d91f84-30cb-4acd-9e39-9dc153edf0a6.json diff --git a/package-lock.json b/package-lock.json index 6337e22c1d7..630e0ca3c4e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "prettier": "^3.3.3", "prettier-plugin-sh": "^0.14.0", "pretty-quick": "^4.0.0", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "typescript": "^5.0.4", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", @@ -25291,7 +25291,7 @@ }, "packages/amazonq": { "name": "amazon-q-vscode", - "version": "1.68.0-SNAPSHOT", + "version": "1.68.0", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" diff --git a/packages/amazonq/.changes/1.68.0.json b/packages/amazonq/.changes/1.68.0.json new file mode 100644 index 00000000000..2c21170aa0b --- /dev/null +++ b/packages/amazonq/.changes/1.68.0.json @@ -0,0 +1,18 @@ +{ + "date": "2025-05-15", + "version": "1.68.0", + "entries": [ + { + "type": "Bug Fix", + "description": "Fix Error: 'Amazon Q service is not signed in'" + }, + { + "type": "Bug Fix", + "description": "Fix Error: 'Amazon Q Profile is not selected for IDC connection type'" + }, + { + "type": "Feature", + "description": "Add inline completion support for abap language" + } + ] +} \ No newline at end of file diff --git a/packages/amazonq/.changes/next-release/Bug Fix-2471c584-3904-4d90-bb7c-61efff219e43.json b/packages/amazonq/.changes/next-release/Bug Fix-2471c584-3904-4d90-bb7c-61efff219e43.json deleted file mode 100644 index f7af0fbb1a4..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-2471c584-3904-4d90-bb7c-61efff219e43.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "Fix Error: 'Amazon Q service is not signed in'" -} diff --git a/packages/amazonq/.changes/next-release/Bug Fix-91d391d4-3777-4053-9e71-15b36dfa1f67.json b/packages/amazonq/.changes/next-release/Bug Fix-91d391d4-3777-4053-9e71-15b36dfa1f67.json deleted file mode 100644 index e3a608296a0..00000000000 --- a/packages/amazonq/.changes/next-release/Bug Fix-91d391d4-3777-4053-9e71-15b36dfa1f67.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Bug Fix", - "description": "Fix Error: 'Amazon Q Profile is not selected for IDC connection type'" -} diff --git a/packages/amazonq/.changes/next-release/Feature-31d91f84-30cb-4acd-9e39-9dc153edf0a6.json b/packages/amazonq/.changes/next-release/Feature-31d91f84-30cb-4acd-9e39-9dc153edf0a6.json deleted file mode 100644 index da0d200410d..00000000000 --- a/packages/amazonq/.changes/next-release/Feature-31d91f84-30cb-4acd-9e39-9dc153edf0a6.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "Feature", - "description": "Add inline completion support for abap language" -} diff --git a/packages/amazonq/CHANGELOG.md b/packages/amazonq/CHANGELOG.md index ceb42f25c55..9d9546ce6f1 100644 --- a/packages/amazonq/CHANGELOG.md +++ b/packages/amazonq/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.68.0 2025-05-15 + +- **Bug Fix** Fix Error: 'Amazon Q service is not signed in' +- **Bug Fix** Fix Error: 'Amazon Q Profile is not selected for IDC connection type' +- **Feature** Add inline completion support for abap language + ## 1.67.0 2025-05-14 - **Bug Fix** Previous and subsequent cells are used as context for completion in a Jupyter notebook diff --git a/packages/amazonq/package.json b/packages/amazonq/package.json index 06c6ce3d30c..eadbec81cc3 100644 --- a/packages/amazonq/package.json +++ b/packages/amazonq/package.json @@ -2,7 +2,7 @@ "name": "amazon-q-vscode", "displayName": "Amazon Q", "description": "The most capable generative AI-powered assistant for building, operating, and transforming software, with advanced capabilities for managing data and AI", - "version": "1.68.0-SNAPSHOT", + "version": "1.68.0", "extensionKind": [ "workspace" ], From c81f7dde476e0830de638624857b7b902032bb71 Mon Sep 17 00:00:00 2001 From: aws-toolkit-automation <> Date: Thu, 15 May 2025 19:42:44 +0000 Subject: [PATCH 29/36] Update version to snapshot version: 3.63.0-SNAPSHOT --- package-lock.json | 4 ++-- packages/toolkit/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 081e144778d..b3b70297de8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "prettier": "^3.3.3", "prettier-plugin-sh": "^0.14.0", "pretty-quick": "^4.0.0", - "ts-node": "^10.9.2", + "ts-node": "^10.9.1", "typescript": "^5.0.4", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", @@ -27005,7 +27005,7 @@ }, "packages/toolkit": { "name": "aws-toolkit-vscode", - "version": "3.62.0", + "version": "3.63.0-SNAPSHOT", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" diff --git a/packages/toolkit/package.json b/packages/toolkit/package.json index b48309d98b8..d4229b0135c 100644 --- a/packages/toolkit/package.json +++ b/packages/toolkit/package.json @@ -2,7 +2,7 @@ "name": "aws-toolkit-vscode", "displayName": "AWS Toolkit", "description": "Including CodeCatalyst, Infrastructure Composer, and support for Lambda, S3, CloudWatch Logs, CloudFormation, and many other services.", - "version": "3.62.0", + "version": "3.63.0-SNAPSHOT", "extensionKind": [ "workspace" ], From c35805e195bacad383f83c18fb3e9d9c82046d39 Mon Sep 17 00:00:00 2001 From: aws-toolkit-automation <> Date: Thu, 15 May 2025 19:53:54 +0000 Subject: [PATCH 30/36] Update version to snapshot version: 1.69.0-SNAPSHOT --- package-lock.json | 4 ++-- packages/amazonq/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 630e0ca3c4e..968b9877687 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "prettier": "^3.3.3", "prettier-plugin-sh": "^0.14.0", "pretty-quick": "^4.0.0", - "ts-node": "^10.9.2", + "ts-node": "^10.9.1", "typescript": "^5.0.4", "webpack": "^5.95.0", "webpack-cli": "^5.1.4", @@ -25291,7 +25291,7 @@ }, "packages/amazonq": { "name": "amazon-q-vscode", - "version": "1.68.0", + "version": "1.69.0-SNAPSHOT", "license": "Apache-2.0", "dependencies": { "aws-core-vscode": "file:../core/" diff --git a/packages/amazonq/package.json b/packages/amazonq/package.json index eadbec81cc3..421dff76d4e 100644 --- a/packages/amazonq/package.json +++ b/packages/amazonq/package.json @@ -2,7 +2,7 @@ "name": "amazon-q-vscode", "displayName": "Amazon Q", "description": "The most capable generative AI-powered assistant for building, operating, and transforming software, with advanced capabilities for managing data and AI", - "version": "1.68.0", + "version": "1.69.0-SNAPSHOT", "extensionKind": [ "workspace" ], From 340309cb5c2184e82fe394883d1b20a25cba360c Mon Sep 17 00:00:00 2001 From: Nikolas Komonen <118216176+nkomonen-amazon@users.noreply.github.com> Date: Fri, 16 May 2025 16:26:35 -0400 Subject: [PATCH 31/36] feat(amazonq): Command to clear extension cache (#7335) ## Problem We need a way to clear `globalState` since it looks like some users are getting in to a bad corrputed state where things stop working. Uninstalling the extension does not clear state, it is intentionally designed that way by vscode, as we don't want to wipe states on extension updates. ## Solution: This creates a new command "Amazon Q: Clear extension cache" which clears the cache and reloads the window. There is safety modal which pops up right before clearing after the command is selected. --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. Signed-off-by: nkomonen-amazon --- packages/amazonq/package.json | 5 +++ packages/amazonq/src/commands.ts | 6 +++- packages/amazonq/src/util/clearCache.ts | 46 +++++++++++++++++++++++++ packages/core/package.nls.json | 1 + 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 packages/amazonq/src/util/clearCache.ts diff --git a/packages/amazonq/package.json b/packages/amazonq/package.json index 421dff76d4e..76510cc2db7 100644 --- a/packages/amazonq/package.json +++ b/packages/amazonq/package.json @@ -805,6 +805,11 @@ { "command": "aws.amazonq.walkthrough.show", "title": "%AWS.amazonq.welcomeWalkthrough%" + }, + { + "command": "aws.amazonq.clearCache", + "title": "%AWS.amazonq.clearCache%", + "category": "%AWS.amazonq.title%" } ], "keybindings": [ diff --git a/packages/amazonq/src/commands.ts b/packages/amazonq/src/commands.ts index 66979146651..494a3f6a3b7 100644 --- a/packages/amazonq/src/commands.ts +++ b/packages/amazonq/src/commands.ts @@ -9,7 +9,11 @@ import * as vscode from 'vscode' import { Auth } from 'aws-core-vscode/auth' import { Commands } from 'aws-core-vscode/shared' +import { clearCacheDeclaration } from './util/clearCache' export function registerCommands(context: vscode.ExtensionContext) { - context.subscriptions.push(Commands.register('_aws.amazonq.auth.autoConnect', Auth.instance.tryAutoConnect)) + context.subscriptions.push( + Commands.register('_aws.amazonq.auth.autoConnect', Auth.instance.tryAutoConnect), + clearCacheDeclaration.register() + ) } diff --git a/packages/amazonq/src/util/clearCache.ts b/packages/amazonq/src/util/clearCache.ts new file mode 100644 index 00000000000..b516c33d43c --- /dev/null +++ b/packages/amazonq/src/util/clearCache.ts @@ -0,0 +1,46 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import { AuthUtil } from 'aws-core-vscode/codewhisperer' +import { Commands, globals } from 'aws-core-vscode/shared' +import vscode from 'vscode' + +/** + * The purpose of this module is to provide a util to clear all extension cache so that it has a clean state + */ + +/** + * Clears "all" cache of the extension, effectively putting the user in a "net new" state. + * + * NOTE: This is a best attempt. There may be state like a file in the filesystem which is not deleted. + * We should aim to add all state clearing in to this method. + */ +async function clearCache() { + // Check a final time if they want to clear their cache + const doContinue = await vscode.window + .showInformationMessage( + 'This will wipe your Amazon Q extension state, then reload your VS Code window. This operation is not dangerous. ', + { modal: true }, + 'Continue' + ) + .then((value) => { + return value === 'Continue' + }) + if (!doContinue) { + return + } + + // SSO cache persists on disk, this should indirectly delete it + const conn = AuthUtil.instance.conn + if (conn) { + await AuthUtil.instance.auth.deleteConnection(conn) + } + + await globals.globalState.clear() + + // Make the IDE reload so all new changes take effect + void vscode.commands.executeCommand('workbench.action.reloadWindow') +} +export const clearCacheDeclaration = Commands.declare({ id: 'aws.amazonq.clearCache' }, () => clearCache) diff --git a/packages/core/package.nls.json b/packages/core/package.nls.json index 81f56a32c57..9922ec6fcd8 100644 --- a/packages/core/package.nls.json +++ b/packages/core/package.nls.json @@ -328,6 +328,7 @@ "AWS.amazonq.title": "Amazon Q", "AWS.amazonq.chat": "Chat", "AWS.amazonq.openChat": "Open Chat", + "AWS.amazonq.clearCache": "Clear extension cache", "AWS.amazonq.context.folders.title": "Folders", "AWS.amazonq.context.folders.description": "Add all files in a folder to context", "AWS.amazonq.context.files.title": "Files", From ea593e295bcdc30f29ac2c8960af1fa69c754daa Mon Sep 17 00:00:00 2001 From: David <60020664+dhasani23@users.noreply.github.com> Date: Fri, 16 May 2025 16:38:11 -0700 Subject: [PATCH 32/36] fix(amazonq): remove target JDK path prompt (#7328) ## Problem /transform was unnecessarily prompting users for their target JDK paths in some cases. ## Solution Remove the prompt. --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --------- Co-authored-by: David Hasani --- .../Bug Fix-636765f1-2278-4a2d-b512-7c63ecc2ce67.json | 4 ++++ packages/core/src/amazonqGumby/chat/controller/controller.ts | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 packages/amazonq/.changes/next-release/Bug Fix-636765f1-2278-4a2d-b512-7c63ecc2ce67.json diff --git a/packages/amazonq/.changes/next-release/Bug Fix-636765f1-2278-4a2d-b512-7c63ecc2ce67.json b/packages/amazonq/.changes/next-release/Bug Fix-636765f1-2278-4a2d-b512-7c63ecc2ce67.json new file mode 100644 index 00000000000..b47be3d7440 --- /dev/null +++ b/packages/amazonq/.changes/next-release/Bug Fix-636765f1-2278-4a2d-b512-7c63ecc2ce67.json @@ -0,0 +1,4 @@ +{ + "type": "Bug Fix", + "description": "/transform: avoid prompting user for target JDK path unnecessarily" +} diff --git a/packages/core/src/amazonqGumby/chat/controller/controller.ts b/packages/core/src/amazonqGumby/chat/controller/controller.ts index af3f462bf95..fea3b89019d 100644 --- a/packages/core/src/amazonqGumby/chat/controller/controller.ts +++ b/packages/core/src/amazonqGumby/chat/controller/controller.ts @@ -688,13 +688,17 @@ export class GumbyController { const pathToJavaHome = extractPath(data.message) if (pathToJavaHome) { transformByQState.setSourceJavaHome(pathToJavaHome) + // TO-DO: delete line below and uncomment the block below when releasing CSB + await this.prepareLanguageUpgradeProject(data.tabID) // if source and target JDK versions are the same, just re-use the source JAVA_HOME and start the build + /* if (transformByQState.getTargetJDKVersion() === transformByQState.getSourceJDKVersion()) { transformByQState.setTargetJavaHome(pathToJavaHome) await this.prepareLanguageUpgradeProject(data.tabID) } else { this.promptJavaHome('target', data.tabID) } + */ } else { this.messenger.sendUnrecoverableErrorResponse('invalid-java-home', data.tabID) } From e564ef6c7db08e9739604f6c702cf60f74224ef7 Mon Sep 17 00:00:00 2001 From: Jiatong Li Date: Mon, 19 May 2025 12:54:39 -0700 Subject: [PATCH 33/36] feat(codewhisperer): add fileUri to FileContext (#7294) ## Problem In order to coordinate the new https://github.com/aws/language-servers/pull/1348 change, GenerateCompletions requests would start expecting the `fileUri` field to be set. ## Solution Add `fileUri` to FileContext --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --------- Co-authored-by: Jiatong Li --- .../test/unit/codewhisperer/util/editorContext.test.ts | 3 +++ packages/core/src/codewhisperer/client/service-2.json | 9 +++++++++ .../core/src/codewhisperer/client/user-service-2.json | 7 +++++++ packages/core/src/codewhisperer/util/editorContext.ts | 1 + 4 files changed, 20 insertions(+) diff --git a/packages/amazonq/test/unit/codewhisperer/util/editorContext.test.ts b/packages/amazonq/test/unit/codewhisperer/util/editorContext.test.ts index f8265a4fa86..3875dbbd0f2 100644 --- a/packages/amazonq/test/unit/codewhisperer/util/editorContext.test.ts +++ b/packages/amazonq/test/unit/codewhisperer/util/editorContext.test.ts @@ -56,6 +56,7 @@ describe('editorContext', function () { const editor = createMockTextEditor('import math\ndef two_sum(nums, target):\n', 'test.py', 'python', 1, 17) const actual = EditorContext.extractContextForCodeWhisperer(editor) const expected: codewhispererClient.FileContext = { + fileUri: 'file:///test.py', filename: 'test.py', programmingLanguage: { languageName: 'python', @@ -76,6 +77,7 @@ describe('editorContext', function () { ) const actual = EditorContext.extractContextForCodeWhisperer(editor) const expected: codewhispererClient.FileContext = { + fileUri: 'file:///test.py', filename: 'test.py', programmingLanguage: { languageName: 'python', @@ -112,6 +114,7 @@ describe('editorContext', function () { const actual = EditorContext.extractContextForCodeWhisperer(editor) const expected: codewhispererClient.FileContext = { + fileUri: editor.document.uri.toString(), filename: 'Untitled-1.py', programmingLanguage: { languageName: 'python', diff --git a/packages/core/src/codewhisperer/client/service-2.json b/packages/core/src/codewhisperer/client/service-2.json index ca57c0f29c6..3e063c38a10 100644 --- a/packages/core/src/codewhisperer/client/service-2.json +++ b/packages/core/src/codewhisperer/client/service-2.json @@ -612,11 +612,20 @@ "filename": { "shape": "FileContextFilenameString" }, + "fileUri": { + "shape": "FileContextFileUriString" + }, "programmingLanguage": { "shape": "ProgrammingLanguage" } } }, + "FileContextFileUriString": { + "type": "string", + "max": 1024, + "min": 1, + "sensitive": true + }, "FileContextFilenameString": { "type": "string", "max": 1024, diff --git a/packages/core/src/codewhisperer/client/user-service-2.json b/packages/core/src/codewhisperer/client/user-service-2.json index 969abf41f1a..714937ed402 100644 --- a/packages/core/src/codewhisperer/client/user-service-2.json +++ b/packages/core/src/codewhisperer/client/user-service-2.json @@ -1852,9 +1852,16 @@ "leftFileContent": { "shape": "FileContextLeftFileContentString" }, "rightFileContent": { "shape": "FileContextRightFileContentString" }, "filename": { "shape": "FileContextFilenameString" }, + "fileUri": { "shape": "FileContextFileUriString" }, "programmingLanguage": { "shape": "ProgrammingLanguage" } } }, + "FileContextFileUriString": { + "type": "string", + "max": 1024, + "min": 1, + "sensitive": true + }, "FileContextFilenameString": { "type": "string", "max": 1024, diff --git a/packages/core/src/codewhisperer/util/editorContext.ts b/packages/core/src/codewhisperer/util/editorContext.ts index 756d9fb2a00..95df5eb509a 100644 --- a/packages/core/src/codewhisperer/util/editorContext.ts +++ b/packages/core/src/codewhisperer/util/editorContext.ts @@ -167,6 +167,7 @@ export function extractContextForCodeWhisperer(editor: vscode.TextEditor): codew } return { + fileUri: editor.document.uri.toString().substring(0, CodeWhispererConstants.filenameCharsLimit), filename: getFileRelativePath(editor), programmingLanguage: { languageName: languageName, From 1d585e99e6cfad694898b0baaaf10fc0ee3031c6 Mon Sep 17 00:00:00 2001 From: Jason Guo <81202082+jguoamz@users.noreply.github.com> Date: Mon, 19 May 2025 14:12:26 -0700 Subject: [PATCH 34/36] feat(chat): Add ripgrep path and make it executable (#7325) ## Problem - AgenticChat will add a grepSearch tool which depends on ripgrep binary ## Solution - Add ripgrep path and make it executable --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --- packages/amazonq/src/lsp/lspInstaller.ts | 13 ++++++++++++- packages/core/src/shared/lsp/utils/platform.ts | 4 ++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/amazonq/src/lsp/lspInstaller.ts b/packages/amazonq/src/lsp/lspInstaller.ts index 72fa091f027..84d5ee8961b 100644 --- a/packages/amazonq/src/lsp/lspInstaller.ts +++ b/packages/amazonq/src/lsp/lspInstaller.ts @@ -3,12 +3,17 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { fs, getNodeExecutableName, BaseLspInstaller, ResourcePaths } from 'aws-core-vscode/shared' +import { fs, getNodeExecutableName, getRgExecutableName, BaseLspInstaller, ResourcePaths } from 'aws-core-vscode/shared' import path from 'path' import { ExtendedAmazonQLSPConfig, getAmazonQLspConfig } from './config' export interface AmazonQResourcePaths extends ResourcePaths { ui: string + /** + * Path to `rg` (or `rg.exe`) executable/binary. + * Example: `"/aws/toolkits/language-servers/AmazonQ/3.3.0/servers/rg"` + */ + ripGrep: string } export class AmazonQLspInstaller extends BaseLspInstaller.BaseLspInstaller< @@ -22,6 +27,9 @@ export class AmazonQLspInstaller extends BaseLspInstaller.BaseLspInstaller< protected override async postInstall(assetDirectory: string): Promise { const resourcePaths = this.resourcePaths(assetDirectory) await fs.chmod(resourcePaths.node, 0o755) + if (await fs.exists(resourcePaths.ripGrep)) { + await fs.chmod(resourcePaths.ripGrep, 0o755) + } } protected override resourcePaths(assetDirectory?: string): AmazonQResourcePaths { @@ -29,14 +37,17 @@ export class AmazonQLspInstaller extends BaseLspInstaller.BaseLspInstaller< return { lsp: this.config.path ?? '', node: getNodeExecutableName(), + ripGrep: `ripgrep/${getRgExecutableName()}`, ui: this.config.ui ?? '', } } const nodePath = path.join(assetDirectory, `servers/${getNodeExecutableName()}`) + const rgPath = path.join(assetDirectory, `servers/ripgrep/${getRgExecutableName()}`) return { lsp: path.join(assetDirectory, 'servers/aws-lsp-codewhisperer.js'), node: nodePath, + ripGrep: rgPath, ui: path.join(assetDirectory, 'clients/amazonq-ui.js'), } } diff --git a/packages/core/src/shared/lsp/utils/platform.ts b/packages/core/src/shared/lsp/utils/platform.ts index 2555793ceb5..39284e8a0ac 100644 --- a/packages/core/src/shared/lsp/utils/platform.ts +++ b/packages/core/src/shared/lsp/utils/platform.ts @@ -13,6 +13,10 @@ export function getNodeExecutableName(): string { return process.platform === 'win32' ? 'node.exe' : 'node' } +export function getRgExecutableName(): string { + return process.platform === 'win32' ? 'rg.exe' : 'rg' +} + /** * Get a json payload that will be sent to the language server, who is waiting to know what the encryption key is. * Code reference: https://github.com/aws/language-servers/blob/7da212185a5da75a72ce49a1a7982983f438651a/client/vscode/src/credentialsActivation.ts#L77 From 3d30dcdc209a7efebdff54e935bd704d5958d404 Mon Sep 17 00:00:00 2001 From: David <60020664+dhasani23@users.noreply.github.com> Date: Tue, 20 May 2025 11:04:01 -0700 Subject: [PATCH 35/36] feat(amazonq): parse new transformation plan (#7340) ## Problem Our transformation now looks different, so we want the IDE to be able to handle the new plan response. ## Solution Implement parsing logic. --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --------- Co-authored-by: David Hasani --- .../commands/startTransformByQ.ts | 23 ---- .../core/src/codewhisperer/models/model.ts | 1 + .../transformByQ/transformApiHandler.ts | 109 ++++++++++++++---- .../commands/transformByQ.test.ts | 32 ++++- 4 files changed, 114 insertions(+), 51 deletions(-) diff --git a/packages/core/src/codewhisperer/commands/startTransformByQ.ts b/packages/core/src/codewhisperer/commands/startTransformByQ.ts index eb31839686d..88171dd5b83 100644 --- a/packages/core/src/codewhisperer/commands/startTransformByQ.ts +++ b/packages/core/src/codewhisperer/commands/startTransformByQ.ts @@ -27,7 +27,6 @@ import { downloadHilResultArchive, findDownloadArtifactStep, getArtifactsFromProgressUpdate, - getTransformationPlan, getTransformationSteps, pollTransformationJob, resumeTransformationJob, @@ -554,28 +553,6 @@ export async function pollTransformationStatusUntilPlanReady(jobId: string, prof // for now, no plan shown with SQL conversions. later, we may add one return } - let plan = undefined - try { - plan = await getTransformationPlan(jobId, profile) - } catch (error) { - // means API call failed - getLogger().error(`CodeTransformation: ${CodeWhispererConstants.failedToCompleteJobNotification}`, error) - transformByQState.setJobFailureErrorNotification( - `${CodeWhispererConstants.failedToGetPlanNotification} ${(error as Error).message}` - ) - transformByQState.setJobFailureErrorChatMessage( - `${CodeWhispererConstants.failedToGetPlanChatMessage} ${(error as Error).message}` - ) - throw new Error('Get plan failed') - } - - if (plan !== undefined) { - const planFilePath = path.join(transformByQState.getProjectPath(), 'transformation-plan.md') - fs.writeFileSync(planFilePath, plan) - await vscode.commands.executeCommand('markdown.showPreview', vscode.Uri.file(planFilePath)) - transformByQState.setPlanFilePath(planFilePath) - await setContext('gumby.isPlanAvailable', true) - } jobPlanProgress['generatePlan'] = StepProgress.Succeeded throwIfCancelled() } diff --git a/packages/core/src/codewhisperer/models/model.ts b/packages/core/src/codewhisperer/models/model.ts index 28072249371..9c48838afe3 100644 --- a/packages/core/src/codewhisperer/models/model.ts +++ b/packages/core/src/codewhisperer/models/model.ts @@ -686,6 +686,7 @@ export class ZipManifest { version: string = '1.0' hilCapabilities: string[] = ['HIL_1pDependency_VersionUpgrade'] // TO-DO: add 'CLIENT_SIDE_BUILD' here when releasing + // TO-DO: add something like AGENTIC_PLAN_V1 here when BE allowlists everyone transformCapabilities: string[] = ['EXPLAINABILITY_V1'] customBuildCommand: string = 'clean test' requestedConversions?: { diff --git a/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts b/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts index 476123f2d6d..9214fb23572 100644 --- a/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts +++ b/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts @@ -51,6 +51,7 @@ import { encodeHTML } from '../../../shared/utilities/textUtilities' import { convertToTimeString } from '../../../shared/datetime' import { getAuthType } from '../../../auth/utils' import { UserWrittenCodeTracker } from '../../tracker/userWrittenCodeTracker' +import { setContext } from '../../../shared/vscode/setContext' import { AuthUtil } from '../../util/authUtil' import { DiffModel } from './transformationResultsViewProvider' import { spawnSync } from 'child_process' // eslint-disable-line no-restricted-imports @@ -521,20 +522,33 @@ export function getFormattedString(s: string) { return CodeWhispererConstants.formattedStringMap.get(s) ?? s } -export function addTableMarkdown(plan: string, stepId: string, tableMapping: { [key: string]: string }) { - const tableObj = tableMapping[stepId] - if (!tableObj) { - // no table present for this step +export function addTableMarkdown(plan: string, stepId: string, tableMapping: { [key: string]: string[] }) { + const tableObjects = tableMapping[stepId] + if (!tableObjects || tableObjects.length === 0 || tableObjects.every((table: string) => table === '')) { + // no tables for this stepId return plan } - const table = JSON.parse(tableObj) - if (table.rows.length === 0) { - // empty table - plan += `\n\nThere are no ${table.name.toLowerCase()} to display.\n\n` + const tables: any[] = [] + // eslint-disable-next-line unicorn/no-array-for-each + tableObjects.forEach((tableObj: string) => { + try { + const table = JSON.parse(tableObj) + if (table) { + tables.push(table) + } + } catch (e) { + getLogger().error(`CodeTransformation: Failed to parse table JSON, skipping: ${e}`) + } + }) + + if (tables.every((table: any) => table.rows.length === 0)) { + // empty tables for this stepId + plan += `\n\nThere are no ${tables[0].name.toLowerCase()} to display.\n\n` return plan } - plan += `\n\n\n${table.name}\n|` - const columns = table.columnNames + // table name and columns are shared, so only add to plan once + plan += `\n\n\n${tables[0].name}\n|` + const columns = tables[0].columnNames // eslint-disable-next-line unicorn/no-array-for-each columns.forEach((columnName: string) => { plan += ` ${getFormattedString(columnName)} |` @@ -544,16 +558,21 @@ export function addTableMarkdown(plan: string, stepId: string, tableMapping: { [ columns.forEach((_: any) => { plan += '-----|' }) + // add all rows of all tables // eslint-disable-next-line unicorn/no-array-for-each - table.rows.forEach((row: any) => { - plan += '\n|' + tables.forEach((table: any) => { // eslint-disable-next-line unicorn/no-array-for-each - columns.forEach((columnName: string) => { - if (columnName === 'relativePath') { - plan += ` [${row[columnName]}](${row[columnName]}) |` // add MD link only for files - } else { - plan += ` ${row[columnName]} |` - } + table.rows.forEach((row: any) => { + plan += '\n|' + // eslint-disable-next-line unicorn/no-array-for-each + columns.forEach((columnName: string) => { + if (columnName === 'relativePath') { + // add markdown link only for file paths + plan += ` [${row[columnName]}](${row[columnName]}) |` + } else { + plan += ` ${row[columnName]} |` + } + }) }) }) plan += '\n\n' @@ -561,11 +580,13 @@ export function addTableMarkdown(plan: string, stepId: string, tableMapping: { [ } export function getTableMapping(stepZeroProgressUpdates: ProgressUpdates) { - const map: { [key: string]: string } = {} + const map: { [key: string]: string[] } = {} for (const update of stepZeroProgressUpdates) { - // description should never be undefined since even if no data we show an empty table - // but just in case, empty string allows us to skip this table without errors when rendering - map[update.name] = update.description ?? '' + if (!map[update.name]) { + map[update.name] = [] + } + // empty string allows us to skip this table when rendering + map[update.name].push(update.description ?? '') } return map } @@ -604,7 +625,7 @@ export async function getTransformationPlan(jobId: string, profile: RegionProfil // gets a mapping between the ID ('name' field) of each progressUpdate (substep) and the associated table const tableMapping = getTableMapping(stepZeroProgressUpdates) - const jobStatistics = JSON.parse(tableMapping['0']).rows // ID of '0' reserved for job statistics table + const jobStatistics = JSON.parse(tableMapping['0'][0]).rows // ID of '0' reserved for job statistics table; only 1 table there // get logo directly since we only use one logo regardless of color theme const logoIcon = getTransformationIcon('transformLogo') @@ -631,7 +652,7 @@ export async function getTransformationPlan(jobId: string, profile: RegionProfil } plan += `
    ` plan += `

    Appendix
    Scroll to top


    ` - plan = addTableMarkdown(plan, '-1', tableMapping) // ID of '-1' reserved for appendix table + plan = addTableMarkdown(plan, '-1', tableMapping) // ID of '-1' reserved for appendix table; only 1 table there return plan } catch (e: any) { const errorMessage = (e as Error).message @@ -663,6 +684,7 @@ export async function getTransformationSteps(jobId: string, profile: RegionProfi export async function pollTransformationJob(jobId: string, validStates: string[], profile: RegionProfile | undefined) { let status: string = '' + let isPlanComplete = false while (true) { throwIfCancelled() try { @@ -699,6 +721,19 @@ export async function pollTransformationJob(jobId: string, validStates: string[] `${CodeWhispererConstants.failedToCompleteJobGenericNotification} ${errorMessage}` ) } + + if ( + CodeWhispererConstants.validStatesForPlanGenerated.includes(status) && + transformByQState.getTransformationType() === TransformationType.LANGUAGE_UPGRADE && + !isPlanComplete + ) { + const plan = await openTransformationPlan(jobId, profile) + if (plan?.toLowerCase().includes('dependency changes')) { + // final plan is complete; show to user + isPlanComplete = true + } + } + if (validStates.includes(status)) { break } @@ -738,6 +773,32 @@ export async function pollTransformationJob(jobId: string, validStates: string[] return status } +async function openTransformationPlan(jobId: string, profile?: RegionProfile) { + let plan = undefined + try { + plan = await getTransformationPlan(jobId, profile) + } catch (error) { + // means API call failed + getLogger().error(`CodeTransformation: ${CodeWhispererConstants.failedToCompleteJobNotification}`, error) + transformByQState.setJobFailureErrorNotification( + `${CodeWhispererConstants.failedToGetPlanNotification} ${(error as Error).message}` + ) + transformByQState.setJobFailureErrorChatMessage( + `${CodeWhispererConstants.failedToGetPlanChatMessage} ${(error as Error).message}` + ) + throw new Error('Get plan failed') + } + + if (plan) { + const planFilePath = path.join(transformByQState.getProjectPath(), 'transformation-plan.md') + nodefs.writeFileSync(planFilePath, plan) + await vscode.commands.executeCommand('markdown.showPreview', vscode.Uri.file(planFilePath)) + transformByQState.setPlanFilePath(planFilePath) + await setContext('gumby.isPlanAvailable', true) + } + return plan +} + async function attemptLocalBuild() { const jobId = transformByQState.getJobId() let artifactId diff --git a/packages/core/src/test/codewhisperer/commands/transformByQ.test.ts b/packages/core/src/test/codewhisperer/commands/transformByQ.test.ts index 4b478e1876e..ea2aefce277 100644 --- a/packages/core/src/test/codewhisperer/commands/transformByQ.test.ts +++ b/packages/core/src/test/codewhisperer/commands/transformByQ.test.ts @@ -247,7 +247,25 @@ dependencyManagement: }, transformationJob: { status: 'COMPLETED' }, } + const mockPlanResponse = { + $response: { + data: { + transformationPlan: { transformationSteps: [] }, + }, + requestId: 'requestId', + hasNextPage: () => false, + error: undefined, + nextPage: () => null, // eslint-disable-line unicorn/no-null + redirectCount: 0, + retryCount: 0, + httpResponse: new HttpResponse(), + }, + transformationPlan: { transformationSteps: [] }, + } sinon.stub(codeWhisperer.codeWhispererClient, 'codeModernizerGetCodeTransformation').resolves(mockJobResponse) + sinon + .stub(codeWhisperer.codeWhispererClient, 'codeModernizerGetCodeTransformationPlan') + .resolves(mockPlanResponse) transformByQState.setToSucceeded() const status = await pollTransformationJob( 'dummyId', @@ -488,12 +506,18 @@ dependencyManagement: const actual = getTableMapping(stepZeroProgressUpdates) const expected = { - '0': '{"columnNames":["name","value"],"rows":[{"name":"Lines of code in your application","value":"3000"},{"name":"Dependencies to be replaced","value":"5"},{"name":"Deprecated code instances to be replaced","value":"10"},{"name":"Files to be updated","value":"7"}]}', - '1-dependency-change-abc': + '0': [ + '{"columnNames":["name","value"],"rows":[{"name":"Lines of code in your application","value":"3000"},{"name":"Dependencies to be replaced","value":"5"},{"name":"Deprecated code instances to be replaced","value":"10"},{"name":"Files to be updated","value":"7"}]}', + ], + '1-dependency-change-abc': [ '{"columnNames":["dependencyName","action","currentVersion","targetVersion"],"rows":[{"dependencyName":"org.springboot.com","action":"Update","currentVersion":"2.1","targetVersion":"2.4"}, {"dependencyName":"com.lombok.java","action":"Remove","currentVersion":"1.7","targetVersion":"-"}]}', - '2-deprecated-code-xyz': + ], + '2-deprecated-code-xyz': [ '{"columnNames":["apiFullyQualifiedName","numChangedFiles"],“rows”:[{"apiFullyQualifiedName":"java.lang.Thread.stop()","numChangedFiles":"6"}, {"apiFullyQualifiedName":"java.math.bad()","numChangedFiles":"3"}]}', - '-1': '{"columnNames":["relativePath","action"],"rows":[{"relativePath":"pom.xml","action":"Update"}, {"relativePath":"src/main/java/com/bhoruka/bloodbank/BloodbankApplication.java","action":"Update"}]}', + ], + '-1': [ + '{"columnNames":["relativePath","action"],"rows":[{"relativePath":"pom.xml","action":"Update"}, {"relativePath":"src/main/java/com/bhoruka/bloodbank/BloodbankApplication.java","action":"Update"}]}', + ], } assert.deepStrictEqual(actual, expected) }) From 196de6f566fe29399dfa7147e3f948fa27582ba6 Mon Sep 17 00:00:00 2001 From: David <60020664+dhasani23@users.noreply.github.com> Date: Tue, 20 May 2025 11:06:10 -0700 Subject: [PATCH 36/36] feat(amazonq): remove option to select multiple diffs (#7327) ## Problem Prompting users to select one or multiple diffs is a very infrequently used feature. ## Solution Remove it. --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license. --------- Co-authored-by: David Hasani --- ...-4bab219b-28df-44af-8b7f-6ea50dbb02a8.json | 4 + .../test/e2e/amazonq/transformByQ.test.ts | 27 +---- .../amazonqGumby/resources/files/diff.json | 9 -- .../transformationResultsHandler.test.ts | 47 +------- .../chat/controller/controller.ts | 33 +---- .../chat/controller/messenger/messenger.ts | 62 ++-------- .../controller/messenger/messengerUtils.ts | 1 - .../commands/startTransformByQ.ts | 9 +- .../src/codewhisperer/models/constants.ts | 62 +--------- .../core/src/codewhisperer/models/model.ts | 21 ---- .../transformByQ/transformApiHandler.ts | 6 +- .../transformationResultsViewProvider.ts | 113 ++---------------- 12 files changed, 40 insertions(+), 354 deletions(-) create mode 100644 packages/amazonq/.changes/next-release/Removal-4bab219b-28df-44af-8b7f-6ea50dbb02a8.json delete mode 100644 packages/amazonq/test/unit/amazonqGumby/resources/files/diff.json diff --git a/packages/amazonq/.changes/next-release/Removal-4bab219b-28df-44af-8b7f-6ea50dbb02a8.json b/packages/amazonq/.changes/next-release/Removal-4bab219b-28df-44af-8b7f-6ea50dbb02a8.json new file mode 100644 index 00000000000..fc4359df5d9 --- /dev/null +++ b/packages/amazonq/.changes/next-release/Removal-4bab219b-28df-44af-8b7f-6ea50dbb02a8.json @@ -0,0 +1,4 @@ +{ + "type": "Removal", + "description": "/transform: remove option to select multiple diffs" +} diff --git a/packages/amazonq/test/e2e/amazonq/transformByQ.test.ts b/packages/amazonq/test/e2e/amazonq/transformByQ.test.ts index 74f788732dd..4493a7c2387 100644 --- a/packages/amazonq/test/e2e/amazonq/transformByQ.test.ts +++ b/packages/amazonq/test/e2e/amazonq/transformByQ.test.ts @@ -123,29 +123,8 @@ describe('Amazon Q Code Transformation', function () { formItemValues: skipTestsFormValues, }) - // 3 additional chat messages (including message with 3rd form) get sent after 2nd form submitted; wait for all of them - await tab.waitForEvent(() => tab.getChatItems().length > 9, { - waitTimeoutInMs: 5000, - waitIntervalInMs: 1000, - }) - const multipleDiffsForm = tab.getChatItems().pop() - assert.strictEqual( - multipleDiffsForm?.formItems?.[0]?.id ?? undefined, - 'GumbyTransformOneOrMultipleDiffsForm' - ) - - const oneOrMultipleDiffsFormItemValues = { - GumbyTransformOneOrMultipleDiffsForm: 'One diff', - } - const oneOrMultipleDiffsFormValues: Record = { ...oneOrMultipleDiffsFormItemValues } - tab.clickCustomFormButton({ - id: 'gumbyTransformOneOrMultipleDiffsFormConfirm', - text: 'Confirm', - formItemValues: oneOrMultipleDiffsFormValues, - }) - // 2 additional chat messages get sent after 3rd form submitted; wait for both of them - await tab.waitForEvent(() => tab.getChatItems().length > 11, { + await tab.waitForEvent(() => tab.getChatItems().length > 8, { waitTimeoutInMs: 5000, waitIntervalInMs: 1000, }) @@ -172,7 +151,7 @@ describe('Amazon Q Code Transformation', function () { tab.addChatMessage({ prompt: '/dummy/path/to/jdk8' }) // 2 additional chat messages get sent after JDK path submitted; wait for both of them - await tab.waitForEvent(() => tab.getChatItems().length > 13, { + await tab.waitForEvent(() => tab.getChatItems().length > 10, { waitTimeoutInMs: 5000, waitIntervalInMs: 1000, }) @@ -194,7 +173,7 @@ describe('Amazon Q Code Transformation', function () { text: 'View summary', }) - await tab.waitForEvent(() => tab.getChatItems().length > 14, { + await tab.waitForEvent(() => tab.getChatItems().length > 11, { waitTimeoutInMs: 5000, waitIntervalInMs: 1000, }) diff --git a/packages/amazonq/test/unit/amazonqGumby/resources/files/diff.json b/packages/amazonq/test/unit/amazonqGumby/resources/files/diff.json deleted file mode 100644 index 5b73cdd201b..00000000000 --- a/packages/amazonq/test/unit/amazonqGumby/resources/files/diff.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "content": [ - { - "name": "Added file", - "fileName": "resources/files/addedFile.diff", - "isSuccessful": true - } - ] -} diff --git a/packages/amazonq/test/unit/amazonqGumby/transformationResultsHandler.test.ts b/packages/amazonq/test/unit/amazonqGumby/transformationResultsHandler.test.ts index 4e1ce627bd3..143346674d9 100644 --- a/packages/amazonq/test/unit/amazonqGumby/transformationResultsHandler.test.ts +++ b/packages/amazonq/test/unit/amazonqGumby/transformationResultsHandler.test.ts @@ -5,18 +5,12 @@ import assert from 'assert' import sinon from 'sinon' import { DiffModel, AddedChangeNode, ModifiedChangeNode } from 'aws-core-vscode/codewhisperer/node' -import { DescriptionContent } from 'aws-core-vscode/codewhisperer' import path from 'path' import { getTestResourceFilePath } from './amazonQGumbyUtil' import { fs } from 'aws-core-vscode/shared' import { createTestWorkspace } from 'aws-core-vscode/test' describe('DiffModel', function () { - let parsedTestDescriptions: DescriptionContent - beforeEach(async () => { - parsedTestDescriptions = JSON.parse(await fs.readFileText(getTestResourceFilePath('resources/files/diff.json'))) - }) - afterEach(() => { sinon.restore() }) @@ -34,18 +28,12 @@ describe('DiffModel', function () { return true }) - testDiffModel.parseDiff( - getTestResourceFilePath('resources/files/addedFile.diff'), - workspacePath, - parsedTestDescriptions.content[0], - 1 - ) + testDiffModel.parseDiff(getTestResourceFilePath('resources/files/addedFile.diff'), workspacePath) assert.strictEqual( testDiffModel.patchFileNodes[0].patchFilePath, getTestResourceFilePath('resources/files/addedFile.diff') ) - assert(testDiffModel.patchFileNodes[0].label.includes(parsedTestDescriptions.content[0].name)) const change = testDiffModel.patchFileNodes[0].children[0] assert.strictEqual(change instanceof AddedChangeNode, true) @@ -64,44 +52,13 @@ describe('DiffModel', function () { testDiffModel.parseDiff( getTestResourceFilePath('resources/files/modifiedFile.diff'), - workspaceFolder.uri.fsPath, - parsedTestDescriptions.content[0], - 1 - ) - - assert.strictEqual( - testDiffModel.patchFileNodes[0].patchFilePath, - getTestResourceFilePath('resources/files/modifiedFile.diff') - ) - assert(testDiffModel.patchFileNodes[0].label.includes(parsedTestDescriptions.content[0].name)) - const change = testDiffModel.patchFileNodes[0].children[0] - - assert.strictEqual(change instanceof ModifiedChangeNode, true) - }) - - it('WHEN parsing a diff patch where diff.json is not present and a file was modified THEN returns an array representing the modified file', async function () { - const testDiffModel = new DiffModel() - - const fileAmount = 1 - const workspaceFolder = await createTestWorkspace(fileAmount, { fileContent: '' }) - - await fs.writeFile( - path.join(workspaceFolder.uri.fsPath, 'README.md'), - 'This guide walks you through using Gradle to build a simple Java project.' - ) - - testDiffModel.parseDiff( - getTestResourceFilePath('resources/files/modifiedFile.diff'), - workspaceFolder.uri.fsPath, - undefined, - 1 + workspaceFolder.uri.fsPath ) assert.strictEqual( testDiffModel.patchFileNodes[0].patchFilePath, getTestResourceFilePath('resources/files/modifiedFile.diff') ) - assert(testDiffModel.patchFileNodes[0].label.endsWith('modifiedFile.diff')) const change = testDiffModel.patchFileNodes[0].children[0] assert.strictEqual(change instanceof ModifiedChangeNode, true) diff --git a/packages/core/src/amazonqGumby/chat/controller/controller.ts b/packages/core/src/amazonqGumby/chat/controller/controller.ts index fea3b89019d..57367143cd4 100644 --- a/packages/core/src/amazonqGumby/chat/controller/controller.ts +++ b/packages/core/src/amazonqGumby/chat/controller/controller.ts @@ -367,16 +367,12 @@ export class GumbyController { this.transformationFinished({ message: CodeWhispererConstants.jobCancelledChatMessage, tabID: message.tabID, - includeStartNewTransformationButton: true, }) }) break case ButtonActions.CONFIRM_SKIP_TESTS_FORM: await this.handleSkipTestsSelection(message) break - case ButtonActions.CONFIRM_SELECTIVE_TRANSFORMATION_FORM: - await this.handleOneOrMultipleDiffs(message) - break case ButtonActions.CONFIRM_SQL_CONVERSION_TRANSFORMATION_FORM: await this.handleUserSQLConversionProjectSelection(message) break @@ -441,25 +437,6 @@ export class GumbyController { userChoice: skipTestsSelection, }) this.messenger.sendSkipTestsSelectionMessage(skipTestsSelection, message.tabID) - await this.messenger.sendOneOrMultipleDiffsPrompt(message.tabID) - }) - } - - private async handleOneOrMultipleDiffs(message: any) { - await telemetry.codeTransform_submitSelection.run(async () => { - const oneOrMultipleDiffsSelection = message.formSelectedValues['GumbyTransformOneOrMultipleDiffsForm'] - if (oneOrMultipleDiffsSelection === CodeWhispererConstants.multipleDiffsMessage) { - transformByQState.setMultipleDiffs(true) - } else { - transformByQState.setMultipleDiffs(false) - } - - telemetry.record({ - codeTransformSessionId: CodeTransformTelemetryState.instance.getSessionId(), - userChoice: oneOrMultipleDiffsSelection, - }) - - this.messenger.sendOneOrMultipleDiffsMessage(oneOrMultipleDiffsSelection, message.tabID) this.promptJavaHome('source', message.tabID) // TO-DO: delete line above and uncomment line below when releasing CSB // await this.messenger.sendCustomDependencyVersionMessage(message.tabID) @@ -618,7 +595,6 @@ export class GumbyController { this.transformationFinished({ message: CodeWhispererConstants.jobCancelledChatMessage, tabID: message.tabID, - includeStartNewTransformationButton: true, }) return } @@ -647,15 +623,11 @@ export class GumbyController { ) } - private transformationFinished(data: { - message: string | undefined - tabID: string - includeStartNewTransformationButton: boolean - }) { + private transformationFinished(data: { message: string | undefined; tabID: string }) { this.resetTransformationChatFlow() // at this point job is either completed, partially_completed, cancelled, or failed if (data.message) { - this.messenger.sendJobFinishedMessage(data.tabID, data.message, data.includeStartNewTransformationButton) + this.messenger.sendJobFinishedMessage(data.tabID, data.message) } } @@ -783,7 +755,6 @@ export class GumbyController { this.transformationFinished({ tabID: message.tabID, message: (err as Error).message, - includeStartNewTransformationButton: true, }) } diff --git a/packages/core/src/amazonqGumby/chat/controller/messenger/messenger.ts b/packages/core/src/amazonqGumby/chat/controller/messenger/messenger.ts index 30324bab06f..9d15271aa1e 100644 --- a/packages/core/src/amazonqGumby/chat/controller/messenger/messenger.ts +++ b/packages/core/src/amazonqGumby/chat/controller/messenger/messenger.ts @@ -157,47 +157,6 @@ export class Messenger { ) } - public async sendOneOrMultipleDiffsPrompt(tabID: string) { - const formItems: ChatItemFormItem[] = [] - formItems.push({ - id: 'GumbyTransformOneOrMultipleDiffsForm', - type: 'select', - title: CodeWhispererConstants.selectiveTransformationFormTitle, - mandatory: true, - options: [ - { - value: CodeWhispererConstants.oneDiffMessage, - label: CodeWhispererConstants.oneDiffMessage, - }, - { - value: CodeWhispererConstants.multipleDiffsMessage, - label: CodeWhispererConstants.multipleDiffsMessage, - }, - ], - }) - - this.dispatcher.sendAsyncEventProgress( - new AsyncEventProgressMessage(tabID, { - inProgress: true, - message: CodeWhispererConstants.userPatchDescriptionChatMessage( - transformByQState.getTargetJDKVersion() ?? '' - ), - }) - ) - - this.dispatcher.sendChatPrompt( - new ChatPrompt( - { - message: 'Q Code Transformation', - formItems: formItems, - }, - 'TransformOneOrMultipleDiffsForm', - tabID, - false - ) - ) - } - public async sendLanguageUpgradeProjectPrompt(projects: TransformationCandidateProject[], tabID: string) { const projectFormOptions: { value: any; label: string }[] = [] const detectedJavaVersions = new Array() @@ -501,16 +460,14 @@ export class Messenger { this.dispatcher.sendCommandMessage(new SendCommandMessage(message.command, message.tabID, message.eventId)) } - public sendJobFinishedMessage(tabID: string, message: string, includeStartNewTransformationButton: boolean = true) { + public sendJobFinishedMessage(tabID: string, message: string) { const buttons: ChatItemButton[] = [] - if (includeStartNewTransformationButton) { - buttons.push({ - keepCardAfterClick: false, - text: CodeWhispererConstants.startTransformationButtonText, - id: ButtonActions.CONFIRM_START_TRANSFORMATION_FLOW, - disabled: false, - }) - } + buttons.push({ + keepCardAfterClick: false, + text: CodeWhispererConstants.startTransformationButtonText, + id: ButtonActions.CONFIRM_START_TRANSFORMATION_FLOW, + disabled: false, + }) if (transformByQState.isPartiallySucceeded() || transformByQState.isSucceeded()) { buttons.push({ @@ -598,11 +555,6 @@ export class Messenger { this.dispatcher.sendChatMessage(new ChatMessage({ message, messageType: 'ai-prompt' }, tabID)) } - public sendOneOrMultipleDiffsMessage(selectiveTransformationSelection: string, tabID: string) { - const message = `Okay, I will create ${selectiveTransformationSelection.toLowerCase()} with my proposed changes.` - this.dispatcher.sendChatMessage(new ChatMessage({ message, messageType: 'ai-prompt' }, tabID)) - } - public sendHumanInTheLoopInitialMessage(tabID: string, codeSnippet: string) { let message = `I was not able to upgrade all dependencies. To resolve it, I will try to find an updated depedency in your local Maven repository. I will need additional information from you to continue.` diff --git a/packages/core/src/amazonqGumby/chat/controller/messenger/messengerUtils.ts b/packages/core/src/amazonqGumby/chat/controller/messenger/messengerUtils.ts index ad1aade7c7e..af9f9f47a7b 100644 --- a/packages/core/src/amazonqGumby/chat/controller/messenger/messengerUtils.ts +++ b/packages/core/src/amazonqGumby/chat/controller/messenger/messengerUtils.ts @@ -18,7 +18,6 @@ export enum ButtonActions { CONFIRM_SQL_CONVERSION_TRANSFORMATION_FORM = 'gumbySQLConversionTransformFormConfirm', CANCEL_TRANSFORMATION_FORM = 'gumbyTransformFormCancel', // shared between Language Upgrade & SQL Conversion CONFIRM_SKIP_TESTS_FORM = 'gumbyTransformSkipTestsFormConfirm', - CONFIRM_SELECTIVE_TRANSFORMATION_FORM = 'gumbyTransformOneOrMultipleDiffsFormConfirm', SELECT_SQL_CONVERSION_METADATA_FILE = 'gumbySQLConversionMetadataTransformFormConfirm', SELECT_CUSTOM_DEPENDENCY_VERSION_FILE = 'gumbyCustomDependencyVersionTransformFormConfirm', CONTINUE_TRANSFORMATION_FORM = 'gumbyTransformFormContinue', diff --git a/packages/core/src/codewhisperer/commands/startTransformByQ.ts b/packages/core/src/codewhisperer/commands/startTransformByQ.ts index 88171dd5b83..5e8256b7f77 100644 --- a/packages/core/src/codewhisperer/commands/startTransformByQ.ts +++ b/packages/core/src/codewhisperer/commands/startTransformByQ.ts @@ -676,11 +676,10 @@ export async function postTransformationJob() { } let chatMessage = transformByQState.getJobFailureErrorChatMessage() - const diffMessage = CodeWhispererConstants.diffMessage(transformByQState.getMultipleDiffs()) if (transformByQState.isSucceeded()) { - chatMessage = CodeWhispererConstants.jobCompletedChatMessage(diffMessage) + chatMessage = CodeWhispererConstants.jobCompletedChatMessage } else if (transformByQState.isPartiallySucceeded()) { - chatMessage = CodeWhispererConstants.jobPartiallyCompletedChatMessage(diffMessage) + chatMessage = CodeWhispererConstants.jobPartiallyCompletedChatMessage } transformByQState.getChatControllers()?.transformationFinished.fire({ @@ -709,13 +708,13 @@ export async function postTransformationJob() { } if (transformByQState.isSucceeded()) { - void vscode.window.showInformationMessage(CodeWhispererConstants.jobCompletedNotification(diffMessage), { + void vscode.window.showInformationMessage(CodeWhispererConstants.jobCompletedNotification, { title: localizedText.ok, }) } else if (transformByQState.isPartiallySucceeded()) { void vscode.window .showInformationMessage( - CodeWhispererConstants.jobPartiallyCompletedNotification(diffMessage), + CodeWhispererConstants.jobPartiallyCompletedNotification, CodeWhispererConstants.amazonQFeedbackText ) .then((choice) => { diff --git a/packages/core/src/codewhisperer/models/constants.ts b/packages/core/src/codewhisperer/models/constants.ts index 73b0b475a2b..289a89828c3 100644 --- a/packages/core/src/codewhisperer/models/constants.ts +++ b/packages/core/src/codewhisperer/models/constants.ts @@ -22,23 +22,6 @@ export const AWSTemplateKeyWords = ['AWSTemplateFormatVersion', 'Resources', 'AW export const AWSTemplateCaseInsensitiveKeyWords = ['cloudformation', 'cfn', 'template', 'description'] -const patchDescriptions: { [key: string]: string } = { - 'Prepare minimal upgrade to Java 17': - 'This diff patch covers the set of upgrades for Springboot, JUnit, and PowerMockito frameworks in Java 17.', - 'Prepare minimal upgrade to Java 21': - 'This diff patch covers the set of upgrades for Springboot, JUnit, and PowerMockito frameworks in Java 21.', - 'Popular Enterprise Specifications and Application Frameworks upgrade': - 'This diff patch covers the set of upgrades for Jakarta EE 10, Hibernate 6.2, and Micronaut 3.', - 'HTTP Client Utilities, Apache Commons Utilities, and Web Frameworks': - 'This diff patch covers the set of upgrades for Apache HTTP Client 5, Apache Commons utilities (Collections, IO, Lang, Math), and Struts 6.0.', - 'Testing Tools and Frameworks upgrade': - 'This diff patch covers the set of upgrades for ArchUnit, Mockito, TestContainers, and Cucumber, in addition to the Jenkins plugins and the Maven Wrapper.', - 'Miscellaneous Processing Documentation upgrade': - 'This diff patch covers a diverse set of upgrades spanning ORMs, XML processing, API documentation, and more.', - 'Deprecated API replacement, dependency upgrades, and formatting': - 'This diff patch replaces deprecated APIs, makes additional dependency version upgrades, and formats code changes.', -} - export const JsonConfigFileNamingConvention = new Set([ 'app.json', 'appsettings.json', @@ -672,27 +655,13 @@ export const enterJavaHomePlaceholder = 'Enter the path to your Java installatio export const openNewTabPlaceholder = 'Open a new tab to chat with Q' -export const diffMessage = (multipleDiffs: boolean) => { - return multipleDiffs - ? 'You can review the diffs to see my proposed changes and accept or reject them. You will be able to accept changes from one diff at a time. If you reject changes in one diff, you will not be able to view or accept changes in the other diffs.' - : 'You can review the diff to see my proposed changes and accept or reject them.' -} - -export const jobCompletedChatMessage = (multipleDiffsString: string) => { - return `I completed your transformation. ${multipleDiffsString} The transformation summary has details about the changes I'm proposing.` -} +export const jobCompletedChatMessage = `I completed your transformation. You can review the diff to see my proposed changes and accept or reject them. The transformation summary has details about the changes I'm proposing.` -export const jobCompletedNotification = (multipleDiffsString: string) => { - return `Amazon Q transformed your code. ${multipleDiffsString} The transformation summary has details about the changes.` -} +export const jobCompletedNotification = `Amazon Q transformed your code. You can review the diff to see my proposed changes and accept or reject them. The transformation summary has details about the changes.` -export const jobPartiallyCompletedChatMessage = (multipleDiffsString: string) => { - return `I transformed part of your code. ${multipleDiffsString} The transformation summary has details about the files I updated and the errors that prevented a complete transformation.` -} +export const jobPartiallyCompletedChatMessage = `I transformed part of your code. You can review the diff to see my proposed changes and accept or reject them. The transformation summary has details about the files I updated and the errors that prevented a complete transformation.` -export const jobPartiallyCompletedNotification = (multipleDiffsString: string) => { - return `Amazon Q transformed part of your code. ${multipleDiffsString} The transformation summary has details about the files I updated and the errors that prevented a complete transformation.` -} +export const jobPartiallyCompletedNotification = `Amazon Q transformed part of your code. You can review the diff to see my proposed changes and accept or reject them. The transformation summary has details about the files I updated and the errors that prevented a complete transformation.` export const noPomXmlFoundChatMessage = `I couldn\'t find a project that I can upgrade. I couldn\'t find a pom.xml file in any of your open projects, nor could I find any embedded SQL statements. Currently, I can upgrade Java 8, 11, or 17 projects built on Maven, or Oracle SQL to PostgreSQL statements in Java projects. For more information, see the [Amazon Q documentation](${codeTransformPrereqDoc}).` @@ -730,25 +699,8 @@ export const viewProposedChangesNotification = export const changesAppliedChatMessageOneDiff = 'I applied the changes to your project.' -export const changesAppliedChatMessageMultipleDiffs = ( - currentPatchIndex: number, - totalPatchFiles: number, - description: string | undefined -) => - description - ? `I applied the changes in diff patch ${currentPatchIndex + 1} of ${totalPatchFiles} to your project. ${patchDescriptions[description]}` - : 'I applied the changes to your project.' - export const changesAppliedNotificationOneDiff = 'Amazon Q applied the changes to your project' -export const changesAppliedNotificationMultipleDiffs = (currentPatchIndex: number, totalPatchFiles: number) => { - if (totalPatchFiles === 1) { - return 'Amazon Q applied the changes to your project.' - } else { - return `Amazon Q applied the changes in diff patch ${currentPatchIndex + 1} of ${totalPatchFiles} to your project.` - } -} - export const noOpenProjectsFoundChatMessage = `I couldn\'t find a project that I can upgrade. Currently, I support Java 8, Java 11, Java 17, and Java 21 projects built on Maven. Make sure your project is open in the IDE. For more information, see the [Amazon Q documentation](${codeTransformPrereqDoc}).` export const noOpenFileFoundChatMessage = `Sorry, there isn't a source file open right now that I can generate a test for. Make sure you open a source file so I can generate tests.` @@ -807,21 +759,15 @@ export const chooseProjectSchemaFormMessage = 'To continue, choose the project a export const skipUnitTestsFormTitle = 'Choose to skip unit tests' -export const selectiveTransformationFormTitle = 'Choose how to receive proposed changes' - export const skipUnitTestsFormMessage = 'I will build your project using `mvn clean test` by default. If you would like me to build your project without running unit tests, I will use `mvn clean test-compile`.' export const runUnitTestsMessage = 'Run unit tests' -export const oneDiffMessage = 'One diff' - export const doNotSkipUnitTestsBuildCommand = 'clean test' export const skipUnitTestsMessage = 'Skip unit tests' -export const multipleDiffsMessage = 'Multiple diffs' - export const skipUnitTestsBuildCommand = 'clean test-compile' export const planTitle = 'Code Transformation plan by Amazon Q' diff --git a/packages/core/src/codewhisperer/models/model.ts b/packages/core/src/codewhisperer/models/model.ts index 9c48838afe3..128d34757fc 100644 --- a/packages/core/src/codewhisperer/models/model.ts +++ b/packages/core/src/codewhisperer/models/model.ts @@ -66,16 +66,6 @@ export type CrossFileStrategy = 'opentabs' | 'codemap' | 'bm25' | 'default' export type SupplementalContextStrategy = CrossFileStrategy | UtgStrategy | 'empty' -export type PatchInfo = { - name: string - filename: string - isSuccessful: boolean -} - -export type DescriptionContent = { - content: PatchInfo[] -} - export interface CodeWhispererSupplementalContext { isUtg: boolean isProcessTimeout: boolean @@ -758,8 +748,6 @@ export class TransformByQState { private targetJDKVersion: JDKVersion | undefined = undefined - private produceMultipleDiffs: boolean = false - private customBuildCommand: string = '' private sourceDB: DB | undefined = undefined @@ -856,10 +844,6 @@ export class TransformByQState { return this.linesOfCodeSubmitted } - public getMultipleDiffs() { - return this.produceMultipleDiffs - } - public getPreBuildLogFilePath() { return this.preBuildLogFilePath } @@ -1036,10 +1020,6 @@ export class TransformByQState { this.linesOfCodeSubmitted = lines } - public setMultipleDiffs(produceMultipleDiffs: boolean) { - this.produceMultipleDiffs = produceMultipleDiffs - } - public setStartTime(time: string) { this.startTime = time } @@ -1182,7 +1162,6 @@ export class TransformByQState { this.buildLog = '' this.customBuildCommand = '' this.intervalId = undefined - this.produceMultipleDiffs = false } } diff --git a/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts b/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts index 9214fb23572..7c520786869 100644 --- a/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts +++ b/packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts @@ -348,10 +348,6 @@ export async function zipCode( getLogger().info(`CodeTransformation: source code files size = ${sourceFilesSize}`) } - if (transformByQState.getMultipleDiffs() && zipManifest instanceof ZipManifest) { - zipManifest.transformCapabilities.push('SELECTIVE_TRANSFORMATION_V1') - } - if ( transformByQState.getTransformationType() === TransformationType.SQL_CONVERSION && zipManifest instanceof ZipManifest @@ -849,7 +845,7 @@ async function processClientInstructions(jobId: string, clientInstructionsPath: await extractOriginalProjectSources(destinationPath) getLogger().info(`CodeTransformation: copied project to ${destinationPath}`) const diffModel = new DiffModel() - diffModel.parseDiff(clientInstructionsPath, path.join(destinationPath, 'sources'), undefined, 1, true) + diffModel.parseDiff(clientInstructionsPath, path.join(destinationPath, 'sources'), true) // show user the diff.patch const doc = await vscode.workspace.openTextDocument(clientInstructionsPath) await vscode.window.showTextDocument(doc, { viewColumn: vscode.ViewColumn.One }) diff --git a/packages/core/src/codewhisperer/service/transformByQ/transformationResultsViewProvider.ts b/packages/core/src/codewhisperer/service/transformByQ/transformationResultsViewProvider.ts index 411571f0693..e5de2099753 100644 --- a/packages/core/src/codewhisperer/service/transformByQ/transformationResultsViewProvider.ts +++ b/packages/core/src/codewhisperer/service/transformByQ/transformationResultsViewProvider.ts @@ -10,13 +10,7 @@ import { parsePatch, applyPatches, ParsedDiff } from 'diff' import path from 'path' import vscode from 'vscode' import { ExportIntent } from '@amzn/codewhisperer-streaming' -import { - TransformByQReviewStatus, - transformByQState, - PatchInfo, - DescriptionContent, - TransformationType, -} from '../../models/model' +import { TransformByQReviewStatus, transformByQState, TransformationType } from '../../models/model' import { ExportResultArchiveStructure, downloadExportResultArchive } from '../../../shared/utilities/download' import { getLogger } from '../../../shared/logger/logger' import { telemetry } from '../../../shared/telemetry/telemetry' @@ -119,11 +113,9 @@ export class PatchFileNode { readonly patchFilePath: string children: ProposedChangeNode[] = [] - constructor(description: PatchInfo | undefined = undefined, patchFilePath: string) { + constructor(patchFilePath: string) { this.patchFilePath = patchFilePath - this.label = description - ? `${description.name} (${description.isSuccessful ? 'Success' : 'Failure'})` - : path.basename(patchFilePath) + this.label = path.basename(patchFilePath) } } @@ -164,13 +156,7 @@ export class DiffModel { * @param pathToWorkspace Path to the project that was transformed * @returns List of nodes containing the paths of files that were modified, added, or removed */ - public parseDiff( - pathToDiff: string, - pathToWorkspace: string, - diffDescription: PatchInfo | undefined, - totalDiffPatches: number, - isIntermediateBuild: boolean = false - ): PatchFileNode { + public parseDiff(pathToDiff: string, pathToWorkspace: string, isIntermediateBuild: boolean = false): PatchFileNode { this.patchFileNodes = [] const diffContents = fs.readFileSync(pathToDiff, 'utf8') @@ -214,8 +200,7 @@ export class DiffModel { } }, }) - const patchFileNode = new PatchFileNode(diffDescription, pathToDiff) - patchFileNode.label = `Patch ${this.currentPatchIndex + 1} of ${totalDiffPatches}: ${patchFileNode.label}` + const patchFileNode = new PatchFileNode(pathToDiff) patchFileNode.children = changedFiles.flatMap((file) => { /* ex. file.oldFileName = 'a/src/java/com/project/component/MyFile.java' * ex. file.newFileName = 'b/src/java/com/project/component/MyFile.java' @@ -331,7 +316,6 @@ export class ProposedTransformationExplorer { let patchFiles: string[] = [] let singlePatchFile: string = '' - let patchFilesDescriptions: DescriptionContent | undefined = undefined const reset = async () => { await setContext('gumby.transformationProposalReviewInProgress', false) @@ -446,45 +430,9 @@ export class ProposedTransformationExplorer { const zip = new AdmZip(pathToArchive) zip.extractAllTo(pathContainingArchive) const files = fs.readdirSync(path.join(pathContainingArchive, ExportResultArchiveStructure.PathToPatch)) - if (files.length === 1) { - singlePatchFile = path.join( - pathContainingArchive, - ExportResultArchiveStructure.PathToPatch, - files[0] - ) - } else { - const jsonFile = files.find((file) => file.endsWith('.json')) - if (!jsonFile) { - throw new Error('Expected JSON file not found') - } - const filePath = path.join( - pathContainingArchive, - ExportResultArchiveStructure.PathToPatch, - jsonFile - ) - const jsonData = fs.readFileSync(filePath, 'utf-8') - patchFilesDescriptions = JSON.parse(jsonData) - } - if (patchFilesDescriptions !== undefined) { - for (const patchInfo of patchFilesDescriptions.content) { - patchFiles.push( - path.join( - pathContainingArchive, - ExportResultArchiveStructure.PathToPatch, - patchInfo.filename - ) - ) - } - } else { - patchFiles.push(singlePatchFile) - } - // Because multiple patches are returned once the ZIP is downloaded, we want to show the first one to start - diffModel.parseDiff( - patchFiles[0], - transformByQState.getProjectPath(), - patchFilesDescriptions ? patchFilesDescriptions.content[0] : undefined, - patchFiles.length - ) + singlePatchFile = path.join(pathContainingArchive, ExportResultArchiveStructure.PathToPatch, files[0]) + patchFiles.push(singlePatchFile) + diffModel.parseDiff(patchFiles[0], transformByQState.getProjectPath()) await setContext('gumby.reviewState', TransformByQReviewStatus.InReview) transformDataProvider.refresh() @@ -548,51 +496,16 @@ export class ProposedTransformationExplorer { telemetry.record({ codeTransformSessionId: CodeTransformTelemetryState.instance.getSessionId(), codeTransformJobId: transformByQState.getJobId(), - userChoice: `acceptChanges-${patchFilesDescriptions?.content[diffModel.currentPatchIndex].name}`, + userChoice: 'acceptChanges', }) }) - if (transformByQState.getMultipleDiffs()) { - void vscode.window.showInformationMessage( - CodeWhispererConstants.changesAppliedNotificationMultipleDiffs( - diffModel.currentPatchIndex, - patchFiles.length - ) - ) - } else { - void vscode.window.showInformationMessage(CodeWhispererConstants.changesAppliedNotificationOneDiff) - } - - // We do this to ensure that the changesAppliedChatMessage is only sent to user when they accept the first diff.patch + void vscode.window.showInformationMessage(CodeWhispererConstants.changesAppliedNotificationOneDiff) transformByQState.getChatControllers()?.transformationFinished.fire({ - message: CodeWhispererConstants.changesAppliedChatMessageMultipleDiffs( - diffModel.currentPatchIndex, - patchFiles.length, - patchFilesDescriptions - ? patchFilesDescriptions.content[diffModel.currentPatchIndex].name - : undefined - ), + message: CodeWhispererConstants.changesAppliedChatMessageOneDiff, tabID: ChatSessionManager.Instance.getSession().tabID, - includeStartNewTransformationButton: diffModel.currentPatchIndex === patchFiles.length - 1, }) - - // Load the next patch file - diffModel.currentPatchIndex++ - if (diffModel.currentPatchIndex < patchFiles.length) { - const nextPatchFile = patchFiles[diffModel.currentPatchIndex] - const nextPatchFileDescription = patchFilesDescriptions - ? patchFilesDescriptions.content[diffModel.currentPatchIndex] - : undefined - diffModel.parseDiff( - nextPatchFile, - transformByQState.getProjectPath(), - nextPatchFileDescription, - patchFiles.length - ) - transformDataProvider.refresh() - } else { - // All patches have been applied, reset the state - await reset() - } + // reset after applying the patch + await reset() }) vscode.commands.registerCommand('aws.amazonq.transformationHub.reviewChanges.rejectChanges', async () => {