From 817cfe2656cb1deec6111c699c4ba46b4ba53e00 Mon Sep 17 00:00:00 2001 From: Dung Dong Date: Tue, 12 Aug 2025 17:03:29 -0700 Subject: [PATCH 001/158] fix(amazonq): persist mcp configs in agent json on start-up (#2112) --- .../src/language-server/agenticChat/tools/mcp/mcpUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts index 45ab34170c..7b212bad49 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts @@ -920,8 +920,8 @@ async function migrateConfigToAgent( ...existingAgentConfig, // Merge MCP servers, keeping existing ones if they exist mcpServers: { - ...existingAgentConfig.mcpServers, ...newAgentConfig.mcpServers, + ...existingAgentConfig.mcpServers, }, // Merge tools lists without duplicates tools: [...new Set([...existingAgentConfig.tools, ...newAgentConfig.tools])], From fd6e9a829c6229c276de5340dffce52b426a864d Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Wed, 13 Aug 2025 10:28:53 -0700 Subject: [PATCH 002/158] feat(amazonq): added mcp admin level configuration with GetProfile (#2000) * feat(amazonq): added mcp admin level configuration with GetProfile * feat(amazonq): added UX message for mcp admin control * test: add unit tests for ProfileStatusMonitor static functionality * test: add comprehensive unit tests for MCP admin control features * fix: fix to wait for serviceManager is initialzied to initialize mcp managers * fix: fix for unit test failures * fix: fix for UI changes * fix(amazonq): fix to to rename mcp enabled function and max time limit of 10 seconds * fix: fix to add async initialization for mcp manager * fix: fix to move action buttons to mcpEventHandler for listMcpServers * fix: added try and catch block for mcp initialization * fix: fix for merge conflicts * fix: fix for test failure * fix: remove the unnecessary feature flag * fix: fix for mynah test failure * fix: fix to retry function to common util * fix: fix to add retryUtils --- chat-client/src/client/mcpMynahUi.test.ts | 6 +- chat-client/src/client/mcpMynahUi.ts | 19 +- core/aws-lsp-core/src/index.ts | 1 + core/aws-lsp-core/src/util/retryUtils.test.ts | 120 ++++++++++++ core/aws-lsp-core/src/util/retryUtils.ts | 77 ++++++++ .../client/token/bearer-token-service.json | 85 ++++++++ .../token/codewhispererbearertokenclient.d.ts | 26 +++ .../agenticChat/constants/constants.ts | 2 + .../tools/mcp/mcpEventHandler.test.ts | 105 ++++++++++ .../agenticChat/tools/mcp/mcpEventHandler.ts | 56 +++++- .../tools/mcp/profileStatusMonitor.test.ts | 182 ++++++++++++++++++ .../tools/mcp/profileStatusMonitor.ts | 129 +++++++++++++ .../agenticChat/tools/toolServer.ts | 122 ++++++++++-- .../src/shared/codeWhispererService.ts | 7 + 14 files changed, 899 insertions(+), 38 deletions(-) create mode 100644 core/aws-lsp-core/src/util/retryUtils.test.ts create mode 100644 core/aws-lsp-core/src/util/retryUtils.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts diff --git a/chat-client/src/client/mcpMynahUi.test.ts b/chat-client/src/client/mcpMynahUi.test.ts index 9d1dec5407..947e5bc604 100644 --- a/chat-client/src/client/mcpMynahUi.test.ts +++ b/chat-client/src/client/mcpMynahUi.test.ts @@ -107,10 +107,8 @@ describe('McpMynahUi', () => { assert.strictEqual(callArgs.detailedList.header.description, 'Test Description') assert.deepStrictEqual(callArgs.detailedList.header.status, { status: 'success' }) - // Verify the actions in the header - assert.strictEqual(callArgs.detailedList.header.actions.length, 2) - assert.strictEqual(callArgs.detailedList.header.actions[0].id, 'add-new-mcp') - assert.strictEqual(callArgs.detailedList.header.actions[1].id, 'refresh-mcp-list') + // Verify the actions in the header (no default actions are added when header is provided) + assert.strictEqual(callArgs.detailedList.header.actions.length, 0) // Verify the list structure assert.strictEqual(callArgs.detailedList.list.length, 1) diff --git a/chat-client/src/client/mcpMynahUi.ts b/chat-client/src/client/mcpMynahUi.ts index f9216b8168..5ece955dfa 100644 --- a/chat-client/src/client/mcpMynahUi.ts +++ b/chat-client/src/client/mcpMynahUi.ts @@ -272,20 +272,11 @@ export class McpMynahUi { title: params.header.title, description: params.header.description, status: params.header.status, - actions: [ - { - id: MCP_IDS.ADD_NEW, - icon: toMynahIcon('plus'), - status: 'clear', - description: 'Add new MCP', - }, - { - id: MCP_IDS.REFRESH_LIST, - icon: toMynahIcon('refresh'), - status: 'clear', - description: 'Refresh MCP servers', - }, - ], + actions: + params.header.actions?.map(action => ({ + ...action, + icon: action.icon ? toMynahIcon(action.icon) : undefined, + })) || [], } : undefined, filterOptions: params.filterOptions?.map(filter => ({ diff --git a/core/aws-lsp-core/src/index.ts b/core/aws-lsp-core/src/index.ts index 1ad391dc8f..030a4fa2e3 100644 --- a/core/aws-lsp-core/src/index.ts +++ b/core/aws-lsp-core/src/index.ts @@ -19,3 +19,4 @@ export * as workspaceUtils from './util/workspaceUtils' export * as processUtils from './util/processUtils' export * as collectionUtils from './util/collectionUtils' export * as loggingUtils from './util/loggingUtils' +export * as retryUtils from './util/retryUtils' diff --git a/core/aws-lsp-core/src/util/retryUtils.test.ts b/core/aws-lsp-core/src/util/retryUtils.test.ts new file mode 100644 index 0000000000..4223e1f3bf --- /dev/null +++ b/core/aws-lsp-core/src/util/retryUtils.test.ts @@ -0,0 +1,120 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. + * All Rights Reserved. SPDX-License-Identifier: Apache-2.0 + */ + +import { expect } from 'chai' +import * as sinon from 'sinon' +import { retryWithBackoff, DEFAULT_MAX_RETRIES, DEFAULT_BASE_DELAY } from './retryUtils' + +describe('retryUtils', () => { + let clock: sinon.SinonFakeTimers + + beforeEach(() => { + clock = sinon.useFakeTimers() + }) + + afterEach(() => { + clock.restore() + }) + + describe('retryWithBackoff', () => { + it('should return result on first success', async () => { + const fn = sinon.stub().resolves('success') + + const result = await retryWithBackoff(fn) + + expect(result).to.equal('success') + expect(fn.callCount).to.equal(1) + }) + + it('should retry on retryable errors', async () => { + const fn = sinon.stub() + fn.onFirstCall().rejects({ code: 'ThrottlingException' }) + fn.onSecondCall().resolves('success') + + const promise = retryWithBackoff(fn) + await clock.tickAsync(DEFAULT_BASE_DELAY) + const result = await promise + + expect(result).to.equal('success') + expect(fn.callCount).to.equal(2) + }) + + it('should not retry on non-retryable client errors', async () => { + const error = { statusCode: 404 } + const fn = sinon.stub().rejects(error) + + try { + await retryWithBackoff(fn) + expect.fail('Expected function to throw') + } catch (e) { + expect(e).to.equal(error) + } + expect(fn.callCount).to.equal(1) + }) + + it('should retry on server errors', async () => { + const fn = sinon.stub() + fn.onFirstCall().rejects({ statusCode: 500 }) + fn.onSecondCall().resolves('success') + + const promise = retryWithBackoff(fn) + await clock.tickAsync(DEFAULT_BASE_DELAY) + const result = await promise + + expect(result).to.equal('success') + expect(fn.callCount).to.equal(2) + }) + + it('should use exponential backoff by default', async () => { + const fn = sinon.stub() + const error = { code: 'ThrottlingException' } + fn.onFirstCall().rejects(error) + fn.onSecondCall().rejects(error) + + const promise = retryWithBackoff(fn) + + // First retry after baseDelay * 1 + await clock.tickAsync(DEFAULT_BASE_DELAY) + // Second retry after baseDelay * 2 + await clock.tickAsync(DEFAULT_BASE_DELAY * 2) + + try { + await promise + expect.fail('Expected function to throw') + } catch (e) { + expect(e).to.equal(error) + } + expect(fn.callCount).to.equal(DEFAULT_MAX_RETRIES) + }) + + it('should respect custom maxRetries', async () => { + const error = { code: 'ThrottlingException' } + const fn = sinon.stub().rejects(error) + + try { + await retryWithBackoff(fn, { maxRetries: 1 }) + expect.fail('Expected function to throw') + } catch (e) { + expect(e).to.equal(error) + } + expect(fn.callCount).to.equal(1) + }) + + it('should use custom isRetryable function', async () => { + const error = { custom: 'error' } + const fn = sinon.stub().rejects(error) + const isRetryable = sinon.stub().returns(false) + + try { + await retryWithBackoff(fn, { isRetryable }) + expect.fail('Expected function to throw') + } catch (e) { + expect(e).to.equal(error) + } + expect(fn.callCount).to.equal(1) + expect(isRetryable.calledWith(error)).to.equal(true) + }) + }) +}) diff --git a/core/aws-lsp-core/src/util/retryUtils.ts b/core/aws-lsp-core/src/util/retryUtils.ts new file mode 100644 index 0000000000..dc135ce23d --- /dev/null +++ b/core/aws-lsp-core/src/util/retryUtils.ts @@ -0,0 +1,77 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. + * All Rights Reserved. SPDX-License-Identifier: Apache-2.0 + */ + +// Default retry configuration constants +export const DEFAULT_MAX_RETRIES = 2 +export const DEFAULT_BASE_DELAY = 500 +export const DEFAULT_EXPONENTIAL_BACKOFF = true + +// HTTP status code constants +const CLIENT_ERROR_MIN = 400 +const CLIENT_ERROR_MAX = 500 +const INTERNAL_SERVER_ERROR = 500 +const SERVICE_UNAVAILABLE = 503 + +// AWS error code constants +const THROTTLING_EXCEPTION = 'ThrottlingException' +const INTERNAL_SERVER_EXCEPTION = 'InternalServerException' + +export interface RetryOptions { + /** Maximum number of retry attempts (default: DEFAULT_MAX_RETRIES) */ + maxRetries?: number + /** Base delay in milliseconds (default: DEFAULT_BASE_DELAY) */ + baseDelay?: number + /** Whether to use exponential backoff (default: DEFAULT_EXPONENTIAL_BACKOFF) */ + exponentialBackoff?: boolean + /** Custom function to determine if an error is retryable */ + isRetryable?: (error: any) => boolean +} + +/** + * Default AWS error retry logic + */ +function defaultIsRetryable(error: any): boolean { + const errorCode = error.code || error.name + const statusCode = error.statusCode + + // Fast fail on non-retryable client errors (except throttling) + if (statusCode >= CLIENT_ERROR_MIN && statusCode < CLIENT_ERROR_MAX && errorCode !== THROTTLING_EXCEPTION) { + return false + } + + // Retry on throttling, server errors, and specific status codes + return ( + errorCode === THROTTLING_EXCEPTION || + errorCode === INTERNAL_SERVER_EXCEPTION || + statusCode === INTERNAL_SERVER_ERROR || + statusCode === SERVICE_UNAVAILABLE + ) +} + +/** + * Executes a function with retry logic and exponential backoff + */ +export async function retryWithBackoff(fn: () => Promise, options: RetryOptions = {}): Promise { + const { + maxRetries = DEFAULT_MAX_RETRIES, + baseDelay = DEFAULT_BASE_DELAY, + exponentialBackoff = DEFAULT_EXPONENTIAL_BACKOFF, + isRetryable = defaultIsRetryable, + } = options + + for (let attempt = 0; attempt < maxRetries; attempt++) { + try { + return await fn() + } catch (error: any) { + if (!isRetryable(error) || attempt === maxRetries - 1) { + throw error + } + + const delay = exponentialBackoff ? baseDelay * (attempt + 1) : baseDelay + await new Promise(resolve => setTimeout(resolve, delay)) + } + } + throw new Error('Retry failed') +} diff --git a/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json b/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json index 2120382d25..a5704fca16 100644 --- a/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json +++ b/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json @@ -516,6 +516,37 @@ ], "documentation": "

API to get code transformation status.

" }, + "GetProfile": { + "name": "GetProfile", + "http": { + "method": "POST", + "requestUri": "/" + }, + "input": { + "shape": "GetProfileRequest" + }, + "output": { + "shape": "GetProfileResponse" + }, + "errors": [ + { + "shape": "ThrottlingException" + }, + { + "shape": "ResourceNotFoundException" + }, + { + "shape": "InternalServerException" + }, + { + "shape": "ValidationException" + }, + { + "shape": "AccessDeniedException" + } + ], + "documentation": "

Get the requested CodeWhisperer profile.

" + }, "GetUsageLimits": { "name": "GetUsageLimits", "http": { @@ -3126,6 +3157,24 @@ } } }, + "GetProfileRequest": { + "type": "structure", + "required": ["profileArn"], + "members": { + "profileArn": { + "shape": "ProfileArn" + } + } + }, + "GetProfileResponse": { + "type": "structure", + "required": ["profile"], + "members": { + "profile": { + "shape": "ProfileInfo" + } + } + }, "GetTaskAssistCodeGenerationRequest": { "type": "structure", "required": ["conversationId", "codeGenerationId"], @@ -3787,6 +3836,15 @@ "type": "long", "box": true }, + "MCPConfiguration": { + "type": "structure", + "required": ["toggle"], + "members": { + "toggle": { + "shape": "OptInFeatureToggle" + } + } + }, "MemoryEntry": { "type": "structure", "required": ["id", "memoryEntryString", "metadata"], @@ -3995,6 +4053,9 @@ }, "workspaceContext": { "shape": "WorkspaceContext" + }, + "mcpConfiguration": { + "shape": "MCPConfiguration" } } }, @@ -4189,6 +4250,30 @@ } } }, + "ProfileInfo": { + "type": "structure", + "required": ["arn"], + "members": { + "arn": { + "shape": "ProfileArn" + }, + "profileName": { + "shape": "ProfileName" + }, + "description": { + "shape": "ProfileDescription" + }, + "status": { + "shape": "ProfileStatus" + }, + "profileType": { + "shape": "ProfileType" + }, + "optInFeatures": { + "shape": "OptInFeatures" + } + } + }, "ProfileArn": { "type": "string", "max": 950, diff --git a/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts b/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts index 2189944d4f..c885612888 100644 --- a/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts +++ b/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts @@ -144,6 +144,14 @@ declare class CodeWhispererBearerTokenClient extends Service { * API to get code transformation status. */ getTransformationPlan(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetTransformationPlanResponse) => void): Request; + /** + * Get the requested CodeWhisperer profile. + */ + getProfile(params: CodeWhispererBearerTokenClient.Types.GetProfileRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetProfileResponse) => void): Request; + /** + * Get the requested CodeWhisperer profile. + */ + getProfile(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetProfileResponse) => void): Request; /** * API to get current usage limits */ @@ -961,6 +969,12 @@ declare namespace CodeWhispererBearerTokenClient { jobStatus?: CodeFixJobStatus; suggestedFix?: SuggestedFix; } + export interface GetProfileRequest { + profileArn: ProfileArn; + } + export interface GetProfileResponse { + profile: ProfileInfo; + } export interface GetTaskAssistCodeGenerationRequest { conversationId: ConversationId; codeGenerationId: CodeGenerationId; @@ -1189,6 +1203,9 @@ declare namespace CodeWhispererBearerTokenClient { nextToken?: String; } export type Long = number; + export interface MCPConfiguration { + toggle: OptInFeatureToggle; + } export interface MemoryEntry { /** * A unique identifier for a single memory entry @@ -1260,6 +1277,7 @@ declare namespace CodeWhispererBearerTokenClient { dashboardAnalytics?: DashboardAnalytics; notifications?: Notifications; workspaceContext?: WorkspaceContext; + mcpConfiguration?: MCPConfiguration; } export type OptOutPreference = "OPTIN"|"OPTOUT"|string; export type Origin = "CHATBOT"|"CONSOLE"|"DOCUMENTATION"|"MARKETING"|"MOBILE"|"SERVICE_INTERNAL"|"UNIFIED_SEARCH"|"UNKNOWN"|"MD"|"IDE"|"SAGE_MAKER"|"CLI"|"AI_EDITOR"|"OPENSEARCH_DASHBOARD"|"GITLAB"|string; @@ -1315,6 +1333,14 @@ declare namespace CodeWhispererBearerTokenClient { permissionUpdateRequired?: Boolean; applicationProperties?: ApplicationPropertiesList; } + export interface ProfileInfo { + arn: ProfileArn; + profileName?: ProfileName; + description?: ProfileDescription; + status?: ProfileStatus; + profileType?: ProfileType; + optInFeatures?: OptInFeatures; + } export type ProfileArn = string; export type ProfileDescription = string; export type ProfileList = Profile[]; diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts index 09fbb20436..1729c10c1d 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts @@ -9,6 +9,8 @@ export const RESPONSE_TIMEOUT_PARTIAL_MSG = 'Response processing timed out after export const LOADING_THRESHOLD_MS = 2000 export const CLIENT_TIMEOUT_MS = 245_000 export const RESPONSE_TIMEOUT_MS = 240_000 +export const SERVICE_MANAGER_TIMEOUT_MS = 10_000 //10 seconds +export const SERVICE_MANAGER_POLL_INTERVAL_MS = 100 // LLM Constants export const GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT = 500_000 diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts index 01984a310e..cb645eec43 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts @@ -240,4 +240,109 @@ describe('McpEventHandler error handling', () => { expect(result.header).to.not.be.undefined expect(result.header.title).to.equal('Edit MCP Server') }) + + describe('#getListMcpServersStatus', () => { + beforeEach(() => { + sinon.restore() + sinon.stub(mcpUtils, 'getGlobalAgentConfigPath').returns('/fake/home/.aws/amazonq/agents/default.json') + saveAgentConfigStub = sinon.stub(mcpUtils, 'saveAgentConfig').resolves() + }) + + it('returns admin disabled status when MCP state is false', async () => { + // Stub ProfileStatusMonitor.getMcpState to return false + const { ProfileStatusMonitor } = await import('./profileStatusMonitor') + sinon.stub(ProfileStatusMonitor, 'getMcpState').returns(false) + + loadStub = sinon.stub(mcpUtils, 'loadAgentConfig').resolves({ + servers: new Map(), + serverNameMapping: new Map(), + errors: new Map(), + agentConfig: { + name: 'test-agent', + version: '1.0.0', + description: 'Test agent', + mcpServers: {}, + tools: [], + allowedTools: [], + toolsSettings: {}, + includedFiles: [], + resources: [], + }, + }) + + await McpManager.init([], features) + const result = await eventHandler.onListMcpServers({}) + + expect(result.header.status).to.deep.equal({ + title: 'MCP functionality has been disabled by your administrator', + icon: 'info', + status: 'info', + }) + }) + + it('returns config error status when MCP state is not false but config errors exist', async () => { + // Stub ProfileStatusMonitor.getMcpState to return true + const { ProfileStatusMonitor } = await import('./profileStatusMonitor') + sinon.stub(ProfileStatusMonitor, 'getMcpState').returns(true) + + const mockErrors = new Map([['file1.json', 'Config error']]) + loadStub = sinon.stub(mcpUtils, 'loadAgentConfig').resolves({ + servers: new Map(), + serverNameMapping: new Map(), + errors: mockErrors, + agentConfig: { + name: 'test-agent', + version: '1.0.0', + description: 'Test agent', + mcpServers: {}, + tools: [], + allowedTools: [], + toolsSettings: {}, + includedFiles: [], + resources: [], + }, + }) + + await McpManager.init([], features) + sinon.stub(McpManager.instance, 'getConfigLoadErrors').returns('File: file1.json, Error: Config error') + + const result = await eventHandler.onListMcpServers({}) + + expect(result.header.status).to.deep.equal({ + title: 'File: file1.json, Error: Config error', + icon: 'cancel-circle', + status: 'error', + }) + }) + + it('returns undefined status when MCP state is not false and no config errors', async () => { + // Stub ProfileStatusMonitor.getMcpState to return true + const { ProfileStatusMonitor } = await import('./profileStatusMonitor') + sinon.stub(ProfileStatusMonitor, 'getMcpState').returns(true) + + loadStub = sinon.stub(mcpUtils, 'loadAgentConfig').resolves({ + servers: new Map(), + serverNameMapping: new Map(), + errors: new Map(), + agentConfig: { + name: 'test-agent', + version: '1.0.0', + description: 'Test agent', + mcpServers: {}, + tools: [], + allowedTools: [], + toolsSettings: {}, + includedFiles: [], + resources: [], + }, + }) + + await McpManager.init([], features) + sinon.stub(McpManager.instance, 'getConfigLoadErrors').returns(undefined) + + const result = await eventHandler.onListMcpServers({}) + + expect(result.header.status).to.be.undefined + }) + }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts index 4596bc0646..bf8c91b533 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts @@ -30,6 +30,7 @@ import { } from './mcpTypes' import { TelemetryService } from '../../../../shared/telemetry/telemetryService' import { URI } from 'vscode-uri' +import { ProfileStatusMonitor } from './profileStatusMonitor' interface PermissionOption { label: string @@ -222,18 +223,63 @@ export class McpEventHandler { } // Return the result in the expected format + const mcpState = ProfileStatusMonitor.getMcpState() const header = { title: 'MCP Servers', - description: "Add MCP servers to extend Q's capabilities.", - // only show error on list mcp server page if unable to read mcp.json file - status: configLoadErrors - ? { title: configLoadErrors, icon: 'cancel-circle', status: 'error' as Status } - : undefined, + description: mcpState === false ? '' : "Add MCP servers to extend Q's capabilities.", + status: this.#getListMcpServersStatus(configLoadErrors, mcpState), + actions: this.#getListMcpServersActions(configLoadErrors, mcpState), } return { header, list: groups } } + /** + * Gets the status for the list MCP servers header + */ + #getListMcpServersStatus( + configLoadErrors: string | undefined, + mcpState: boolean | undefined + ): { title: string; icon: string; status: Status } | undefined { + if (mcpState === false) { + return { + title: 'MCP functionality has been disabled by your administrator', + icon: 'info', + status: 'info' as Status, + } + } + + if (configLoadErrors) { + return { title: configLoadErrors, icon: 'cancel-circle', status: 'error' as Status } + } + + return undefined + } + + /** + * Gets the actions for the list MCP servers header + */ + #getListMcpServersActions(configLoadErrors: string | undefined, mcpState: boolean | undefined) { + return mcpState !== false && (!configLoadErrors || configLoadErrors === '') + ? [ + { + id: 'add-new-mcp', + icon: 'plus', + status: 'clear', + text: 'Add new MCP server', + description: 'Add new MCP server', + }, + { + id: 'refresh-mcp-list', + icon: 'refresh', + status: 'clear', + text: 'Refresh MCP servers', + description: 'Refresh MCP servers', + }, + ] + : [] + } + /** * Handles MCP server click events */ diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.test.ts new file mode 100644 index 0000000000..8ee8454374 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.test.ts @@ -0,0 +1,182 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. + * All Rights Reserved. SPDX-License-Identifier: Apache-2.0 + */ + +import { expect } from 'chai' +import * as sinon from 'sinon' +import { ProfileStatusMonitor } from './profileStatusMonitor' +import * as AmazonQTokenServiceManagerModule from '../../../../shared/amazonQServiceManager/AmazonQTokenServiceManager' + +describe('ProfileStatusMonitor', () => { + let profileStatusMonitor: ProfileStatusMonitor + let mockCredentialsProvider: any + let mockWorkspace: any + let mockLogging: any + let mockSdkInitializator: any + let mockOnMcpDisabled: sinon.SinonStub + let mockOnMcpEnabled: sinon.SinonStub + let clock: sinon.SinonFakeTimers + + beforeEach(() => { + clock = sinon.useFakeTimers() + + mockCredentialsProvider = { + hasCredentials: sinon.stub().returns(true), + } + + mockWorkspace = {} + + mockLogging = { + info: sinon.stub(), + debug: sinon.stub(), + } + + mockSdkInitializator = {} + mockOnMcpDisabled = sinon.stub() + mockOnMcpEnabled = sinon.stub() + + profileStatusMonitor = new ProfileStatusMonitor( + mockCredentialsProvider, + mockWorkspace, + mockLogging, + mockSdkInitializator, + mockOnMcpDisabled, + mockOnMcpEnabled + ) + }) + + afterEach(() => { + clock.restore() + sinon.restore() + profileStatusMonitor.stop() + }) + + describe('start', () => { + it('should start monitoring and log info message', () => { + profileStatusMonitor.start() + + expect( + mockLogging.info.calledWith('ProfileStatusMonitor started - checking MCP configuration every 24 hours') + ).to.be.true + }) + + it('should not start multiple times', () => { + profileStatusMonitor.start() + profileStatusMonitor.start() + + expect(mockLogging.info.callCount).to.equal(1) + }) + }) + + describe('stop', () => { + it('should stop monitoring and log info message', () => { + profileStatusMonitor.start() + profileStatusMonitor.stop() + + expect(mockLogging.info.calledWith('ProfileStatusMonitor stopped')).to.be.true + }) + }) + + describe('checkInitialState', () => { + it('should return true when no profile ARN is available', async () => { + sinon.stub(AmazonQTokenServiceManagerModule.AmazonQTokenServiceManager, 'getInstance').returns({ + getActiveProfileArn: () => undefined, + } as any) + + const result = await profileStatusMonitor.checkInitialState() + expect(result).to.be.true + }) + + it('should return true and log debug message on error', async () => { + // Stub the private isMcpEnabled method to throw an error + sinon.stub(profileStatusMonitor as any, 'isMcpEnabled').throws(new Error('Service manager not ready')) + + const result = await profileStatusMonitor.checkInitialState() + expect(result).to.be.true + expect(mockLogging.debug.calledWith(sinon.match('Initial MCP state check failed, defaulting to enabled'))) + .to.be.true + }) + }) + + describe('getMcpState', () => { + beforeEach(() => { + // Reset static state before each test + ;(ProfileStatusMonitor as any).lastMcpState = undefined + }) + + it('should return undefined initially', () => { + expect(ProfileStatusMonitor.getMcpState()).to.be.undefined + }) + + it('should return the last MCP state after it is set', () => { + // Access the private static property through reflection for testing + ;(ProfileStatusMonitor as any).lastMcpState = true + expect(ProfileStatusMonitor.getMcpState()).to.be.true + ;(ProfileStatusMonitor as any).lastMcpState = false + expect(ProfileStatusMonitor.getMcpState()).to.be.false + }) + + it('should be accessible across different instances', () => { + const monitor1 = new ProfileStatusMonitor( + mockCredentialsProvider, + mockWorkspace, + mockLogging, + mockSdkInitializator, + mockOnMcpDisabled, + mockOnMcpEnabled + ) + + const monitor2 = new ProfileStatusMonitor( + mockCredentialsProvider, + mockWorkspace, + mockLogging, + mockSdkInitializator, + mockOnMcpDisabled, + mockOnMcpEnabled + ) + + // Set state through static property + ;(ProfileStatusMonitor as any).lastMcpState = true + + // Should be accessible from both instances + expect(ProfileStatusMonitor.getMcpState()).to.be.true + }) + }) + + describe('static lastMcpState', () => { + beforeEach(() => { + // Reset static state before each test + ;(ProfileStatusMonitor as any).lastMcpState = undefined + }) + + it('should maintain state across multiple instances', () => { + const monitor1 = new ProfileStatusMonitor( + mockCredentialsProvider, + mockWorkspace, + mockLogging, + mockSdkInitializator, + mockOnMcpDisabled, + mockOnMcpEnabled + ) + + const monitor2 = new ProfileStatusMonitor( + mockCredentialsProvider, + mockWorkspace, + mockLogging, + mockSdkInitializator, + mockOnMcpDisabled, + mockOnMcpEnabled + ) + + // Initially undefined + expect(ProfileStatusMonitor.getMcpState()).to.be.undefined + + // Set through internal mechanism (simulating state change) + ;(ProfileStatusMonitor as any).lastMcpState = false + + // Both instances should see the same state + expect(ProfileStatusMonitor.getMcpState()).to.be.false + }) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts new file mode 100644 index 0000000000..4a1cc705e4 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts @@ -0,0 +1,129 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. + * All Rights Reserved. SPDX-License-Identifier: Apache-2.0 + */ + +import { + CredentialsProvider, + Logging, + SDKInitializator, + Workspace, +} from '@aws/language-server-runtimes/server-interface' +import { retryUtils } from '@aws/lsp-core' +import { CodeWhispererServiceToken } from '../../../../shared/codeWhispererService' +import { DEFAULT_AWS_Q_ENDPOINT_URL, DEFAULT_AWS_Q_REGION } from '../../../../shared/constants' +import { AmazonQTokenServiceManager } from '../../../../shared/amazonQServiceManager/AmazonQTokenServiceManager' + +export class ProfileStatusMonitor { + private intervalId?: NodeJS.Timeout + private readonly CHECK_INTERVAL = 24 * 60 * 60 * 1000 // 24 hours + private codeWhispererClient?: CodeWhispererServiceToken + private cachedProfileArn?: string + private static lastMcpState?: boolean + + constructor( + private credentialsProvider: CredentialsProvider, + private workspace: Workspace, + private logging: Logging, + private sdkInitializator: SDKInitializator, + private onMcpDisabled: () => void, + private onMcpEnabled?: () => void + ) {} + + async checkInitialState(): Promise { + try { + const isMcpEnabled = await this.isMcpEnabled() + return isMcpEnabled !== false // Return true if enabled or API failed + } catch (error) { + this.logging.debug(`Initial MCP state check failed, defaulting to enabled: ${error}`) + ProfileStatusMonitor.lastMcpState = true + return true + } + } + + start(): void { + if (this.intervalId) { + return + } + + this.intervalId = setInterval(() => { + void this.isMcpEnabled() + }, this.CHECK_INTERVAL) + + this.logging.info('ProfileStatusMonitor started - checking MCP configuration every 24 hours') + } + + stop(): void { + if (this.intervalId) { + clearInterval(this.intervalId) + this.intervalId = undefined + this.logging.info('ProfileStatusMonitor stopped') + } + } + + private async isMcpEnabled(): Promise { + try { + const profileArn = this.getProfileArn() + if (!profileArn) { + this.logging.debug('No profile ARN available for MCP configuration check') + ProfileStatusMonitor.lastMcpState = true // Default to enabled if no profile + return true + } + + if (!this.codeWhispererClient) { + this.codeWhispererClient = new CodeWhispererServiceToken( + this.credentialsProvider, + this.workspace, + this.logging, + process.env.CODEWHISPERER_REGION || DEFAULT_AWS_Q_REGION, + process.env.CODEWHISPERER_ENDPOINT || DEFAULT_AWS_Q_ENDPOINT_URL, + this.sdkInitializator + ) + this.codeWhispererClient.profileArn = profileArn + } + + const response = await retryUtils.retryWithBackoff(() => + this.codeWhispererClient!.getProfile({ profileArn }) + ) + const isMcpEnabled = response?.profile?.optInFeatures?.mcpConfiguration?.toggle === 'ON' + + if (ProfileStatusMonitor.lastMcpState !== isMcpEnabled) { + ProfileStatusMonitor.lastMcpState = isMcpEnabled + if (!isMcpEnabled) { + this.logging.info('MCP configuration disabled - removing tools') + this.onMcpDisabled() + } else if (isMcpEnabled && this.onMcpEnabled) { + this.logging.info('MCP configuration enabled - initializing tools') + this.onMcpEnabled() + } + } + + return isMcpEnabled + } catch (error) { + this.logging.debug(`MCP configuration check failed, defaulting to enabled: ${error}`) + ProfileStatusMonitor.lastMcpState = true + return true + } + } + + private getProfileArn(): string | undefined { + // Use cached value if available + if (this.cachedProfileArn) { + return this.cachedProfileArn + } + + try { + // Get profile ARN from service manager like in agenticChatController + const serviceManager = AmazonQTokenServiceManager.getInstance() + this.cachedProfileArn = serviceManager.getActiveProfileArn() + return this.cachedProfileArn + } catch (error) { + this.logging.debug(`Failed to get profile ARN: ${error}`) + } + return undefined + } + + static getMcpState(): boolean | undefined { + return ProfileStatusMonitor.lastMcpState + } +} diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts index 54eba4c852..fd692e6e8e 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts @@ -24,6 +24,9 @@ import { FsReplace, FsReplaceParams } from './fsReplace' import { CodeReviewUtils } from './qCodeAnalysis/codeReviewUtils' import { DEFAULT_AWS_Q_ENDPOINT_URL, DEFAULT_AWS_Q_REGION } from '../../../shared/constants' import { DisplayFindings } from './qCodeAnalysis/displayFindings' +import { ProfileStatusMonitor } from './mcp/profileStatusMonitor' +import { AmazonQTokenServiceManager } from '../../../shared/amazonQServiceManager/AmazonQTokenServiceManager' +import { SERVICE_MANAGER_TIMEOUT_MS, SERVICE_MANAGER_POLL_INTERVAL_MS } from '../constants/constants' export const FsToolsServer: Server = ({ workspace, logging, agent, lsp }) => { const fsReadTool = new FsRead({ workspace, lsp, logging }) @@ -199,10 +202,45 @@ export const LspToolsServer: Server = ({ workspace, logging, lsp, agent }) => { return () => {} } -export const McpToolsServer: Server = ({ credentialsProvider, workspace, logging, lsp, agent, telemetry, runtime }) => { +export const McpToolsServer: Server = ({ + credentialsProvider, + workspace, + logging, + lsp, + agent, + telemetry, + runtime, + sdkInitializator, + chat, +}) => { const registered: Record = {} - const allNamespacedTools = new Set() + let profileStatusMonitor: ProfileStatusMonitor | undefined + + function removeAllMcpTools(): void { + logging.info('Removing all MCP tools due to admin configuration') + for (const [server, toolNames] of Object.entries(registered)) { + for (const name of toolNames) { + agent.removeTool(name) + allNamespacedTools.delete(name) + logging.info(`MCP: removed tool ${name}`) + } + registered[server] = [] + } + void McpManager.instance.close(true) //keep the instance but close all servers. + + try { + chat?.sendChatUpdate({ + tabId: 'mcpserver', + data: { + placeholderText: 'mcp-server-update', + messages: [], + }, + }) + } catch (error) { + logging.error(`Failed to send chatOptionsUpdate: ${error}`) + } + } function registerServerTools(server: string, defs: McpToolDefinition[]) { // 1) remove old tools @@ -257,20 +295,13 @@ export const McpToolsServer: Server = ({ credentialsProvider, workspace, logging } } - lsp.onInitialized(async () => { + async function initializeMcp() { try { - if (!enabledMCP(lsp.getClientInitializeParams())) { - logging.warn('MCP is currently not supported') - return - } - const wsUris = workspace.getAllWorkspaceFolders()?.map(f => f.uri) ?? [] - // Get agent paths const wsAgentPaths = getWorkspaceAgentConfigPaths(wsUris) const globalAgentPath = getGlobalAgentConfigPath(workspace.fs.getUserHomeDir()) const allAgentPaths = [...wsAgentPaths, globalAgentPath] - // Migrate config and persona files to agent config await migrateToAgentConfig(workspace, logging, agent) const mgr = await McpManager.init(allAgentPaths, { @@ -282,13 +313,9 @@ export const McpToolsServer: Server = ({ credentialsProvider, workspace, logging runtime, }) - // Clear tool name mapping before registering all tools to avoid conflicts from previous registrations McpManager.instance.clearToolNameMapping() const byServer: Record = {} - - logging.info(`enabled Tools: ${mgr.getEnabledTools().entries()}`) - // only register enabled tools for (const d of mgr.getEnabledTools()) { ;(byServer[d.serverName] ||= []).push(d) } @@ -300,11 +327,76 @@ export const McpToolsServer: Server = ({ credentialsProvider, workspace, logging registerServerTools(server, defs) }) } catch (e) { - console.warn('Caught error during MCP tool initialization; initialization may be incomplete:', e) + logging.error(`Failed to initialize MCP:' ${e}`) + } + } + + lsp.onInitialized(async () => { + try { + if (!enabledMCP(lsp.getClientInitializeParams())) { + logging.warn('MCP is currently not supported') + return + } + + if (sdkInitializator) { + profileStatusMonitor = new ProfileStatusMonitor( + credentialsProvider, + workspace, + logging, + sdkInitializator, + removeAllMcpTools, + async () => { + logging.info('MCP enabled by profile status monitor') + await initializeMcp() + } + ) + + // Wait for profile ARN to be available before checking MCP state + const checkAndInitialize = async () => { + const shouldInitialize = await profileStatusMonitor!.checkInitialState() + if (shouldInitialize) { + logging.info('MCP enabled, initializing immediately') + await initializeMcp() + } + profileStatusMonitor!.start() + } + + // Check if service manager is ready + try { + const serviceManager = AmazonQTokenServiceManager.getInstance() + if (serviceManager.getState() === 'INITIALIZED') { + await checkAndInitialize() + } else { + // Poll for service manager to be ready with 10s timeout + const startTime = Date.now() + const pollForReady = async () => { + if (serviceManager.getState() === 'INITIALIZED') { + await checkAndInitialize() + } else if (Date.now() - startTime < SERVICE_MANAGER_TIMEOUT_MS) { + setTimeout(pollForReady, SERVICE_MANAGER_POLL_INTERVAL_MS) + } else { + logging.warn('Service manager not ready after 10s, defaulting MCP to enabled') + await initializeMcp() + profileStatusMonitor!.start() + } + } + setTimeout(pollForReady, SERVICE_MANAGER_POLL_INTERVAL_MS) + } + } catch (error) { + // Service manager not initialized yet, default to enabled + logging.info('Service manager not ready, defaulting MCP to enabled') + await initializeMcp() + profileStatusMonitor!.start() + } + } + } catch (error) { + console.warn('Caught error during MCP tool initialization; initialization may be incomplete:', error) + logging.error(`Failed to initialize MCP in onInitialized: ${error}`) } }) return async () => { + profileStatusMonitor?.stop() await McpManager.instance.close() } } diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index a162ff44e6..aafc0aaf4d 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -581,6 +581,13 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { return this.client.getCodeAnalysis(this.withProfileArn(request)).promise() } + /** + * @description Get profile details + */ + async getProfile(request: { profileArn: string }) { + return this.client.getProfile(request).promise() + } + /** * @description Once scan completed successfully, send a request to get list of all the findings for the given scan. */ From 91c839857f8aa4d79098189f9fb620b361c51289 Mon Sep 17 00:00:00 2001 From: Lei Gao <97199248+leigaol@users.noreply.github.com> Date: Wed, 13 Aug 2025 14:04:19 -0700 Subject: [PATCH 003/158] fix: Use file context override in the inline completion params for Jupyter Notebook (#2114) --- app/aws-lsp-antlr4-runtimes/package.json | 2 +- app/aws-lsp-buildspec-runtimes/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- app/aws-lsp-identity-runtimes/package.json | 2 +- app/aws-lsp-json-runtimes/package.json | 2 +- .../package.json | 2 +- app/aws-lsp-partiql-runtimes/package.json | 2 +- app/aws-lsp-s3-runtimes/package.json | 2 +- app/aws-lsp-yaml-json-webworker/package.json | 2 +- app/aws-lsp-yaml-runtimes/package.json | 2 +- app/hello-world-lsp-runtimes/package.json | 2 +- chat-client/package.json | 2 +- client/vscode/package.json | 2 +- core/aws-lsp-core/package.json | 2 +- .../q-agentic-chat-server/package.json | 2 +- package-lock.json | 70 +++++++++---------- server/aws-lsp-antlr4/package.json | 2 +- server/aws-lsp-buildspec/package.json | 2 +- server/aws-lsp-cloudformation/package.json | 2 +- server/aws-lsp-codewhisperer/package.json | 2 +- .../codeWhispererServer.test.ts | 49 ++++++++++++- .../inline-completion/codeWhispererServer.ts | 46 +++++++++--- .../inline-completion/trigger.ts | 17 ++--- .../src/shared/codeWhispererService.ts | 20 +++--- server/aws-lsp-identity/package.json | 2 +- server/aws-lsp-json/package.json | 2 +- server/aws-lsp-notification/package.json | 2 +- server/aws-lsp-partiql/package.json | 2 +- server/aws-lsp-s3/package.json | 2 +- server/aws-lsp-yaml/package.json | 2 +- server/device-sso-auth-lsp/package.json | 2 +- server/hello-world-lsp/package.json | 2 +- 33 files changed, 163 insertions(+), 95 deletions(-) diff --git a/app/aws-lsp-antlr4-runtimes/package.json b/app/aws-lsp-antlr4-runtimes/package.json index bf7cf47bf1..4289cec4b1 100644 --- a/app/aws-lsp-antlr4-runtimes/package.json +++ b/app/aws-lsp-antlr4-runtimes/package.json @@ -12,7 +12,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-antlr4": "*", "antlr4-c3": "^3.4.1", "antlr4ng": "^3.0.4" diff --git a/app/aws-lsp-buildspec-runtimes/package.json b/app/aws-lsp-buildspec-runtimes/package.json index b9c36946b2..700afb3e7f 100644 --- a/app/aws-lsp-buildspec-runtimes/package.json +++ b/app/aws-lsp-buildspec-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-buildspec": "^0.0.1" } } diff --git a/app/aws-lsp-cloudformation-runtimes/package.json b/app/aws-lsp-cloudformation-runtimes/package.json index a88386db4e..5cc04150cb 100644 --- a/app/aws-lsp-cloudformation-runtimes/package.json +++ b/app/aws-lsp-cloudformation-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-cloudformation": "^0.0.1" } } diff --git a/app/aws-lsp-codewhisperer-runtimes/package.json b/app/aws-lsp-codewhisperer-runtimes/package.json index 487d2c5b1a..fc31e64589 100644 --- a/app/aws-lsp-codewhisperer-runtimes/package.json +++ b/app/aws-lsp-codewhisperer-runtimes/package.json @@ -23,7 +23,7 @@ "local-build": "node scripts/local-build.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", diff --git a/app/aws-lsp-identity-runtimes/package.json b/app/aws-lsp-identity-runtimes/package.json index 46abf7d958..869a30cb20 100644 --- a/app/aws-lsp-identity-runtimes/package.json +++ b/app/aws-lsp-identity-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-identity": "^0.0.1" } } diff --git a/app/aws-lsp-json-runtimes/package.json b/app/aws-lsp-json-runtimes/package.json index 24ae3535ac..f63dd4e985 100644 --- a/app/aws-lsp-json-runtimes/package.json +++ b/app/aws-lsp-json-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-json": "*" }, "devDependencies": { diff --git a/app/aws-lsp-notification-runtimes/package.json b/app/aws-lsp-notification-runtimes/package.json index 1e7641e2a8..faf9e4c24c 100644 --- a/app/aws-lsp-notification-runtimes/package.json +++ b/app/aws-lsp-notification-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-notification": "^0.0.1" } } diff --git a/app/aws-lsp-partiql-runtimes/package.json b/app/aws-lsp-partiql-runtimes/package.json index 0d5e07cddf..d483f3d0ce 100644 --- a/app/aws-lsp-partiql-runtimes/package.json +++ b/app/aws-lsp-partiql-runtimes/package.json @@ -11,7 +11,7 @@ "package": "npm run compile && npm run compile:webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.120", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-partiql": "^0.0.5" }, "devDependencies": { diff --git a/app/aws-lsp-s3-runtimes/package.json b/app/aws-lsp-s3-runtimes/package.json index ad84f62776..42efa998be 100644 --- a/app/aws-lsp-s3-runtimes/package.json +++ b/app/aws-lsp-s3-runtimes/package.json @@ -10,7 +10,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-s3": "^0.0.1" } } diff --git a/app/aws-lsp-yaml-json-webworker/package.json b/app/aws-lsp-yaml-json-webworker/package.json index 7079d1fa3b..6190893816 100644 --- a/app/aws-lsp-yaml-json-webworker/package.json +++ b/app/aws-lsp-yaml-json-webworker/package.json @@ -11,7 +11,7 @@ "serve:webpack": "NODE_ENV=development webpack serve" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, diff --git a/app/aws-lsp-yaml-runtimes/package.json b/app/aws-lsp-yaml-runtimes/package.json index a59f919477..eb76a46e38 100644 --- a/app/aws-lsp-yaml-runtimes/package.json +++ b/app/aws-lsp-yaml-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-yaml": "*" }, "devDependencies": { diff --git a/app/hello-world-lsp-runtimes/package.json b/app/hello-world-lsp-runtimes/package.json index 54018d89d0..14a3a75ff4 100644 --- a/app/hello-world-lsp-runtimes/package.json +++ b/app/hello-world-lsp-runtimes/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@aws/hello-world-lsp": "^0.0.1", - "@aws/language-server-runtimes": "^0.2.123" + "@aws/language-server-runtimes": "^0.2.125" }, "devDependencies": { "@types/chai": "^4.3.5", diff --git a/chat-client/package.json b/chat-client/package.json index df0378f3e4..2ee60a8bec 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/language-server-runtimes-types": "^0.1.50", "@aws/mynah-ui": "^4.36.4" }, diff --git a/client/vscode/package.json b/client/vscode/package.json index 975a395d66..409a4fc50d 100644 --- a/client/vscode/package.json +++ b/client/vscode/package.json @@ -352,7 +352,7 @@ "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", diff --git a/core/aws-lsp-core/package.json b/core/aws-lsp-core/package.json index aeff582d34..5a3d438d47 100644 --- a/core/aws-lsp-core/package.json +++ b/core/aws-lsp-core/package.json @@ -28,7 +28,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", diff --git a/integration-tests/q-agentic-chat-server/package.json b/integration-tests/q-agentic-chat-server/package.json index 5431142f5c..1e93a252dd 100644 --- a/integration-tests/q-agentic-chat-server/package.json +++ b/integration-tests/q-agentic-chat-server/package.json @@ -9,7 +9,7 @@ "test-integ": "npm run compile && mocha --timeout 30000 \"./out/**/*.test.js\" --retries 2" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "*" }, "devDependencies": { diff --git a/package-lock.json b/package-lock.json index b42f206c44..d1ac2ece1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,7 +48,7 @@ "name": "@aws/lsp-antlr4-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-antlr4": "*", "antlr4-c3": "^3.4.1", "antlr4ng": "^3.0.4" @@ -71,7 +71,7 @@ "name": "@aws/lsp-buildspec-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-buildspec": "^0.0.1" } }, @@ -79,7 +79,7 @@ "name": "@aws/lsp-cloudformation-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-cloudformation": "^0.0.1" } }, @@ -87,7 +87,7 @@ "name": "@aws/lsp-codewhisperer-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", @@ -120,7 +120,7 @@ "name": "@aws/lsp-identity-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-identity": "^0.0.1" } }, @@ -128,7 +128,7 @@ "name": "@aws/lsp-json-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-json": "*" }, "devDependencies": { @@ -148,7 +148,7 @@ "name": "@aws/lsp-notification-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-notification": "^0.0.1" } }, @@ -156,7 +156,7 @@ "name": "@aws/lsp-partiql-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.120", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-partiql": "^0.0.5" }, "devDependencies": { @@ -181,7 +181,7 @@ "name": "@aws/lsp-s3-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-s3": "^0.0.1" }, "bin": { @@ -192,7 +192,7 @@ "name": "@aws/lsp-yaml-json-webworker", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, @@ -212,7 +212,7 @@ "name": "@aws/lsp-yaml-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-yaml": "*" }, "devDependencies": { @@ -234,7 +234,7 @@ "version": "0.0.1", "dependencies": { "@aws/hello-world-lsp": "^0.0.1", - "@aws/language-server-runtimes": "^0.2.123" + "@aws/language-server-runtimes": "^0.2.125" }, "devDependencies": { "@types/chai": "^4.3.5", @@ -255,7 +255,7 @@ "license": "Apache-2.0", "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/language-server-runtimes-types": "^0.1.50", "@aws/mynah-ui": "^4.36.4" }, @@ -280,7 +280,7 @@ "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", @@ -296,7 +296,7 @@ "version": "0.0.13", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", @@ -327,7 +327,7 @@ "name": "@aws/q-agentic-chat-server-integration-tests", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "*" }, "devDependencies": { @@ -4036,12 +4036,12 @@ "link": true }, "node_modules/@aws/language-server-runtimes": { - "version": "0.2.123", - "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.2.123.tgz", - "integrity": "sha512-gxjnBcQY+HR9+F1NXQUEQ6ikJhrLMJEbrpIxlBLILtQ75hVtRDsfGET3KW5Nn0dgbrQTx6VqwvXDfolUkmi06g==", + "version": "0.2.125", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.2.125.tgz", + "integrity": "sha512-tjXJEagZ6rm09fcgJGu1zbFNzi0+7R1mdNFa6zCIv68c76xq5JHjc++Hne9aOgp61O6BM9uNnX3KR57v9/0E1g==", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes-types": "^0.1.55", + "@aws/language-server-runtimes-types": "^0.1.56", "@opentelemetry/api": "^1.9.0", "@opentelemetry/api-logs": "^0.200.0", "@opentelemetry/core": "^2.0.0", @@ -4068,9 +4068,9 @@ } }, "node_modules/@aws/language-server-runtimes-types": { - "version": "0.1.55", - "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.55.tgz", - "integrity": "sha512-KRy3fTCNGvAQxA4amTODXPuubxrYlqKsyJOXPaIn+YDACwJa7shrOryHg6xrib6uHAHT2fEkcTMk9TT4MRPxQA==", + "version": "0.1.56", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.56.tgz", + "integrity": "sha512-Md/L750JShCHUsCQUJva51Ofkn/GDBEX8PpZnWUIVqkpddDR00SLQS2smNf4UHtKNJ2fefsfks/Kqfuatjkjvg==", "license": "Apache-2.0", "dependencies": { "vscode-languageserver-textdocument": "^1.0.12", @@ -28608,7 +28608,7 @@ "version": "0.1.17", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "^0.0.13" }, "devDependencies": { @@ -28650,7 +28650,7 @@ "name": "@aws/lsp-buildspec", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", @@ -28661,7 +28661,7 @@ "name": "@aws/lsp-cloudformation", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", @@ -28683,7 +28683,7 @@ "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "^0.0.13", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", @@ -28823,7 +28823,7 @@ "dependencies": { "@aws-sdk/client-sso-oidc": "^3.616.0", "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "^0.0.12", "@smithy/node-http-handler": "^3.2.5", "@smithy/shared-ini-file-loader": "^4.0.1", @@ -28888,7 +28888,7 @@ "version": "0.1.17", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "^0.0.13", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" @@ -28905,7 +28905,7 @@ "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1" }, @@ -28966,7 +28966,7 @@ "version": "0.0.16", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "antlr4-c3": "3.4.2", "antlr4ng": "3.0.14", "web-tree-sitter": "0.22.6" @@ -28988,7 +28988,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" @@ -29019,7 +29019,7 @@ "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "^0.0.13", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", @@ -29033,7 +29033,7 @@ "name": "@amzn/device-sso-auth-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "vscode-languageserver": "^9.0.1" }, "devDependencies": { @@ -29044,7 +29044,7 @@ "name": "@aws/hello-world-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/server/aws-lsp-antlr4/package.json b/server/aws-lsp-antlr4/package.json index 9d6c925b40..f540c8ae21 100644 --- a/server/aws-lsp-antlr4/package.json +++ b/server/aws-lsp-antlr4/package.json @@ -28,7 +28,7 @@ "clean": "rm -rf node_modules" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "^0.0.13" }, "peerDependencies": { diff --git a/server/aws-lsp-buildspec/package.json b/server/aws-lsp-buildspec/package.json index f59edb5549..2cf0b776ac 100644 --- a/server/aws-lsp-buildspec/package.json +++ b/server/aws-lsp-buildspec/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-cloudformation/package.json b/server/aws-lsp-cloudformation/package.json index bfc8ebd7e5..ad01b4457a 100644 --- a/server/aws-lsp-cloudformation/package.json +++ b/server/aws-lsp-cloudformation/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index fdd34884b1..8600148090 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -36,7 +36,7 @@ "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "^0.0.13", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts index 29390248f7..8151602dd4 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts @@ -12,7 +12,7 @@ import { TestFeatures } from '@aws/language-server-runtimes/testing' import * as assert from 'assert' import { AWSError } from 'aws-sdk' import sinon, { StubbedInstance } from 'ts-sinon' -import { CodewhispererServerFactory } from './codeWhispererServer' +import { CodewhispererServerFactory, getLanguageIdFromUri } from './codeWhispererServer' import { CodeWhispererServiceBase, CodeWhispererServiceToken, @@ -2427,4 +2427,51 @@ describe('CodeWhisperer Server', () => { TestAmazonQServiceManager.resetInstance() }) }) + describe('getLanguageIdFromUri', () => { + it('should return python for notebook cell URIs', () => { + const uri = 'vscode-notebook-cell:/some/path/notebook.ipynb#cell1' + assert.strictEqual(getLanguageIdFromUri(uri), 'python') + }) + + it('should return abap for files with ABAP extensions', () => { + const uris = ['file:///path/to/file.asprog'] + + uris.forEach(uri => { + assert.strictEqual(getLanguageIdFromUri(uri), 'abap') + }) + }) + + it('should return empty string for non-ABAP files', () => { + const uris = ['file:///path/to/file.js', 'file:///path/to/file.ts', 'file:///path/to/file.py'] + + uris.forEach(uri => { + assert.strictEqual(getLanguageIdFromUri(uri), '') + }) + }) + + it('should return empty string for invalid URIs', () => { + const invalidUris = ['', 'invalid-uri', 'file:///'] + + invalidUris.forEach(uri => { + assert.strictEqual(getLanguageIdFromUri(uri), '') + }) + }) + + it('should log errors when provided with a logging object', () => { + const mockLogger = { + log: sinon.spy(), + } + + const invalidUri = {} as string // Force type error + getLanguageIdFromUri(invalidUri, mockLogger) + + sinon.assert.calledOnce(mockLogger.log) + sinon.assert.calledWith(mockLogger.log, sinon.match(/Error parsing URI to determine language:.*/)) + }) + + it('should handle URIs without extensions', () => { + const uri = 'file:///path/to/file' + assert.strictEqual(getLanguageIdFromUri(uri), '') + }) + }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts index 23a72e3528..c1f2b464b2 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts @@ -15,13 +15,14 @@ import { } from '@aws/language-server-runtimes/server-interface' import { autoTrigger, getAutoTriggerType, getNormalizeOsName, triggerType } from './auto-trigger/autoTrigger' import { + FileContext, GenerateSuggestionsRequest, GenerateSuggestionsResponse, getFileContext, Suggestion, SuggestionType, } from '../../shared/codeWhispererService' -import { getSupportedLanguageId } from '../../shared/languageDetection' +import { CodewhispererLanguage, getSupportedLanguageId } from '../../shared/languageDetection' import { mergeEditSuggestionsWithFileContext, truncateOverlapWithRightContext } from './mergeRightUtils' import { CodeWhispererSession, SessionManager } from './session/sessionManager' import { CodePercentageTracker } from './codePercentage' @@ -41,7 +42,6 @@ import { AmazonQWorkspaceConfig } from '../../shared/amazonQServiceManager/confi import { hasConnectionExpired } from '../../shared/utils' import { getOrThrowBaseIAMServiceManager } from '../../shared/amazonQServiceManager/AmazonQIAMServiceManager' import { WorkspaceFolderManager } from '../workspaceContext/workspaceFolderManager' -import path = require('path') import { UserWrittenCodeTracker } from '../../shared/userWrittenCodeTracker' import { RecentEditTracker, RecentEditTrackerDefaultConfig } from './tracker/codeEditTracker' import { CursorTracker } from './tracker/cursorTracker' @@ -191,7 +191,10 @@ export const CodewhispererServerFactory = return EMPTY_RESULT } - const inferredLanguageId = getSupportedLanguageId(textDocument) + let inferredLanguageId = getSupportedLanguageId(textDocument) + if (params.fileContextOverride?.programmingLanguage) { + inferredLanguageId = params.fileContextOverride?.programmingLanguage as CodewhispererLanguage + } if (!inferredLanguageId) { logging.log( `textDocument [${params.textDocument.uri}] with languageId [${textDocument.languageId}] not supported` @@ -204,12 +207,29 @@ export const CodewhispererServerFactory = params.context.triggerKind == InlineCompletionTriggerKind.Automatic const maxResults = isAutomaticLspTriggerKind ? 1 : 5 const selectionRange = params.context.selectedCompletionInfo?.range - const fileContext = getFileContext({ - textDocument, - inferredLanguageId, - position: params.position, - workspaceFolder: workspace.getWorkspaceFolder(textDocument.uri), - }) + + // For Jupyter Notebook in VSC, the language server does not have access to + // its internal states including current active cell index, etc + // we rely on VSC to calculate file context + let fileContext: FileContext | undefined = undefined + if (params.fileContextOverride) { + fileContext = { + leftFileContent: params.fileContextOverride.leftFileContent, + rightFileContent: params.fileContextOverride.rightFileContent, + filename: params.fileContextOverride.filename, + fileUri: params.fileContextOverride.fileUri, + programmingLanguage: { + languageName: inferredLanguageId, + }, + } + } else { + fileContext = getFileContext({ + textDocument, + inferredLanguageId, + position: params.position, + workspaceFolder: workspace.getWorkspaceFolder(textDocument.uri), + }) + } const workspaceState = WorkspaceFolderManager.getInstance()?.getWorkspaceState() const workspaceId = workspaceState?.webSocketClient?.isConnected() @@ -327,7 +347,7 @@ export const CodewhispererServerFactory = document: textDocument, startPosition: params.position, triggerType: isAutomaticLspTriggerKind ? 'AutoTrigger' : 'OnDemand', - language: fileContext.programmingLanguage.languageName, + language: fileContext.programmingLanguage.languageName as CodewhispererLanguage, requestContext: requestContext, autoTriggerType: isAutomaticLspTriggerKind ? codewhispererAutoTriggerType : undefined, triggerCharacter: triggerCharacters, @@ -892,8 +912,12 @@ export const CodewhispererServerFactory = export const CodeWhispererServerIAM = CodewhispererServerFactory(getOrThrowBaseIAMServiceManager) export const CodeWhispererServerToken = CodewhispererServerFactory(getOrThrowBaseTokenServiceManager) -const getLanguageIdFromUri = (uri: string, logging?: any): string => { +export const getLanguageIdFromUri = (uri: string, logging?: any): string => { try { + if (uri.startsWith('vscode-notebook-cell:')) { + // use python for now as lsp does not support JL cell language detection + return 'python' + } const extension = uri.split('.').pop()?.toLowerCase() return ABAP_EXTENSIONS.has(extension || '') ? 'abap' : '' } catch (err) { diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/trigger.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/trigger.ts index 06453355a8..305b9b6e5c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/trigger.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/trigger.ts @@ -1,24 +1,19 @@ -import { CodewhispererLanguage } from '../../shared/languageDetection' import { SessionManager } from './session/sessionManager' import { InlineCompletionWithReferencesParams } from '@aws/language-server-runtimes/protocol' import { editPredictionAutoTrigger } from './auto-trigger/editPredictionAutoTrigger' import { CursorTracker } from './tracker/cursorTracker' import { RecentEditTracker } from './tracker/codeEditTracker' -import { CodeWhispererServiceBase, CodeWhispererServiceToken } from '../../shared/codeWhispererService' +import { + CodeWhispererServiceBase, + CodeWhispererServiceToken, + ClientFileContext, +} from '../../shared/codeWhispererService' export class NepTrigger {} export function shouldTriggerEdits( service: CodeWhispererServiceBase, - fileContext: { - fileUri: string - filename: string - programmingLanguage: { - languageName: CodewhispererLanguage - } - leftFileContent: string - rightFileContent: string - }, + fileContext: ClientFileContext, inlineParams: InlineCompletionWithReferencesParams, cursorTracker: CursorTracker, recentEditsTracker: RecentEditTracker, diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index aafc0aaf4d..01101d68a8 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -71,20 +71,22 @@ export interface GenerateSuggestionsResponse { responseContext: ResponseContext } +export interface ClientFileContext { + leftFileContent: string + rightFileContent: string + filename: string + fileUri: string + programmingLanguage: { + languageName: CodewhispererLanguage + } +} + export function getFileContext(params: { textDocument: TextDocument position: Position inferredLanguageId: CodewhispererLanguage workspaceFolder: WorkspaceFolder | null | undefined -}): { - fileUri: string - filename: string - programmingLanguage: { - languageName: CodewhispererLanguage - } - leftFileContent: string - rightFileContent: string -} { +}): ClientFileContext { const left = params.textDocument.getText({ start: { line: 0, character: 0 }, end: params.position, diff --git a/server/aws-lsp-identity/package.json b/server/aws-lsp-identity/package.json index e8cb3b2c8a..acaeb6d15d 100644 --- a/server/aws-lsp-identity/package.json +++ b/server/aws-lsp-identity/package.json @@ -26,7 +26,7 @@ "dependencies": { "@aws-sdk/client-sso-oidc": "^3.616.0", "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "^0.0.12", "@smithy/node-http-handler": "^3.2.5", "@smithy/shared-ini-file-loader": "^4.0.1", diff --git a/server/aws-lsp-json/package.json b/server/aws-lsp-json/package.json index 298f3820f0..7b1768f995 100644 --- a/server/aws-lsp-json/package.json +++ b/server/aws-lsp-json/package.json @@ -26,7 +26,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "^0.0.13", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" diff --git a/server/aws-lsp-notification/package.json b/server/aws-lsp-notification/package.json index a9e3cf9d4c..45194be66b 100644 --- a/server/aws-lsp-notification/package.json +++ b/server/aws-lsp-notification/package.json @@ -22,7 +22,7 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1" }, diff --git a/server/aws-lsp-partiql/package.json b/server/aws-lsp-partiql/package.json index 9ff685cfdc..263275dced 100644 --- a/server/aws-lsp-partiql/package.json +++ b/server/aws-lsp-partiql/package.json @@ -24,7 +24,7 @@ "out" ], "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "antlr4-c3": "3.4.2", "antlr4ng": "3.0.14", "web-tree-sitter": "0.22.6" diff --git a/server/aws-lsp-s3/package.json b/server/aws-lsp-s3/package.json index caa7801b5f..53355ff18a 100644 --- a/server/aws-lsp-s3/package.json +++ b/server/aws-lsp-s3/package.json @@ -9,7 +9,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" diff --git a/server/aws-lsp-yaml/package.json b/server/aws-lsp-yaml/package.json index 58fd5e591d..deeddd9694 100644 --- a/server/aws-lsp-yaml/package.json +++ b/server/aws-lsp-yaml/package.json @@ -26,7 +26,7 @@ "postinstall": "node patchYamlPackage.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "@aws/lsp-core": "^0.0.13", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", diff --git a/server/device-sso-auth-lsp/package.json b/server/device-sso-auth-lsp/package.json index 573170a3a9..698bbf353e 100644 --- a/server/device-sso-auth-lsp/package.json +++ b/server/device-sso-auth-lsp/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/server/hello-world-lsp/package.json b/server/hello-world-lsp/package.json index 827509803e..a0ad8e8469 100644 --- a/server/hello-world-lsp/package.json +++ b/server/hello-world-lsp/package.json @@ -13,7 +13,7 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.123", + "@aws/language-server-runtimes": "^0.2.125", "vscode-languageserver": "^9.0.1" }, "devDependencies": { From 93cf229149ba60491f9f5763793db4a9f570b611 Mon Sep 17 00:00:00 2001 From: Tai Lai Date: Wed, 13 Aug 2025 16:19:26 -0700 Subject: [PATCH 004/158] feat(amazonq): read tool ui revamp (#2113) (#2121) * feat(amazonq): read tool ui revamp * feat(amazonq): read tool message revamp (#2049) * feat(amazonq): read tool message revamp * fix tests * feat: file search ui (#2078) * feat: file search ui * fix tests * fix integration tests * remove unnecessary type check * fix: use quotes instead of backticks * fix header update issue * fix integration test --- chat-client/src/client/mynahUi.ts | 16 +- .../src/tests/agenticChatInteg.test.ts | 13 +- .../agenticChat/agenticChatController.test.ts | 6 +- .../agenticChat/agenticChatController.ts | 188 ++++++++++++------ .../agenticChat/agenticChatResultStream.ts | 63 ++---- .../agenticChat/tools/fileSearch.ts | 4 + 6 files changed, 163 insertions(+), 127 deletions(-) diff --git a/chat-client/src/client/mynahUi.ts b/chat-client/src/client/mynahUi.ts index 3b42249331..527dea06f3 100644 --- a/chat-client/src/client/mynahUi.ts +++ b/chat-client/src/client/mynahUi.ts @@ -1353,10 +1353,15 @@ export const createMynahUi = ( fileTreeTitle: '', hideFileCount: true, details: toDetailsWithoutIcon(header.fileList.details), + renderAsPills: + !header.fileList.details || + (Object.values(header.fileList.details).every(detail => !detail.changes) && + (!header.buttons || !header.buttons.some(button => button.id === 'undo-changes')) && + !header.status?.icon), } } if (!isPartialResult) { - if (processedHeader) { + if (processedHeader && !message.header?.status) { processedHeader.status = undefined } } @@ -1369,7 +1374,8 @@ export const createMynahUi = ( processedHeader.buttons !== null && processedHeader.buttons.length > 0) || processedHeader.status !== undefined || - processedHeader.icon !== undefined) + processedHeader.icon !== undefined || + processedHeader.fileList !== undefined) const padding = message.type === 'tool' ? (fileList ? true : message.messageId?.endsWith('_permission')) : undefined @@ -1380,8 +1386,10 @@ export const createMynahUi = ( // Adding this conditional check to show the stop message in the center. const contentHorizontalAlignment: ChatItem['contentHorizontalAlignment'] = undefined - // If message.header?.status?.text is Stopped or Rejected or Ignored or Completed etc.. card should be in disabled state. - const shouldMute = message.header?.status?.text !== undefined && message.header?.status?.text !== 'Completed' + // If message.header?.status?.text is Stopped or Rejected or Ignored etc.. card should be in disabled state. + const shouldMute = + message.header?.status?.text !== undefined && + ['Stopped', 'Rejected', 'Ignored', 'Failed', 'Error'].includes(message.header.status.text) return { body: message.body, diff --git a/integration-tests/q-agentic-chat-server/src/tests/agenticChatInteg.test.ts b/integration-tests/q-agentic-chat-server/src/tests/agenticChatInteg.test.ts index 897ee02071..c5a8046bd5 100644 --- a/integration-tests/q-agentic-chat-server/src/tests/agenticChatInteg.test.ts +++ b/integration-tests/q-agentic-chat-server/src/tests/agenticChatInteg.test.ts @@ -169,11 +169,11 @@ describe('Q Agentic Chat Server Integration Tests', async () => { expect(decryptedResult.additionalMessages).to.be.an('array') const fsReadMessage = decryptedResult.additionalMessages?.find( - msg => msg.type === 'tool' && msg.fileList?.rootFolderTitle === '1 file read' + msg => msg.type === 'tool' && msg.header?.body === '1 file read' ) expect(fsReadMessage).to.exist const expectedPath = path.join(rootPath, 'test.py') - const actualPaths = fsReadMessage?.fileList?.filePaths?.map(normalizePath) || [] + const actualPaths = fsReadMessage?.header?.fileList?.filePaths?.map(normalizePath) || [] expect(actualPaths).to.include.members([normalizePath(expectedPath)]) expect(fsReadMessage?.messageId?.startsWith('tooluse_')).to.be.true }) @@ -191,10 +191,10 @@ describe('Q Agentic Chat Server Integration Tests', async () => { expect(decryptedResult.additionalMessages).to.be.an('array') const listDirectoryMessage = decryptedResult.additionalMessages?.find( - msg => msg.type === 'tool' && msg.fileList?.rootFolderTitle === '1 directory listed' + msg => msg.type === 'tool' && msg.header?.body === '1 directory listed' ) expect(listDirectoryMessage).to.exist - const actualPaths = listDirectoryMessage?.fileList?.filePaths?.map(normalizePath) || [] + const actualPaths = listDirectoryMessage?.header?.fileList?.filePaths?.map(normalizePath) || [] expect(actualPaths).to.include.members([normalizePath(rootPath)]) expect(listDirectoryMessage?.messageId?.startsWith('tooluse_')).to.be.true }) @@ -371,11 +371,12 @@ describe('Q Agentic Chat Server Integration Tests', async () => { expect(decryptedResult.additionalMessages).to.be.an('array') const fileSearchMessage = decryptedResult.additionalMessages?.find( - msg => msg.type === 'tool' && msg.fileList?.rootFolderTitle === '1 directory searched' + msg => msg.type === 'tool' && msg.header?.body === 'Searched for "test" in ' ) expect(fileSearchMessage).to.exist expect(fileSearchMessage?.messageId?.startsWith('tooluse_')).to.be.true - const actualPaths = fileSearchMessage?.fileList?.filePaths?.map(normalizePath) || [] + expect(fileSearchMessage?.header?.status?.text).to.equal('3 results found') + const actualPaths = fileSearchMessage?.header?.fileList?.filePaths?.map(normalizePath) || [] expect(actualPaths).to.include.members([normalizePath(rootPath)]) }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts index 6c8af7a272..616848d0b5 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts @@ -451,7 +451,7 @@ describe('AgenticChatController', () => { assert.deepStrictEqual(chatResult, { additionalMessages: [], - body: '\n\nHello World!', + body: '\nHello World!', messageId: 'mock-message-id', buttons: [], codeReference: [], @@ -1150,7 +1150,7 @@ describe('AgenticChatController', () => { sinon.assert.callCount(testFeatures.lsp.sendProgress, mockChatResponseList.length + 1) // response length + 1 loading messages assert.deepStrictEqual(chatResult, { additionalMessages: [], - body: '\n\nHello World!', + body: '\nHello World!', messageId: 'mock-message-id', codeReference: [], buttons: [], @@ -1169,7 +1169,7 @@ describe('AgenticChatController', () => { sinon.assert.callCount(testFeatures.lsp.sendProgress, mockChatResponseList.length + 1) // response length + 1 loading message assert.deepStrictEqual(chatResult, { additionalMessages: [], - body: '\n\nHello World!', + body: '\nHello World!', messageId: 'mock-message-id', buttons: [], codeReference: [], diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 72217fae07..09bf965819 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -169,7 +169,7 @@ import { ExecuteBash, ExecuteBashParams } from './tools/executeBash' import { ExplanatoryParams, InvokeOutput, ToolApprovalException } from './tools/toolShared' import { validatePathBasic, validatePathExists, validatePaths as validatePathsSync } from './utils/pathValidation' import { GrepSearch, SanitizedRipgrepOutput } from './tools/grepSearch' -import { FileSearch, FileSearchParams } from './tools/fileSearch' +import { FileSearch, FileSearchParams, isFileSearchParams } from './tools/fileSearch' import { FsReplace, FsReplaceParams } from './tools/fsReplace' import { loggingUtils, timeoutUtils } from '@aws/lsp-core' import { diffLines } from 'diff' @@ -1695,8 +1695,7 @@ export class AgenticChatController implements ChatHandlers { // remove progress UI await chatResultStream.removeResultBlockAndUpdateUI(progressPrefix + toolUse.toolUseId) - // fsRead and listDirectory write to an existing card and could show nothing in the current position - if (![FS_WRITE, FS_REPLACE, FS_READ, LIST_DIRECTORY].includes(toolUse.name)) { + if (![FS_WRITE, FS_REPLACE].includes(toolUse.name)) { await this.#showUndoAllIfRequired(chatResultStream, session) } // fsWrite can take a long time, so we render fsWrite Explanatory upon partial streaming responses. @@ -1911,10 +1910,19 @@ export class AgenticChatController implements ChatHandlers { switch (toolUse.name) { case FS_READ: case LIST_DIRECTORY: + const readToolResult = await this.#processReadTool(toolUse, chatResultStream) + if (readToolResult) { + await chatResultStream.writeResultBlock(readToolResult) + } + break case FILE_SEARCH: - const initialListDirResult = this.#processReadOrListOrSearch(toolUse, chatResultStream) - if (initialListDirResult) { - await chatResultStream.writeResultBlock(initialListDirResult) + if (isFileSearchParams(toolUse.input)) { + await this.#processFileSearchTool( + toolUse.input, + toolUse.toolUseId, + result, + chatResultStream + ) } break // no need to write tool result for listDir,fsRead,fileSearch into chat stream @@ -2315,7 +2323,6 @@ export class AgenticChatController implements ChatHandlers { } const toolMsgId = toolUse.toolUseId! - const chatMsgId = chatResultStream.getResult().messageId let headerEmitted = false const initialHeader: ChatMessage['header'] = { @@ -2353,13 +2360,6 @@ export class AgenticChatController implements ChatHandlers { header: completedHeader, }) - await chatResultStream.writeResultBlock({ - type: 'answer', - messageId: chatMsgId, - body: '', - header: undefined, - }) - this.#stoppedToolUses.add(toolMsgId) }, }) @@ -2877,70 +2877,135 @@ export class AgenticChatController implements ChatHandlers { } } - #processReadOrListOrSearch(toolUse: ToolUse, chatResultStream: AgenticChatResultStream): ChatMessage | undefined { - let messageIdToUpdate = toolUse.toolUseId! - const currentId = chatResultStream.getMessageIdToUpdateForTool(toolUse.name!) + async #processFileSearchTool( + toolInput: FileSearchParams, + toolUseId: string, + result: InvokeOutput, + chatResultStream: AgenticChatResultStream + ): Promise { + if (typeof result.output.content !== 'string') return - if (currentId) { - messageIdToUpdate = currentId - } else { - chatResultStream.setMessageIdToUpdateForTool(toolUse.name!, messageIdToUpdate) + const { queryName, path: inputPath } = toolInput + const resultCount = result.output.content + .split('\n') + .filter(line => line.trim().startsWith('[F]') || line.trim().startsWith('[D]')).length + + const chatMessage: ChatMessage = { + type: 'tool', + messageId: toolUseId, + header: { + body: `Searched for "${queryName}" in `, + icon: 'search', + status: { + text: `${resultCount} result${resultCount !== 1 ? 's' : ''} found`, + }, + fileList: { + filePaths: [inputPath], + details: { + [inputPath]: { + description: inputPath, + visibleName: path.basename(inputPath), + clickable: false, + }, + }, + }, + }, } - let currentPaths = [] + await chatResultStream.writeResultBlock(chatMessage) + } + + async #processReadTool( + toolUse: ToolUse, + chatResultStream: AgenticChatResultStream + ): Promise { + let currentPaths: string[] = [] if (toolUse.name === FS_READ) { - currentPaths = (toolUse.input as unknown as FsReadParams)?.paths + currentPaths = (toolUse.input as unknown as FsReadParams)?.paths || [] + } else if (toolUse.name === LIST_DIRECTORY) { + const singlePath = (toolUse.input as unknown as ListDirectoryParams)?.path + if (singlePath) { + currentPaths = [singlePath] + } + } else if (toolUse.name === FILE_SEARCH) { + const queryName = (toolUse.input as unknown as FileSearchParams)?.queryName + if (queryName) { + currentPaths = [queryName] + } } else { - currentPaths.push((toolUse.input as unknown as ListDirectoryParams | FileSearchParams)?.path) + return } - if (!currentPaths) return + if (currentPaths.length === 0) return - for (const currentPath of currentPaths) { - const existingPaths = chatResultStream.getMessageOperation(messageIdToUpdate)?.filePaths || [] - // Check if path already exists in the list - const isPathAlreadyProcessed = existingPaths.some(path => path.relativeFilePath === currentPath) - if (!isPathAlreadyProcessed) { - const currentFileDetail = { - relativeFilePath: currentPath, - lineRanges: [{ first: -1, second: -1 }], - } - chatResultStream.addMessageOperation(messageIdToUpdate, toolUse.name!, [ - ...existingPaths, - currentFileDetail, - ]) + // Check if the last message is the same tool type + const lastMessage = chatResultStream.getLastMessage() + const isSameToolType = + lastMessage?.type === 'tool' && lastMessage.header?.icon === this.#toolToIcon(toolUse.name) + + let allPaths = currentPaths + + if (isSameToolType && lastMessage.messageId) { + // Combine with existing paths and overwrite the last message + const existingPaths = lastMessage.header?.fileList?.filePaths || [] + allPaths = [...existingPaths, ...currentPaths] + + const blockId = chatResultStream.getMessageBlockId(lastMessage.messageId) + if (blockId !== undefined) { + // Create the updated message with combined paths + const updatedMessage = this.#createFileListToolMessage(toolUse, allPaths, lastMessage.messageId) + // Overwrite the existing block + await chatResultStream.overwriteResultBlock(updatedMessage, blockId) + return undefined // Don't return a message since we already wrote it } } + + // Create new message with current paths + return this.#createFileListToolMessage(toolUse, allPaths, toolUse.toolUseId!) + } + + #createFileListToolMessage(toolUse: ToolUse, filePaths: string[], messageId: string): ChatMessage { + const itemCount = filePaths.length let title: string - const itemCount = chatResultStream.getMessageOperation(messageIdToUpdate)?.filePaths.length - const filePathsPushed = chatResultStream.getMessageOperation(messageIdToUpdate)?.filePaths ?? [] - if (!itemCount) { + if (itemCount === 0) { title = 'Gathering context' } else { title = toolUse.name === FS_READ ? `${itemCount} file${itemCount > 1 ? 's' : ''} read` - : toolUse.name === FILE_SEARCH - ? `${itemCount} ${itemCount === 1 ? 'directory' : 'directories'} searched` - : `${itemCount} ${itemCount === 1 ? 'directory' : 'directories'} listed` + : toolUse.name === LIST_DIRECTORY + ? `${itemCount} ${itemCount === 1 ? 'directory' : 'directories'} listed` + : '' } const details: Record = {} - for (const item of filePathsPushed) { - details[item.relativeFilePath] = { - lineRanges: item.lineRanges, - description: item.relativeFilePath, + for (const filePath of filePaths) { + details[filePath] = { + description: filePath, + visibleName: path.basename(filePath), + clickable: toolUse.name === FS_READ, } } - - const fileList: FileList = { - rootFolderTitle: title, - filePaths: filePathsPushed.map(item => item.relativeFilePath), - details, - } return { type: 'tool', - fileList, - messageId: messageIdToUpdate, - body: '', + header: { + body: title, + icon: this.#toolToIcon(toolUse.name), + fileList: { + filePaths, + details, + }, + }, + messageId, + } + } + + #toolToIcon(toolName: string | undefined): string | undefined { + switch (toolName) { + case FS_READ: + return 'eye' + case LIST_DIRECTORY: + return 'check-list' + default: + return undefined } } @@ -2956,14 +3021,7 @@ export class AgenticChatController implements ChatHandlers { return undefined } - let messageIdToUpdate = toolUse.toolUseId! - const currentId = chatResultStream.getMessageIdToUpdateForTool(toolUse.name!) - - if (currentId) { - messageIdToUpdate = currentId - } else { - chatResultStream.setMessageIdToUpdateForTool(toolUse.name!, messageIdToUpdate) - } + const messageIdToUpdate = toolUse.toolUseId! // Extract search results from the tool output const output = result.output.content as SanitizedRipgrepOutput diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatResultStream.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatResultStream.ts index 70b3452361..195e1e880b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatResultStream.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatResultStream.ts @@ -1,4 +1,4 @@ -import { ChatResult, FileDetails, ChatMessage } from '@aws/language-server-runtimes/protocol' +import { ChatResult, ChatMessage } from '@aws/language-server-runtimes/protocol' import { randomUUID } from 'crypto' export interface ResultStreamWriter { @@ -32,33 +32,20 @@ export interface ResultStreamWriter { close(): Promise } +export const progressPrefix = 'progress_' + /** * This class wraps around lsp.sendProgress to provide a more helpful interface for streaming a ChatResult to the client. * ChatResults are grouped into blocks that can be written directly, or streamed in. * In the final message, blocks are seperated by resultDelimiter defined below. */ - -interface FileDetailsWithPath extends FileDetails { - relativeFilePath: string -} - -type OperationType = 'read' | 'write' | 'listDir' - -export const progressPrefix = 'progress_' - -interface FileOperation { - type: OperationType - filePaths: FileDetailsWithPath[] -} export class AgenticChatResultStream { - static readonly resultDelimiter = '\n\n' + static readonly resultDelimiter = '\n' #state = { chatResultBlocks: [] as ChatMessage[], isLocked: false, uuid: randomUUID(), messageId: undefined as string | undefined, - messageIdToUpdateForTool: new Map(), - messageOperations: new Map(), } readonly #sendProgress: (newChatResult: ChatResult | string) => Promise @@ -70,33 +57,6 @@ export class AgenticChatResultStream { return this.#joinResults(this.#state.chatResultBlocks, only) } - setMessageIdToUpdateForTool(toolName: string, messageId: string) { - this.#state.messageIdToUpdateForTool.set(toolName as OperationType, messageId) - } - - getMessageIdToUpdateForTool(toolName: string): string | undefined { - return this.#state.messageIdToUpdateForTool.get(toolName as OperationType) - } - - /** - * Adds a file operation for a specific message - * @param messageId The ID of the message - * @param type The type of operation ('fsRead' or 'listDirectory' or 'fsWrite') - * @param filePaths Array of FileDetailsWithPath involved in the operation - */ - addMessageOperation(messageId: string, type: string, filePaths: FileDetailsWithPath[]) { - this.#state.messageOperations.set(messageId, { type: type as OperationType, filePaths }) - } - - /** - * Gets the file operation details for a specific message - * @param messageId The ID of the message - * @returns The file operation details or undefined if not found - */ - getMessageOperation(messageId: string): FileOperation | undefined { - return this.#state.messageOperations.get(messageId) - } - #joinResults(chatResults: ChatMessage[], only?: string): ChatResult { const result: ChatResult = { body: '', @@ -111,9 +71,9 @@ export class AgenticChatResultStream { return { ...acc, buttons: [...(acc.buttons ?? []), ...(c.buttons ?? [])], - body: acc.body + AgenticChatResultStream.resultDelimiter + c.body, - ...(c.contextList && { contextList: c.contextList }), - header: Object.prototype.hasOwnProperty.call(c, 'header') ? c.header : acc.header, + body: acc.body + (c.body ? AgenticChatResultStream.resultDelimiter + c.body : ''), + ...(c.contextList && c.type !== 'tool' && { contextList: c.contextList }), + header: c.header !== undefined ? c.header : acc.header, codeReference: [...(acc.codeReference ?? []), ...(c.codeReference ?? [])], } } else if (acc.additionalMessages!.some(am => am.messageId === c.messageId)) { @@ -127,9 +87,10 @@ export class AgenticChatResultStream { : am.buttons, body: am.messageId === c.messageId - ? am.body + AgenticChatResultStream.resultDelimiter + c.body + ? am.body + (c.body ? AgenticChatResultStream.resultDelimiter + c.body : '') : am.body, ...(am.messageId === c.messageId && + c.type !== 'tool' && (c.contextList || acc.contextList) && { contextList: { filePaths: [ @@ -161,7 +122,7 @@ export class AgenticChatResultStream { }, }, }), - header: Object.prototype.hasOwnProperty.call(c, 'header') ? c.header : am.header, + ...(am.messageId === c.messageId && c.header !== undefined && { header: c.header }), })), } } else { @@ -246,6 +207,10 @@ export class AgenticChatResultStream { return undefined } + getLastMessage(): ChatMessage { + return this.#state.chatResultBlocks[this.#state.chatResultBlocks.length - 1] + } + getResultStreamWriter(): ResultStreamWriter { // Note: if write calls are not awaited, stream can be out-of-order. if (this.#state.isLocked) { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/fileSearch.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/fileSearch.ts index fb6486996e..37d11afe4f 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/fileSearch.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/fileSearch.ts @@ -158,3 +158,7 @@ export class FileSearch { } as const } } + +export function isFileSearchParams(input: any): input is FileSearchParams { + return input && typeof input.path === 'string' && typeof input.queryName === 'string' +} From 8975f10e3e709da20f164397604a54df83202f8b Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Thu, 14 Aug 2025 12:09:38 -0700 Subject: [PATCH 005/158] refactor: improve generateCompletion logging format (#2125) --- .../src/shared/codeWhispererService.ts | 72 ++++++++++--------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index 01101d68a8..030f7f7ee4 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -422,58 +422,60 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { async generateSuggestions(request: GenerateSuggestionsRequest): Promise { // add cancellation check // add error check - if (this.customizationArn) request.customizationArn = this.customizationArn - const beforeApiCall = performance.now() - let recentEditsLogStr = '' - const recentEdits = request.supplementalContexts?.filter(it => it.type === 'PreviousEditorState') - if (recentEdits) { - if (recentEdits.length === 0) { - recentEditsLogStr += `No recent edits` - } else { - recentEditsLogStr += '\n' - for (let i = 0; i < recentEdits.length; i++) { - const e = recentEdits[i] - recentEditsLogStr += `[recentEdits ${i}th]:\n` - recentEditsLogStr += `${e.content}\n` + let logstr = `GenerateCompletion activity:\n` + try { + if (this.customizationArn) request.customizationArn = this.customizationArn + const beforeApiCall = performance.now() + let recentEditsLogStr = '' + const recentEdits = request.supplementalContexts?.filter(it => it.type === 'PreviousEditorState') + if (recentEdits) { + if (recentEdits.length === 0) { + recentEditsLogStr += `No recent edits` + } else { + recentEditsLogStr += '\n' + for (let i = 0; i < recentEdits.length; i++) { + const e = recentEdits[i] + recentEditsLogStr += `[recentEdits ${i}th]:\n` + recentEditsLogStr += `${e.content}\n` + } } } - } - this.logging.info( - `GenerateCompletion request: + logstr += `@@request metadata@@ "endpoint": ${this.codeWhispererEndpoint}, "predictionType": ${request.predictionTypes?.toString() ?? 'Not specified (COMPLETIONS)'}, "filename": ${request.fileContext.filename}, "language": ${request.fileContext.programmingLanguage.languageName}, "supplementalContextCount": ${request.supplementalContexts?.length ?? 0}, "request.nextToken": ${request.nextToken}, - "recentEdits": ${recentEditsLogStr}` - ) + "recentEdits": ${recentEditsLogStr}\n` - const response = await this.client.generateCompletions(this.withProfileArn(request)).promise() + const response = await this.client.generateCompletions(this.withProfileArn(request)).promise() - const responseContext = { - requestId: response?.$response?.requestId, - codewhispererSessionId: response?.$response?.httpResponse?.headers['x-amzn-sessionid'], - nextToken: response.nextToken, - } + const responseContext = { + requestId: response?.$response?.requestId, + codewhispererSessionId: response?.$response?.httpResponse?.headers['x-amzn-sessionid'], + nextToken: response.nextToken, + } - const r = this.mapCodeWhispererApiResponseToSuggestion(response, responseContext) - const firstSuggestionLogstr = r.suggestions.length > 0 ? `\n${r.suggestions[0].content}` : 'No suggestion' + const r = this.mapCodeWhispererApiResponseToSuggestion(response, responseContext) + const firstSuggestionLogstr = r.suggestions.length > 0 ? `\n${r.suggestions[0].content}` : 'No suggestion' - this.logging.info( - `GenerateCompletion response: - "endpoint": ${this.codeWhispererEndpoint}, + logstr += `@@response metadata@@ "requestId": ${responseContext.requestId}, "sessionId": ${responseContext.codewhispererSessionId}, - "responseCompletionCount": ${response.completions?.length ?? 0}, - "responsePredictionCount": ${response.predictions?.length ?? 0}, - "predictionType": ${request.predictionTypes?.toString() ?? ''}, + "response.completions.length": ${response.completions?.length ?? 0}, + "response.predictions.length": ${response.predictions?.length ?? 0}, "latency": ${performance.now() - beforeApiCall}, - "filename": ${request.fileContext.filename}, "response.nextToken": ${response.nextToken}, "firstSuggestion": ${firstSuggestionLogstr}` - ) - return r + + return r + } catch (e) { + logstr += `error: ${(e as Error).message}` + throw e + } finally { + this.logging.info(logstr) + } } private mapCodeWhispererApiResponseToSuggestion( From 0e23e2d29b8cad14403d372b9bbb08ca8ffa7ac7 Mon Sep 17 00:00:00 2001 From: BlakeLazarine Date: Thu, 14 Aug 2025 12:36:43 -0700 Subject: [PATCH 006/158] fix(amazonq): handle case where multiple rules are provided with the same name (#2118) * fix(amazonq): handle case where multiple rules are provided with the same name * fix(amazonq): add unit test for duplicate custom guidelines * fix(amazonq): add unit test for processToolUses * fix(amazonq): set context type for AmazonQ.md to rule * fix(amazonq): add README.md back as rule context type --------- Co-authored-by: Blake Lazarine --- .../agenticChat/agenticChatController.test.ts | 86 ++++++++++++++++++- .../agenticChat/agenticChatController.ts | 25 ++++-- .../tools/qCodeAnalysis/codeReview.test.ts | 28 ++++++ .../tools/qCodeAnalysis/codeReview.ts | 5 ++ 4 files changed, 134 insertions(+), 10 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts index 616848d0b5..a307ce3fc6 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts @@ -241,7 +241,7 @@ describe('AgenticChatController', () => { testFeatures.agent = { runTool: sinon.stub().resolves({}), getTools: sinon.stub().returns( - ['mock-tool-name', 'mock-tool-name-1', 'mock-tool-name-2'].map(toolName => ({ + ['mock-tool-name', 'mock-tool-name-1', 'mock-tool-name-2', 'codeReview'].map(toolName => ({ toolSpecification: { name: toolName, description: 'Mock tool for testing' }, })) ), @@ -3283,6 +3283,90 @@ ${' '.repeat(8)}} assert.strictEqual(returnValue, undefined) }) }) + + describe('processToolUses', () => { + it('filters rule artifacts from additionalContext for CodeReview tool', async () => { + const mockAdditionalContext = [ + { + type: 'file', + description: '', + name: '', + relativePath: '', + startLine: 0, + endLine: 0, + path: '/test/file.js', + }, + { + type: 'rule', + description: '', + name: '', + relativePath: '', + startLine: 0, + endLine: 0, + path: '/test/rule1.json', + }, + { + type: 'rule', + description: '', + name: '', + relativePath: '', + startLine: 0, + endLine: 0, + path: '/test/rule2.json', + }, + ] + + const toolUse = { + toolUseId: 'test-id', + name: 'codeReview', + input: { fileLevelArtifacts: [{ path: '/test/file.js' }] }, + stop: true, + } + + const runToolStub = testFeatures.agent.runTool as sinon.SinonStub + runToolStub.resolves({}) + + // Create a mock session with toolUseLookup + const mockSession = { + toolUseLookup: new Map(), + pairProgrammingMode: true, + } as any + + // Create a minimal mock of AgenticChatResultStream + const mockChatResultStream = { + removeResultBlockAndUpdateUI: sinon.stub().resolves(), + writeResultBlock: sinon.stub().resolves(1), + overwriteResultBlock: sinon.stub().resolves(), + removeResultBlock: sinon.stub().resolves(), + getMessageBlockId: sinon.stub().returns(undefined), + hasMessage: sinon.stub().returns(false), + updateOngoingProgressResult: sinon.stub().resolves(), + getResult: sinon.stub().returns({ messageId: 'test', body: '' }), + setMessageIdToUpdateForTool: sinon.stub(), + getMessageIdToUpdateForTool: sinon.stub().returns(undefined), + addMessageOperation: sinon.stub(), + getMessageOperation: sinon.stub().returns(undefined), + } + + // Call processToolUses directly + await chatController.processToolUses( + [toolUse], + mockChatResultStream as any, + mockSession, + 'tabId', + mockCancellationToken, + mockAdditionalContext + ) + + // Verify runTool was called with ruleArtifacts + sinon.assert.calledOnce(runToolStub) + const toolInput = runToolStub.firstCall.args[1] + assert.ok(toolInput.ruleArtifacts) + assert.strictEqual(toolInput.ruleArtifacts.length, 2) + assert.strictEqual(toolInput.ruleArtifacts[0].path, '/test/rule1.json') + assert.strictEqual(toolInput.ruleArtifacts[1].path, '/test/rule2.json') + }) + }) }) // The body may include text-based progress updates from tool invocations. diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 09bf965819..991d95a6ad 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -1387,7 +1387,14 @@ export class AgenticChatController implements ChatHandlers { session.setConversationType('AgenticChatWithToolUse') if (result.success) { // Process tool uses and update the request input for the next iteration - toolResults = await this.#processToolUses(pendingToolUses, chatResultStream, session, tabId, token) + toolResults = await this.processToolUses( + pendingToolUses, + chatResultStream, + session, + tabId, + token, + additionalContext + ) if (toolResults.some(toolResult => this.#shouldSendBackErrorContent(toolResult))) { content = 'There was an error processing one or more tool uses. Try again, do not apologize.' shouldDisplayMessage = false @@ -1662,12 +1669,13 @@ export class AgenticChatController implements ChatHandlers { /** * Processes tool uses by running the tools and collecting results */ - async #processToolUses( + async processToolUses( toolUses: Array, chatResultStream: AgenticChatResultStream, session: ChatSessionService, tabId: string, - token?: CancellationToken + token?: CancellationToken, + additionalContext?: AdditionalContentEntryAddition[] ): Promise { const results: ToolResult[] = [] @@ -1868,12 +1876,11 @@ export class AgenticChatController implements ChatHandlers { if (toolUse.name === CodeReview.toolName) { try { let initialInput = JSON.parse(JSON.stringify(toolUse.input)) - let ruleArtifacts = await this.#additionalContextProvider.collectWorkspaceRules(tabId) - if (ruleArtifacts !== undefined || ruleArtifacts !== null) { - this.#features.logging.info(`RuleArtifacts: ${JSON.stringify(ruleArtifacts)}`) - let pathsToRulesMap = ruleArtifacts.map(ruleArtifact => ({ path: ruleArtifact.id })) - this.#features.logging.info(`PathsToRules: ${JSON.stringify(pathsToRulesMap)}`) - initialInput['ruleArtifacts'] = pathsToRulesMap + + if (additionalContext !== undefined) { + initialInput['ruleArtifacts'] = additionalContext + .filter(c => c.type === 'rule') + .map(c => ({ path: c.path })) } toolUse.input = initialInput } catch (e) { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts index c587253bbc..3509cd1730 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts @@ -385,6 +385,34 @@ describe('CodeReview', () => { expect(error.message).to.include('There are no valid files to scan') } }) + + it('should handle duplicate rule filenames with unique UUIDs', async () => { + const fileArtifacts = [{ path: '/test/file.js' }] + const folderArtifacts: any[] = [] + const ruleArtifacts = [{ path: '/test/path1/rule.json' }, { path: '/test/path2/rule.json' }] + + const mockZip = { + file: sandbox.stub(), + generateAsync: sandbox.stub().resolves(Buffer.from('test')), + } + sandbox.stub(JSZip.prototype, 'file').callsFake(mockZip.file) + sandbox.stub(JSZip.prototype, 'generateAsync').callsFake(mockZip.generateAsync) + sandbox.stub(CodeReviewUtils, 'countZipFiles').returns(3) + sandbox.stub(require('crypto'), 'randomUUID').returns('test-uuid-123') + + await (codeReview as any).prepareFilesAndFoldersForUpload( + fileArtifacts, + folderArtifacts, + ruleArtifacts, + false + ) + + // Verify first file uses original name + expect(mockZip.file.firstCall.args[0]).to.include('/test/file.js') + expect(mockZip.file.secondCall.args[0]).to.include('rule.json') + // Verify second file gets UUID suffix + expect(mockZip.file.thirdCall.args[0]).to.include('rule_test-uuid-123.json') + }) }) describe('collectFindings', () => { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts index adcea2ec33..b1ef4c3e61 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts @@ -716,6 +716,7 @@ export class CodeReview { * @param customerCodeZip JSZip instance for the customer code */ private async processRuleArtifacts(ruleArtifacts: RuleArtifacts, customerCodeZip: JSZip): Promise { + let ruleNameSet = new Set() for (const artifact of ruleArtifacts) { await CodeReviewUtils.withErrorHandling( async () => { @@ -725,6 +726,10 @@ export class CodeReview { !CodeReviewUtils.shouldSkipFile(fileName) && existsSync(artifact.path) ) { + if (ruleNameSet.has(fileName)) { + fileName = fileName.split('.')[0] + '_' + crypto.randomUUID() + '.' + fileName.split('.')[1] + } + ruleNameSet.add(fileName) const fileContent = await this.workspace.fs.readFile(artifact.path) customerCodeZip.file( `${CodeReview.CUSTOMER_CODE_BASE_PATH}/${CodeReview.RULE_ARTIFACT_PATH}/${fileName}`, From 963b6e9b7887da23a85a826c55a6ed95ff36d956 Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Thu, 14 Aug 2025 14:15:39 -0700 Subject: [PATCH 007/158] perf: remove edit completion retry mechanism on document change (#2124) --- .../inline-completion/codeWhispererServer.ts | 4 +- .../inline-completion/constants.ts | 1 - .../editCompletionHandler.ts | 85 ++++++++----------- .../session/sessionManager.ts | 12 ++- 4 files changed, 48 insertions(+), 54 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts index c1f2b464b2..46a3241978 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts @@ -633,7 +633,9 @@ export const CodewhispererServerFactory = } if (session.state !== 'ACTIVE') { - logging.log(`ERROR: Trying to record trigger decision for not-active session ${sessionId}`) + logging.log( + `ERROR: Trying to record trigger decision for not-active session ${sessionId} with wrong state ${session.state}` + ) return } diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/constants.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/constants.ts index c5810924b6..8cab372053 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/constants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/constants.ts @@ -3,7 +3,6 @@ export const FILENAME_CHARS_LIMIT = 1024 export const CONTEXT_CHARACTERS_LIMIT = 10240 export const EMPTY_RESULT = { sessionId: '', items: [] } export const EDIT_DEBOUNCE_INTERVAL_MS = 500 -export const EDIT_STALE_RETRY_COUNT = 3 // ABAP ADT extensions commonly used with Eclipse export const ABAP_EXTENSIONS = new Set([ 'asprog', diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts index 3c72e368f4..28e29ee271 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts @@ -16,7 +16,6 @@ import { GenerateSuggestionsRequest, GenerateSuggestionsResponse, getFileContext, - SuggestionType, } from '../../shared/codeWhispererService' import { CodeWhispererSession, SessionManager } from './session/sessionManager' import { CursorTracker } from './tracker/cursorTracker' @@ -36,7 +35,7 @@ import { RejectedEditTracker } from './tracker/rejectedEditTracker' import { getErrorMessage, hasConnectionExpired } from '../../shared/utils' import { AmazonQError, AmazonQServiceConnectionExpiredError } from '../../shared/amazonQServiceManager/errors' import { DocumentChangedListener } from './documentChangedListener' -import { EMPTY_RESULT, EDIT_DEBOUNCE_INTERVAL_MS, EDIT_STALE_RETRY_COUNT } from './constants' +import { EMPTY_RESULT, EDIT_DEBOUNCE_INTERVAL_MS } from './constants' export class EditCompletionHandler { private readonly editsEnabled: boolean @@ -74,12 +73,12 @@ export class EditCompletionHandler { */ documentChanged() { if (this.debounceTimeout) { - this.logging.info('[NEP] refresh timeout') - this.debounceTimeout.refresh() - } - - if (this.isWaiting) { - this.hasDocumentChangedSinceInvocation = true + if (this.isWaiting) { + this.hasDocumentChangedSinceInvocation = true + } else { + this.logging.info(`refresh and debounce edits suggestion for another ${EDIT_DEBOUNCE_INTERVAL_MS}`) + this.debounceTimeout.refresh() + } } } @@ -87,9 +86,6 @@ export class EditCompletionHandler { params: InlineCompletionWithReferencesParams, token: CancellationToken ): Promise { - this.hasDocumentChangedSinceInvocation = false - this.debounceTimeout = undefined - // On every new completion request close current inflight session. const currentSession = this.sessionManager.getCurrentSession() if (currentSession && currentSession.state == 'REQUESTING' && !params.partialResultToken) { @@ -156,46 +152,37 @@ export class EditCompletionHandler { } } - // TODO: telemetry, discarded suggestions - // The other easy way to do this is simply not return any suggestion (which is used when retry > 3) - const invokeWithRetry = async (attempt: number = 0): Promise => { - return new Promise(async resolve => { - this.debounceTimeout = setTimeout(async () => { - try { - this.isWaiting = true - const result = await this._invoke( - params, - token, - textDocument, - inferredLanguageId, - currentSession - ).finally(() => { - this.isWaiting = false + return new Promise(async resolve => { + this.debounceTimeout = setTimeout(async () => { + try { + this.isWaiting = true + const result = await this._invoke( + params, + token, + textDocument, + inferredLanguageId, + currentSession + ).finally(() => { + this.isWaiting = false + }) + if (this.hasDocumentChangedSinceInvocation) { + this.logging.info( + 'EditCompletionHandler - Document changed during execution, resolving empty result' + ) + resolve({ + sessionId: SessionManager.getInstance('EDITS').getActiveSession()?.id ?? '', + items: [], }) - if (this.hasDocumentChangedSinceInvocation) { - if (attempt < EDIT_STALE_RETRY_COUNT) { - this.logging.info( - `EditCompletionHandler - Document changed during execution, retrying (attempt ${attempt + 1})` - ) - this.hasDocumentChangedSinceInvocation = false - const retryResult = await invokeWithRetry(attempt + 1) - resolve(retryResult) - } else { - this.logging.info('EditCompletionHandler - Max retries reached, returning empty result') - resolve(EMPTY_RESULT) - } - } else { - this.logging.info('EditCompletionHandler - No document changes, resolving result') - resolve(result) - } - } finally { - this.debounceTimeout = undefined + } else { + this.logging.info('EditCompletionHandler - No document changes, resolving result') + resolve(result) } - }, EDIT_DEBOUNCE_INTERVAL_MS) - }) - } - - return invokeWithRetry() + } finally { + this.debounceTimeout = undefined + this.hasDocumentChangedSinceInvocation = false + } + }, EDIT_DEBOUNCE_INTERVAL_MS) + }) } async _invoke( diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts index cb873a2920..a0ddf742f6 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts @@ -14,7 +14,6 @@ import { } from '../../../shared/codeWhispererService' import { CodewhispererLanguage } from '../../../shared/languageDetection' import { CodeWhispererSupplementalContext } from '../../../shared/models/model' -import { Logging } from '@aws/language-server-runtimes/server-interface' type SessionState = 'REQUESTING' | 'ACTIVE' | 'CLOSED' | 'ERROR' | 'DISCARD' export type UserDecision = 'Empty' | 'Filter' | 'Discard' | 'Accept' | 'Ignore' | 'Reject' | 'Unseen' @@ -45,7 +44,13 @@ export class CodeWhispererSession { startTime: number // Time when Session was closed and final state of user decisions is recorded in suggestionsStates closeTime?: number = 0 - state: SessionState + private _state: SessionState + get state(): SessionState { + return this._state + } + private set state(newState: SessionState) { + this._state = newState + } codewhispererSessionId?: string startPosition: Position = { line: 0, @@ -96,7 +101,8 @@ export class CodeWhispererSession { this.classifierThreshold = data.classifierThreshold this.customizationArn = data.customizationArn this.supplementalMetadata = data.supplementalMetadata - this.state = 'REQUESTING' + this._state = 'REQUESTING' + this.startTime = new Date().getTime() } From 0bf825ec41e0593766e34e4c1b21f063931e03d1 Mon Sep 17 00:00:00 2001 From: Richard Li <742829+rli@users.noreply.github.com> Date: Thu, 14 Aug 2025 14:18:35 -0700 Subject: [PATCH 008/158] ci: remove need for custom PAT for release branch workflow (#2126) The token from GitHub Actions is sufficient --- .../workflows/create-release-candidate-branch.yml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/workflows/create-release-candidate-branch.yml b/.github/workflows/create-release-candidate-branch.yml index 2071f69ed4..b447f11803 100644 --- a/.github/workflows/create-release-candidate-branch.yml +++ b/.github/workflows/create-release-candidate-branch.yml @@ -28,14 +28,15 @@ jobs: setupRcBranch: name: Set up a Release Candidate Branch runs-on: ubuntu-latest + permissions: + contents: write steps: - name: Sync code uses: actions/checkout@v4 with: ref: ${{ inputs.commitId }} - # Use RELEASE_CANDIDATE_BRANCH_CREATION_PAT to ensure workflow triggering works - token: ${{ secrets.RELEASE_CANDIDATE_BRANCH_CREATION_PAT }} + token: ${{ secrets.GITHUB_TOKEN }} persist-credentials: true - name: Setup Node.js @@ -109,15 +110,8 @@ jobs: env: BRANCH_NAME: ${{ steps.release-branch.outputs.BRANCH_NAME }} RELEASE_VERSION: ${{ steps.release-version.outputs.RELEASE_VERSION }} - # We use the toolkit-automation account, basically something that - # isn't the default GitHub Token, because you cannot chain actions with that. - # In our case, after pushing a commit (below), we want create-agent-standalone.yml - # to start automatically. - REPO_PAT: ${{ secrets.RELEASE_CANDIDATE_BRANCH_CREATION_PAT }} run: | git config --global user.email "<>" git config --global user.name "aws-toolkit-automation" - # Configure git to use the PAT token for authentication - git remote set-url origin "https://x-access-token:${REPO_PAT}@github.com/${{ github.repository }}.git" - git commit -m "chore: bump agentic version: $RELEASE_VERSION" + git commit --no-verify -m "chore: bump agentic version: $RELEASE_VERSION" git push --set-upstream origin "$BRANCH_NAME" From 971eaa505d948e9d2090c85f9b965f554ea7f2c8 Mon Sep 17 00:00:00 2001 From: chungjac Date: Fri, 15 Aug 2025 15:55:37 -0700 Subject: [PATCH 009/158] fix: proper path handling for additional context (#2129) * fix: proper pathing for additonal context * fix: update existing tests to also mock path.join() --- .../context/additionalContextProvider.test.ts | 117 ++++++++++++++++++ .../context/additionalContextProvider.ts | 2 +- 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/additionalContextProvider.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/additionalContextProvider.test.ts index 6c745f20b3..e6742fee1b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/additionalContextProvider.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/additionalContextProvider.test.ts @@ -174,6 +174,12 @@ describe('AdditionalContextProvider', () => { workspaceFolder: mockWorkspaceFolder, } + // Mock path.join to simulate Unix behavior + sinon.stub(path, 'join').callsFake((...args) => { + // Simulate Unix path.join behavior + return args.join('/').replace(/\\/g, '/') + }) + const explicitContext = [ { id: 'explicit-file', @@ -208,6 +214,9 @@ describe('AdditionalContextProvider', () => { assert.strictEqual(result.length, 1) assert.strictEqual(result[0].name, 'Explicit File') assert.strictEqual(result[0].pinned, false) + + // Restore original path.join + ;(path.join as sinon.SinonStub).restore() }) it('should avoid duplicates between explicit and pinned context', async () => { @@ -220,6 +229,12 @@ describe('AdditionalContextProvider', () => { workspaceFolder: mockWorkspaceFolder, } + // Mock path.join to simulate Unix behavior + sinon.stub(path, 'join').callsFake((...args) => { + // Simulate Unix path.join behavior + return args.join('/').replace(/\\/g, '/') + }) + const sharedContext = { id: 'shared-file', command: 'Shared File', @@ -255,6 +270,9 @@ describe('AdditionalContextProvider', () => { assert.strictEqual(result.length, 1) assert.strictEqual(result[0].name, 'Shared File') assert.strictEqual(result[0].pinned, false) // Should be marked as explicit, not pinned + + // Restore original path.join + ;(path.join as sinon.SinonStub).restore() }) it('should handle Active File context correctly', async () => { @@ -358,6 +376,105 @@ describe('AdditionalContextProvider', () => { assert.strictEqual(triggerContext.contextInfo?.pinnedContextCount.codeContextCount, 1) assert.strictEqual(triggerContext.contextInfo?.pinnedContextCount.promptContextCount, 1) }) + + it('should handle Unix path separators correctly', async () => { + const mockWorkspaceFolder = { uri: URI.file('/workspace').toString(), name: 'test' } + sinon.stub(workspaceUtils, 'getWorkspaceFolderPaths').returns(['/workspace']) + + // Mock path.join to simulate Unix behavior + sinon.stub(path, 'join').callsFake((...args) => { + // Simulate Unix path.join behavior + return args.join('/').replace(/\\/g, '/') + }) + + const explicitContext = [ + { + id: 'unix-prompt', + command: 'Unix Prompt', + label: 'file' as any, + route: ['/Users/test/.aws/amazonq/prompts', 'hello.md'], + }, + ] + + fsExistsStub.callsFake((path: string) => path.includes('.amazonq/rules')) + fsReadDirStub.resolves([]) + + // Reset stub - return data for first call (explicit context), empty for second call (pinned context) + getContextCommandPromptStub.reset() + getContextCommandPromptStub.onFirstCall().resolves([ + { + // promptContextCommands - explicit context + name: 'Unix Prompt', + content: 'content', + filePath: '/Users/test/.aws/amazonq/prompts/hello.md', // Proper Unix path + relativePath: 'hello.md', + startLine: 1, + endLine: 10, + }, + ]) + getContextCommandPromptStub.onSecondCall().resolves([]) // pinnedContextCommands - empty + + const result = await provider.getAdditionalContext( + { workspaceFolder: mockWorkspaceFolder }, + 'tab1', + explicitContext + ) + assert.strictEqual(result.length, 1) + assert.strictEqual(result[0].name, 'Unix Prompt') + + // Restore original path.join + ;(path.join as sinon.SinonStub).restore() + }) + + it('should handle Windows path separators correctly', async () => { + const mockWorkspaceFolder = { uri: URI.file('/workspace').toString(), name: 'test' } + sinon.stub(workspaceUtils, 'getWorkspaceFolderPaths').returns(['/workspace']) + + // Mock path.join to simulate Windows behavior + const originalPathJoin = path.join + sinon.stub(path, 'join').callsFake((...args) => { + // Simulate Windows path.join behavior + return args.join('\\').replace(/\//g, '\\') + }) + + const explicitContext = [ + { + id: 'windows-prompt', + command: 'Windows Prompt', + label: 'file' as any, + route: ['C:\\Users\\test\\.aws\\amazonq\\prompts', 'hello.md'], + }, + ] + + fsExistsStub.callsFake((path: string) => path.includes('.amazonq/rules')) + fsReadDirStub.resolves([]) + + // Reset stub - return data for first call (explicit context), empty for second call (pinned context) + getContextCommandPromptStub.reset() + getContextCommandPromptStub.onFirstCall().resolves([ + { + // promptContextCommands - explicit context + name: 'Windows Prompt', + content: 'content', + filePath: 'C:\\Users\\test\\.aws\\amazonq\\prompts\\hello.md', // Proper Windows path + relativePath: 'hello.md', + startLine: 1, + endLine: 10, + }, + ]) + getContextCommandPromptStub.onSecondCall().resolves([]) // pinnedContextCommands - empty + + const result = await provider.getAdditionalContext( + { workspaceFolder: mockWorkspaceFolder }, + 'tab1', + explicitContext + ) + assert.strictEqual(result.length, 1) + assert.strictEqual(result[0].name, 'Windows Prompt') + + // Restore original path.join + ;(path.join as sinon.SinonStub).restore() + }) }) describe('getFileListFromContext', () => { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/additionalContextProvider.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/additionalContextProvider.ts index d71da1a1fe..733d1df28c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/additionalContextProvider.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/additionalContextProvider.ts @@ -406,7 +406,7 @@ export class AdditionalContextProvider { const image = imageMap.get(item.description) if (image) ordered.push(image) } else { - const doc = item.route ? docMap.get(item.route.join('/')) : undefined + const doc = item.route ? docMap.get(path.join(...item.route)) : undefined if (doc) ordered.push(doc) } } From e4e8bbb89e4b597926582bead2b14ffc43f2a7f8 Mon Sep 17 00:00:00 2001 From: Dung Dong Date: Mon, 18 Aug 2025 09:59:45 -0700 Subject: [PATCH 010/158] fix(amazonq): fix regression of mcp config in agent config (#2101) * fix(amazonq): update process-permission-updates to be the same as previous behavior * fix(chat-client): update package.json chat-client to prod * fix(amazonq): retain mcp permissions after disable/enable server * fix: dont call initOneServer on Built-in * fix: deny permission does not persist after restart IDE --------- Co-authored-by: Boyu --- .../agenticChat/tools/mcp/mcpEventHandler.ts | 71 ++++----- .../agenticChat/tools/mcp/mcpManager.ts | 137 +++++++++--------- .../agenticChat/tools/mcp/mcpUtils.ts | 56 +------ 3 files changed, 98 insertions(+), 166 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts index bf8c91b533..5b3ac84e98 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts @@ -35,6 +35,7 @@ import { ProfileStatusMonitor } from './profileStatusMonitor' interface PermissionOption { label: string value: string + description?: string } export class McpEventHandler { @@ -913,20 +914,15 @@ export class McpEventHandler { } const mcpManager = McpManager.instance - // Get the appropriate agent path const agentPath = mcpManager.getAllServerConfigs().get(serverName)?.__configPath__ - - const perm: MCPServerPermission = { - enabled: true, - toolPerms: {}, - __configPath__: agentPath, - } - // Set flag to ignore file changes during permission update this.#isProgrammaticChange = true try { + const perm = mcpManager.getMcpServerPermissions(serverName)! + perm.enabled = true + perm.__configPath__ = agentPath await mcpManager.updateServerPermission(serverName, perm) this.#emitMCPConfigEvent() } catch (error) { @@ -944,21 +940,15 @@ export class McpEventHandler { if (!serverName) { return { id: params.id } } - const mcpManager = McpManager.instance - // Get the appropriate agent path + // Set flag to ignore file changes during permission update const agentPath = mcpManager.getAllServerConfigs().get(serverName)?.__configPath__ - - const perm: MCPServerPermission = { - enabled: false, - toolPerms: {}, - __configPath__: agentPath, - } - // Set flag to ignore file changes during permission update this.#isProgrammaticChange = true - try { + const perm = mcpManager.getMcpServerPermissions(serverName)! + perm.enabled = false + perm.__configPath__ = agentPath await mcpManager.updateServerPermission(serverName, perm) this.#emitMCPConfigEvent() } catch (error) { @@ -1078,17 +1068,16 @@ export class McpEventHandler { // Add tool select options toolsWithPermissions.forEach(item => { const toolName = item.tool.toolName - const currentPermission = this.#getCurrentPermission(item.permission) // For Built-in server, use a special function that doesn't include the 'Deny' option - const permissionOptions = this.#buildPermissionOptions(item.permission) + let permissionOptions = this.#buildPermissionOptions() filterOptions.push({ type: 'select', id: `${toolName}`, title: toolName, description: item.tool.description, - placeholder: currentPermission, options: permissionOptions, + ...{ value: item.permission, boldTitle: true, mandatory: true, hideMandatoryIcon: true }, }) }) @@ -1141,20 +1130,22 @@ export class McpEventHandler { /** * Builds permission options excluding the current one */ - #buildPermissionOptions(currentPermission: string) { + #buildPermissionOptions() { const permissionOptions: PermissionOption[] = [] - if (currentPermission !== McpPermissionType.alwaysAllow) { - permissionOptions.push({ label: 'Always allow', value: McpPermissionType.alwaysAllow }) - } + permissionOptions.push({ + label: 'Ask', + value: McpPermissionType.ask, + description: 'Ask for your approval each time this tool is run', + }) - if (currentPermission !== McpPermissionType.ask) { - permissionOptions.push({ label: 'Ask', value: McpPermissionType.ask }) - } + permissionOptions.push({ + label: 'Always allow', + value: McpPermissionType.alwaysAllow, + description: 'Always allow this tool to run without asking for approval', + }) - if (currentPermission !== McpPermissionType.deny) { - permissionOptions.push({ label: 'Deny', value: McpPermissionType.deny }) - } + permissionOptions.push({ label: 'Deny', value: McpPermissionType.deny, description: 'Never run this tool' }) return permissionOptions } @@ -1203,6 +1194,7 @@ export class McpEventHandler { } const mcpServerPermission = await this.#processPermissionUpdates( + serverName, updatedPermissionConfig, serverConfig?.__configPath__ ) @@ -1400,27 +1392,20 @@ export class McpEventHandler { /** * Processes permission updates from the UI */ - async #processPermissionUpdates(updatedPermissionConfig: any, agentPath: string | undefined) { + async #processPermissionUpdates(serverName: string, updatedPermissionConfig: any, agentPath: string | undefined) { + const builtInToolAgentPath = await this.#getAgentPath() const perm: MCPServerPermission = { enabled: true, toolPerms: {}, - __configPath__: agentPath, + __configPath__: serverName === 'Built-in' ? builtInToolAgentPath : agentPath, } // Process each tool permission setting for (const [key, val] of Object.entries(updatedPermissionConfig)) { if (key === 'scope') continue - // // Get the default permission for this tool from McpManager - // let defaultPermission = McpManager.instance.getToolPerm(serverName, key) - - // // If no default permission is found, use 'alwaysAllow' for Built-in and 'ask' for MCP servers - // if (!defaultPermission) { - // defaultPermission = serverName === 'Built-in' ? 'alwaysAllow' : 'ask' - // } - - // If the value is an empty string (''), skip this tool to preserve its existing permission in the persona file - if (val === '') continue + const currentPerm = McpManager.instance.getToolPerm(serverName, key) + if (val === currentPerm) continue switch (val) { case McpPermissionType.alwaysAllow: perm.toolPerms[key] = McpPermissionType.alwaysAllow diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index 04f827ff2c..e639807929 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -178,14 +178,49 @@ export class McpManager { // Reset permissions map this.mcpServerPermissions.clear() - - // Initialize permissions for servers from agent config + // Create init state for (const [sanitizedName, _] of this.mcpServers.entries()) { - const name = this.serverNameMapping.get(sanitizedName) || sanitizedName - // Set server status to UNINITIALIZED initially this.setState(sanitizedName, McpServerStatus.UNINITIALIZED, 0) + } + // Get all servers that need to be initialized + const serversToInit: Array<[string, MCPServerConfig]> = [] + + for (const [name, cfg] of this.mcpServers.entries()) { + if (this.isServerDisabled(name)) { + this.features.logging.info(`MCP: server '${name}' is disabled by persona settings, skipping`) + this.setState(name, McpServerStatus.DISABLED, 0) + this.emitToolsChanged(name) + continue + } + serversToInit.push([name, cfg]) + } + + // Process servers in batches of 5 at a time + const MAX_CONCURRENT_SERVERS = 5 + const totalServers = serversToInit.length + + if (totalServers > 0) { + this.features.logging.info( + `MCP: initializing ${totalServers} servers with max concurrency of ${MAX_CONCURRENT_SERVERS}` + ) + + // Process servers in batches + for (let i = 0; i < totalServers; i += MAX_CONCURRENT_SERVERS) { + const batch = serversToInit.slice(i, i + MAX_CONCURRENT_SERVERS) + const batchPromises = batch.map(([name, cfg]) => this.initOneServer(name, cfg)) + + this.features.logging.debug( + `MCP: initializing batch of ${batch.length} servers (${i + 1}-${Math.min(i + MAX_CONCURRENT_SERVERS, totalServers)} of ${totalServers})` + ) + await Promise.all(batchPromises) + } + this.features.logging.info(`MCP: completed initialization of ${totalServers} servers`) + } + + for (const [sanitizedName, _] of this.mcpServers.entries()) { + const name = this.serverNameMapping.get(sanitizedName) || sanitizedName // Initialize permissions for this server const serverPrefix = `@${name}` @@ -208,9 +243,18 @@ export class McpManager { }) } else { // Only specific tools are enabled + // get allTools of this server, if it's not in tools --> it's denied + // have to move the logic after all servers finish init, because that's when we have list of tools + const deniedTools = new Set( + this.getAllTools() + .filter(tool => tool.serverName === name) + .map(tool => tool.toolName) + ) this.agentConfig.tools.forEach(tool => { if (tool.startsWith(serverPrefix + '/')) { + // remove this from deniedTools const toolName = tool.substring(serverPrefix.length + 1) + deniedTools.delete(toolName) if (toolName) { // Check if tool is in allowedTools if (this.agentConfig.allowedTools.includes(tool)) { @@ -221,6 +265,11 @@ export class McpManager { } } }) + + // update permission to deny for rest of the tools + deniedTools.forEach(tool => { + toolPerms[tool] = McpPermissionType.deny + }) } this.mcpServerPermissions.set(sanitizedName, { @@ -228,42 +277,6 @@ export class McpManager { toolPerms, }) } - - // Get all servers that need to be initialized - const serversToInit: Array<[string, MCPServerConfig]> = [] - - for (const [name, cfg] of this.mcpServers.entries()) { - if (this.isServerDisabled(name)) { - this.features.logging.info(`MCP: server '${name}' is disabled by persona settings, skipping`) - this.setState(name, McpServerStatus.DISABLED, 0) - this.emitToolsChanged(name) - continue - } - serversToInit.push([name, cfg]) - } - - // Process servers in batches of 5 at a time - const MAX_CONCURRENT_SERVERS = 5 - const totalServers = serversToInit.length - - if (totalServers > 0) { - this.features.logging.info( - `MCP: initializing ${totalServers} servers with max concurrency of ${MAX_CONCURRENT_SERVERS}` - ) - - // Process servers in batches - for (let i = 0; i < totalServers; i += MAX_CONCURRENT_SERVERS) { - const batch = serversToInit.slice(i, i + MAX_CONCURRENT_SERVERS) - const batchPromises = batch.map(([name, cfg]) => this.initOneServer(name, cfg)) - - this.features.logging.debug( - `MCP: initializing batch of ${batch.length} servers (${i + 1}-${Math.min(i + MAX_CONCURRENT_SERVERS, totalServers)} of ${totalServers})` - ) - await Promise.all(batchPromises) - } - - this.features.logging.info(`MCP: completed initialization of ${totalServers} servers`) - } } /** @@ -658,13 +671,7 @@ export class McpManager { } // Save agent config once with all changes - await saveAgentConfig( - this.features.workspace, - this.features.logging, - this.agentConfig, - agentPath, - serverName - ) + await saveAgentConfig(this.features.workspace, this.features.logging, this.agentConfig, agentPath) // Add server tools to tools list after initialization await this.initOneServer(sanitizedName, newCfg) @@ -728,13 +735,7 @@ export class McpManager { }) // Save agent config - await saveAgentConfig( - this.features.workspace, - this.features.logging, - this.agentConfig, - cfg.__configPath__, - unsanitizedName - ) + await saveAgentConfig(this.features.workspace, this.features.logging, this.agentConfig, cfg.__configPath__) // Get all config paths and delete the server from each one const wsUris = this.features.workspace.getAllWorkspaceFolders()?.map(f => f.uri) ?? [] @@ -817,13 +818,7 @@ export class McpManager { this.agentConfig.mcpServers[unsanitizedServerName] = updatedConfig // Save agent config - await saveAgentConfig( - this.features.workspace, - this.features.logging, - this.agentConfig, - agentPath, - unsanitizedServerName - ) + await saveAgentConfig(this.features.workspace, this.features.logging, this.agentConfig, agentPath) } const newCfg: MCPServerConfig = { @@ -1035,13 +1030,7 @@ export class McpManager { // Save agent config const agentPath = perm.__configPath__ if (agentPath) { - await saveAgentConfig( - this.features.workspace, - this.features.logging, - this.agentConfig, - agentPath, - unsanitizedServerName - ) + await saveAgentConfig(this.features.workspace, this.features.logging, this.agentConfig, agentPath) } // Update mcpServerPermissions map @@ -1059,7 +1048,7 @@ export class McpManager { } this.setState(serverName, McpServerStatus.DISABLED, 0) } else { - if (!this.clients.has(serverName)) { + if (!this.clients.has(serverName) && serverName !== 'Built-in') { await this.initOneServer(serverName, this.mcpServers.get(serverName)!) } } @@ -1087,6 +1076,13 @@ export class McpManager { return !this.agentConfig.allowedTools.includes(toolId) } + /** + * get server's tool permission + */ + public getMcpServerPermissions(serverName: string): MCPServerPermission | undefined { + return this.mcpServerPermissions.get(serverName) + } + /** * Returns any errors that occurred during loading of MCP configuration files */ @@ -1152,8 +1148,7 @@ export class McpManager { this.features.workspace, this.features.logging, this.agentConfig, - cfg.__configPath__, - unsanitizedName + cfg.__configPath__ ) } } catch (err) { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts index 7b212bad49..ffd2cfb4fc 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts @@ -958,61 +958,13 @@ export async function saveAgentConfig( workspace: Workspace, logging: Logger, config: AgentConfig, - configPath: string, - serverName?: string + configPath: string ): Promise { try { await workspace.fs.mkdir(path.dirname(configPath), { recursive: true }) - - if (!serverName) { - // Save the whole config - await workspace.fs.writeFile(configPath, JSON.stringify(config, null, 2)) - logging.info(`Saved agent config to ${configPath}`) - return - } - - // Read existing config if it exists, otherwise use default - let existingConfig: any - try { - const configExists = await workspace.fs.exists(configPath) - if (configExists) { - const raw = (await workspace.fs.readFile(configPath)).toString().trim() - existingConfig = raw ? JSON.parse(raw) : JSON.parse(DEFAULT_AGENT_RAW) - } else { - existingConfig = JSON.parse(DEFAULT_AGENT_RAW) - } - } catch (err) { - logging.warn(`Failed to read existing config at ${configPath}: ${err}`) - existingConfig = JSON.parse(DEFAULT_AGENT_RAW) - } - - // Update only the specific server's config - if (config.mcpServers[serverName]) { - existingConfig.mcpServers[serverName] = config.mcpServers[serverName] - } - - // Remove existing tools for this server - const serverToolPattern = `@${serverName}` - existingConfig.tools = existingConfig.tools.filter( - (tool: string) => tool !== serverToolPattern && !tool.startsWith(`${serverToolPattern}/`) - ) - existingConfig.allowedTools = existingConfig.allowedTools.filter( - (tool: string) => tool !== serverToolPattern && !tool.startsWith(`${serverToolPattern}/`) - ) - - // Add only tools for this server - const serverTools = config.tools.filter( - tool => tool === serverToolPattern || tool.startsWith(`${serverToolPattern}/`) - ) - const serverAllowedTools = config.allowedTools.filter( - tool => tool === serverToolPattern || tool.startsWith(`${serverToolPattern}/`) - ) - - existingConfig.tools.push(...serverTools) - existingConfig.allowedTools.push(...serverAllowedTools) - - await workspace.fs.writeFile(configPath, JSON.stringify(existingConfig, null, 2)) - logging.info(`Saved agent config for server ${serverName} to ${configPath}`) + // Save the whole config + await workspace.fs.writeFile(configPath, JSON.stringify(config, null, 2)) + logging.info(`Saved agent config to ${configPath}`) } catch (err: any) { logging.error(`Failed to save agent config to ${configPath}: ${err.message}`) throw err From d397161cc3448c63016e27f5ac2a1917cdaae1cb Mon Sep 17 00:00:00 2001 From: Rajanna-Karthik Date: Mon, 18 Aug 2025 10:04:18 -0700 Subject: [PATCH 011/158] feat: remove project type validation from LSP layer (#2103) * feat: remove project type validation from LSP layer * refactor: remove unused validation functions from LSP layer --- .../resources/SupportedProjects.ts | 3 + .../netTransform/tests/validation.test.ts | 120 +----------------- .../netTransform/transformHandler.ts | 12 -- .../netTransform/validation.ts | 30 +---- 4 files changed, 5 insertions(+), 160 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/resources/SupportedProjects.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/resources/SupportedProjects.ts index a3d6322a07..69881dfc89 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/resources/SupportedProjects.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/resources/SupportedProjects.ts @@ -1,3 +1,6 @@ +/** + * Reference only - validation moved to backend service. + */ export const supportedProjects = [ 'AspNetCoreMvc', 'AspNetCoreWebApi', diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/validation.test.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/validation.test.ts index a8cfcf3475..90ce3d1f7a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/validation.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/validation.test.ts @@ -1,6 +1,6 @@ import { expect } from 'chai' import { StartTransformRequest, TransformProjectMetadata } from '../models' -import { isProject, isSolution, validateProject, validateSolution } from '../validation' +import { isProject, isSolution } from '../validation' import { supportedProjects, unsupportedViewComponents } from '../resources/SupportedProjects' import mock = require('mock-fs') import { Logging } from '@aws/language-server-runtimes/server-interface' @@ -46,122 +46,4 @@ describe('Test validation functionality', () => { mockStartTransformationRequest.SelectedProjectPath = 'test.csproj' expect(isSolution(mockStartTransformationRequest)).to.equal(false) }) - - it('should return true when project is a supported type', () => { - let mockStartTransformationRequest: StartTransformRequest = sampleStartTransformRequest - const mockProjectMeta = { - Name: '', - ProjectTargetFramework: '', - ProjectPath: 'test.csproj', - SourceCodeFilePaths: [], - ProjectLanguage: '', - ProjectType: 'AspNetCoreMvc', - ExternalReferences: [], - } - mockStartTransformationRequest.ProjectMetadata.push(mockProjectMeta) - - expect(validateProject(mockStartTransformationRequest, mockedLogging)).to.equal(true) - }) - - it('should return false when project is not a supported type', () => { - let mockStartTransformationRequest: StartTransformRequest = sampleStartTransformRequest - const mockProjectMeta = { - Name: '', - ProjectTargetFramework: '', - ProjectPath: 'test.csproj', - SourceCodeFilePaths: [], - ProjectLanguage: '', - ProjectType: 'not supported', - ExternalReferences: [], - } - mockStartTransformationRequest.ProjectMetadata = [] - mockStartTransformationRequest.ProjectMetadata.push(mockProjectMeta) - - expect(validateProject(mockStartTransformationRequest, mockedLogging)).to.equal(false) - }) - - it('should return false when there is no project path that is the same as the selected project path', () => { - let mockStartTransformationRequest: StartTransformRequest = sampleStartTransformRequest - const mockProjectMeta = { - Name: '', - ProjectTargetFramework: '', - ProjectPath: 'different.csproj', - SourceCodeFilePaths: [], - ProjectLanguage: '', - ProjectType: 'AspNetCoreMvc', - ExternalReferences: [], - } - mockStartTransformationRequest.ProjectMetadata = [] - mockStartTransformationRequest.ProjectMetadata.push(mockProjectMeta) - - expect(validateProject(mockStartTransformationRequest, mockedLogging)).to.equal(false) - }) - - // New tests for AspNetWebForms validation - it('should return true when project is AspNetWebForms type', () => { - let mockStartTransformationRequest: StartTransformRequest = sampleStartTransformRequest - const mockProjectMeta = { - Name: '', - ProjectTargetFramework: '', - ProjectPath: 'test.csproj', - SourceCodeFilePaths: [], - ProjectLanguage: '', - ProjectType: 'AspNetWebForms', - ExternalReferences: [], - } - mockStartTransformationRequest.ProjectMetadata = [] - mockStartTransformationRequest.ProjectMetadata.push(mockProjectMeta) - - expect(validateProject(mockStartTransformationRequest, mockedLogging)).to.equal(true) - }) - - it('should not include AspNetWebForms in unsupported projects list', () => { - let mockStartTransformationRequest: StartTransformRequest = sampleStartTransformRequest - - // Add a supported project - const supportedProjectMeta = { - Name: 'Supported', - ProjectTargetFramework: '', - ProjectPath: 'supported.csproj', - SourceCodeFilePaths: [], - ProjectLanguage: '', - ProjectType: 'AspNetCoreMvc', - ExternalReferences: [], - } - - // Add an unsupported project - const unsupportedProjectMeta = { - Name: 'Unsupported', - ProjectTargetFramework: '', - ProjectPath: 'unsupported.csproj', - SourceCodeFilePaths: [], - ProjectLanguage: '', - ProjectType: 'UnsupportedType', - ExternalReferences: [], - } - - // Add an AspNetWebForms project - const webFormsProjectMeta = { - Name: 'WebForms', - ProjectTargetFramework: '', - ProjectPath: 'webforms.csproj', - SourceCodeFilePaths: [], - ProjectLanguage: '', - ProjectType: 'AspNetWebForms', - ExternalReferences: [], - } - - mockStartTransformationRequest.ProjectMetadata = [ - supportedProjectMeta, - unsupportedProjectMeta, - webFormsProjectMeta, - ] - - const unsupportedProjects = validateSolution(mockStartTransformationRequest) - - // Should only contain the unsupported project, not the AspNetWebForms project - expect(unsupportedProjects).to.have.lengthOf(1) - expect(unsupportedProjects[0]).to.equal('unsupported.csproj') - expect(unsupportedProjects).to.not.include('webforms.csproj') - }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/transformHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/transformHandler.ts index b0afaa06f1..b8bc80b30c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/transformHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/transformHandler.ts @@ -54,18 +54,6 @@ export class TransformHandler { isProject, this.logging ) - if (isProject) { - let isValid = validation.validateProject(userInputrequest, this.logging) - if (!isValid) { - return { - Error: 'NotSupported', - IsSupported: false, - ContainsUnsupportedViews: containsUnsupportedViews, - } as StartTransformResponse - } - } else { - unsupportedProjects = validation.validateSolution(userInputrequest) - } const artifactManager = new ArtifactManager( this.workspace, diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/validation.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/validation.ts index 0d244e09a8..efb443fb0f 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/validation.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/validation.ts @@ -6,9 +6,7 @@ import { TransformationJob } from '../../client/token/codewhispererbearertokencl import { TransformationErrorCode } from './models' /** - * TEMPORARY HACK: AspNetWebForms project type is allowed in validateProject and validateSolution - * functions without being added to the supportedProjects array. This is to enable WebForms to Blazor - * transformation without officially supporting it yet. + * Project type validation moved to backend service. */ export function isProject(userInputrequest: StartTransformRequest): boolean { @@ -19,32 +17,6 @@ export function isSolution(userInputrequest: StartTransformRequest): boolean { return userInputrequest.SelectedProjectPath.endsWith('.sln') } -export function validateProject(userInputrequest: StartTransformRequest, logging: Logging): boolean { - var selectedProject = userInputrequest.ProjectMetadata.find( - project => project.ProjectPath == userInputrequest.SelectedProjectPath - ) - - if (selectedProject) { - // Temporary hack: Allow AspNetWebForms project type without adding it to supportedProjects - var isValid = - supportedProjects.includes(selectedProject?.ProjectType) || - selectedProject?.ProjectType === 'AspNetWebForms' - logging.log( - `Selected project ${userInputrequest?.SelectedProjectPath} has project type ${selectedProject.ProjectType}` + - (isValid ? '' : ' that is not supported') - ) - return isValid - } - logging.log(`Error occured in verifying selected project with path ${userInputrequest.SelectedProjectPath}`) - return false -} - -export function validateSolution(userInputrequest: StartTransformRequest): string[] { - return userInputrequest.ProjectMetadata.filter( - project => !supportedProjects.includes(project.ProjectType) && project.ProjectType !== 'AspNetWebForms' - ).map(project => project.ProjectPath) -} - export async function checkForUnsupportedViews( userInputRequest: StartTransformRequest, isProject: boolean, From 2a4171a74c15c23c23c481060496162bcc9e6284 Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Mon, 18 Aug 2025 13:04:17 -0700 Subject: [PATCH 012/158] fix: fix for button text and remove profilearn caching (#2137) --- chat-client/src/client/mcpMynahUi.ts | 1 + .../agenticChat/tools/mcp/profileStatusMonitor.ts | 13 +++---------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/chat-client/src/client/mcpMynahUi.ts b/chat-client/src/client/mcpMynahUi.ts index 5ece955dfa..5cdae85da1 100644 --- a/chat-client/src/client/mcpMynahUi.ts +++ b/chat-client/src/client/mcpMynahUi.ts @@ -276,6 +276,7 @@ export class McpMynahUi { params.header.actions?.map(action => ({ ...action, icon: action.icon ? toMynahIcon(action.icon) : undefined, + text: undefined, })) || [], } : undefined, diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts index 4a1cc705e4..a436e152ff 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts @@ -18,7 +18,6 @@ export class ProfileStatusMonitor { private intervalId?: NodeJS.Timeout private readonly CHECK_INTERVAL = 24 * 60 * 60 * 1000 // 24 hours private codeWhispererClient?: CodeWhispererServiceToken - private cachedProfileArn?: string private static lastMcpState?: boolean constructor( @@ -85,7 +84,8 @@ export class ProfileStatusMonitor { const response = await retryUtils.retryWithBackoff(() => this.codeWhispererClient!.getProfile({ profileArn }) ) - const isMcpEnabled = response?.profile?.optInFeatures?.mcpConfiguration?.toggle === 'ON' + const mcpConfig = response?.profile?.optInFeatures?.mcpConfiguration + const isMcpEnabled = mcpConfig ? mcpConfig.toggle === 'ON' : true if (ProfileStatusMonitor.lastMcpState !== isMcpEnabled) { ProfileStatusMonitor.lastMcpState = isMcpEnabled @@ -107,16 +107,9 @@ export class ProfileStatusMonitor { } private getProfileArn(): string | undefined { - // Use cached value if available - if (this.cachedProfileArn) { - return this.cachedProfileArn - } - try { - // Get profile ARN from service manager like in agenticChatController const serviceManager = AmazonQTokenServiceManager.getInstance() - this.cachedProfileArn = serviceManager.getActiveProfileArn() - return this.cachedProfileArn + return serviceManager.getActiveProfileArn() } catch (error) { this.logging.debug(`Failed to get profile ARN: ${error}`) } From b3938c1c3ef33e9872d84782d1dd0d6dff617f44 Mon Sep 17 00:00:00 2001 From: tsmithsz <84354541+tsmithsz@users.noreply.github.com> Date: Mon, 18 Aug 2025 15:29:49 -0700 Subject: [PATCH 013/158] chore: bump runtimes to 0.2.126 (#2138) --- app/aws-lsp-antlr4-runtimes/package.json | 2 +- app/aws-lsp-buildspec-runtimes/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- app/aws-lsp-identity-runtimes/package.json | 2 +- app/aws-lsp-json-runtimes/package.json | 2 +- .../package.json | 2 +- app/aws-lsp-s3-runtimes/package.json | 2 +- app/aws-lsp-yaml-json-webworker/package.json | 2 +- app/aws-lsp-yaml-runtimes/package.json | 2 +- app/hello-world-lsp-runtimes/package.json | 2 +- chat-client/package.json | 2 +- client/vscode/package.json | 2 +- core/aws-lsp-core/package.json | 2 +- .../q-agentic-chat-server/package.json | 2 +- package-lock.json | 60 +++++++++---------- server/aws-lsp-antlr4/package.json | 2 +- server/aws-lsp-buildspec/package.json | 2 +- server/aws-lsp-cloudformation/package.json | 2 +- server/aws-lsp-codewhisperer/package.json | 2 +- server/aws-lsp-identity/package.json | 2 +- server/aws-lsp-json/package.json | 2 +- server/aws-lsp-notification/package.json | 2 +- server/aws-lsp-partiql/package.json | 2 +- server/aws-lsp-s3/package.json | 2 +- server/aws-lsp-yaml/package.json | 2 +- server/device-sso-auth-lsp/package.json | 2 +- server/hello-world-lsp/package.json | 2 +- 28 files changed, 57 insertions(+), 57 deletions(-) diff --git a/app/aws-lsp-antlr4-runtimes/package.json b/app/aws-lsp-antlr4-runtimes/package.json index 4289cec4b1..30b9b57a65 100644 --- a/app/aws-lsp-antlr4-runtimes/package.json +++ b/app/aws-lsp-antlr4-runtimes/package.json @@ -12,7 +12,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-antlr4": "*", "antlr4-c3": "^3.4.1", "antlr4ng": "^3.0.4" diff --git a/app/aws-lsp-buildspec-runtimes/package.json b/app/aws-lsp-buildspec-runtimes/package.json index 700afb3e7f..47a88b907a 100644 --- a/app/aws-lsp-buildspec-runtimes/package.json +++ b/app/aws-lsp-buildspec-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-buildspec": "^0.0.1" } } diff --git a/app/aws-lsp-cloudformation-runtimes/package.json b/app/aws-lsp-cloudformation-runtimes/package.json index 5cc04150cb..68547449cc 100644 --- a/app/aws-lsp-cloudformation-runtimes/package.json +++ b/app/aws-lsp-cloudformation-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-cloudformation": "^0.0.1" } } diff --git a/app/aws-lsp-codewhisperer-runtimes/package.json b/app/aws-lsp-codewhisperer-runtimes/package.json index fc31e64589..24e06d87ea 100644 --- a/app/aws-lsp-codewhisperer-runtimes/package.json +++ b/app/aws-lsp-codewhisperer-runtimes/package.json @@ -23,7 +23,7 @@ "local-build": "node scripts/local-build.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", diff --git a/app/aws-lsp-identity-runtimes/package.json b/app/aws-lsp-identity-runtimes/package.json index 869a30cb20..2bf37011c3 100644 --- a/app/aws-lsp-identity-runtimes/package.json +++ b/app/aws-lsp-identity-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-identity": "^0.0.1" } } diff --git a/app/aws-lsp-json-runtimes/package.json b/app/aws-lsp-json-runtimes/package.json index f63dd4e985..8a2ea3203a 100644 --- a/app/aws-lsp-json-runtimes/package.json +++ b/app/aws-lsp-json-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-json": "*" }, "devDependencies": { diff --git a/app/aws-lsp-notification-runtimes/package.json b/app/aws-lsp-notification-runtimes/package.json index faf9e4c24c..b1877ae13e 100644 --- a/app/aws-lsp-notification-runtimes/package.json +++ b/app/aws-lsp-notification-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-notification": "^0.0.1" } } diff --git a/app/aws-lsp-s3-runtimes/package.json b/app/aws-lsp-s3-runtimes/package.json index 42efa998be..a242281ff2 100644 --- a/app/aws-lsp-s3-runtimes/package.json +++ b/app/aws-lsp-s3-runtimes/package.json @@ -10,7 +10,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-s3": "^0.0.1" } } diff --git a/app/aws-lsp-yaml-json-webworker/package.json b/app/aws-lsp-yaml-json-webworker/package.json index 6190893816..8eebf1ea84 100644 --- a/app/aws-lsp-yaml-json-webworker/package.json +++ b/app/aws-lsp-yaml-json-webworker/package.json @@ -11,7 +11,7 @@ "serve:webpack": "NODE_ENV=development webpack serve" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, diff --git a/app/aws-lsp-yaml-runtimes/package.json b/app/aws-lsp-yaml-runtimes/package.json index eb76a46e38..1428ef3058 100644 --- a/app/aws-lsp-yaml-runtimes/package.json +++ b/app/aws-lsp-yaml-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-yaml": "*" }, "devDependencies": { diff --git a/app/hello-world-lsp-runtimes/package.json b/app/hello-world-lsp-runtimes/package.json index 14a3a75ff4..352bf82f88 100644 --- a/app/hello-world-lsp-runtimes/package.json +++ b/app/hello-world-lsp-runtimes/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@aws/hello-world-lsp": "^0.0.1", - "@aws/language-server-runtimes": "^0.2.125" + "@aws/language-server-runtimes": "^0.2.126" }, "devDependencies": { "@types/chai": "^4.3.5", diff --git a/chat-client/package.json b/chat-client/package.json index 2ee60a8bec..65dee12960 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/language-server-runtimes-types": "^0.1.50", "@aws/mynah-ui": "^4.36.4" }, diff --git a/client/vscode/package.json b/client/vscode/package.json index 409a4fc50d..4cb42a0752 100644 --- a/client/vscode/package.json +++ b/client/vscode/package.json @@ -352,7 +352,7 @@ "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", diff --git a/core/aws-lsp-core/package.json b/core/aws-lsp-core/package.json index 5a3d438d47..04081f13fc 100644 --- a/core/aws-lsp-core/package.json +++ b/core/aws-lsp-core/package.json @@ -28,7 +28,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", diff --git a/integration-tests/q-agentic-chat-server/package.json b/integration-tests/q-agentic-chat-server/package.json index 1e93a252dd..7415e1653e 100644 --- a/integration-tests/q-agentic-chat-server/package.json +++ b/integration-tests/q-agentic-chat-server/package.json @@ -9,7 +9,7 @@ "test-integ": "npm run compile && mocha --timeout 30000 \"./out/**/*.test.js\" --retries 2" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "*" }, "devDependencies": { diff --git a/package-lock.json b/package-lock.json index d1ac2ece1c..128ae8083d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,7 +48,7 @@ "name": "@aws/lsp-antlr4-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-antlr4": "*", "antlr4-c3": "^3.4.1", "antlr4ng": "^3.0.4" @@ -71,7 +71,7 @@ "name": "@aws/lsp-buildspec-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-buildspec": "^0.0.1" } }, @@ -79,7 +79,7 @@ "name": "@aws/lsp-cloudformation-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-cloudformation": "^0.0.1" } }, @@ -87,7 +87,7 @@ "name": "@aws/lsp-codewhisperer-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", @@ -120,7 +120,7 @@ "name": "@aws/lsp-identity-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-identity": "^0.0.1" } }, @@ -128,7 +128,7 @@ "name": "@aws/lsp-json-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-json": "*" }, "devDependencies": { @@ -148,7 +148,7 @@ "name": "@aws/lsp-notification-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-notification": "^0.0.1" } }, @@ -181,7 +181,7 @@ "name": "@aws/lsp-s3-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-s3": "^0.0.1" }, "bin": { @@ -192,7 +192,7 @@ "name": "@aws/lsp-yaml-json-webworker", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, @@ -212,7 +212,7 @@ "name": "@aws/lsp-yaml-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-yaml": "*" }, "devDependencies": { @@ -234,7 +234,7 @@ "version": "0.0.1", "dependencies": { "@aws/hello-world-lsp": "^0.0.1", - "@aws/language-server-runtimes": "^0.2.125" + "@aws/language-server-runtimes": "^0.2.126" }, "devDependencies": { "@types/chai": "^4.3.5", @@ -255,7 +255,7 @@ "license": "Apache-2.0", "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/language-server-runtimes-types": "^0.1.50", "@aws/mynah-ui": "^4.36.4" }, @@ -280,7 +280,7 @@ "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", @@ -296,7 +296,7 @@ "version": "0.0.13", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", @@ -327,7 +327,7 @@ "name": "@aws/q-agentic-chat-server-integration-tests", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "*" }, "devDependencies": { @@ -4036,9 +4036,9 @@ "link": true }, "node_modules/@aws/language-server-runtimes": { - "version": "0.2.125", - "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.2.125.tgz", - "integrity": "sha512-tjXJEagZ6rm09fcgJGu1zbFNzi0+7R1mdNFa6zCIv68c76xq5JHjc++Hne9aOgp61O6BM9uNnX3KR57v9/0E1g==", + "version": "0.2.126", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.2.126.tgz", + "integrity": "sha512-dUIKTL6+AOxdberwHLvigSJcbhFv6oUS3POhZWoNlBV9XJZRWwzNW9gkjkUsI03YTVshqMuVHT/HaoRW/hDkIA==", "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes-types": "^0.1.56", @@ -28608,7 +28608,7 @@ "version": "0.1.17", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "^0.0.13" }, "devDependencies": { @@ -28650,7 +28650,7 @@ "name": "@aws/lsp-buildspec", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", @@ -28661,7 +28661,7 @@ "name": "@aws/lsp-cloudformation", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", @@ -28683,7 +28683,7 @@ "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "^0.0.13", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", @@ -28823,7 +28823,7 @@ "dependencies": { "@aws-sdk/client-sso-oidc": "^3.616.0", "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "^0.0.12", "@smithy/node-http-handler": "^3.2.5", "@smithy/shared-ini-file-loader": "^4.0.1", @@ -28888,7 +28888,7 @@ "version": "0.1.17", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "^0.0.13", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" @@ -28905,7 +28905,7 @@ "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1" }, @@ -28966,7 +28966,7 @@ "version": "0.0.16", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "antlr4-c3": "3.4.2", "antlr4ng": "3.0.14", "web-tree-sitter": "0.22.6" @@ -28988,7 +28988,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" @@ -29019,7 +29019,7 @@ "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "^0.0.13", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", @@ -29033,7 +29033,7 @@ "name": "@amzn/device-sso-auth-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "vscode-languageserver": "^9.0.1" }, "devDependencies": { @@ -29044,7 +29044,7 @@ "name": "@aws/hello-world-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/server/aws-lsp-antlr4/package.json b/server/aws-lsp-antlr4/package.json index f540c8ae21..9ba8186aab 100644 --- a/server/aws-lsp-antlr4/package.json +++ b/server/aws-lsp-antlr4/package.json @@ -28,7 +28,7 @@ "clean": "rm -rf node_modules" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "^0.0.13" }, "peerDependencies": { diff --git a/server/aws-lsp-buildspec/package.json b/server/aws-lsp-buildspec/package.json index 2cf0b776ac..3a23338dac 100644 --- a/server/aws-lsp-buildspec/package.json +++ b/server/aws-lsp-buildspec/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-cloudformation/package.json b/server/aws-lsp-cloudformation/package.json index ad01b4457a..75223b4791 100644 --- a/server/aws-lsp-cloudformation/package.json +++ b/server/aws-lsp-cloudformation/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 8600148090..78297c702e 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -36,7 +36,7 @@ "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "^0.0.13", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", diff --git a/server/aws-lsp-identity/package.json b/server/aws-lsp-identity/package.json index acaeb6d15d..0e61d97dc8 100644 --- a/server/aws-lsp-identity/package.json +++ b/server/aws-lsp-identity/package.json @@ -26,7 +26,7 @@ "dependencies": { "@aws-sdk/client-sso-oidc": "^3.616.0", "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "^0.0.12", "@smithy/node-http-handler": "^3.2.5", "@smithy/shared-ini-file-loader": "^4.0.1", diff --git a/server/aws-lsp-json/package.json b/server/aws-lsp-json/package.json index 7b1768f995..66604360fa 100644 --- a/server/aws-lsp-json/package.json +++ b/server/aws-lsp-json/package.json @@ -26,7 +26,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "^0.0.13", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" diff --git a/server/aws-lsp-notification/package.json b/server/aws-lsp-notification/package.json index 45194be66b..f6483e3e32 100644 --- a/server/aws-lsp-notification/package.json +++ b/server/aws-lsp-notification/package.json @@ -22,7 +22,7 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1" }, diff --git a/server/aws-lsp-partiql/package.json b/server/aws-lsp-partiql/package.json index 263275dced..efc073c7e9 100644 --- a/server/aws-lsp-partiql/package.json +++ b/server/aws-lsp-partiql/package.json @@ -24,7 +24,7 @@ "out" ], "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "antlr4-c3": "3.4.2", "antlr4ng": "3.0.14", "web-tree-sitter": "0.22.6" diff --git a/server/aws-lsp-s3/package.json b/server/aws-lsp-s3/package.json index 53355ff18a..b574da9bc0 100644 --- a/server/aws-lsp-s3/package.json +++ b/server/aws-lsp-s3/package.json @@ -9,7 +9,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" diff --git a/server/aws-lsp-yaml/package.json b/server/aws-lsp-yaml/package.json index deeddd9694..e18a72ea29 100644 --- a/server/aws-lsp-yaml/package.json +++ b/server/aws-lsp-yaml/package.json @@ -26,7 +26,7 @@ "postinstall": "node patchYamlPackage.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "@aws/lsp-core": "^0.0.13", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", diff --git a/server/device-sso-auth-lsp/package.json b/server/device-sso-auth-lsp/package.json index 698bbf353e..6eba3692a9 100644 --- a/server/device-sso-auth-lsp/package.json +++ b/server/device-sso-auth-lsp/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/server/hello-world-lsp/package.json b/server/hello-world-lsp/package.json index a0ad8e8469..b221272541 100644 --- a/server/hello-world-lsp/package.json +++ b/server/hello-world-lsp/package.json @@ -13,7 +13,7 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.126", "vscode-languageserver": "^9.0.1" }, "devDependencies": { From f947e1a9da4431d6089b22825f992010c30a470b Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Tue, 19 Aug 2025 08:59:01 -0700 Subject: [PATCH 014/158] fix: fix to add disk caching for mcp admin state (#2139) * fix: fix to add disk caching for mcp admin state * fix: fix to add logging * fix: fix to initialize mcpManager in any case and discover servers based on mcpState * fix: fix for unit test failure --- .../agenticChat/tools/mcp/mcpManager.ts | 18 ++++- .../tools/mcp/profileStatusMonitor.test.ts | 4 +- .../tools/mcp/profileStatusMonitor.ts | 72 ++++++++++++++++--- .../agenticChat/tools/toolServer.ts | 62 +++++++++++----- .../AmazonQTokenServiceManager.ts | 19 +++++ 5 files changed, 142 insertions(+), 33 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index e639807929..844a872485 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -37,6 +37,7 @@ import { Mutex } from 'async-mutex' import path = require('path') import { URI } from 'vscode-uri' import { sanitizeInput } from '../../../../shared/utils' +import { ProfileStatusMonitor } from './profileStatusMonitor' export const MCP_SERVER_STATUS_CHANGED = 'mcpServerStatusChanged' export const AGENT_TOOLS_CHANGED = 'agentToolsChanged' @@ -85,8 +86,15 @@ export class McpManager { if (!McpManager.#instance) { const mgr = new McpManager(agentPaths, features) McpManager.#instance = mgr - await mgr.discoverAllServers() - features.logging.info(`MCP: discovered ${mgr.mcpTools.length} tools across all servers`) + + const shouldDiscoverServers = ProfileStatusMonitor.getMcpState() + + if (shouldDiscoverServers) { + await mgr.discoverAllServers() + features.logging.info(`MCP: discovered ${mgr.mcpTools.length} tools across all servers`) + } else { + features.logging.info('MCP: initialized without server discovery') + } // Emit MCP configuration metrics const serverConfigs = mgr.getAllServerConfigs() @@ -896,7 +904,11 @@ export class McpManager { // Restore the saved tool name mapping this.setToolNameMapping(savedToolNameMapping) - await this.discoverAllServers() + const shouldDiscoverServers = ProfileStatusMonitor.getMcpState() + + if (shouldDiscoverServers) { + await this.discoverAllServers() + } const reinitializedServerCount = McpManager.#instance?.mcpServers.size this.features.logging.info( diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.test.ts index 8ee8454374..77080bf08a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.test.ts @@ -169,8 +169,8 @@ describe('ProfileStatusMonitor', () => { mockOnMcpEnabled ) - // Initially undefined - expect(ProfileStatusMonitor.getMcpState()).to.be.undefined + // Initially true (default value) + expect(ProfileStatusMonitor.getMcpState()).to.be.true // Set through internal mechanism (simulating state change) ;(ProfileStatusMonitor as any).lastMcpState = false diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts index a436e152ff..ad34550270 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts @@ -13,12 +13,22 @@ import { retryUtils } from '@aws/lsp-core' import { CodeWhispererServiceToken } from '../../../../shared/codeWhispererService' import { DEFAULT_AWS_Q_ENDPOINT_URL, DEFAULT_AWS_Q_REGION } from '../../../../shared/constants' import { AmazonQTokenServiceManager } from '../../../../shared/amazonQServiceManager/AmazonQTokenServiceManager' +import * as fs from 'fs' +import * as path from 'path' +import * as os from 'os' +import { EventEmitter } from 'events' + +export const AUTH_SUCCESS_EVENT = 'authSuccess' export class ProfileStatusMonitor { private intervalId?: NodeJS.Timeout private readonly CHECK_INTERVAL = 24 * 60 * 60 * 1000 // 24 hours private codeWhispererClient?: CodeWhispererServiceToken - private static lastMcpState?: boolean + private static lastMcpState: boolean = true + private static readonly MCP_CACHE_DIR = path.join(os.homedir(), '.aws', 'amazonq', 'mcpAdmin') + private static readonly MCP_CACHE_FILE = path.join(ProfileStatusMonitor.MCP_CACHE_DIR, 'mcp-state.json') + private static eventEmitter = new EventEmitter() + private static logging?: Logging constructor( private credentialsProvider: CredentialsProvider, @@ -27,7 +37,15 @@ export class ProfileStatusMonitor { private sdkInitializator: SDKInitializator, private onMcpDisabled: () => void, private onMcpEnabled?: () => void - ) {} + ) { + ProfileStatusMonitor.logging = logging + ProfileStatusMonitor.loadMcpStateFromDisk() + + // Listen for auth success events + ProfileStatusMonitor.eventEmitter.on(AUTH_SUCCESS_EVENT, () => { + void this.isMcpEnabled() + }) + } async checkInitialState(): Promise { try { @@ -35,8 +53,7 @@ export class ProfileStatusMonitor { return isMcpEnabled !== false // Return true if enabled or API failed } catch (error) { this.logging.debug(`Initial MCP state check failed, defaulting to enabled: ${error}`) - ProfileStatusMonitor.lastMcpState = true - return true + return ProfileStatusMonitor.getMcpState() } } @@ -65,7 +82,7 @@ export class ProfileStatusMonitor { const profileArn = this.getProfileArn() if (!profileArn) { this.logging.debug('No profile ARN available for MCP configuration check') - ProfileStatusMonitor.lastMcpState = true // Default to enabled if no profile + ProfileStatusMonitor.setMcpState(true) return true } @@ -88,7 +105,7 @@ export class ProfileStatusMonitor { const isMcpEnabled = mcpConfig ? mcpConfig.toggle === 'ON' : true if (ProfileStatusMonitor.lastMcpState !== isMcpEnabled) { - ProfileStatusMonitor.lastMcpState = isMcpEnabled + ProfileStatusMonitor.setMcpState(isMcpEnabled) if (!isMcpEnabled) { this.logging.info('MCP configuration disabled - removing tools') this.onMcpDisabled() @@ -101,8 +118,7 @@ export class ProfileStatusMonitor { return isMcpEnabled } catch (error) { this.logging.debug(`MCP configuration check failed, defaulting to enabled: ${error}`) - ProfileStatusMonitor.lastMcpState = true - return true + return ProfileStatusMonitor.getMcpState() } } @@ -116,7 +132,45 @@ export class ProfileStatusMonitor { return undefined } - static getMcpState(): boolean | undefined { + static getMcpState(): boolean { return ProfileStatusMonitor.lastMcpState } + + private static loadMcpStateFromDisk(): void { + try { + if (fs.existsSync(ProfileStatusMonitor.MCP_CACHE_FILE)) { + const data = fs.readFileSync(ProfileStatusMonitor.MCP_CACHE_FILE, 'utf8') + const parsed = JSON.parse(data) + ProfileStatusMonitor.lastMcpState = parsed.enabled ?? true + } + } catch (error) { + ProfileStatusMonitor.logging?.debug(`Failed to load MCP state from disk: ${error}`) + } + ProfileStatusMonitor.setMcpState(ProfileStatusMonitor.lastMcpState) + } + + private static saveMcpStateToDisk(): void { + try { + fs.mkdirSync(ProfileStatusMonitor.MCP_CACHE_DIR, { recursive: true }) + fs.writeFileSync( + ProfileStatusMonitor.MCP_CACHE_FILE, + JSON.stringify({ enabled: ProfileStatusMonitor.lastMcpState }) + ) + } catch (error) { + ProfileStatusMonitor.logging?.debug(`Failed to save MCP state to disk: ${error}`) + } + } + + private static setMcpState(enabled: boolean): void { + ProfileStatusMonitor.lastMcpState = enabled + ProfileStatusMonitor.saveMcpStateToDisk() + } + + static resetMcpState(): void { + ProfileStatusMonitor.setMcpState(true) + } + + static emitAuthSuccess(): void { + ProfileStatusMonitor.eventEmitter.emit(AUTH_SUCCESS_EVENT) + } } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts index fd692e6e8e..78871faa69 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts @@ -227,7 +227,16 @@ export const McpToolsServer: Server = ({ } registered[server] = [] } - void McpManager.instance.close(true) //keep the instance but close all servers. + + // Only close McpManager if it has been initialized + try { + if (McpManager.instance) { + void McpManager.instance.close(true) //keep the instance but close all servers. + } + } catch (error) { + // McpManager not initialized, skip closing + logging.debug('McpManager not initialized, skipping close operation') + } try { chat?.sendChatUpdate({ @@ -255,11 +264,19 @@ export const McpToolsServer: Server = ({ // Sanitize the tool name // Check if this tool name is already in use + let toolNameMapping = new Map() + try { + toolNameMapping = McpManager.instance.getToolNameMapping() + } catch (error) { + // McpManager not initialized, use empty mapping + logging.debug('McpManager not initialized, using empty tool name mapping') + } + const namespaced = createNamespacedToolName( def.serverName, def.toolName, allNamespacedTools, - McpManager.instance.getToolNameMapping() + toolNameMapping ) const tool = new McpTool({ logging, workspace, lsp }, def) @@ -315,17 +332,20 @@ export const McpToolsServer: Server = ({ McpManager.instance.clearToolNameMapping() - const byServer: Record = {} - for (const d of mgr.getEnabledTools()) { - ;(byServer[d.serverName] ||= []).push(d) - } - for (const [server, defs] of Object.entries(byServer)) { - registerServerTools(server, defs) - } + // Only register tools if MCP is enabled + if (ProfileStatusMonitor.getMcpState()) { + const byServer: Record = {} + for (const d of mgr.getEnabledTools()) { + ;(byServer[d.serverName] ||= []).push(d) + } + for (const [server, defs] of Object.entries(byServer)) { + registerServerTools(server, defs) + } - mgr.events.on(AGENT_TOOLS_CHANGED, (server: string, defs: McpToolDefinition[]) => { - registerServerTools(server, defs) - }) + mgr.events.on(AGENT_TOOLS_CHANGED, (server: string, defs: McpToolDefinition[]) => { + registerServerTools(server, defs) + }) + } } catch (e) { logging.error(`Failed to initialize MCP:' ${e}`) } @@ -353,11 +373,15 @@ export const McpToolsServer: Server = ({ // Wait for profile ARN to be available before checking MCP state const checkAndInitialize = async () => { - const shouldInitialize = await profileStatusMonitor!.checkInitialState() - if (shouldInitialize) { - logging.info('MCP enabled, initializing immediately') - await initializeMcp() + await profileStatusMonitor!.checkInitialState() + // Always initialize McpManager to handle UI requests + await initializeMcp() + + // Remove tools if MCP is disabled + if (!ProfileStatusMonitor.getMcpState()) { + removeAllMcpTools() } + profileStatusMonitor!.start() } @@ -375,7 +399,7 @@ export const McpToolsServer: Server = ({ } else if (Date.now() - startTime < SERVICE_MANAGER_TIMEOUT_MS) { setTimeout(pollForReady, SERVICE_MANAGER_POLL_INTERVAL_MS) } else { - logging.warn('Service manager not ready after 10s, defaulting MCP to enabled') + logging.warn('Service manager not ready after 10s, initializing MCP manager') await initializeMcp() profileStatusMonitor!.start() } @@ -383,8 +407,8 @@ export const McpToolsServer: Server = ({ setTimeout(pollForReady, SERVICE_MANAGER_POLL_INTERVAL_MS) } } catch (error) { - // Service manager not initialized yet, default to enabled - logging.info('Service manager not ready, defaulting MCP to enabled') + // Service manager not initialized yet, always initialize McpManager + logging.info('Service manager not ready, initializing MCP manager') await initializeMcp() profileStatusMonitor!.start() } diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts index 8db60a69ab..5a919c9192 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts @@ -33,6 +33,7 @@ import { getAmazonQRegionAndEndpoint } from './configurationUtils' import { getUserAgent } from '../telemetryUtils' import { StreamingClientServiceToken } from '../streamingClientService' import { parse } from '@aws-sdk/util-arn-parser' +import { ProfileStatusMonitor } from '../../language-server/agenticChat/tools/mcp/profileStatusMonitor' /** * AmazonQTokenServiceManager manages state and provides centralized access to @@ -152,6 +153,9 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< this.resetCodewhispererService() this.connectionType = 'none' this.state = 'PENDING_CONNECTION' + + // Reset MCP state cache when auth changes + ProfileStatusMonitor.resetMcpState() } public async handleOnUpdateConfiguration(params: UpdateConfigurationParams, _token: CancellationToken) { @@ -245,6 +249,9 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< this.state = 'INITIALIZED' this.log('Initialized Amazon Q service with builderId connection') + // Emit auth success event + ProfileStatusMonitor.emitAuthSuccess() + return } @@ -267,6 +274,9 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< this.state = 'INITIALIZED' this.log('Initialized Amazon Q service with identityCenter connection') + // Emit auth success event + ProfileStatusMonitor.emitAuthSuccess() + return } @@ -375,6 +385,9 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< `Initialized identityCenter connection to region ${newProfile.identityDetails.region} for profile ${newProfile.arn}` ) + // Emit auth success event + ProfileStatusMonitor.emitAuthSuccess() + return } @@ -385,6 +398,9 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< this.activeIdcProfile = newProfile this.state = 'INITIALIZED' + // Emit auth success event + ProfileStatusMonitor.emitAuthSuccess() + return } @@ -428,6 +444,9 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< ) this.state = 'INITIALIZED' + // Emit auth success event + ProfileStatusMonitor.emitAuthSuccess() + return } From 43bc9b1120e52f206a4178d0125572aaaccf3c8b Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Tue, 19 Aug 2025 09:44:39 -0700 Subject: [PATCH 015/158] refactor: cleanup old nep code path which is no longered being used in codewhispererServer.ts (#2141) --- .../inline-completion/codeWhispererServer.ts | 124 +++++++----------- 1 file changed, 44 insertions(+), 80 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts index 46a3241978..988bdd418f 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts @@ -468,93 +468,57 @@ export const CodewhispererServerFactory = return false }) - if (suggestionResponse.suggestionType === SuggestionType.COMPLETION) { - const { includeImportsWithSuggestions } = amazonQServiceManager.getConfiguration() - const suggestionsWithRightContext = mergeSuggestionsWithRightContext( - session.requestContext.fileContext.rightFileContent, - filteredSuggestions, - includeImportsWithSuggestions, - selectionRange - ).filter(suggestion => { - // Discard suggestions that have empty string insertText after right context merge and can't be displayed anymore - if (suggestion.insertText === '') { - session.setSuggestionState(suggestion.itemId, 'Discard') - return false - } - - return true - }) - - suggestionsWithRightContext.forEach(suggestion => { - const cachedSuggestion = session.suggestions.find(s => s.itemId === suggestion.itemId) - if (cachedSuggestion) cachedSuggestion.insertText = suggestion.insertText.toString() - }) + const { includeImportsWithSuggestions } = amazonQServiceManager.getConfiguration() + const suggestionsWithRightContext = mergeSuggestionsWithRightContext( + session.requestContext.fileContext.rightFileContent, + filteredSuggestions, + includeImportsWithSuggestions, + selectionRange + ).filter(suggestion => { + // Discard suggestions that have empty string insertText after right context merge and can't be displayed anymore + if (suggestion.insertText === '') { + session.setSuggestionState(suggestion.itemId, 'Discard') + return false + } - // TODO: need dedupe after right context merging but I don't see one - session.suggestionsAfterRightContextMerge.push(...suggestionsWithRightContext) + return true + }) - session.codewhispererSuggestionImportCount = - session.codewhispererSuggestionImportCount + - suggestionsWithRightContext.reduce((total, suggestion) => { - return total + (suggestion.mostRelevantMissingImports?.length || 0) - }, 0) + suggestionsWithRightContext.forEach(suggestion => { + const cachedSuggestion = session.suggestions.find(s => s.itemId === suggestion.itemId) + if (cachedSuggestion) cachedSuggestion.insertText = suggestion.insertText.toString() + }) - // If after all server-side filtering no suggestions can be displayed, and there is no nextToken - // close session and return empty results - if ( - session.suggestionsAfterRightContextMerge.length === 0 && - !suggestionResponse.responseContext.nextToken - ) { - completionSessionManager.closeSession(session) - await emitUserTriggerDecisionTelemetry( - telemetry, - telemetryService, - session, - timeSinceLastUserModification - ) + // TODO: need dedupe after right context merging but I don't see one + session.suggestionsAfterRightContextMerge.push(...suggestionsWithRightContext) - return EMPTY_RESULT - } + session.codewhispererSuggestionImportCount = + session.codewhispererSuggestionImportCount + + suggestionsWithRightContext.reduce((total, suggestion) => { + return total + (suggestion.mostRelevantMissingImports?.length || 0) + }, 0) - return { - items: suggestionsWithRightContext, - sessionId: session.id, - partialResultToken: suggestionResponse.responseContext.nextToken, - } - } else { - return { - items: suggestionResponse.suggestions - .map(suggestion => { - // Check if this suggestion is similar to a previously rejected edit - const isSimilarToRejected = rejectedEditTracker.isSimilarToRejected( - suggestion.content, - textDocument?.uri || '' - ) + // If after all server-side filtering no suggestions can be displayed, and there is no nextToken + // close session and return empty results + if ( + session.suggestionsAfterRightContextMerge.length === 0 && + !suggestionResponse.responseContext.nextToken + ) { + completionSessionManager.closeSession(session) + await emitUserTriggerDecisionTelemetry( + telemetry, + telemetryService, + session, + timeSinceLastUserModification + ) - if (isSimilarToRejected) { - // Mark as rejected in the session - session.setSuggestionState(suggestion.itemId, 'Reject') - logging.debug( - `[EDIT_PREDICTION] Filtered out suggestion similar to previously rejected edit` - ) - // Return empty item that will be filtered out - return { - insertText: '', - isInlineEdit: true, - itemId: suggestion.itemId, - } - } + return EMPTY_RESULT + } - return { - insertText: suggestion.content, - isInlineEdit: true, - itemId: suggestion.itemId, - } - }) - .filter(item => item.insertText !== ''), - sessionId: session.id, - partialResultToken: suggestionResponse.responseContext.nextToken, - } + return { + items: suggestionsWithRightContext, + sessionId: session.id, + partialResultToken: suggestionResponse.responseContext.nextToken, } } From 5e4435dfaea7bf8c00e6a27b9bb0d40f699d4e01 Mon Sep 17 00:00:00 2001 From: Jiatong Li Date: Tue, 19 Aug 2025 12:12:39 -0700 Subject: [PATCH 016/158] fix(amazonq): add server side control for WCS features (#2128) Co-authored-by: Jiatong Li --- .../workspaceContext/IdleWorkspaceManager.ts | 6 +- .../workspaceContextServer.ts | 3 +- .../workspaceFolderManager.test.ts | 90 +++++++++++++++++++ .../workspaceFolderManager.ts | 47 ++++++++-- 4 files changed, 139 insertions(+), 7 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/IdleWorkspaceManager.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/IdleWorkspaceManager.ts index 5a8359ccac..1e27a7f762 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/IdleWorkspaceManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/IdleWorkspaceManager.ts @@ -2,7 +2,7 @@ import { WorkspaceFolderManager } from './workspaceFolderManager' export class IdleWorkspaceManager { private static readonly idleThreshold = 30 * 60 * 1000 // 30 minutes - private static lastActivityTimestamp = 0 // treat session as idle as the start + private static lastActivityTimestamp = 0 // treat session as idle at the start private constructor() {} @@ -30,6 +30,10 @@ export class IdleWorkspaceManager { } } + public static setSessionAsIdle(): void { + IdleWorkspaceManager.lastActivityTimestamp = 0 + } + public static isSessionIdle(): boolean { const currentTime = Date.now() const timeSinceLastActivity = currentTime - IdleWorkspaceManager.lastActivityTimestamp diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts index c536c1087d..3d638e337a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts @@ -221,6 +221,7 @@ export const WorkspaceContextServer = (): Server => features => { isLoggedInUsingBearerToken(credentialsProvider) && abTestingEnabled && !workspaceFolderManager.getOptOutStatus() && + !workspaceFolderManager.isFeatureDisabled() && workspaceIdentifier ) } @@ -302,7 +303,7 @@ export const WorkspaceContextServer = (): Server => features => { await evaluateABTesting() isWorkflowInitialized = true - workspaceFolderManager.resetAdminOptOutStatus() + workspaceFolderManager.resetAdminOptOutAndFeatureDisabledStatus() if (!isUserEligibleForWorkspaceContext()) { return } diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts index 7ab596a930..cbdb71db1d 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts @@ -8,6 +8,7 @@ import { ArtifactManager } from './artifactManager' import { CodeWhispererServiceToken } from '../../shared/codeWhispererService' import { ListWorkspaceMetadataResponse } from '../../client/token/codewhispererbearertokenclient' import { IdleWorkspaceManager } from './IdleWorkspaceManager' +import { AWSError } from 'aws-sdk' describe('WorkspaceFolderManager', () => { let mockServiceManager: StubbedInstance @@ -135,4 +136,93 @@ describe('WorkspaceFolderManager', () => { ) }) }) + + describe('isFeatureDisabled', () => { + it('should return true when feature is disabled', async () => { + // Setup + const workspaceFolders: WorkspaceFolder[] = [ + { + uri: 'file:///test/workspace', + name: 'test-workspace', + }, + ] + + // Mock listWorkspaceMetadata to throw AccessDeniedException with feature not supported + const mockError: AWSError = { + name: 'AccessDeniedException', + message: 'Feature is not supported', + code: 'AccessDeniedException', + time: new Date(), + retryable: false, + statusCode: 403, + } + + mockCodeWhispererService.listWorkspaceMetadata.rejects(mockError) + + // Create the WorkspaceFolderManager instance + workspaceFolderManager = WorkspaceFolderManager.createInstance( + mockServiceManager, + mockLogging, + mockArtifactManager, + mockDependencyDiscoverer, + workspaceFolders, + mockCredentialsProvider, + 'test-workspace-identifier' + ) + + // Spy on clearAllWorkspaceResources and related methods + const clearAllWorkspaceResourcesSpy = sinon.stub( + workspaceFolderManager as any, + 'clearAllWorkspaceResources' + ) + + // Act - trigger listWorkspaceMetadata which sets feature disabled state + await (workspaceFolderManager as any).listWorkspaceMetadata() + + // Assert + expect(workspaceFolderManager.isFeatureDisabled()).toBe(true) + + // Verify that clearAllWorkspaceResources was called + sinon.assert.calledOnce(clearAllWorkspaceResourcesSpy) + }) + + it('should return false when feature is not disabled', async () => { + // Setup + const workspaceFolders: WorkspaceFolder[] = [ + { + uri: 'file:///test/workspace', + name: 'test-workspace', + }, + ] + + // Mock successful response + const mockResponse: ListWorkspaceMetadataResponse = { + workspaces: [ + { + workspaceId: 'test-workspace-id', + workspaceStatus: 'RUNNING', + }, + ], + } + + mockCodeWhispererService.listWorkspaceMetadata.resolves(mockResponse as any) + + // Create the WorkspaceFolderManager instance + workspaceFolderManager = WorkspaceFolderManager.createInstance( + mockServiceManager, + mockLogging, + mockArtifactManager, + mockDependencyDiscoverer, + workspaceFolders, + mockCredentialsProvider, + 'test-workspace-identifier' + ) + + // Act - trigger listWorkspaceMetadata + await (workspaceFolderManager as any).listWorkspaceMetadata() + + // Assert + expect(workspaceFolderManager.isFeatureDisabled()).toBe(false) + }) + }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts index 99fc9c4628..1644851258 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts @@ -55,6 +55,7 @@ export class WorkspaceFolderManager { private optOutMonitorInterval: NodeJS.Timeout | undefined private messageQueueConsumerInterval: NodeJS.Timeout | undefined private isOptedOut: boolean = false + private featureDisabled: boolean = false // Serve as a server-side control. If true, stop WCS features private isCheckingRemoteWorkspaceStatus: boolean = false private isArtifactUploadedToRemoteWorkspace: boolean = false @@ -139,8 +140,13 @@ export class WorkspaceFolderManager { return this.isOptedOut } - resetAdminOptOutStatus(): void { + resetAdminOptOutAndFeatureDisabledStatus(): void { this.isOptedOut = false + this.featureDisabled = false + } + + isFeatureDisabled(): boolean { + return this.featureDisabled } getWorkspaceState(): WorkspaceState { @@ -326,6 +332,7 @@ export class WorkspaceFolderManager { // Reset workspace ID to force operations to wait for new remote workspace information this.resetRemoteWorkspaceId() + IdleWorkspaceManager.setSessionAsIdle() this.isArtifactUploadedToRemoteWorkspace = false // Set up message queue consumer @@ -371,7 +378,9 @@ export class WorkspaceFolderManager { return resolve(false) } - const { metadata, optOut } = await this.listWorkspaceMetadata(this.workspaceIdentifier) + const { metadata, optOut, featureDisabled } = await this.listWorkspaceMetadata( + this.workspaceIdentifier + ) if (optOut) { this.logging.log(`User opted out during initial connection`) @@ -381,6 +390,13 @@ export class WorkspaceFolderManager { return resolve(false) } + if (featureDisabled) { + this.logging.log(`Feature disabled during initial connection`) + this.featureDisabled = true + this.clearAllWorkspaceResources() + return resolve(false) + } + if (!metadata) { // Continue polling by exiting only this iteration return @@ -437,7 +453,9 @@ export class WorkspaceFolderManager { } this.logging.log(`Checking remote workspace status for workspace [${this.workspaceIdentifier}]`) - const { metadata, optOut, error } = await this.listWorkspaceMetadata(this.workspaceIdentifier) + const { metadata, optOut, featureDisabled, error } = await this.listWorkspaceMetadata( + this.workspaceIdentifier + ) if (optOut) { this.logging.log('User opted out, clearing all resources and starting opt-out monitor') @@ -447,6 +465,13 @@ export class WorkspaceFolderManager { return } + if (featureDisabled) { + this.logging.log('Feature disabled, clearing all resources and stoping server-side indexing features') + this.featureDisabled = true + this.clearAllWorkspaceResources() + return + } + if (error) { // Do not do anything if we received an exception but not caused by optOut return @@ -528,7 +553,14 @@ export class WorkspaceFolderManager { if (this.optOutMonitorInterval === undefined) { const intervalId = setInterval(async () => { try { - const { optOut } = await this.listWorkspaceMetadata() + const { optOut, featureDisabled } = await this.listWorkspaceMetadata() + + if (featureDisabled) { + // Stop opt-out monitor when WCS feature is disabled from server-side + this.featureDisabled = true + clearInterval(intervalId) + this.optOutMonitorInterval = undefined + } if (!optOut) { this.isOptedOut = false @@ -735,10 +767,12 @@ export class WorkspaceFolderManager { private async listWorkspaceMetadata(workspaceRoot?: WorkspaceRoot): Promise<{ metadata: WorkspaceMetadata | undefined | null optOut: boolean + featureDisabled: boolean error: any }> { let metadata: WorkspaceMetadata | undefined | null let optOut = false + let featureDisabled = false let error: any try { const params = workspaceRoot ? { workspaceRoot } : {} @@ -754,8 +788,11 @@ export class WorkspaceFolderManager { this.logging.log(`User's administrator opted out server-side workspace context`) optOut = true } + if (isAwsError(e) && e.code === 'AccessDeniedException' && e.message.includes('Feature is not supported')) { + featureDisabled = true + } } - return { metadata, optOut, error } + return { metadata, optOut, featureDisabled, error } } private async createWorkspace(workspaceRoot: WorkspaceRoot): Promise<{ From b76cd85f1f09bcbffed3e368aaf15dd537ddb3f1 Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Tue, 19 Aug 2025 13:00:37 -0700 Subject: [PATCH 017/158] chore: update STE userContext version metadata (#2142) --- .../agenticChat/qAgenticChatServer.ts | 2 +- .../src/language-server/chat/qChatServer.ts | 4 ++- .../inline-completion/codeWhispererServer.ts | 4 ++- .../workspaceContextServer.ts | 7 ++++- .../BaseAmazonQServiceManager.ts | 5 ++++ .../src/shared/telemetryUtils.test.ts | 30 +++++++++++-------- .../src/shared/telemetryUtils.ts | 13 +++++--- 7 files changed, 45 insertions(+), 20 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/qAgenticChatServer.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/qAgenticChatServer.ts index 205e5aff69..445ca78d85 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/qAgenticChatServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/qAgenticChatServer.ts @@ -110,7 +110,7 @@ export const QAgenticChatServer = ) ) - const userContext = makeUserContextObject(clientParams, runtime.platform, 'CHAT') + const userContext = makeUserContextObject(clientParams, runtime.platform, 'CHAT', amazonQServiceManager.serverInfo) telemetryService.updateUserContext(userContext) chatController = new AgenticChatController( diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/qChatServer.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/qChatServer.ts index 2452426b1b..d110ea4e41 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/qChatServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/qChatServer.ts @@ -59,7 +59,9 @@ export const QChatServerFactory = 'TelemetryService initialized before LSP connection was initialized.' ) ) - telemetryService.updateUserContext(makeUserContextObject(clientParams, runtime.platform, 'CHAT')) + telemetryService.updateUserContext( + makeUserContextObject(clientParams, runtime.platform, 'CHAT', amazonQServiceManager.serverInfo) + ) chatController = new ChatController( chatSessionManagementService, diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts index 988bdd418f..33113fa318 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts @@ -723,7 +723,9 @@ export const CodewhispererServerFactory = ?.inlineCompletionWithReferences?.inlineEditSupport ?? false telemetryService = new TelemetryService(amazonQServiceManager, credentialsProvider, telemetry, logging) - telemetryService.updateUserContext(makeUserContextObject(clientParams, runtime.platform, 'INLINE')) + telemetryService.updateUserContext( + makeUserContextObject(clientParams, runtime.platform, 'INLINE', amazonQServiceManager.serverInfo) + ) codePercentageTracker = new CodePercentageTracker(telemetryService) codeDiffTracker = new CodeDiffTracker( diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts index 3d638e337a..92dc0823e3 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts @@ -188,7 +188,12 @@ export const WorkspaceContextServer = (): Server => features => { abTestingEnabled = true } else { const clientParams = safeGet(lsp.getClientInitializeParams()) - const userContext = makeUserContextObject(clientParams, runtime.platform, 'CodeWhisperer') ?? { + const userContext = makeUserContextObject( + clientParams, + runtime.platform, + 'CodeWhisperer', + amazonQServiceManager.serverInfo + ) ?? { ideCategory: 'VSCODE', operatingSystem: 'MAC', product: 'CodeWhisperer', diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts index 9c241809a7..cc21cd8766 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts @@ -17,6 +17,7 @@ import { } from './configurationUtils' import { AmazonQServiceInitializationError } from './errors' import { StreamingClientServiceBase } from '../streamingClientService' +import { UserContext } from '../../client/token/codewhispererbearertokenclient' export interface QServiceManagerFeatures { lsp: Lsp @@ -86,6 +87,10 @@ export abstract class BaseAmazonQServiceManager< abstract getCodewhispererService(): C abstract getStreamingClient(): S + get serverInfo() { + return this.features.runtime.serverInfo + } + public getConfiguration(): Readonly { return this.configurationCache.getConfig() } diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.test.ts b/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.test.ts index 565a9505a4..0cfa7fd768 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.test.ts @@ -1,6 +1,6 @@ import * as assert from 'assert' import * as sinon from 'sinon' -import { InitializeParams, Platform } from '@aws/language-server-runtimes/server-interface' +import { InitializeParams, Platform, ServerInfo } from '@aws/language-server-runtimes/server-interface' import { getUserAgent, makeUserContextObject } from './telemetryUtils' describe('getUserAgent', () => { @@ -115,6 +115,7 @@ describe('getUserAgent', () => { describe('makeUserContextObject', () => { let mockInitializeParams: InitializeParams + let mockServerInfo: ServerInfo // let osStub: sinon.SinonStubbedInstance<{ now: () => number }> beforeEach(() => { @@ -123,10 +124,10 @@ describe('makeUserContextObject', () => { aws: { clientInfo: { name: 'test-custom-client-name', - version: '1.2.3', + version: '1.0.0', extension: { name: 'AmazonQ-For-VSCode', - version: '2.2.2', + version: '2.0.0', }, clientId: 'test-client-id', }, @@ -138,6 +139,11 @@ describe('makeUserContextObject', () => { }, } as InitializeParams + mockServerInfo = { + name: 'foo', + version: '3.0.0', + } + sinon.stub(process, 'platform').value('win32') }) @@ -146,33 +152,33 @@ describe('makeUserContextObject', () => { }) it('should return a valid UserContext object', () => { - const result = makeUserContextObject(mockInitializeParams, 'win32', 'TestProduct') + const result = makeUserContextObject(mockInitializeParams, 'win32', 'TestProduct', mockServerInfo) assert(result) assert.ok('ideCategory' in result) assert.ok('operatingSystem' in result) assert.strictEqual(result.operatingSystem, 'WINDOWS') assert.strictEqual(result.product, 'TestProduct') assert.strictEqual(result.clientId, 'test-client-id') - assert.strictEqual(result.ideVersion, '1.2.3') + assert.strictEqual(result.ideVersion, 'ide=1.0.0;plugin=2.0.0;lsp=3.0.0') }) it('should prefer initializationOptions.aws version over clientInfo version', () => { - const result = makeUserContextObject(mockInitializeParams, 'linux', 'TestProduct') - assert.strictEqual(result?.ideVersion, '1.2.3') + const result = makeUserContextObject(mockInitializeParams, 'linux', 'TestProduct', mockServerInfo) + assert.strictEqual(result?.ideVersion, 'ide=1.0.0;plugin=2.0.0;lsp=3.0.0') }) it('should use clientInfo version if initializationOptions.aws version is not available', () => { // @ts-ignore mockInitializeParams.initializationOptions.aws.clientInfo.version = undefined - const result = makeUserContextObject(mockInitializeParams, 'linux', 'TestProduct') - assert.strictEqual(result?.ideVersion, '1.1.1') + const result = makeUserContextObject(mockInitializeParams, 'linux', 'TestProduct', mockServerInfo) + assert.strictEqual(result?.ideVersion, 'ide=1.1.1;plugin=2.0.0;lsp=3.0.0') }) it('should return undefined if ideCategory is not in IDE_CATEGORY_MAP', () => { // @ts-ignore mockInitializeParams.initializationOptions.aws.clientInfo.extension.name = 'Unknown IDE' - const result = makeUserContextObject(mockInitializeParams, 'linux', 'TestProduct') + const result = makeUserContextObject(mockInitializeParams, 'linux', 'TestProduct', mockServerInfo) assert.strictEqual(result, undefined) }) @@ -188,7 +194,7 @@ describe('makeUserContextObject', () => { // @ts-ignore mockInitializeParams.initializationOptions.aws.clientInfo.extension.name = clientName - const result = makeUserContextObject(mockInitializeParams, 'linux', 'TestProduct') + const result = makeUserContextObject(mockInitializeParams, 'linux', 'TestProduct', mockServerInfo) switch (clientName) { case 'AmazonQ-For-VSCode': assert.strictEqual(result?.ideCategory, 'VSCODE') @@ -222,7 +228,7 @@ describe('makeUserContextObject', () => { ] platforms.forEach(platform => { - const result = makeUserContextObject(mockInitializeParams, platform, 'TestProduct') + const result = makeUserContextObject(mockInitializeParams, platform, 'TestProduct', mockServerInfo) switch (platform) { case 'win32': assert.strictEqual(result?.operatingSystem, 'WINDOWS') diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.ts b/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.ts index 73e94d4233..49020a8822 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.ts @@ -89,15 +89,20 @@ const getOperatingSystem = (platform: Platform) => { export const makeUserContextObject = ( initializeParams: InitializeParams, platform: Platform, - product: string + product: string, + serverInfo: ServerInfo ): UserContext | undefined => { + const ide = getIdeCategory(initializeParams) + const ideVersion = + initializeParams.initializationOptions?.aws?.clientInfo?.version || initializeParams.clientInfo?.version + const pluginVersion = initializeParams.initializationOptions?.aws?.clientInfo?.extension?.version || '' + const lspVersion = serverInfo.version ?? '' const userContext: UserContext = { - ideCategory: getIdeCategory(initializeParams), + ideCategory: ide, operatingSystem: getOperatingSystem(platform), product: product, clientId: initializeParams.initializationOptions?.aws?.clientInfo?.clientId, - ideVersion: - initializeParams.initializationOptions?.aws?.clientInfo?.version || initializeParams.clientInfo?.version, + ideVersion: `ide=${ideVersion};plugin=${pluginVersion};lsp=${lspVersion}`, } if (userContext.ideCategory === 'UNKNOWN' || userContext.operatingSystem === 'UNKNOWN') { From 04588dfc33f0d85dbd488814a474b5e354398df0 Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Tue, 19 Aug 2025 13:12:00 -0700 Subject: [PATCH 018/158] fix: fix to turn on and off MCP servers incase of error based on last state (#2143) Co-authored-by: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> --- .../agenticChat/tools/mcp/profileStatusMonitor.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts index ad34550270..53a4da9090 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts @@ -118,7 +118,13 @@ export class ProfileStatusMonitor { return isMcpEnabled } catch (error) { this.logging.debug(`MCP configuration check failed, defaulting to enabled: ${error}`) - return ProfileStatusMonitor.getMcpState() + const mcpState = ProfileStatusMonitor.getMcpState() + if (!mcpState) { + this.onMcpDisabled() + } else if (this.onMcpEnabled) { + this.onMcpEnabled() + } + return mcpState } } From b8e52682ac2b2337e1d0a32759e8beccde889cee Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Tue, 19 Aug 2025 14:57:14 -0700 Subject: [PATCH 019/158] fix: empty userTriggerDecision not being sent for NEP code path (#2140) * refactor: clean up old NEP code path which is no longer used * fix: empty userTriggerDecision not being sent for NEP code path * test: disable telemetry test temporarily * fix: patch * revert: a * revert: a --- .../editCompletionHandler.ts | 41 +++++-------------- .../inline-completion/telemetry.ts | 30 ++++++++++++++ 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts index 28e29ee271..005b5ab3f0 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts @@ -23,12 +23,12 @@ import { CodewhispererLanguage, getSupportedLanguageId } from '../../shared/lang import { WorkspaceFolderManager } from '../workspaceContext/workspaceFolderManager' import { shouldTriggerEdits } from './trigger' import { + emitEmptyUserTriggerDecisionTelemetry, emitServiceInvocationFailure, emitServiceInvocationTelemetry, emitUserTriggerDecisionTelemetry, } from './telemetry' import { TelemetryService } from '../../shared/telemetry/telemetryService' -import { mergeEditSuggestionsWithFileContext } from './mergeRightUtils' import { textUtils } from '@aws/lsp-core' import { AmazonQBaseServiceManager } from '../../shared/amazonQServiceManager/BaseAmazonQServiceManager' import { RejectedEditTracker } from './tracker/rejectedEditTracker' @@ -353,35 +353,16 @@ export class EditCompletionHandler { this.sessionManager.activateSession(session) // Process suggestions to apply Empty or Filter filters - const filteredSuggestions = suggestionResponse.suggestions - // Empty suggestion filter - .filter(suggestion => { - if (suggestion.content === '') { - session.setSuggestionState(suggestion.itemId, 'Empty') - return false - } - - return true - }) - // References setting filter - .filter(suggestion => { - // State to track whether code with references should be included in - // the response. No locking or concurrency controls, filtering is done - // right before returning and is only guaranteed to be consistent within - // the context of a single response. - const { includeSuggestionsWithCodeReferences } = this.amazonQServiceManager.getConfiguration() - if (includeSuggestionsWithCodeReferences) { - return true - } - - if (suggestion.references == null || suggestion.references.length === 0) { - return true - } - - // Filter out suggestions that have references when includeSuggestionsWithCodeReferences setting is true - session.setSuggestionState(suggestion.itemId, 'Filter') - return false - }) + if (suggestionResponse.suggestions.length === 0) { + this.sessionManager.closeSession(session) + await emitEmptyUserTriggerDecisionTelemetry( + this.telemetryService, + session, + this.documentChangedListener.timeSinceLastUserModification, + this.editsEnabled ? this.sessionManager.getAndUpdateStreakLength(false) : 0 + ) + return EMPTY_RESULT + } return { items: suggestionResponse.suggestions diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts index d53d141a2b..73e3a526a4 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts @@ -106,6 +106,36 @@ export const emitPerceivedLatencyTelemetry = (telemetry: Telemetry, session: Cod }) } +export async function emitEmptyUserTriggerDecisionTelemetry( + telemetryService: TelemetryService, + session: CodeWhispererSession, + timeSinceLastUserModification?: number, + streakLength?: number +) { + // Prevent reporting user decision if it was already sent + if (session.reportedUserDecision) { + return + } + + // Non-blocking + emitAggregatedUserTriggerDecisionTelemetry( + telemetryService, + session, + 'Empty', + timeSinceLastUserModification, + 0, + 0, + [], + [], + streakLength + ) + .then() + .catch(e => {}) + .finally(() => { + session.reportedUserDecision = true + }) +} + export const emitUserTriggerDecisionTelemetry = async ( telemetry: Telemetry, telemetryService: TelemetryService, From c5468cbe6a594d16b7619a6ed37676f9f1045c19 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 20 Aug 2025 13:03:46 -0700 Subject: [PATCH 020/158] chore(release): release packages from branch main (#2117) --- .release-please-manifest.json | 14 ++++----- chat-client/CHANGELOG.md | 14 +++++++++ chat-client/package.json | 2 +- core/aws-lsp-core/CHANGELOG.md | 12 ++++++++ core/aws-lsp-core/package.json | 2 +- package-lock.json | 22 +++++++------- server/aws-lsp-antlr4/CHANGELOG.md | 14 +++++++++ server/aws-lsp-antlr4/package.json | 4 +-- server/aws-lsp-codewhisperer/CHANGELOG.md | 35 +++++++++++++++++++++++ server/aws-lsp-codewhisperer/package.json | 4 +-- server/aws-lsp-json/CHANGELOG.md | 14 +++++++++ server/aws-lsp-json/package.json | 4 +-- server/aws-lsp-partiql/CHANGELOG.md | 7 +++++ server/aws-lsp-partiql/package.json | 2 +- server/aws-lsp-yaml/CHANGELOG.md | 14 +++++++++ server/aws-lsp-yaml/package.json | 4 +-- 16 files changed, 139 insertions(+), 29 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e6abdf7be2..159795a30e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,9 +1,9 @@ { - "chat-client": "0.1.32", - "core/aws-lsp-core": "0.0.13", - "server/aws-lsp-antlr4": "0.1.17", - "server/aws-lsp-codewhisperer": "0.0.73", - "server/aws-lsp-json": "0.1.17", - "server/aws-lsp-partiql": "0.0.16", - "server/aws-lsp-yaml": "0.1.17" + "chat-client": "0.1.33", + "core/aws-lsp-core": "0.0.14", + "server/aws-lsp-antlr4": "0.1.18", + "server/aws-lsp-codewhisperer": "0.0.74", + "server/aws-lsp-json": "0.1.18", + "server/aws-lsp-partiql": "0.0.17", + "server/aws-lsp-yaml": "0.1.18" } diff --git a/chat-client/CHANGELOG.md b/chat-client/CHANGELOG.md index 1cd9acfbe0..995ddc8ae6 100644 --- a/chat-client/CHANGELOG.md +++ b/chat-client/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [0.1.33](https://github.com/aws/language-servers/compare/chat-client/v0.1.32...chat-client/v0.1.33) (2025-08-19) + + +### Features + +* **amazonq:** added mcp admin level configuration with GetProfile ([#2000](https://github.com/aws/language-servers/issues/2000)) ([fd6e9a8](https://github.com/aws/language-servers/commit/fd6e9a829c6229c276de5340dffce52b426a864d)) +* **amazonq:** read tool ui revamp ([#2113](https://github.com/aws/language-servers/issues/2113)) ([#2121](https://github.com/aws/language-servers/issues/2121)) ([93cf229](https://github.com/aws/language-servers/commit/93cf229149ba60491f9f5763793db4a9f570b611)) + + +### Bug Fixes + +* fix for button text and remove profilearn caching ([#2137](https://github.com/aws/language-servers/issues/2137)) ([2a4171a](https://github.com/aws/language-servers/commit/2a4171a74c15c23c23c481060496162bcc9e6284)) +* Use file context override in the inline completion params for Jupyter Notebook ([#2114](https://github.com/aws/language-servers/issues/2114)) ([91c8398](https://github.com/aws/language-servers/commit/91c839857f8aa4d79098189f9fb620b361c51289)) + ## [0.1.32](https://github.com/aws/language-servers/compare/chat-client/v0.1.31...chat-client/v0.1.32) (2025-08-11) diff --git a/chat-client/package.json b/chat-client/package.json index 65dee12960..1af265fdfe 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -1,6 +1,6 @@ { "name": "@aws/chat-client", - "version": "0.1.32", + "version": "0.1.33", "description": "AWS Chat Client", "main": "out/index.js", "repository": { diff --git a/core/aws-lsp-core/CHANGELOG.md b/core/aws-lsp-core/CHANGELOG.md index 9e2e616f55..0e1e63dd38 100644 --- a/core/aws-lsp-core/CHANGELOG.md +++ b/core/aws-lsp-core/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [0.0.14](https://github.com/aws/language-servers/compare/lsp-core/v0.0.13...lsp-core/v0.0.14) (2025-08-19) + + +### Features + +* **amazonq:** added mcp admin level configuration with GetProfile ([#2000](https://github.com/aws/language-servers/issues/2000)) ([fd6e9a8](https://github.com/aws/language-servers/commit/fd6e9a829c6229c276de5340dffce52b426a864d)) + + +### Bug Fixes + +* Use file context override in the inline completion params for Jupyter Notebook ([#2114](https://github.com/aws/language-servers/issues/2114)) ([91c8398](https://github.com/aws/language-servers/commit/91c839857f8aa4d79098189f9fb620b361c51289)) + ## [0.0.13](https://github.com/aws/language-servers/compare/lsp-core/v0.0.12...lsp-core/v0.0.13) (2025-08-04) diff --git a/core/aws-lsp-core/package.json b/core/aws-lsp-core/package.json index 04081f13fc..4ecdd4e238 100644 --- a/core/aws-lsp-core/package.json +++ b/core/aws-lsp-core/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-core", - "version": "0.0.13", + "version": "0.0.14", "description": "Core library, contains common code and utilities", "main": "out/index.js", "repository": { diff --git a/package-lock.json b/package-lock.json index 128ae8083d..97b89d43b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -251,7 +251,7 @@ }, "chat-client": { "name": "@aws/chat-client", - "version": "0.1.32", + "version": "0.1.33", "license": "Apache-2.0", "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", @@ -293,7 +293,7 @@ }, "core/aws-lsp-core": { "name": "@aws/lsp-core", - "version": "0.0.13", + "version": "0.0.14", "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes": "^0.2.126", @@ -28605,11 +28605,11 @@ }, "server/aws-lsp-antlr4": { "name": "@aws/lsp-antlr4", - "version": "0.1.17", + "version": "0.1.18", "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes": "^0.2.126", - "@aws/lsp-core": "^0.0.13" + "@aws/lsp-core": "^0.0.14" }, "devDependencies": { "@babel/plugin-transform-modules-commonjs": "^7.24.1", @@ -28670,7 +28670,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.73", + "version": "0.0.74", "bundleDependencies": [ "@amzn/codewhisperer-streaming", "@amzn/amazon-q-developer-streaming-client" @@ -28684,7 +28684,7 @@ "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", "@aws/language-server-runtimes": "^0.2.126", - "@aws/lsp-core": "^0.0.13", + "@aws/lsp-core": "^0.0.14", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", "adm-zip": "^0.5.10", @@ -28885,11 +28885,11 @@ }, "server/aws-lsp-json": { "name": "@aws/lsp-json", - "version": "0.1.17", + "version": "0.1.18", "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes": "^0.2.126", - "@aws/lsp-core": "^0.0.13", + "@aws/lsp-core": "^0.0.14", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" }, @@ -28963,7 +28963,7 @@ }, "server/aws-lsp-partiql": { "name": "@aws/lsp-partiql", - "version": "0.0.16", + "version": "0.0.17", "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes": "^0.2.126", @@ -29015,12 +29015,12 @@ }, "server/aws-lsp-yaml": { "name": "@aws/lsp-yaml", - "version": "0.1.17", + "version": "0.1.18", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes": "^0.2.126", - "@aws/lsp-core": "^0.0.13", + "@aws/lsp-core": "^0.0.14", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", "yaml-language-server": "1.13.0" diff --git a/server/aws-lsp-antlr4/CHANGELOG.md b/server/aws-lsp-antlr4/CHANGELOG.md index bde43f2c3c..e1458575e1 100644 --- a/server/aws-lsp-antlr4/CHANGELOG.md +++ b/server/aws-lsp-antlr4/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [0.1.18](https://github.com/aws/language-servers/compare/lsp-antlr4/v0.1.17...lsp-antlr4/v0.1.18) (2025-08-19) + + +### Bug Fixes + +* Use file context override in the inline completion params for Jupyter Notebook ([#2114](https://github.com/aws/language-servers/issues/2114)) ([91c8398](https://github.com/aws/language-servers/commit/91c839857f8aa4d79098189f9fb620b361c51289)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @aws/lsp-core bumped from ^0.0.13 to ^0.0.14 + ## [0.1.17](https://github.com/aws/language-servers/compare/lsp-antlr4/v0.1.16...lsp-antlr4/v0.1.17) (2025-08-04) diff --git a/server/aws-lsp-antlr4/package.json b/server/aws-lsp-antlr4/package.json index 9ba8186aab..b61239d633 100644 --- a/server/aws-lsp-antlr4/package.json +++ b/server/aws-lsp-antlr4/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-antlr4", - "version": "0.1.17", + "version": "0.1.18", "description": "ANTLR4 language server", "main": "out/index.js", "repository": { @@ -29,7 +29,7 @@ }, "dependencies": { "@aws/language-server-runtimes": "^0.2.126", - "@aws/lsp-core": "^0.0.13" + "@aws/lsp-core": "^0.0.14" }, "peerDependencies": { "antlr4-c3": ">=3.4 < 4", diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index 1b2f1011df..048eaee59c 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,40 @@ # Changelog +## [0.0.74](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.73...lsp-codewhisperer/v0.0.74) (2025-08-19) + + +### Features + +* **amazonq:** added mcp admin level configuration with GetProfile ([#2000](https://github.com/aws/language-servers/issues/2000)) ([fd6e9a8](https://github.com/aws/language-servers/commit/fd6e9a829c6229c276de5340dffce52b426a864d)) +* **amazonq:** read tool ui revamp ([#2113](https://github.com/aws/language-servers/issues/2113)) ([#2121](https://github.com/aws/language-servers/issues/2121)) ([93cf229](https://github.com/aws/language-servers/commit/93cf229149ba60491f9f5763793db4a9f570b611)) +* remove project type validation from LSP layer ([#2103](https://github.com/aws/language-servers/issues/2103)) ([d397161](https://github.com/aws/language-servers/commit/d397161cc3448c63016e27f5ac2a1917cdaae1cb)) + + +### Bug Fixes + +* **amazonq:** add server side control for WCS features ([#2128](https://github.com/aws/language-servers/issues/2128)) ([5e4435d](https://github.com/aws/language-servers/commit/5e4435dfaea7bf8c00e6a27b9bb0d40f699d4e01)) +* **amazonq:** fix regression of mcp config in agent config ([#2101](https://github.com/aws/language-servers/issues/2101)) ([e4e8bbb](https://github.com/aws/language-servers/commit/e4e8bbb89e4b597926582bead2b14ffc43f2a7f8)) +* **amazonq:** handle case where multiple rules are provided with the same name ([#2118](https://github.com/aws/language-servers/issues/2118)) ([0e23e2d](https://github.com/aws/language-servers/commit/0e23e2d29b8cad14403d372b9bbb08ca8ffa7ac7)) +* **amazonq:** persist mcp configs in agent json on start-up ([#2112](https://github.com/aws/language-servers/issues/2112)) ([817cfe2](https://github.com/aws/language-servers/commit/817cfe2656cb1deec6111c699c4ba46b4ba53e00)) +* empty userTriggerDecision not being sent for NEP code path ([#2140](https://github.com/aws/language-servers/issues/2140)) ([b8e5268](https://github.com/aws/language-servers/commit/b8e52682ac2b2337e1d0a32759e8beccde889cee)) +* fix for button text and remove profilearn caching ([#2137](https://github.com/aws/language-servers/issues/2137)) ([2a4171a](https://github.com/aws/language-servers/commit/2a4171a74c15c23c23c481060496162bcc9e6284)) +* fix to add disk caching for mcp admin state ([#2139](https://github.com/aws/language-servers/issues/2139)) ([f947e1a](https://github.com/aws/language-servers/commit/f947e1a9da4431d6089b22825f992010c30a470b)) +* fix to turn on and off MCP servers incase of error based on last state ([#2143](https://github.com/aws/language-servers/issues/2143)) ([04588df](https://github.com/aws/language-servers/commit/04588dfc33f0d85dbd488814a474b5e354398df0)) +* proper path handling for additional context ([#2129](https://github.com/aws/language-servers/issues/2129)) ([971eaa5](https://github.com/aws/language-servers/commit/971eaa505d948e9d2090c85f9b965f554ea7f2c8)) +* Use file context override in the inline completion params for Jupyter Notebook ([#2114](https://github.com/aws/language-servers/issues/2114)) ([91c8398](https://github.com/aws/language-servers/commit/91c839857f8aa4d79098189f9fb620b361c51289)) + + +### Performance Improvements + +* remove edit completion retry mechanism on document change ([#2124](https://github.com/aws/language-servers/issues/2124)) ([963b6e9](https://github.com/aws/language-servers/commit/963b6e9b7887da23a85a826c55a6ed95ff36d956)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @aws/lsp-core bumped from ^0.0.13 to ^0.0.14 + ## [0.0.73](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.72...lsp-codewhisperer/v0.0.73) (2025-08-11) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 78297c702e..c4264e5988 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.73", + "version": "0.0.74", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { @@ -37,7 +37,7 @@ "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", "@aws/language-server-runtimes": "^0.2.126", - "@aws/lsp-core": "^0.0.13", + "@aws/lsp-core": "^0.0.14", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", "adm-zip": "^0.5.10", diff --git a/server/aws-lsp-json/CHANGELOG.md b/server/aws-lsp-json/CHANGELOG.md index 31c977b978..ecac136295 100644 --- a/server/aws-lsp-json/CHANGELOG.md +++ b/server/aws-lsp-json/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [0.1.18](https://github.com/aws/language-servers/compare/lsp-json/v0.1.17...lsp-json/v0.1.18) (2025-08-19) + + +### Bug Fixes + +* Use file context override in the inline completion params for Jupyter Notebook ([#2114](https://github.com/aws/language-servers/issues/2114)) ([91c8398](https://github.com/aws/language-servers/commit/91c839857f8aa4d79098189f9fb620b361c51289)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @aws/lsp-core bumped from ^0.0.13 to ^0.0.14 + ## [0.1.17](https://github.com/aws/language-servers/compare/lsp-json/v0.1.16...lsp-json/v0.1.17) (2025-08-04) diff --git a/server/aws-lsp-json/package.json b/server/aws-lsp-json/package.json index 66604360fa..d129734444 100644 --- a/server/aws-lsp-json/package.json +++ b/server/aws-lsp-json/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-json", - "version": "0.1.17", + "version": "0.1.18", "description": "JSON Language Server", "main": "out/index.js", "repository": { @@ -27,7 +27,7 @@ }, "dependencies": { "@aws/language-server-runtimes": "^0.2.126", - "@aws/lsp-core": "^0.0.13", + "@aws/lsp-core": "^0.0.14", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" }, diff --git a/server/aws-lsp-partiql/CHANGELOG.md b/server/aws-lsp-partiql/CHANGELOG.md index b1be4c4050..dc68bdb063 100644 --- a/server/aws-lsp-partiql/CHANGELOG.md +++ b/server/aws-lsp-partiql/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.0.17](https://github.com/aws/language-servers/compare/lsp-partiql/v0.0.16...lsp-partiql/v0.0.17) (2025-08-19) + + +### Bug Fixes + +* Use file context override in the inline completion params for Jupyter Notebook ([#2114](https://github.com/aws/language-servers/issues/2114)) ([91c8398](https://github.com/aws/language-servers/commit/91c839857f8aa4d79098189f9fb620b361c51289)) + ## [0.0.16](https://github.com/aws/language-servers/compare/lsp-partiql/v0.0.15...lsp-partiql/v0.0.16) (2025-08-04) diff --git a/server/aws-lsp-partiql/package.json b/server/aws-lsp-partiql/package.json index efc073c7e9..2a5a5bb73f 100644 --- a/server/aws-lsp-partiql/package.json +++ b/server/aws-lsp-partiql/package.json @@ -3,7 +3,7 @@ "author": "Amazon Web Services", "license": "Apache-2.0", "description": "PartiQL language server", - "version": "0.0.16", + "version": "0.0.17", "repository": { "type": "git", "url": "https://github.com/aws/language-servers" diff --git a/server/aws-lsp-yaml/CHANGELOG.md b/server/aws-lsp-yaml/CHANGELOG.md index 965da41cfc..5858e6eb66 100644 --- a/server/aws-lsp-yaml/CHANGELOG.md +++ b/server/aws-lsp-yaml/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [0.1.18](https://github.com/aws/language-servers/compare/lsp-yaml/v0.1.17...lsp-yaml/v0.1.18) (2025-08-19) + + +### Bug Fixes + +* Use file context override in the inline completion params for Jupyter Notebook ([#2114](https://github.com/aws/language-servers/issues/2114)) ([91c8398](https://github.com/aws/language-servers/commit/91c839857f8aa4d79098189f9fb620b361c51289)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @aws/lsp-core bumped from ^0.0.13 to ^0.0.14 + ## [0.1.17](https://github.com/aws/language-servers/compare/lsp-yaml/v0.1.16...lsp-yaml/v0.1.17) (2025-08-04) diff --git a/server/aws-lsp-yaml/package.json b/server/aws-lsp-yaml/package.json index e18a72ea29..7d2b942ab5 100644 --- a/server/aws-lsp-yaml/package.json +++ b/server/aws-lsp-yaml/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-yaml", - "version": "0.1.17", + "version": "0.1.18", "description": "YAML Language Server", "main": "out/index.js", "repository": { @@ -27,7 +27,7 @@ }, "dependencies": { "@aws/language-server-runtimes": "^0.2.126", - "@aws/lsp-core": "^0.0.13", + "@aws/lsp-core": "^0.0.14", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", "yaml-language-server": "1.13.0" From 0767e074c91682a91d2fe7a6b2a7369c4dea280c Mon Sep 17 00:00:00 2001 From: andrewyuq <89420755+andrewyuq@users.noreply.github.com> Date: Thu, 21 Aug 2025 11:48:21 -0700 Subject: [PATCH 021/158] fix(amazonq): don't let flare send discard for the still valid suggestion in JB (#2145) * fix(amazonq): don't let flare send discard for the still valid suggestion in JB if a valid sessionId is returned back to JB, JB will eventually send a decision for it, but when user types a character to reject the current suggestion, on JB side it will 1) send reject for the current one 2) send a new trigger for the latest context. 2) will happen before 1) which will discard the current active session on flare's end. We don't want flare to do that for JB. * fix(amazonq): createSession doesn't need to close the previous session it should be handled together with telemetry reporting * fix(amazonq): fix test * fix(amazonq): test fix attempt * fix(amazonq): test fix attempt --- .../codeWhispererServer.test.ts | 35 +-------------- .../inline-completion/codeWhispererServer.ts | 44 ++++++++----------- .../editCompletionHandler.ts | 1 + .../session/sessionManager.test.ts | 28 +++--------- .../session/sessionManager.ts | 8 ---- .../userTriggerDecision.test.ts | 6 +-- 6 files changed, 29 insertions(+), 93 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts index 8151602dd4..e15400434c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts @@ -1503,7 +1503,7 @@ describe('CodeWhisperer Server', () => { manager.activateSession(session) const session2 = manager.createSession(sessionData) manager.activateSession(session2) - assert.equal(session.state, 'CLOSED') + assert.equal(session.state, 'ACTIVE') assert.equal(session2.state, 'ACTIVE') await features.doLogInlineCompletionSessionResults(sessionResultData) @@ -2300,39 +2300,6 @@ describe('CodeWhisperer Server', () => { sinon.assert.calledOnceWithExactly(sessionManagerSpy.closeSession, currentSession) }) - it('Manual completion invocation should close previous session', async () => { - const TRIGGER_KIND = InlineCompletionTriggerKind.Invoked - - const result = await features.doInlineCompletionWithReferences( - { - textDocument: { uri: SOME_FILE.uri }, - position: { line: 0, character: 0 }, - // Manual trigger kind - context: { triggerKind: TRIGGER_KIND }, - }, - CancellationToken.None - ) - - assert.deepEqual(result, EXPECTED_RESULT) - const firstSession = sessionManager.getActiveSession() - - // There is ACTIVE session - assert(firstSession) - assert.equal(sessionManager.getCurrentSession(), firstSession) - assert.equal(firstSession.state, 'ACTIVE') - - const secondResult = await features.doInlineCompletionWithReferences( - { - textDocument: { uri: SOME_FILE.uri }, - position: { line: 0, character: 0 }, - context: { triggerKind: TRIGGER_KIND }, - }, - CancellationToken.None - ) - assert.deepEqual(secondResult, { ...EXPECTED_RESULT, sessionId: SESSION_IDS_LOG[1] }) - sinon.assert.called(sessionManagerSpy.closeCurrentSession) - }) - it('should discard inflight session if merge right recommendations resulted in list of empty strings', async () => { // The suggestion returned by generateSuggestions will be equal to the contents of the file // This test fails when the file starts with a new line, probably due to the way we handle right context merge diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts index 33113fa318..9f2073d85e 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts @@ -311,34 +311,27 @@ export const CodewhispererServerFactory = // Close ACTIVE session and record Discard trigger decision immediately if (currentSession && currentSession.state === 'ACTIVE') { - if (editsEnabled && currentSession.suggestionType === SuggestionType.EDIT) { - const mergedSuggestions = mergeEditSuggestionsWithFileContext( + // Emit user trigger decision at session close time for active session + // TODO: yuxqiang workaround to exclude JB from this logic because JB and VSC handle a + // bit differently in the case when there's a new trigger while a reject/discard event is sent + // for the previous trigger + if (ideCategory !== 'JETBRAINS') { + completionSessionManager.discardSession(currentSession) + const streakLength = editsEnabled + ? completionSessionManager.getAndUpdateStreakLength(false) + : 0 + await emitUserTriggerDecisionTelemetry( + telemetry, + telemetryService, currentSession, - textDocument, - fileContext + timeSinceLastUserModification, + 0, + 0, + [], + [], + streakLength ) - - if (mergedSuggestions.length > 0) { - return { - items: mergedSuggestions, - sessionId: currentSession.id, - } - } } - // Emit user trigger decision at session close time for active session - completionSessionManager.discardSession(currentSession) - const streakLength = editsEnabled ? completionSessionManager.getAndUpdateStreakLength(false) : 0 - await emitUserTriggerDecisionTelemetry( - telemetry, - telemetryService, - currentSession, - timeSinceLastUserModification, - 0, - 0, - [], - [], - streakLength - ) } const supplementalMetadata = supplementalContext?.supContextData @@ -529,6 +522,7 @@ export const CodewhispererServerFactory = logging.log('Recommendation failure: ' + error) emitServiceInvocationFailure(telemetry, session, error) + // UTDE telemetry is not needed here because in error cases we don't care about UTDE for errored out sessions completionSessionManager.closeSession(session) let translatedError = error diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts index 005b5ab3f0..99737d027c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts @@ -403,6 +403,7 @@ export class EditCompletionHandler { this.logging.log('Recommendation failure: ' + error) emitServiceInvocationFailure(this.telemetry, session, error) + // UTDE telemetry is not needed here because in error cases we don't care about UTDE for errored out sessions this.sessionManager.closeSession(session) let translatedError = error diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.test.ts index db34f885ff..bef684eb9b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.test.ts @@ -529,12 +529,12 @@ describe('SessionManager', function () { assert.strictEqual(manager.getCurrentSession()?.state, 'REQUESTING') }) - it('should deactivate previous session when creating a new session', function () { + it('should not deactivate previous session when creating a new session', function () { const manager = SessionManager.getInstance() const session = manager.createSession(data) session.activate() manager.createSession(data) - assert.strictEqual(session.state, 'CLOSED') + assert.strictEqual(session.state, 'ACTIVE') }) it('should set previous active session trigger decision from discarded REQUESTING session', function () { @@ -548,7 +548,7 @@ describe('SessionManager', function () { assert.strictEqual(session2.previousTriggerDecision, 'Discard') }) - it('should set previous active session trigger decision to new session object', function () { + it('should not set previous active session trigger decision to new session object if it is not closed', function () { const manager = SessionManager.getInstance() const session1 = manager.createSession(data) assert.strictEqual(session1?.state, 'REQUESTING') @@ -557,22 +557,8 @@ describe('SessionManager', function () { const session2 = manager.createSession(data) - assert.strictEqual(session1?.state, 'CLOSED') - assert.strictEqual(session2.previousTriggerDecision, 'Empty') - }) - }) - - describe('closeCurrentSession()', function () { - it('should add the current session to the sessions log if it is active', function () { - const manager = SessionManager.getInstance() - const session = manager.createSession(data) - assert.strictEqual(session.state, 'REQUESTING') - session.activate() - assert.strictEqual(session.state, 'ACTIVE') - manager.closeCurrentSession() - assert.strictEqual(manager.getSessionsLog().length, 1) - assert.strictEqual(manager.getSessionsLog()[0], session) - assert.strictEqual(session.state, 'CLOSED') + assert.strictEqual(session1?.state, 'ACTIVE') + assert.strictEqual(session2.previousTriggerDecision, undefined) }) }) @@ -599,7 +585,6 @@ describe('SessionManager', function () { session2.activate() const session3 = manager.createSession(data) session3.activate() - manager.closeCurrentSession() const result = manager.getPreviousSession() assert.strictEqual(result, session3) assert.strictEqual(manager.getSessionsLog().length, 3) @@ -612,7 +597,6 @@ describe('SessionManager', function () { const session2 = manager.createSession(data) const session3 = manager.createSession(data) session3.activate() - manager.closeCurrentSession() const result = manager.getPreviousSession() assert.strictEqual(result, session3) assert.strictEqual(manager.getSessionsLog().length, 3) @@ -632,7 +616,6 @@ describe('SessionManager', function () { session.activate() const session2 = manager.createSession({ ...data, triggerType: 'AutoTrigger' }) session2.activate() - manager.closeCurrentSession() assert.strictEqual(manager.getSessionsLog().length, 2) const sessionId = session.id @@ -644,7 +627,6 @@ describe('SessionManager', function () { const manager = SessionManager.getInstance() const session = manager.createSession(data) session.activate() - manager.closeCurrentSession() assert.strictEqual(manager.getSessionsLog().length, 1) const sessionId = session.id + '1' diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts index a0ddf742f6..235c464234 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts @@ -305,8 +305,6 @@ export class SessionManager { } public createSession(data: SessionData): CodeWhispererSession { - this.closeCurrentSession() - // Remove oldest session from log if (this.sessionsLog.length > this.maxHistorySize) { this.sessionsLog.shift() @@ -327,12 +325,6 @@ export class SessionManager { return session } - closeCurrentSession() { - if (this.currentSession) { - this.closeSession(this.currentSession) - } - } - closeSession(session: CodeWhispererSession) { session.close() } diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/userTriggerDecision.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/userTriggerDecision.test.ts index b554b5ef23..c583815b6b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/userTriggerDecision.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/userTriggerDecision.test.ts @@ -505,7 +505,7 @@ describe('Telemetry', () => { sinon.assert.called(telemetryServiceSpy) }) - it('should not emit User Decision event when session results are received after session was closed', async () => { + it('should not emit User Decision event after second trigger is received', async () => { setServiceResponse(DEFAULT_SUGGESTIONS, { ...EXPECTED_RESPONSE_CONTEXT, codewhispererSessionId: 'cwspr-session-id-1', @@ -519,7 +519,7 @@ describe('Telemetry', () => { sinon.assert.notCalled(sessionManagerSpy.closeSession) sinon.assert.notCalled(telemetryServiceSpy) - // Send second completion request to close first one + // Send second completion request should not close first one setServiceResponse(DEFAULT_SUGGESTIONS, { ...EXPECTED_RESPONSE_CONTEXT, codewhispererSessionId: 'cwspr-session-id-2', @@ -528,7 +528,7 @@ describe('Telemetry', () => { assert.equal(firstSession.state, 'DISCARD') assert.notEqual(firstSession, sessionManager.getCurrentSession()) - sinon.assert.calledWithExactly(sessionManagerSpy.closeSession, firstSession) + sinon.assert.notCalled(sessionManagerSpy.closeSession) // Test that session reports it's status when second request is received const expectedEvent = aUserTriggerDecision({ state: 'DISCARD', From d3cd4556c0fc6cf08d93e0e0733798525ea0b7f8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 12:20:09 -0700 Subject: [PATCH 022/158] chore(release): release packages from branch main (#2149) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- package-lock.json | 2 +- server/aws-lsp-codewhisperer/CHANGELOG.md | 7 +++++++ server/aws-lsp-codewhisperer/package.json | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 159795a30e..49f118f219 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -2,7 +2,7 @@ "chat-client": "0.1.33", "core/aws-lsp-core": "0.0.14", "server/aws-lsp-antlr4": "0.1.18", - "server/aws-lsp-codewhisperer": "0.0.74", + "server/aws-lsp-codewhisperer": "0.0.75", "server/aws-lsp-json": "0.1.18", "server/aws-lsp-partiql": "0.0.17", "server/aws-lsp-yaml": "0.1.18" diff --git a/package-lock.json b/package-lock.json index 97b89d43b8..8dbdc6d513 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28670,7 +28670,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.74", + "version": "0.0.75", "bundleDependencies": [ "@amzn/codewhisperer-streaming", "@amzn/amazon-q-developer-streaming-client" diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index 048eaee59c..a70284a4c2 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.0.75](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.74...lsp-codewhisperer/v0.0.75) (2025-08-21) + + +### Bug Fixes + +* **amazonq:** don't let flare send discard for the still valid suggestion in JB ([#2145](https://github.com/aws/language-servers/issues/2145)) ([0767e07](https://github.com/aws/language-servers/commit/0767e074c91682a91d2fe7a6b2a7369c4dea280c)) + ## [0.0.74](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.73...lsp-codewhisperer/v0.0.74) (2025-08-19) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index c4264e5988..c0f6c16afd 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.74", + "version": "0.0.75", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { From 28d46a7ff65bbc702606d01a616085e572eb1ab5 Mon Sep 17 00:00:00 2001 From: manodnyab <66754471+manodnyab@users.noreply.github.com> Date: Thu, 21 Aug 2025 19:56:29 -0700 Subject: [PATCH 023/158] chore: merge agentic version 1.29.0 (#2151) * chore: bump agentic version: 1.29.0 * chore: empty commit to start Github Action (#2150) --------- Co-authored-by: aws-toolkit-automation <> --- app/aws-lsp-codewhisperer-runtimes/src/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/src/version.json b/app/aws-lsp-codewhisperer-runtimes/src/version.json index 4c93c3f549..93401eb637 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/version.json +++ b/app/aws-lsp-codewhisperer-runtimes/src/version.json @@ -1,3 +1,3 @@ { - "agenticChat": "1.27.0" + "agenticChat": "1.29.0" } From 2fb896e094de0bc5a1b4881067e7dcceb3826015 Mon Sep 17 00:00:00 2001 From: Boyu Date: Thu, 21 Aug 2025 22:08:16 -0700 Subject: [PATCH 024/158] feat: add basic OAuth client for remote MCP (#2136) * feat: add basic mcp oauth client * fix: relax condition for triggering oauth flow; add resilience checks for as availability * feat: add unit test for auth client * fix: multiple fixes for remote mcp error and timeout --- .../agenticChat/tools/mcp/mcpEventHandler.ts | 65 +-- .../agenticChat/tools/mcp/mcpManager.ts | 53 ++- .../tools/mcp/mcpOauthClient.test.ts | 120 +++++ .../agenticChat/tools/mcp/mcpOauthClient.ts | 437 ++++++++++++++++++ 4 files changed, 635 insertions(+), 40 deletions(-) create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts index 5b3ac84e98..a5090319ba 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts @@ -3,7 +3,6 @@ import { MCP_SERVER_STATUS_CHANGED, McpManager } from './mcpManager' import { ChatTelemetryController } from '../../../chat/telemetry/chatTelemetryController' import { ChokidarFileWatcher } from './chokidarFileWatcher' // eslint-disable-next-line import/no-nodejs-modules -import * as path from 'path' import { DetailedListGroup, DetailedListItem, @@ -13,14 +12,7 @@ import { Status, } from '@aws/language-server-runtimes/protocol' -import { - getGlobalMcpConfigPath, - getGlobalAgentConfigPath, - getWorkspaceMcpConfigPaths, - getWorkspaceAgentConfigPaths, - sanitizeName, - normalizePathFromUri, -} from './mcpUtils' +import { getGlobalAgentConfigPath, getWorkspaceAgentConfigPaths, sanitizeName, normalizePathFromUri } from './mcpUtils' import { McpPermissionType, MCPServerConfig, @@ -29,7 +21,6 @@ import { McpServerStatus, } from './mcpTypes' import { TelemetryService } from '../../../../shared/telemetry/telemetryService' -import { URI } from 'vscode-uri' import { ProfileStatusMonitor } from './profileStatusMonitor' interface PermissionOption { @@ -38,6 +29,11 @@ interface PermissionOption { description?: string } +enum TransportType { + STDIO = 'stdio', + HTTP = 'http', +} + export class McpEventHandler { #features: Features #eventListenerRegistered: boolean @@ -393,7 +389,7 @@ export class McpEventHandler { const serverStatusError = this.#getServerStatusError(existingValues.name) || {} // Determine which transport is selected (default to stdio) - const selectedTransport = existingValues.transport || 'stdio' + const selectedTransport = existingValues.transport || TransportType.STDIO return { id: params.id, @@ -432,14 +428,14 @@ export class McpEventHandler { title: 'Transport', mandatory: true, options: [ - { label: 'stdio', value: 'stdio' }, - { label: 'http', value: 'http' }, + { label: TransportType.STDIO, value: TransportType.STDIO }, + { label: TransportType.HTTP, value: TransportType.HTTP }, ], value: selectedTransport, }, ] - if (selectedTransport === 'http') { + if (selectedTransport === TransportType.HTTP) { return [ ...common, { @@ -603,8 +599,13 @@ export class McpEventHandler { errors.push('Either command or url is required') } else if (command && url) { errors.push('Provide either command OR url, not both') - } else if (transport && ((transport === 'stdio' && !command) || (transport !== 'stdio' && !url))) { - errors.push(`${transport === 'stdio' ? 'Command' : 'URL'} is required for ${transport} transport`) + } else if ( + transport && + ((transport === TransportType.STDIO && !command) || (transport !== TransportType.STDIO && !url)) + ) { + errors.push( + `${transport === TransportType.STDIO ? 'Command' : 'URL'} is required for ${transport} transport` + ) } if (values.timeout && values.timeout.trim() !== '') { @@ -692,7 +693,7 @@ export class McpEventHandler { // stdio‑specific parsing let args: string[] = [] let env: Record = {} - if (selectedTransport === 'stdio') { + if (selectedTransport === TransportType.STDIO) { try { args = (Array.isArray(params.optionsValues.args) ? params.optionsValues.args : []) .map((item: any) => @@ -719,7 +720,7 @@ export class McpEventHandler { // http‑specific parsing let headers: Record = {} - if (selectedTransport === 'http') { + if (selectedTransport === TransportType.HTTP) { try { const raw = Array.isArray(params.optionsValues.headers) ? params.optionsValues.headers : [] headers = raw.reduce((acc: Record, item: any) => { @@ -743,7 +744,7 @@ export class McpEventHandler { // build final config (no transport field persisted) let config: MCPServerConfig - if (selectedTransport === 'http') { + if (selectedTransport === TransportType.HTTP) { config = { url: params.optionsValues.url, headers, @@ -786,14 +787,15 @@ export class McpEventHandler { } this.#currentEditingServerName = undefined + this.#serverNameBeforeUpdate = undefined // need to check server state now, as there is possibility of error during server initialization const serverStatusError = this.#getServerStatusError(serverName) this.#telemetryController?.emitMCPServerInitializeEvent({ source: isEditMode ? 'updateServer' : 'addServer', - command: selectedTransport === 'stdio' ? params.optionsValues.command : undefined, - url: selectedTransport === 'http' ? params.optionsValues.url : undefined, + command: selectedTransport === TransportType.STDIO ? params.optionsValues.command : undefined, + url: selectedTransport === TransportType.HTTP ? params.optionsValues.url : undefined, enabled: true, numTools: McpManager.instance.getAllToolsWithPermissions(serverName).length, scope: params.optionsValues['scope'] === 'global' ? 'global' : 'workspace', @@ -1014,7 +1016,7 @@ export class McpEventHandler { } // Respect a user flip first; otherwise fall back to what the stored configuration implies. - const transport = params.optionsValues?.transport ?? (config.url ? 'http' : 'stdio') + const transport = params.optionsValues?.transport ?? (config.url ? TransportType.HTTP : TransportType.STDIO) // Convert stored structures to UI‑friendly lists const argsList = (config.args ?? []).map(a => ({ arg_key: a })) // for stdio @@ -1090,8 +1092,9 @@ export class McpEventHandler { // Clean up transport-specific fields if (optionsValues) { - const transport = optionsValues.transport ?? 'stdio' // Maintain default to 'stdio' - const fieldsToDelete = transport === 'http' ? ['command', 'args', 'env_variables'] : ['url', 'headers'] + const transport = optionsValues.transport ?? TransportType.STDIO // Maintain default to 'stdio' + const fieldsToDelete = + transport === TransportType.HTTP ? ['command', 'args', 'env_variables'] : ['url', 'headers'] fieldsToDelete.forEach(field => delete optionsValues[field]) } @@ -1238,11 +1241,11 @@ export class McpEventHandler { const serverConfig = McpManager.instance.getAllServerConfigs().get(serverName) if (serverConfig) { // Emit server initialize event after permission change - const transportType = serverConfig.command ? 'stdio' : 'http' + const transportType = serverConfig.command?.trim() ? TransportType.STDIO : TransportType.HTTP this.#telemetryController?.emitMCPServerInitializeEvent({ source: 'updatePermission', - command: transportType === 'stdio' ? serverConfig.command : undefined, - url: transportType === 'http' ? serverConfig.url : undefined, + command: transportType === TransportType.STDIO ? serverConfig.command : undefined, + url: transportType === TransportType.HTTP ? serverConfig.url : undefined, enabled: true, numTools: McpManager.instance.getAllToolsWithPermissions(serverName).length, scope: @@ -1310,16 +1313,16 @@ export class McpEventHandler { // Emit server initialize events for all active servers for (const [serverName, config] of serverConfigs.entries()) { - const transportType = config.command ? 'stdio' : 'http' + const transportType = config.command ? TransportType.STDIO : TransportType.HTTP const enabled = !mcpManager.isServerDisabled(serverName) this.#telemetryController?.emitMCPServerInitializeEvent({ source: 'reload', - command: transportType === 'stdio' ? config.command : undefined, - url: transportType === 'http' ? config.url : undefined, + command: transportType === TransportType.STDIO ? config.command : undefined, + url: transportType === TransportType.HTTP ? config.url : undefined, enabled: enabled, numTools: mcpManager.getAllToolsWithPermissions(serverName).length, scope: config.__configPath__ === globalAgentPath ? 'global' : 'workspace', - transportType: 'stdio', + transportType: transportType, languageServerVersion: this.#features.runtime.serverInfo.version, }) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index 844a872485..7ac6257641 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -38,6 +38,7 @@ import path = require('path') import { URI } from 'vscode-uri' import { sanitizeInput } from '../../../../shared/utils' import { ProfileStatusMonitor } from './profileStatusMonitor' +import { OAuthClient } from './mcpOauthClient' export const MCP_SERVER_STATUS_CHANGED = 'mcpServerStatusChanged' export const AGENT_TOOLS_CHANGED = 'agentToolsChanged' @@ -299,7 +300,7 @@ export class McpManager { this.features.logging.debug(`MCP: initializing server [${serverName}]`) const client = new Client({ - name: `mcp-client-${serverName}`, + name: `q-chat-plugin`, // Do not use server name in the client name to avoid polluting builder-mcp metrics version: '1.0.0', }) @@ -307,6 +308,7 @@ export class McpManager { const isStdio = !!cfg.command const doConnect = async () => { if (isStdio) { + // stdio transport const mergedEnv = { ...(process.env as Record), // Make sure we do not have empty key and value in mergedEnv, or adding server through UI will fail on Windows @@ -347,11 +349,33 @@ export class McpManager { ) } } else { + // streamable http/SSE transport const base = new URL(cfg.url!) try { + // Use HEAD to check if it needs OAuth + let headers: Record = { ...(cfg.headers ?? {}) } + let needsOAuth = false + try { + const headResp = await fetch(base, { method: 'HEAD', headers }) + const www = headResp.headers.get('www-authenticate') || '' + needsOAuth = headResp.status === 401 || headResp.status === 403 || /bearer/i.test(www) + } catch { + this.features.logging.info(`MCP: HEAD not available`) + } + + if (needsOAuth) { + OAuthClient.initialize(this.features.workspace, this.features.logging) + const bearer = await OAuthClient.getValidAccessToken(base) + // add authorization header if we are able to obtain a bearer token + if (bearer) { + headers = { ...headers, Authorization: `Bearer ${bearer}` } + } + } + try { // try streamable http first - transport = new StreamableHTTPClientTransport(base, this.buildHttpOpts(cfg.headers)) + transport = new StreamableHTTPClientTransport(base, this.buildHttpOpts(headers)) + this.features.logging.info(`MCP: Connecting MCP server using StreamableHTTPClientTransport`) await client.connect(transport) } catch (err) { @@ -359,13 +383,14 @@ export class McpManager { this.features.logging.info( `MCP: streamable http connect failed for [${serverName}], fallback to SSEClientTransport: ${String(err)}` ) - transport = new SSEClientTransport(new URL(cfg.url!), this.buildSseOpts(cfg.headers)) + transport = new SSEClientTransport(new URL(cfg.url!), this.buildSseOpts(headers)) await client.connect(transport) } } catch (err: any) { let errorMessage = err?.message ?? String(err) + const oauthHint = /oauth/i.test(errorMessage) ? ' (OAuth)' : '' throw new AgenticChatError( - `MCP: server '${serverName}' failed to connect: ${errorMessage}`, + `MCP: server '${serverName}' failed to connect${oauthHint}: ${errorMessage}`, 'MCPServerConnectionFailed' ) } @@ -645,7 +670,7 @@ export class McpManager { disabled: cfg.disabled ?? false, } // Only add timeout to agent config if it's not 0 - if (cfg.timeout !== 0) { + if (cfg.timeout !== undefined) { serverConfig.timeout = cfg.timeout } if (cfg.args && cfg.args.length > 0) { @@ -1268,11 +1293,21 @@ export class McpManager { private handleError(server: string | undefined, err: unknown) { const msg = err instanceof Error ? err.message : String(err) - this.features.logging.error(`MCP ERROR${server ? ` [${server}]` : ''}: ${msg}`) + const isBenignSseDisconnect = + /SSE error:\s*TypeError:\s*terminated:\s*Body Timeout Error/i.test(msg) || + /TypeError:\s*terminated:\s*Body Timeout Error/i.test(msg) || + /TypeError:\s*terminated:\s*other side closed/i.test(msg) || + /ECONNRESET|ENETRESET|EPIPE/i.test(msg) - if (server) { - this.setState(server, McpServerStatus.FAILED, 0, msg) - this.emitToolsChanged(server) + if (isBenignSseDisconnect) { + this.features.logging.debug(`MCP SSE idle timeout${server ? ` [${server}]` : ''}: ${msg}`) + } else { + // default path for real errors + this.features.logging.error(`MCP ERROR${server ? ` [${server}]` : ''}: ${msg}`) + if (server) { + this.setState(server, McpServerStatus.FAILED, 0, msg) + this.emitToolsChanged(server) + } } } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.test.ts new file mode 100644 index 0000000000..43f68302eb --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.test.ts @@ -0,0 +1,120 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. + * All Rights Reserved. SPDX-License-Identifier: Apache-2.0 + */ + +import { expect } from 'chai' +import * as sinon from 'sinon' +import * as crypto from 'crypto' +import * as http from 'http' +import { EventEmitter } from 'events' +import * as path from 'path' +import { OAuthClient } from './mcpOauthClient' + +const fakeLogger = { + log: () => {}, + debug: () => {}, + info: () => {}, + warn: () => {}, + error: () => {}, +} + +const fakeWorkspace = { + fs: { + exists: async (_path: string) => false, + readFile: async (_path: string) => Buffer.from('{}'), + writeFile: async (_path: string, _d: any) => {}, + mkdir: async (_dir: string, _opts: any) => {}, + }, +} as any + +function stubFileSystem(tokenObj?: any, regObj?: any): void { + const cacheDir = (OAuthClient as any).cacheDir as string + const tokPath = path.join(cacheDir, 'testkey.token.json') + const regPath = path.join(cacheDir, 'testkey.registration.json') + + const existsStub = sinon.stub(fakeWorkspace.fs, 'exists') + existsStub.callsFake(async (p: any) => { + if (p === tokPath && tokenObj) return true + if (p === regPath && regObj) return true + return false + }) + + const readStub = sinon.stub(fakeWorkspace.fs, 'readFile') + readStub.callsFake(async (p: any) => { + if (p === tokPath && tokenObj) return Buffer.from(JSON.stringify(tokenObj)) + if (p === regPath && regObj) return Buffer.from(JSON.stringify(regObj)) + return Buffer.from('{}') + }) + + sinon.stub(fakeWorkspace.fs, 'writeFile').resolves() + sinon.stub(fakeWorkspace.fs, 'mkdir').resolves() +} + +function stubHttpServer(): void { + sinon.stub(http, 'createServer').callsFake(() => { + const srv = new EventEmitter() as unknown as http.Server & EventEmitter + ;(srv as any).address = () => ({ address: '127.0.0.1', port: 12345, family: 'IPv4' }) + ;(srv as any).listen = (_port?: any, _host?: any, _backlog?: any, cb?: any) => { + if (typeof cb === 'function') cb() + // simulate async readiness like a real server + process.nextTick(() => srv.emit('listening')) + return srv + } + ;(srv as any).close = (cb?: any) => { + if (typeof cb === 'function') cb() + srv.removeAllListeners() + return srv + } + return srv + }) +} + +describe('OAuthClient helpers', () => { + it('computeKey() generates deterministic SHA-256 hex', () => { + const url = new URL('https://example.com/api') + const expected = crypto + .createHash('sha256') + .update(url.origin + url.pathname) + .digest('hex') + const actual = (OAuthClient as any).computeKey(url) + expect(actual).to.equal(expected) + }) + + it('b64url() strips padding and is URL-safe', () => { + const buf = Buffer.from('hello') + const actual = (OAuthClient as any).b64url(buf) + expect(actual).to.equal('aGVsbG8') + }) +}) + +describe('OAuthClient getValidAccessToken()', () => { + const now = Date.now() + + beforeEach(() => { + sinon.restore() + OAuthClient.initialize(fakeWorkspace, fakeLogger as any) + sinon.stub(OAuthClient as any, 'computeKey').returns('testkey') + stubHttpServer() + }) + + afterEach(() => sinon.restore()) + + it('returns cached token when still valid', async () => { + const cachedToken = { + access_token: 'cached_access', + expires_in: 3600, + obtained_at: now - 1_000, + } + const cachedReg = { + client_id: 'cid', + redirect_uri: 'http://localhost:12345', + } + + stubFileSystem(cachedToken, cachedReg) + + const token = await OAuthClient.getValidAccessToken(new URL('https://api.example.com/mcp')) + expect(token).to.equal('cached_access') + expect((http.createServer as any).calledOnce).to.be.true + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts new file mode 100644 index 0000000000..73ffea1a1d --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts @@ -0,0 +1,437 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. + * All Rights Reserved. SPDX-License-Identifier: Apache-2.0 + */ + +import type { RequestInit } from 'node-fetch' +import * as crypto from 'crypto' +import * as path from 'path' +import { spawn } from 'child_process' +import { URL, URLSearchParams } from 'url' +import * as http from 'http' +import { Logger, Workspace } from '@aws/language-server-runtimes/server-interface' + +interface Token { + access_token: string + expires_in: number + refresh_token?: string + obtained_at: number +} + +interface Meta { + authorization_endpoint: string + token_endpoint: string + registration_endpoint?: string +} + +interface Registration { + client_id: string + client_secret?: string + expires_at?: number + redirect_uri: string +} + +export class OAuthClient { + private static logger: Logger + private static workspace: Workspace + + public static initialize(ws: Workspace, logger: Logger): void { + this.workspace = ws + this.logger = logger + } + + /** + * Return a valid Bearer token, reusing cache or refresh-token if possible, + * otherwise driving one interactive PKCE flow. + */ + public static async getValidAccessToken(mcpBase: URL): Promise { + const key = this.computeKey(mcpBase) + const regPath = path.join(this.cacheDir, `${key}.registration.json`) + const tokPath = path.join(this.cacheDir, `${key}.token.json`) + + // 1) Spin up (or reuse) loopback server + redirect URI + let server: http.Server, redirectUri: string + const savedReg = await this.read(regPath) + if (savedReg) { + const port = Number(new URL(savedReg.redirect_uri).port) + server = http.createServer() + try { + await this.listen(server, port) + redirectUri = savedReg.redirect_uri + this.logger.info(`OAuth: reusing redirect URI ${redirectUri}`) + } catch (e: any) { + if (e.code === 'EADDRINUSE') { + try { + server.close() + } catch { + /* ignore */ + } + this.logger.warn(`Port ${port} in use; falling back to new random port`) + ;({ server, redirectUri } = await this.buildCallbackServer()) + this.logger.info(`OAuth: new redirect URI ${redirectUri}`) + await this.workspace.fs.rm(regPath) + } else { + throw e + } + } + } else { + ;({ server, redirectUri } = await this.buildCallbackServer()) + this.logger.info(`OAuth: new redirect URI ${redirectUri}`) + } + + try { + // 2) Try still-valid cached access_token + const cached = await this.read(tokPath) + if (cached) { + const expiry = cached.obtained_at + cached.expires_in * 1000 + if (Date.now() < expiry) { + this.logger.info(`OAuth: using still‑valid cached token`) + return cached.access_token + } + this.logger.info(`OAuth: cached token expired → try refresh`) + } + + // 3) Discover AS metadata + let meta: Meta + try { + meta = await this.discoverAS(mcpBase) + } catch (e: any) { + throw new Error(`OAuth discovery failed: ${e?.message ?? String(e)}`) + } + // 4) Register (or reuse) a dynamic client + const scopes = ['openid', 'offline_access'] + let reg: Registration + try { + reg = await this.obtainClient(meta, regPath, scopes, redirectUri) + } catch (e: any) { + throw new Error(`OAuth client registration failed: ${e?.message ?? String(e)}`) + } + + // 5) Refresh‑token grant (one shot) + const attemptedRefresh = !!cached?.refresh_token + if (cached?.refresh_token) { + const refreshed = await this.refreshGrant(meta, reg, mcpBase, cached.refresh_token) + if (refreshed) { + await this.write(tokPath, refreshed) + this.logger.info(`OAuth: refresh grant succeeded`) + return refreshed.access_token + } + this.logger.info(`OAuth: refresh grant failed`) + } + + // 6) PKCE interactive flow + try { + const fresh = await this.pkceGrant(meta, reg, mcpBase, scopes, redirectUri, server) + await this.write(tokPath, fresh) + return fresh.access_token + } catch (e: any) { + const suffix = attemptedRefresh ? ' after refresh attempt' : '' + throw new Error(`OAuth authorization (PKCE) failed${suffix}: ${e?.message ?? String(e)}`) + } + } finally { + await new Promise(res => server.close(() => res())) + } + } + + /** Spin up a one‑time HTTP listener on localhost:randomPort */ + private static async buildCallbackServer(): Promise<{ server: http.Server; redirectUri: string }> { + const server = http.createServer() + await this.listen(server, 0) + const port = (server.address() as any).port as number + return { server, redirectUri: `http://localhost:${port}` } + } + + /** Discover OAuth endpoints by HEAD/WWW‑Authenticate, well‑known, or fallback */ + private static async discoverAS(rs: URL): Promise { + // a) HEAD → WWW‑Authenticate → resource_metadata + try { + this.logger.info('MCP OAuth: attempting discovery via WWW-Authenticate header') + const h = await this.fetchCompat(rs.toString(), { method: 'HEAD' }) + const header = h.headers.get('www-authenticate') || '' + const m = /resource_metadata=(?:"([^"]+)"|([^,\s]+))/i.exec(header) + if (m) { + const metaUrl = new URL(m[1] || m[2], rs).toString() + this.logger.info(`OAuth: resource_metadata → ${metaUrl}`) + const raw = await this.json(metaUrl) + return await this.fetchASFromResourceMeta(raw, metaUrl) + } + } catch { + this.logger.info('MCP OAuth: no resource_metadata found in WWW-Authenticate header') + } + + // b) well‑known on resource host + this.logger.info('MCP OAuth: attempting discovery via well-known endpoints') + const probes = [ + new URL('.well-known/oauth-authorization-server', rs).toString(), + new URL('.well-known/openid-configuration', rs).toString(), + `${rs.origin}/.well-known/oauth-authorization-server`, + `${rs.origin}/.well-known/openid-configuration`, + ] + for (const url of probes) { + try { + this.logger.info(`MCP OAuth: probing well-known endpoint → ${url}`) + return await this.json(url) + } catch (error) { + this.logger.info(`OAuth: well-known endpoint probe failed for ${url}`) + } + } + + // c) fallback to static OAuth2 endpoints + const base = (rs.origin + rs.pathname).replace(/\/+$/, '') + this.logger.warn(`OAuth: all discovery attempts failed, synthesizing endpoints from ${base}`) + return { + authorization_endpoint: `${base}/authorize`, + token_endpoint: `${base}/access_token`, + } + } + + /** Follow `authorization_server(s)` in resource_metadata JSON */ + private static async fetchASFromResourceMeta(raw: any, metaUrl: string): Promise { + let asBase = raw.authorization_server + if (!asBase && Array.isArray(raw.authorization_servers)) { + asBase = raw.authorization_servers[0] + } + if (!asBase) { + throw new Error(`resource_metadata at ${metaUrl} lacked authorization_server(s)`) + } + + // Attempt both OAuth‑AS and OIDC well‑known + for (const p of ['.well-known/oauth-authorization-server', '.well-known/openid-configuration']) { + try { + return await this.json(new URL(p, asBase).toString()) + } catch { + // next + } + } + // fallback to static OAuth2 endpoints + this.logger.warn(`OAuth: no well-known on ${asBase}, falling back to static endpoints`) + return { + authorization_endpoint: `${asBase}/authorize`, + token_endpoint: `${asBase}/access_token`, + } + } + + /** DCR: POST client metadata → client_id; cache to disk */ + private static async obtainClient( + meta: Meta, + file: string, + scopes: string[], + redirectUri: string + ): Promise { + const existing = await this.read(file) + if (existing && (!existing.expires_at || existing.expires_at * 1000 > Date.now())) { + this.logger.info(`OAuth: reusing client_id ${existing.client_id}`) + return existing + } + + if (!meta.registration_endpoint) { + throw new Error('OAuth: AS does not support dynamic registration') + } + + const body = { + client_name: 'AWS MCP LSP', + grant_types: ['authorization_code', 'refresh_token'], + response_types: ['code'], + token_endpoint_auth_method: 'none', + scope: scopes.join(' '), + redirect_uris: [redirectUri], + } + const resp: any = await this.json(meta.registration_endpoint, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(body), + }) + + const reg: Registration = { + client_id: resp.client_id, + client_secret: resp.client_secret, + expires_at: resp.client_secret_expires_at, + redirect_uri: redirectUri, + } + await this.write(file, reg) + return reg + } + + /** Try one refresh_token grant; returns new Token or `undefined` */ + private static async refreshGrant( + meta: Meta, + reg: Registration, + rs: URL, + refresh: string + ): Promise { + const form = new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: refresh, + client_id: reg.client_id, + resource: rs.toString(), + }) + const res = await this.fetchCompat(meta.token_endpoint, { + method: 'POST', + headers: { 'content-type': 'application/x-www-form-urlencoded' }, + body: form, + }) + if (!res.ok) { + const msg = await res.text().catch(() => '') + this.logger.warn(`OAuth: refresh grant HTTP ${res.status} — ${msg?.slice(0, 300)}`) + return undefined + } + const tokenResponse = (await res.json()) as Record + return { ...(tokenResponse as object), obtained_at: Date.now() } as Token + } + + /** One PKCE flow: browser + loopback → code → token */ + private static async pkceGrant( + meta: Meta, + reg: Registration, + rs: URL, + scopes: string[], + redirectUri: string, + server: http.Server + ): Promise { + // a) generate PKCE params + const verifier = this.b64url(crypto.randomBytes(32)) + const challenge = this.b64url(crypto.createHash('sha256').update(verifier).digest()) + const state = this.b64url(crypto.randomBytes(16)) + + // b) build authorize URL + launch browser + const authz = new URL(meta.authorization_endpoint) + authz.search = new URLSearchParams({ + client_id: reg.client_id, + response_type: 'code', + code_challenge: challenge, + code_challenge_method: 'S256', + resource: rs.toString(), + scope: scopes.join(' '), + redirect_uri: redirectUri, + state: state, + }).toString() + + const opener = + process.platform === 'win32' + ? { cmd: 'cmd', args: ['/c', 'start', authz.toString()] } + : process.platform === 'darwin' + ? { cmd: 'open', args: [authz.toString()] } + : { cmd: 'xdg-open', args: [authz.toString()] } + + void spawn(opener.cmd, opener.args, { detached: true, stdio: 'ignore' }).unref() + + // c) wait for code on our loopback + const { code, rxState, err } = await new Promise<{ code: string; rxState: string; err?: string }>(resolve => { + server.on('request', (req, res) => { + const u = new URL(req.url || '/', redirectUri) + const c = u.searchParams.get('code') || '' + const s = u.searchParams.get('state') || '' + const e = u.searchParams.get('error') || undefined + res.writeHead(200, { 'content-type': 'text/html' }).end('

You may close this tab.

') + resolve({ code: c, rxState: s, err: e }) + }) + }) + if (err) throw new Error(`Authorization error: ${err}`) + if (!code || rxState !== state) throw new Error('Invalid authorization response (state mismatch)') + + // d) exchange code for token + const form2 = new URLSearchParams({ + grant_type: 'authorization_code', + code, + code_verifier: verifier, + client_id: reg.client_id, + redirect_uri: redirectUri, + resource: rs.toString(), + }) + const res2 = await this.fetchCompat(meta.token_endpoint, { + method: 'POST', + headers: { 'content-type': 'application/x-www-form-urlencoded' }, + body: form2, + }) + if (!res2.ok) { + const txt = await res2.text().catch(() => '') + throw new Error(`Token exchange failed (HTTP ${res2.status}): ${txt?.slice(0, 300)}`) + } + const tk = (await res2.json()) as Record + return { ...(tk as object), obtained_at: Date.now() } as Token + } + + /** Fetch + error‑check + parse JSON */ + private static async json(url: string, init?: RequestInit): Promise { + const r = await this.fetchCompat(url, init) + if (!r.ok) { + const txt = await r.text().catch(() => '') + throw new Error(`HTTP ${r.status}@${url} — ${txt}`) + } + return (await r.json()) as T + } + + /** Read & parse JSON file via workspace.fs */ + private static async read(file: string): Promise { + try { + if (!(await this.workspace.fs.exists(file))) return undefined + const buf = await this.workspace.fs.readFile(file) + return JSON.parse(buf.toString()) as T + } catch { + return undefined + } + } + + /** Write JSON, then clamp file perms to 0600 (owner read/write) */ + private static async write(file: string, obj: unknown): Promise { + const dir = path.dirname(file) + await this.workspace.fs.mkdir(dir, { recursive: true }) + await this.workspace.fs.writeFile(file, JSON.stringify(obj, null, 2), { mode: 0o600 }) + } + + /** SHA‑256 of resourceServer URL → hex key */ + private static computeKey(rs: URL): string { + return crypto + .createHash('sha256') + .update(rs.origin + rs.pathname) + .digest('hex') + } + + /** RFC‑7636 base64url without padding */ + private static b64url(buf: Buffer): string { + return buf.toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_') + } + + /** Directory for caching registration + tokens */ + private static readonly cacheDir = path.join( + process.env.HOME || process.env.USERPROFILE || '.', + '.aws', + 'sso', + 'cache' + ) + + /** + * Await server.listen() but reject if it emits 'error' (eg EADDRINUSE), + * so callers can handle it immediately instead of hanging. + */ + private static listen(server: http.Server, port: number, host: string = '127.0.0.1'): Promise { + return new Promise((resolve, reject) => { + const onListening = () => { + server.off('error', onError) + resolve() + } + const onError = (err: NodeJS.ErrnoException) => { + server.off('listening', onListening) + reject(err) + } + server.once('listening', onListening) + server.once('error', onError) + server.listen(port, host) + }) + } + + /** + * Fetch compatibility: use global fetch on Node >= 18, otherwise dynamically import('node-fetch'). + * Using Function('return import(...)') avoids downleveling to require() in CJS builds. + */ + private static async fetchCompat(url: string, init?: RequestInit): Promise { + const globalObj = globalThis as any + if (typeof globalObj.fetch === 'function') { + return globalObj.fetch(url as any, init as any) + } + // Dynamic import of ESM node-fetch (only when global fetch is unavailable) + const mod = await (Function('return import("node-fetch")')() as Promise) + const f = mod.default ?? mod + return f(url as any, init as any) + } +} From a6c64f2995a17697e3d71d30a1f411f5cf0db279 Mon Sep 17 00:00:00 2001 From: atontb <104926752+atonaamz@users.noreply.github.com> Date: Fri, 22 Aug 2025 10:06:22 -0700 Subject: [PATCH 025/158] fix: adding streakTracker to track streakLength across Completions and Edits (#2147) --- .../inline-completion/codeWhispererServer.ts | 10 +-- .../editCompletionHandler.ts | 9 +- .../session/sessionManager.test.ts | 42 --------- .../session/sessionManager.ts | 13 --- .../tracker/streakTracker.test.ts | 85 +++++++++++++++++++ .../tracker/streakTracker.ts | 42 +++++++++ 6 files changed, 138 insertions(+), 63 deletions(-) create mode 100644 server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/streakTracker.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/streakTracker.ts diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts index 9f2073d85e..330cf54735 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts @@ -46,6 +46,7 @@ import { UserWrittenCodeTracker } from '../../shared/userWrittenCodeTracker' import { RecentEditTracker, RecentEditTrackerDefaultConfig } from './tracker/codeEditTracker' import { CursorTracker } from './tracker/cursorTracker' import { RejectedEditTracker, DEFAULT_REJECTED_EDIT_TRACKER_CONFIG } from './tracker/rejectedEditTracker' +import { StreakTracker } from './tracker/streakTracker' import { getAddedAndDeletedLines, getCharacterDifferences } from './diffUtils' import { emitPerceivedLatencyTelemetry, @@ -129,6 +130,7 @@ export const CodewhispererServerFactory = const recentEditTracker = RecentEditTracker.getInstance(logging, RecentEditTrackerDefaultConfig) const cursorTracker = CursorTracker.getInstance() const rejectedEditTracker = RejectedEditTracker.getInstance(logging, DEFAULT_REJECTED_EDIT_TRACKER_CONFIG) + const streakTracker = StreakTracker.getInstance() let editsEnabled = false let isOnInlineCompletionHandlerInProgress = false @@ -317,9 +319,7 @@ export const CodewhispererServerFactory = // for the previous trigger if (ideCategory !== 'JETBRAINS') { completionSessionManager.discardSession(currentSession) - const streakLength = editsEnabled - ? completionSessionManager.getAndUpdateStreakLength(false) - : 0 + const streakLength = editsEnabled ? streakTracker.getAndUpdateStreakLength(false) : 0 await emitUserTriggerDecisionTelemetry( telemetry, telemetryService, @@ -405,7 +405,7 @@ export const CodewhispererServerFactory = if (session.discardInflightSessionOnNewInvocation) { session.discardInflightSessionOnNewInvocation = false completionSessionManager.discardSession(session) - const streakLength = editsEnabled ? completionSessionManager.getAndUpdateStreakLength(false) : 0 + const streakLength = editsEnabled ? streakTracker.getAndUpdateStreakLength(false) : 0 await emitUserTriggerDecisionTelemetry( telemetry, telemetryService, @@ -664,7 +664,7 @@ export const CodewhispererServerFactory = // Always emit user trigger decision at session close sessionManager.closeSession(session) - const streakLength = editsEnabled ? sessionManager.getAndUpdateStreakLength(isAccepted) : 0 + const streakLength = editsEnabled ? streakTracker.getAndUpdateStreakLength(isAccepted) : 0 await emitUserTriggerDecisionTelemetry( telemetry, telemetryService, diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts index 99737d027c..193521cce9 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts @@ -36,12 +36,14 @@ import { getErrorMessage, hasConnectionExpired } from '../../shared/utils' import { AmazonQError, AmazonQServiceConnectionExpiredError } from '../../shared/amazonQServiceManager/errors' import { DocumentChangedListener } from './documentChangedListener' import { EMPTY_RESULT, EDIT_DEBOUNCE_INTERVAL_MS } from './constants' +import { StreakTracker } from './tracker/streakTracker' export class EditCompletionHandler { private readonly editsEnabled: boolean private debounceTimeout: NodeJS.Timeout | undefined private isWaiting: boolean = false private hasDocumentChangedSinceInvocation: boolean = false + private readonly streakTracker: StreakTracker constructor( readonly logging: Logging, @@ -60,6 +62,7 @@ export class EditCompletionHandler { this.editsEnabled = this.clientMetadata.initializationOptions?.aws?.awsClientCapabilities?.textDocument ?.inlineCompletionWithReferences?.inlineEditSupport ?? false + this.streakTracker = StreakTracker.getInstance() } get codeWhispererService() { @@ -264,7 +267,7 @@ export class EditCompletionHandler { if (currentSession && currentSession.state === 'ACTIVE') { // Emit user trigger decision at session close time for active session this.sessionManager.discardSession(currentSession) - const streakLength = this.editsEnabled ? this.sessionManager.getAndUpdateStreakLength(false) : 0 + const streakLength = this.editsEnabled ? this.streakTracker.getAndUpdateStreakLength(false) : 0 await emitUserTriggerDecisionTelemetry( this.telemetry, this.telemetryService, @@ -335,7 +338,7 @@ export class EditCompletionHandler { if (session.discardInflightSessionOnNewInvocation) { session.discardInflightSessionOnNewInvocation = false this.sessionManager.discardSession(session) - const streakLength = this.editsEnabled ? this.sessionManager.getAndUpdateStreakLength(false) : 0 + const streakLength = this.editsEnabled ? this.streakTracker.getAndUpdateStreakLength(false) : 0 await emitUserTriggerDecisionTelemetry( this.telemetry, this.telemetryService, @@ -359,7 +362,7 @@ export class EditCompletionHandler { this.telemetryService, session, this.documentChangedListener.timeSinceLastUserModification, - this.editsEnabled ? this.sessionManager.getAndUpdateStreakLength(false) : 0 + this.editsEnabled ? this.streakTracker.getAndUpdateStreakLength(false) : 0 ) return EMPTY_RESULT } diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.test.ts index bef684eb9b..ddf06ffd40 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.test.ts @@ -673,46 +673,4 @@ describe('SessionManager', function () { assert.equal(session.getSuggestionState('id4'), 'Discard') }) }) - - describe('getAndUpdateStreakLength()', function () { - it('should return 0 if user rejects suggestion A', function () { - const manager = SessionManager.getInstance() - - assert.equal(manager.getAndUpdateStreakLength(false), -1) - assert.equal(manager.streakLength, 0) - }) - - it('should return -1 for A and 1 for B if user accepts suggestion A and rejects B', function () { - const manager = SessionManager.getInstance() - - assert.equal(manager.getAndUpdateStreakLength(true), -1) - assert.equal(manager.streakLength, 1) - assert.equal(manager.getAndUpdateStreakLength(false), 1) - assert.equal(manager.streakLength, 0) - }) - - it('should return -1 for A, -1 for B, and 2 for C if user accepts A, accepts B, and rejects C', function () { - const manager = SessionManager.getInstance() - - assert.equal(manager.getAndUpdateStreakLength(true), -1) - assert.equal(manager.streakLength, 1) - assert.equal(manager.getAndUpdateStreakLength(true), -1) - assert.equal(manager.streakLength, 2) - assert.equal(manager.getAndUpdateStreakLength(false), 2) - assert.equal(manager.streakLength, 0) - }) - - it('should return -1 for A, -1 for B, and 1 for C if user accepts A, make an edit, accepts B, and rejects C', function () { - const manager = SessionManager.getInstance() - - assert.equal(manager.getAndUpdateStreakLength(true), -1) - assert.equal(manager.streakLength, 1) - assert.equal(manager.getAndUpdateStreakLength(false), 1) - assert.equal(manager.streakLength, 0) - assert.equal(manager.getAndUpdateStreakLength(true), -1) - assert.equal(manager.streakLength, 1) - assert.equal(manager.getAndUpdateStreakLength(false), 1) - assert.equal(manager.streakLength, 0) - }) - }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts index 235c464234..34dbb12538 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts @@ -282,7 +282,6 @@ export class SessionManager { private currentSession?: CodeWhispererSession private sessionsLog: CodeWhispererSession[] = [] private maxHistorySize = 5 - streakLength: number = 0 // TODO, for user decision telemetry: accepted suggestions (not necessarily the full corresponding session) should be stored for 5 minutes private constructor() {} @@ -362,16 +361,4 @@ export class SessionManager { this.currentSession.activate() } } - - getAndUpdateStreakLength(isAccepted: boolean | undefined): number { - if (!isAccepted && this.streakLength != 0) { - const currentStreakLength = this.streakLength - this.streakLength = 0 - return currentStreakLength - } else if (isAccepted) { - // increment streakLength everytime a suggestion is accepted. - this.streakLength = this.streakLength + 1 - } - return -1 - } } diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/streakTracker.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/streakTracker.test.ts new file mode 100644 index 0000000000..4c69879115 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/streakTracker.test.ts @@ -0,0 +1,85 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as assert from 'assert' +import { StreakTracker } from './streakTracker' + +describe('StreakTracker', function () { + let tracker: StreakTracker + + beforeEach(function () { + StreakTracker.reset() + tracker = StreakTracker.getInstance() + }) + + afterEach(function () { + StreakTracker.reset() + }) + + describe('getInstance', function () { + it('should return the same instance (singleton)', function () { + const instance1 = StreakTracker.getInstance() + const instance2 = StreakTracker.getInstance() + assert.strictEqual(instance1, instance2) + }) + + it('should create new instance after reset', function () { + const instance1 = StreakTracker.getInstance() + StreakTracker.reset() + const instance2 = StreakTracker.getInstance() + assert.notStrictEqual(instance1, instance2) + }) + }) + + describe('getAndUpdateStreakLength', function () { + it('should return -1 for undefined input', function () { + const result = tracker.getAndUpdateStreakLength(undefined) + assert.strictEqual(result, -1) + }) + + it('should return -1 and increment streak on acceptance', function () { + const result = tracker.getAndUpdateStreakLength(true) + assert.strictEqual(result, -1) + }) + + it('should return -1 for rejection with zero streak', function () { + const result = tracker.getAndUpdateStreakLength(false) + assert.strictEqual(result, -1) + }) + + it('should return previous streak on rejection after acceptances', function () { + tracker.getAndUpdateStreakLength(true) + tracker.getAndUpdateStreakLength(true) + tracker.getAndUpdateStreakLength(true) + + const result = tracker.getAndUpdateStreakLength(false) + assert.strictEqual(result, 3) + }) + + it('should handle acceptance after rejection', function () { + tracker.getAndUpdateStreakLength(true) + tracker.getAndUpdateStreakLength(true) + + const resetResult = tracker.getAndUpdateStreakLength(false) + assert.strictEqual(resetResult, 2) + + tracker.getAndUpdateStreakLength(true) + const newResult = tracker.getAndUpdateStreakLength(true) + assert.strictEqual(newResult, -1) + }) + }) + + describe('cross-instance consistency', function () { + it('should maintain state across getInstance calls', function () { + const tracker1 = StreakTracker.getInstance() + tracker1.getAndUpdateStreakLength(true) + tracker1.getAndUpdateStreakLength(true) + + const tracker2 = StreakTracker.getInstance() + const result = tracker2.getAndUpdateStreakLength(false) + assert.strictEqual(result, 2) + }) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/streakTracker.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/streakTracker.ts new file mode 100644 index 0000000000..21d56c4d74 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/streakTracker.ts @@ -0,0 +1,42 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Tracks acceptance streak across both completion and edit suggestion types. + * Shared singleton to maintain consistent streak count between different code paths. + */ +export class StreakTracker { + private static _instance?: StreakTracker + private streakLength: number = 0 + + private constructor() {} + + public static getInstance(): StreakTracker { + if (!StreakTracker._instance) { + StreakTracker._instance = new StreakTracker() + } + return StreakTracker._instance + } + + public static reset() { + StreakTracker._instance = undefined + } + + /** + * Updates and returns the current streak length based on acceptance status. + * @param isAccepted Whether the suggestion was accepted + * @returns Current streak length before update, or -1 if no change + */ + public getAndUpdateStreakLength(isAccepted: boolean | undefined): number { + if (!isAccepted && this.streakLength !== 0) { + const currentStreakLength = this.streakLength + this.streakLength = 0 + return currentStreakLength + } else if (isAccepted) { + this.streakLength += 1 + } + return -1 + } +} From 71b35952333e7581921644ce40fabbc1e6d3c02f Mon Sep 17 00:00:00 2001 From: Boyu Date: Fri, 22 Aug 2025 14:33:11 -0700 Subject: [PATCH 026/158] feat: disable pkce flow during plugin load (#2153) --- .../src/language-server/agenticChat/errors.ts | 1 + .../agenticChat/tools/mcp/mcpManager.ts | 31 +++++++--- .../agenticChat/tools/mcp/mcpOauthClient.ts | 59 ++++++++++++++++--- 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/errors.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/errors.ts index 3038269463..819211dfab 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/errors.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/errors.ts @@ -11,6 +11,7 @@ type AgenticChatErrorCode = | 'MCPServerInitTimeout' // mcp server failed to start within allowed time | 'MCPToolExecTimeout' // mcp tool call failed to complete within allowed time | 'MCPServerConnectionFailed' // mcp server failed to connect + | 'MCPServerAuthFailed' // mcp server failed to complete auth flow | 'RequestAborted' // request was aborted by the user | 'RequestThrottled' // request was aborted by the user diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index 7ac6257641..555bdb2c89 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -42,6 +42,10 @@ import { OAuthClient } from './mcpOauthClient' export const MCP_SERVER_STATUS_CHANGED = 'mcpServerStatusChanged' export const AGENT_TOOLS_CHANGED = 'agentToolsChanged' +export enum AuthIntent { + Interactive = 'interactive', + Silent = 'silent', +} /** * Manages MCP servers and their tools @@ -166,7 +170,7 @@ export class McpManager { /** * Load configurations and initialize each enabled server. */ - private async discoverAllServers(): Promise { + private async discoverAllServers(authIntent: AuthIntent = AuthIntent.Silent): Promise { // Load agent config const result = await loadAgentConfig(this.features.workspace, this.features.logging, this.agentPaths) @@ -217,7 +221,7 @@ export class McpManager { // Process servers in batches for (let i = 0; i < totalServers; i += MAX_CONCURRENT_SERVERS) { const batch = serversToInit.slice(i, i + MAX_CONCURRENT_SERVERS) - const batchPromises = batch.map(([name, cfg]) => this.initOneServer(name, cfg)) + const batchPromises = batch.map(([name, cfg]) => this.initOneServer(name, cfg, authIntent)) this.features.logging.debug( `MCP: initializing batch of ${batch.length} servers (${i + 1}-${Math.min(i + MAX_CONCURRENT_SERVERS, totalServers)} of ${totalServers})` @@ -292,7 +296,11 @@ export class McpManager { * Start a server process, connect client, and register its tools. * Errors are logged but do not stop discovery of other servers. */ - private async initOneServer(serverName: string, cfg: MCPServerConfig): Promise { + private async initOneServer( + serverName: string, + cfg: MCPServerConfig, + authIntent: AuthIntent = AuthIntent.Silent + ): Promise { const DEFAULT_SERVER_INIT_TIMEOUT_MS = 60_000 this.setState(serverName, McpServerStatus.INITIALIZING, 0) @@ -365,10 +373,19 @@ export class McpManager { if (needsOAuth) { OAuthClient.initialize(this.features.workspace, this.features.logging) - const bearer = await OAuthClient.getValidAccessToken(base) + const bearer = await OAuthClient.getValidAccessToken(base, { + interactive: authIntent === 'interactive', + }) // add authorization header if we are able to obtain a bearer token if (bearer) { headers = { ...headers, Authorization: `Bearer ${bearer}` } + } else if (authIntent === 'silent') { + // In silent mode we never launch a browser. If we cannot obtain a token + // from cache/refresh, surface a clear auth-required error and stop here. + throw new AgenticChatError( + `MCP: server '${serverName}' requires OAuth. Open "Edit MCP Server" and save to sign in.`, + 'MCPServerAuthFailed' + ) } } @@ -707,7 +724,7 @@ export class McpManager { await saveAgentConfig(this.features.workspace, this.features.logging, this.agentConfig, agentPath) // Add server tools to tools list after initialization - await this.initOneServer(sanitizedName, newCfg) + await this.initOneServer(sanitizedName, newCfg, AuthIntent.Interactive) } catch (err) { this.features.logging.error( `Failed to add MCP server '${serverName}': ${err instanceof Error ? err.message : String(err)}` @@ -872,7 +889,7 @@ export class McpManager { this.setState(serverName, McpServerStatus.DISABLED, 0) this.emitToolsChanged(serverName) } else { - await this.initOneServer(serverName, newCfg) + await this.initOneServer(serverName, newCfg, AuthIntent.Interactive) } } catch (err) { this.handleError(serverName, err) @@ -1086,7 +1103,7 @@ export class McpManager { this.setState(serverName, McpServerStatus.DISABLED, 0) } else { if (!this.clients.has(serverName) && serverName !== 'Built-in') { - await this.initOneServer(serverName, this.mcpServers.get(serverName)!) + await this.initOneServer(serverName, this.mcpServers.get(serverName)!, AuthIntent.Silent) } } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts index 73ffea1a1d..86bc7ba027 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts @@ -42,15 +42,55 @@ export class OAuthClient { /** * Return a valid Bearer token, reusing cache or refresh-token if possible, - * otherwise driving one interactive PKCE flow. + * otherwise (when interactive) driving one PKCE flow that may launch a browser. */ - public static async getValidAccessToken(mcpBase: URL): Promise { + public static async getValidAccessToken( + mcpBase: URL, + opts: { interactive?: boolean } = { interactive: true } + ): Promise { + const interactive = opts?.interactive !== false const key = this.computeKey(mcpBase) const regPath = path.join(this.cacheDir, `${key}.registration.json`) const tokPath = path.join(this.cacheDir, `${key}.token.json`) + // ===== Silent branch: try cached token, then refresh, never opens a browser ===== + if (!interactive) { + // 1) cached access token + const cachedTok = await this.read(tokPath) + if (cachedTok) { + const expiry = cachedTok.obtained_at + cachedTok.expires_in * 1000 + if (Date.now() < expiry) { + this.logger.info(`OAuth: using still-valid cached token (silent)`) + return cachedTok.access_token + } + this.logger.info(`OAuth: cached token expired → try refresh (silent)`) + } + + // 2) refresh-token grant (if we have registration and refresh token) + const savedReg = await this.read(regPath) + if (cachedTok?.refresh_token && savedReg) { + try { + const meta = await this.discoverAS(mcpBase) + const refreshed = await this.refreshGrant(meta, savedReg, mcpBase, cachedTok.refresh_token) + if (refreshed) { + await this.write(tokPath, refreshed) + this.logger.info(`OAuth: refresh grant succeeded (silent)`) + return refreshed.access_token + } + this.logger.info(`OAuth: refresh grant did not succeed (silent)`) + } catch (e) { + this.logger.warn(`OAuth: silent refresh failed — ${e instanceof Error ? e.message : String(e)}`) + } + } + + // 3) no token in silent mode → caller should surface auth-required UI + return undefined + } + + // ===== Interactive branch: may open a browser (PKCE) ===== // 1) Spin up (or reuse) loopback server + redirect URI - let server: http.Server, redirectUri: string + let server: http.Server | null = null + let redirectUri: string const savedReg = await this.read(regPath) if (savedReg) { const port = Number(new URL(savedReg.redirect_uri).port) @@ -75,7 +115,9 @@ export class OAuthClient { } } } else { - ;({ server, redirectUri } = await this.buildCallbackServer()) + const created = await this.buildCallbackServer() + server = created.server + redirectUri = created.redirectUri this.logger.info(`OAuth: new redirect URI ${redirectUri}`) } @@ -85,7 +127,7 @@ export class OAuthClient { if (cached) { const expiry = cached.obtained_at + cached.expires_in * 1000 if (Date.now() < expiry) { - this.logger.info(`OAuth: using still‑valid cached token`) + this.logger.info(`OAuth: using still-valid cached token`) return cached.access_token } this.logger.info(`OAuth: cached token expired → try refresh`) @@ -98,6 +140,7 @@ export class OAuthClient { } catch (e: any) { throw new Error(`OAuth discovery failed: ${e?.message ?? String(e)}`) } + // 4) Register (or reuse) a dynamic client const scopes = ['openid', 'offline_access'] let reg: Registration @@ -107,7 +150,7 @@ export class OAuthClient { throw new Error(`OAuth client registration failed: ${e?.message ?? String(e)}`) } - // 5) Refresh‑token grant (one shot) + // 5) Refresh-token grant (one shot) const attemptedRefresh = !!cached?.refresh_token if (cached?.refresh_token) { const refreshed = await this.refreshGrant(meta, reg, mcpBase, cached.refresh_token) @@ -129,7 +172,9 @@ export class OAuthClient { throw new Error(`OAuth authorization (PKCE) failed${suffix}: ${e?.message ?? String(e)}`) } } finally { - await new Promise(res => server.close(() => res())) + if (server) { + await new Promise(res => server!.close(() => res())) + } } } From 7296f9350950a3e28f612d3a9bb75567a6f6a41d Mon Sep 17 00:00:00 2001 From: chungjac Date: Mon, 25 Aug 2025 10:26:21 -0700 Subject: [PATCH 027/158] chore: bump runtimes to 0.2.127 (#2156) --- app/aws-lsp-antlr4-runtimes/package.json | 2 +- app/aws-lsp-buildspec-runtimes/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- app/aws-lsp-identity-runtimes/package.json | 2 +- app/aws-lsp-json-runtimes/package.json | 2 +- .../package.json | 2 +- app/aws-lsp-s3-runtimes/package.json | 2 +- app/aws-lsp-yaml-json-webworker/package.json | 2 +- app/aws-lsp-yaml-runtimes/package.json | 2 +- app/hello-world-lsp-runtimes/package.json | 2 +- chat-client/package.json | 2 +- client/vscode/package.json | 2 +- core/aws-lsp-core/package.json | 2 +- .../q-agentic-chat-server/package.json | 2 +- package-lock.json | 61 +++++++++---------- server/aws-lsp-antlr4/package.json | 2 +- server/aws-lsp-buildspec/package.json | 2 +- server/aws-lsp-cloudformation/package.json | 2 +- server/aws-lsp-codewhisperer/package.json | 2 +- server/aws-lsp-identity/package.json | 2 +- server/aws-lsp-json/package.json | 2 +- server/aws-lsp-notification/package.json | 2 +- server/aws-lsp-partiql/package.json | 2 +- server/aws-lsp-s3/package.json | 2 +- server/aws-lsp-yaml/package.json | 2 +- server/device-sso-auth-lsp/package.json | 2 +- server/hello-world-lsp/package.json | 2 +- 28 files changed, 57 insertions(+), 58 deletions(-) diff --git a/app/aws-lsp-antlr4-runtimes/package.json b/app/aws-lsp-antlr4-runtimes/package.json index 30b9b57a65..89fa95dcb3 100644 --- a/app/aws-lsp-antlr4-runtimes/package.json +++ b/app/aws-lsp-antlr4-runtimes/package.json @@ -12,7 +12,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-antlr4": "*", "antlr4-c3": "^3.4.1", "antlr4ng": "^3.0.4" diff --git a/app/aws-lsp-buildspec-runtimes/package.json b/app/aws-lsp-buildspec-runtimes/package.json index 47a88b907a..0ad07ddb8f 100644 --- a/app/aws-lsp-buildspec-runtimes/package.json +++ b/app/aws-lsp-buildspec-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-buildspec": "^0.0.1" } } diff --git a/app/aws-lsp-cloudformation-runtimes/package.json b/app/aws-lsp-cloudformation-runtimes/package.json index 68547449cc..d211149d0d 100644 --- a/app/aws-lsp-cloudformation-runtimes/package.json +++ b/app/aws-lsp-cloudformation-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-cloudformation": "^0.0.1" } } diff --git a/app/aws-lsp-codewhisperer-runtimes/package.json b/app/aws-lsp-codewhisperer-runtimes/package.json index 24e06d87ea..b890c01a78 100644 --- a/app/aws-lsp-codewhisperer-runtimes/package.json +++ b/app/aws-lsp-codewhisperer-runtimes/package.json @@ -23,7 +23,7 @@ "local-build": "node scripts/local-build.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", diff --git a/app/aws-lsp-identity-runtimes/package.json b/app/aws-lsp-identity-runtimes/package.json index 2bf37011c3..f33fa80da4 100644 --- a/app/aws-lsp-identity-runtimes/package.json +++ b/app/aws-lsp-identity-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-identity": "^0.0.1" } } diff --git a/app/aws-lsp-json-runtimes/package.json b/app/aws-lsp-json-runtimes/package.json index 8a2ea3203a..db1949f54b 100644 --- a/app/aws-lsp-json-runtimes/package.json +++ b/app/aws-lsp-json-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-json": "*" }, "devDependencies": { diff --git a/app/aws-lsp-notification-runtimes/package.json b/app/aws-lsp-notification-runtimes/package.json index b1877ae13e..a5eeecae49 100644 --- a/app/aws-lsp-notification-runtimes/package.json +++ b/app/aws-lsp-notification-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-notification": "^0.0.1" } } diff --git a/app/aws-lsp-s3-runtimes/package.json b/app/aws-lsp-s3-runtimes/package.json index a242281ff2..9feb4f7ddc 100644 --- a/app/aws-lsp-s3-runtimes/package.json +++ b/app/aws-lsp-s3-runtimes/package.json @@ -10,7 +10,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-s3": "^0.0.1" } } diff --git a/app/aws-lsp-yaml-json-webworker/package.json b/app/aws-lsp-yaml-json-webworker/package.json index 8eebf1ea84..fc524cabdc 100644 --- a/app/aws-lsp-yaml-json-webworker/package.json +++ b/app/aws-lsp-yaml-json-webworker/package.json @@ -11,7 +11,7 @@ "serve:webpack": "NODE_ENV=development webpack serve" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, diff --git a/app/aws-lsp-yaml-runtimes/package.json b/app/aws-lsp-yaml-runtimes/package.json index 1428ef3058..09bb93ee9a 100644 --- a/app/aws-lsp-yaml-runtimes/package.json +++ b/app/aws-lsp-yaml-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-yaml": "*" }, "devDependencies": { diff --git a/app/hello-world-lsp-runtimes/package.json b/app/hello-world-lsp-runtimes/package.json index 352bf82f88..bff976d9b3 100644 --- a/app/hello-world-lsp-runtimes/package.json +++ b/app/hello-world-lsp-runtimes/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@aws/hello-world-lsp": "^0.0.1", - "@aws/language-server-runtimes": "^0.2.126" + "@aws/language-server-runtimes": "^0.2.127" }, "devDependencies": { "@types/chai": "^4.3.5", diff --git a/chat-client/package.json b/chat-client/package.json index 1af265fdfe..59720a0187 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/language-server-runtimes-types": "^0.1.50", "@aws/mynah-ui": "^4.36.4" }, diff --git a/client/vscode/package.json b/client/vscode/package.json index 4cb42a0752..a5d7f66d21 100644 --- a/client/vscode/package.json +++ b/client/vscode/package.json @@ -352,7 +352,7 @@ "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", diff --git a/core/aws-lsp-core/package.json b/core/aws-lsp-core/package.json index 4ecdd4e238..54ca980fc1 100644 --- a/core/aws-lsp-core/package.json +++ b/core/aws-lsp-core/package.json @@ -28,7 +28,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", diff --git a/integration-tests/q-agentic-chat-server/package.json b/integration-tests/q-agentic-chat-server/package.json index 7415e1653e..ffb33f1a4e 100644 --- a/integration-tests/q-agentic-chat-server/package.json +++ b/integration-tests/q-agentic-chat-server/package.json @@ -9,7 +9,7 @@ "test-integ": "npm run compile && mocha --timeout 30000 \"./out/**/*.test.js\" --retries 2" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "*" }, "devDependencies": { diff --git a/package-lock.json b/package-lock.json index 8dbdc6d513..e65f8e8c96 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,7 +48,7 @@ "name": "@aws/lsp-antlr4-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-antlr4": "*", "antlr4-c3": "^3.4.1", "antlr4ng": "^3.0.4" @@ -71,7 +71,7 @@ "name": "@aws/lsp-buildspec-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-buildspec": "^0.0.1" } }, @@ -79,7 +79,7 @@ "name": "@aws/lsp-cloudformation-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-cloudformation": "^0.0.1" } }, @@ -87,7 +87,7 @@ "name": "@aws/lsp-codewhisperer-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", @@ -120,7 +120,7 @@ "name": "@aws/lsp-identity-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-identity": "^0.0.1" } }, @@ -128,7 +128,7 @@ "name": "@aws/lsp-json-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-json": "*" }, "devDependencies": { @@ -148,7 +148,7 @@ "name": "@aws/lsp-notification-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-notification": "^0.0.1" } }, @@ -181,7 +181,7 @@ "name": "@aws/lsp-s3-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-s3": "^0.0.1" }, "bin": { @@ -192,7 +192,7 @@ "name": "@aws/lsp-yaml-json-webworker", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, @@ -212,7 +212,7 @@ "name": "@aws/lsp-yaml-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-yaml": "*" }, "devDependencies": { @@ -234,7 +234,7 @@ "version": "0.0.1", "dependencies": { "@aws/hello-world-lsp": "^0.0.1", - "@aws/language-server-runtimes": "^0.2.126" + "@aws/language-server-runtimes": "^0.2.127" }, "devDependencies": { "@types/chai": "^4.3.5", @@ -255,7 +255,7 @@ "license": "Apache-2.0", "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/language-server-runtimes-types": "^0.1.50", "@aws/mynah-ui": "^4.36.4" }, @@ -280,7 +280,7 @@ "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", @@ -296,7 +296,7 @@ "version": "0.0.14", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", @@ -327,7 +327,7 @@ "name": "@aws/q-agentic-chat-server-integration-tests", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "*" }, "devDependencies": { @@ -4036,10 +4036,9 @@ "link": true }, "node_modules/@aws/language-server-runtimes": { - "version": "0.2.126", - "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.2.126.tgz", - "integrity": "sha512-dUIKTL6+AOxdberwHLvigSJcbhFv6oUS3POhZWoNlBV9XJZRWwzNW9gkjkUsI03YTVshqMuVHT/HaoRW/hDkIA==", - "license": "Apache-2.0", + "version": "0.2.127", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.2.127.tgz", + "integrity": "sha512-UWCfv49MYaBhxArVBWTEw2XVfIyunbm6EfS9AxSLPudcwrpOg3KAVLooXearmyM/r2hgNDGCQYI8HuKf5FAnew==", "dependencies": { "@aws/language-server-runtimes-types": "^0.1.56", "@opentelemetry/api": "^1.9.0", @@ -28608,7 +28607,7 @@ "version": "0.1.18", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "^0.0.14" }, "devDependencies": { @@ -28650,7 +28649,7 @@ "name": "@aws/lsp-buildspec", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", @@ -28661,7 +28660,7 @@ "name": "@aws/lsp-cloudformation", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", @@ -28683,7 +28682,7 @@ "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "^0.0.14", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", @@ -28823,7 +28822,7 @@ "dependencies": { "@aws-sdk/client-sso-oidc": "^3.616.0", "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "^0.0.12", "@smithy/node-http-handler": "^3.2.5", "@smithy/shared-ini-file-loader": "^4.0.1", @@ -28888,7 +28887,7 @@ "version": "0.1.18", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "^0.0.14", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" @@ -28905,7 +28904,7 @@ "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1" }, @@ -28966,7 +28965,7 @@ "version": "0.0.17", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "antlr4-c3": "3.4.2", "antlr4ng": "3.0.14", "web-tree-sitter": "0.22.6" @@ -28988,7 +28987,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" @@ -29019,7 +29018,7 @@ "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "^0.0.14", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", @@ -29033,7 +29032,7 @@ "name": "@amzn/device-sso-auth-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "vscode-languageserver": "^9.0.1" }, "devDependencies": { @@ -29044,7 +29043,7 @@ "name": "@aws/hello-world-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/server/aws-lsp-antlr4/package.json b/server/aws-lsp-antlr4/package.json index b61239d633..2ca49593d7 100644 --- a/server/aws-lsp-antlr4/package.json +++ b/server/aws-lsp-antlr4/package.json @@ -28,7 +28,7 @@ "clean": "rm -rf node_modules" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "^0.0.14" }, "peerDependencies": { diff --git a/server/aws-lsp-buildspec/package.json b/server/aws-lsp-buildspec/package.json index 3a23338dac..9754645b7d 100644 --- a/server/aws-lsp-buildspec/package.json +++ b/server/aws-lsp-buildspec/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-cloudformation/package.json b/server/aws-lsp-cloudformation/package.json index 75223b4791..13be6a4859 100644 --- a/server/aws-lsp-cloudformation/package.json +++ b/server/aws-lsp-cloudformation/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index c0f6c16afd..83ff1cdaee 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -36,7 +36,7 @@ "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "^0.0.14", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", diff --git a/server/aws-lsp-identity/package.json b/server/aws-lsp-identity/package.json index 0e61d97dc8..9aa4bedcbf 100644 --- a/server/aws-lsp-identity/package.json +++ b/server/aws-lsp-identity/package.json @@ -26,7 +26,7 @@ "dependencies": { "@aws-sdk/client-sso-oidc": "^3.616.0", "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "^0.0.12", "@smithy/node-http-handler": "^3.2.5", "@smithy/shared-ini-file-loader": "^4.0.1", diff --git a/server/aws-lsp-json/package.json b/server/aws-lsp-json/package.json index d129734444..ee5fbbc47a 100644 --- a/server/aws-lsp-json/package.json +++ b/server/aws-lsp-json/package.json @@ -26,7 +26,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "^0.0.14", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" diff --git a/server/aws-lsp-notification/package.json b/server/aws-lsp-notification/package.json index f6483e3e32..f19ddc54ca 100644 --- a/server/aws-lsp-notification/package.json +++ b/server/aws-lsp-notification/package.json @@ -22,7 +22,7 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1" }, diff --git a/server/aws-lsp-partiql/package.json b/server/aws-lsp-partiql/package.json index 2a5a5bb73f..dc2fc2ee22 100644 --- a/server/aws-lsp-partiql/package.json +++ b/server/aws-lsp-partiql/package.json @@ -24,7 +24,7 @@ "out" ], "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "antlr4-c3": "3.4.2", "antlr4ng": "3.0.14", "web-tree-sitter": "0.22.6" diff --git a/server/aws-lsp-s3/package.json b/server/aws-lsp-s3/package.json index b574da9bc0..914628d14e 100644 --- a/server/aws-lsp-s3/package.json +++ b/server/aws-lsp-s3/package.json @@ -9,7 +9,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" diff --git a/server/aws-lsp-yaml/package.json b/server/aws-lsp-yaml/package.json index 7d2b942ab5..fe115132c8 100644 --- a/server/aws-lsp-yaml/package.json +++ b/server/aws-lsp-yaml/package.json @@ -26,7 +26,7 @@ "postinstall": "node patchYamlPackage.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "@aws/lsp-core": "^0.0.14", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", diff --git a/server/device-sso-auth-lsp/package.json b/server/device-sso-auth-lsp/package.json index 6eba3692a9..e5085aa6bd 100644 --- a/server/device-sso-auth-lsp/package.json +++ b/server/device-sso-auth-lsp/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/server/hello-world-lsp/package.json b/server/hello-world-lsp/package.json index b221272541..8ab207f8b4 100644 --- a/server/hello-world-lsp/package.json +++ b/server/hello-world-lsp/package.json @@ -13,7 +13,7 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.126", + "@aws/language-server-runtimes": "^0.2.127", "vscode-languageserver": "^9.0.1" }, "devDependencies": { From 472220a745cff4fe91a2cabae4ae059a164ceddd Mon Sep 17 00:00:00 2001 From: Boyu Date: Mon, 25 Aug 2025 13:37:00 -0700 Subject: [PATCH 028/158] fix: multiple fixes on auth flow edge cases (#2155) --- .../agenticChat/tools/mcp/mcpEventHandler.ts | 31 ++++++++----- .../agenticChat/tools/mcp/mcpManager.ts | 45 ++++++++++++------- .../tools/mcp/mcpOauthClient.test.ts | 4 +- .../agenticChat/tools/mcp/mcpOauthClient.ts | 33 +++++++++----- 4 files changed, 73 insertions(+), 40 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts index a5090319ba..d167299106 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts @@ -35,6 +35,7 @@ enum TransportType { } export class McpEventHandler { + private static readonly FILE_WATCH_DEBOUNCE_MS = 2000 #features: Features #eventListenerRegistered: boolean #currentEditingServerName: string | undefined @@ -48,6 +49,12 @@ export class McpEventHandler { #lastProgrammaticState: boolean = false #serverNameBeforeUpdate: string | undefined + #releaseProgrammaticAfterDebounce(padMs = 500) { + setTimeout(() => { + this.#isProgrammaticChange = false + }, McpEventHandler.FILE_WATCH_DEBOUNCE_MS + padMs) + } + constructor(features: Features, telemetryService: TelemetryService) { this.#features = features this.#eventListenerRegistered = false @@ -797,7 +804,7 @@ export class McpEventHandler { command: selectedTransport === TransportType.STDIO ? params.optionsValues.command : undefined, url: selectedTransport === TransportType.HTTP ? params.optionsValues.url : undefined, enabled: true, - numTools: McpManager.instance.getAllToolsWithPermissions(serverName).length, + numTools: McpManager.instance.getAllToolsWithPermissions(sanitizedServerName).length, scope: params.optionsValues['scope'] === 'global' ? 'global' : 'workspace', transportType: selectedTransport, languageServerVersion: this.#features.runtime.serverInfo.version, @@ -812,6 +819,7 @@ export class McpEventHandler { // Stay on add/edit page and show error to user // Keep isProgrammaticChange true during error handling to prevent file watcher triggers + this.#releaseProgrammaticAfterDebounce() if (isEditMode) { params.id = 'edit-mcp' params.title = sanitizedServerName @@ -826,7 +834,7 @@ export class McpEventHandler { this.#newlyAddedServers.delete(serverName) } - this.#isProgrammaticChange = false + this.#releaseProgrammaticAfterDebounce() // Go to tools permissions page return this.#handleOpenMcpServer({ id: 'open-mcp-server', title: sanitizedServerName }) @@ -927,9 +935,10 @@ export class McpEventHandler { perm.__configPath__ = agentPath await mcpManager.updateServerPermission(serverName, perm) this.#emitMCPConfigEvent() + this.#releaseProgrammaticAfterDebounce() } catch (error) { this.#features.logging.error(`Failed to enable MCP server: ${error}`) - this.#isProgrammaticChange = false + this.#releaseProgrammaticAfterDebounce() } return { id: params.id } } @@ -953,9 +962,10 @@ export class McpEventHandler { perm.__configPath__ = agentPath await mcpManager.updateServerPermission(serverName, perm) this.#emitMCPConfigEvent() + this.#releaseProgrammaticAfterDebounce() } catch (error) { this.#features.logging.error(`Failed to disable MCP server: ${error}`) - this.#isProgrammaticChange = false + this.#releaseProgrammaticAfterDebounce() } return { id: params.id } @@ -975,11 +985,11 @@ export class McpEventHandler { try { await McpManager.instance.removeServer(serverName) - + this.#releaseProgrammaticAfterDebounce() return { id: params.id } } catch (error) { this.#features.logging.error(`Failed to delete MCP server: ${error}`) - this.#isProgrammaticChange = false + this.#releaseProgrammaticAfterDebounce() return { id: params.id } } } @@ -1262,10 +1272,11 @@ export class McpEventHandler { this.#pendingPermissionConfig = undefined this.#features.logging.info(`Applied permission changes for server: ${serverName}`) + this.#releaseProgrammaticAfterDebounce() return { id: params.id } } catch (error) { this.#features.logging.error(`Failed to save MCP permissions: ${error}`) - this.#isProgrammaticChange = false + this.#releaseProgrammaticAfterDebounce() return { id: params.id } } } @@ -1430,7 +1441,8 @@ export class McpEventHandler { */ #getServerStatusError(serverName: string): { title: string; icon: string; status: Status } | undefined { const serverStates = McpManager.instance.getAllServerStates() - const serverState = serverStates.get(serverName) + const key = serverName ? sanitizeName(serverName) : serverName + const serverState = key ? serverStates.get(key) : undefined if (!serverState) { return undefined @@ -1494,11 +1506,10 @@ export class McpEventHandler { if (!this.#lastProgrammaticState) { await this.#handleRefreshMCPList({ id: 'refresh-mcp-list' }) } else { - this.#isProgrammaticChange = false this.#features.logging.debug('Skipping refresh due to programmatic change') } this.#debounceTimer = null - }, 2000) + }, McpEventHandler.FILE_WATCH_DEBOUNCE_MS) }) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index 555bdb2c89..ec7d16d277 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -170,7 +170,7 @@ export class McpManager { /** * Load configurations and initialize each enabled server. */ - private async discoverAllServers(authIntent: AuthIntent = AuthIntent.Silent): Promise { + private async discoverAllServers(): Promise { // Load agent config const result = await loadAgentConfig(this.features.workspace, this.features.logging, this.agentPaths) @@ -221,7 +221,7 @@ export class McpManager { // Process servers in batches for (let i = 0; i < totalServers; i += MAX_CONCURRENT_SERVERS) { const batch = serversToInit.slice(i, i + MAX_CONCURRENT_SERVERS) - const batchPromises = batch.map(([name, cfg]) => this.initOneServer(name, cfg, authIntent)) + const batchPromises = batch.map(([name, cfg]) => this.initOneServer(name, cfg, AuthIntent.Silent)) this.features.logging.debug( `MCP: initializing batch of ${batch.length} servers (${i + 1}-${Math.min(i + MAX_CONCURRENT_SERVERS, totalServers)} of ${totalServers})` @@ -373,19 +373,29 @@ export class McpManager { if (needsOAuth) { OAuthClient.initialize(this.features.workspace, this.features.logging) - const bearer = await OAuthClient.getValidAccessToken(base, { - interactive: authIntent === 'interactive', - }) - // add authorization header if we are able to obtain a bearer token - if (bearer) { - headers = { ...headers, Authorization: `Bearer ${bearer}` } - } else if (authIntent === 'silent') { - // In silent mode we never launch a browser. If we cannot obtain a token - // from cache/refresh, surface a clear auth-required error and stop here. - throw new AgenticChatError( - `MCP: server '${serverName}' requires OAuth. Open "Edit MCP Server" and save to sign in.`, - 'MCPServerAuthFailed' - ) + try { + const bearer = await OAuthClient.getValidAccessToken(base, { + interactive: authIntent === AuthIntent.Interactive, + }) + if (bearer) { + headers = { ...headers, Authorization: `Bearer ${bearer}` } + } else if (authIntent === AuthIntent.Silent) { + throw new AgenticChatError( + `MCP: server '${serverName}' requires OAuth. Open "Edit MCP Server" and save to sign in.`, + 'MCPServerAuthFailed' + ) + } + } catch (e: any) { + const msg = e?.message || '' + const short = /authorization_timed_out/i.test(msg) + ? 'Sign-in timed out. Please try again.' + : /Authorization error|PKCE|access_denied|login|consent|token exchange failed/i.test( + msg + ) + ? 'Sign-in was cancelled or failed. Please try again.' + : `OAuth failed: ${msg}` + + throw new AgenticChatError(`MCP: ${short}`, 'MCPServerAuthFailed') } } @@ -1156,7 +1166,8 @@ export class McpManager { */ public async removeServerFromConfigFile(serverName: string): Promise { try { - const cfg = this.mcpServers.get(serverName) + const sanitized = sanitizeName(serverName) + const cfg = this.mcpServers.get(sanitized) if (!cfg || !cfg.__configPath__) { this.features.logging.warn( `Cannot remove config for server '${serverName}': Config not found or missing path` @@ -1164,7 +1175,7 @@ export class McpManager { return } - const unsanitizedName = this.serverNameMapping.get(serverName) || serverName + const unsanitizedName = this.serverNameMapping.get(sanitized) || serverName // Remove from agent config if (unsanitizedName && this.agentConfig) { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.test.ts index 43f68302eb..08f8f1dd5c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.test.ts @@ -113,7 +113,9 @@ describe('OAuthClient getValidAccessToken()', () => { stubFileSystem(cachedToken, cachedReg) - const token = await OAuthClient.getValidAccessToken(new URL('https://api.example.com/mcp')) + const token = await OAuthClient.getValidAccessToken(new URL('https://api.example.com/mcp'), { + interactive: true, + }) expect(token).to.equal('cached_access') expect((http.createServer as any).calledOnce).to.be.true }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts index 86bc7ba027..1e9c8745d3 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts @@ -9,6 +9,7 @@ import * as path from 'path' import { spawn } from 'child_process' import { URL, URLSearchParams } from 'url' import * as http from 'http' +import * as os from 'os' import { Logger, Workspace } from '@aws/language-server-runtimes/server-interface' interface Token { @@ -46,9 +47,9 @@ export class OAuthClient { */ public static async getValidAccessToken( mcpBase: URL, - opts: { interactive?: boolean } = { interactive: true } + opts: { interactive?: boolean } = { interactive: false } ): Promise { - const interactive = opts?.interactive !== false + const interactive = opts?.interactive === true const key = this.computeKey(mcpBase) const regPath = path.join(this.cacheDir, `${key}.registration.json`) const tokPath = path.join(this.cacheDir, `${key}.token.json`) @@ -333,6 +334,7 @@ export class OAuthClient { redirectUri: string, server: http.Server ): Promise { + const DEFAULT_PKCE_TIMEOUT_MS = 20_000 // a) generate PKCE params const verifier = this.b64url(crypto.randomBytes(32)) const challenge = this.b64url(crypto.createHash('sha256').update(verifier).digest()) @@ -353,7 +355,10 @@ export class OAuthClient { const opener = process.platform === 'win32' - ? { cmd: 'cmd', args: ['/c', 'start', authz.toString()] } + ? { + cmd: 'cmd', + args: ['/c', 'start', '', `"${authz.toString().replace(/"/g, '""')}"`], + } : process.platform === 'darwin' ? { cmd: 'open', args: [authz.toString()] } : { cmd: 'xdg-open', args: [authz.toString()] } @@ -361,17 +366,26 @@ export class OAuthClient { void spawn(opener.cmd, opener.args, { detached: true, stdio: 'ignore' }).unref() // c) wait for code on our loopback - const { code, rxState, err } = await new Promise<{ code: string; rxState: string; err?: string }>(resolve => { + const waitForFlow = new Promise<{ code: string; rxState: string; err?: string; errDesc?: string }>(resolve => { server.on('request', (req, res) => { const u = new URL(req.url || '/', redirectUri) const c = u.searchParams.get('code') || '' const s = u.searchParams.get('state') || '' const e = u.searchParams.get('error') || undefined + const ed = u.searchParams.get('error_description') || undefined res.writeHead(200, { 'content-type': 'text/html' }).end('

You may close this tab.

') - resolve({ code: c, rxState: s, err: e }) + resolve({ code: c, rxState: s, err: e, errDesc: ed }) }) }) - if (err) throw new Error(`Authorization error: ${err}`) + const { code, rxState, err, errDesc } = await Promise.race([ + waitForFlow, + new Promise((_, reject) => + setTimeout(() => reject(new Error('authorization_timed_out')), DEFAULT_PKCE_TIMEOUT_MS) + ), + ]) + if (err) { + throw new Error(`Authorization error: ${err}${errDesc ? ` - ${errDesc}` : ''}`) + } if (!code || rxState !== state) throw new Error('Invalid authorization response (state mismatch)') // d) exchange code for token @@ -438,12 +452,7 @@ export class OAuthClient { } /** Directory for caching registration + tokens */ - private static readonly cacheDir = path.join( - process.env.HOME || process.env.USERPROFILE || '.', - '.aws', - 'sso', - 'cache' - ) + private static readonly cacheDir = path.join(os.homedir(), '.aws', 'sso', 'cache') /** * Await server.listen() but reject if it emits 'error' (eg EADDRINUSE), From b99df82826d0ba1a1d52df578cb80674c90505b9 Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Mon, 25 Aug 2025 14:31:41 -0700 Subject: [PATCH 029/158] feat: update MCP manager and utilities (#2158) Co-authored-by: Boyu --- .../agenticChat/tools/mcp/mcpManager.test.ts | 15 ++- .../agenticChat/tools/mcp/mcpManager.ts | 24 ---- .../agenticChat/tools/mcp/mcpUtils.test.ts | 6 + .../agenticChat/tools/mcp/mcpUtils.ts | 114 +++++++----------- 4 files changed, 56 insertions(+), 103 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts index 7b239abad0..456b8934df 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts @@ -368,7 +368,7 @@ describe('removeServer()', () => { expect((mgr as any).clients.has('x')).to.be.false }) - it('removes server from all config files', async () => { + it('removes server from agent config', async () => { const mgr = await McpManager.init([], features) const dummy = new Client({ name: 'c', version: 'v' }) ;(mgr as any).clients.set('x', dummy) @@ -395,14 +395,13 @@ describe('removeServer()', () => { await mgr.removeServer('x') - // Verify that writeFile was called for each config path (2 workspace + 1 global) - expect(writeFileStub.callCount).to.equal(3) + // Verify that saveAgentConfig was called + expect(saveAgentConfigStub.calledOnce).to.be.true + expect((mgr as any).clients.has('x')).to.be.false - // Verify the content of the writes (should have removed the server) - writeFileStub.getCalls().forEach(call => { - const content = JSON.parse(call.args[1]) - expect(content.mcpServers).to.not.have.property('x') - }) + // Verify server was removed from agent config + expect((mgr as any).agentConfig.mcpServers).to.not.have.property('x') + expect((mgr as any).agentConfig.tools).to.not.include('@x') }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index ec7d16d277..b66661c1ea 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -796,30 +796,6 @@ export class McpManager { // Save agent config await saveAgentConfig(this.features.workspace, this.features.logging, this.agentConfig, cfg.__configPath__) - - // Get all config paths and delete the server from each one - const wsUris = this.features.workspace.getAllWorkspaceFolders()?.map(f => f.uri) ?? [] - const wsConfigPaths = getWorkspaceMcpConfigPaths(wsUris) - const globalConfigPath = getGlobalMcpConfigPath(this.features.workspace.fs.getUserHomeDir()) - const allConfigPaths = [...wsConfigPaths, globalConfigPath] - - // Delete the server from all config files - for (const configPath of allConfigPaths) { - try { - await this.mutateConfigFile(configPath, json => { - if (json.mcpServers && json.mcpServers[unsanitizedName]) { - delete json.mcpServers[unsanitizedName] - this.features.logging.info( - `Deleted server '${unsanitizedName}' from config file: ${configPath}` - ) - } - }) - } catch (err) { - this.features.logging.warn( - `Failed to delete server '${unsanitizedName}' from config file ${configPath}: ${err}` - ) - } - } } this.mcpServers.delete(serverName) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts index c50f1d62eb..00ec442517 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts @@ -753,6 +753,12 @@ describe('migrateToAgentConfig', () => { }) it('migrates when no existing configs exist', async () => { + // Create empty MCP config to trigger migration + const mcpDir = path.join(tmpDir, '.aws', 'amazonq') + fs.mkdirSync(mcpDir, { recursive: true }) + const mcpPath = path.join(mcpDir, 'mcp.json') + fs.writeFileSync(mcpPath, JSON.stringify({ mcpServers: {} })) + await migrateToAgentConfig(workspace, logger, mockAgent) // Should create default agent config diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts index ffd2cfb4fc..6c5c8a9998 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts @@ -175,7 +175,9 @@ const DEFAULT_AGENT_RAW = `{ "README.md", ".amazonq/rules/**/*.md" ], - "resources": [] + "resources": [], + "createHooks": [], + "promptHooks": [] }` const DEFAULT_PERSONA_RAW = `{ @@ -840,48 +842,40 @@ async function migrateConfigToAgent( const normalizedPersonaPath = normalizePathFromUri(personaPath, logging) agentPath = normalizePathFromUri(agentPath) - // Check if agent config exists + // Check if config and agent files exist + const configExists = await workspace.fs.exists(normalizedConfigPath).catch(() => false) const agentExists = await workspace.fs.exists(agentPath).catch(() => false) - // Load existing agent config if it exists - let existingAgentConfig: AgentConfig | undefined + // Only migrate if agent file does not exist + // If config exists, migrate from it; if not, create default agent config if (agentExists) { - try { - const raw = (await workspace.fs.readFile(agentPath)).toString().trim() - existingAgentConfig = raw ? JSON.parse(raw) : undefined - } catch (err) { - logging.warn(`Failed to read existing agent config at ${agentPath}: ${err}`) - } + return } // Read MCP server configs directly from file const serverConfigs: Record = {} try { - const configExists = await workspace.fs.exists(normalizedConfigPath) - - if (configExists) { - const raw = (await workspace.fs.readFile(normalizedConfigPath)).toString().trim() - if (raw) { - const config = JSON.parse(raw) - - if (config.mcpServers && typeof config.mcpServers === 'object') { - // Add each server to the serverConfigs - for (const [name, serverConfig] of Object.entries(config.mcpServers)) { - serverConfigs[name] = { - command: (serverConfig as any).command, - args: Array.isArray((serverConfig as any).args) ? (serverConfig as any).args : undefined, - env: typeof (serverConfig as any).env === 'object' ? (serverConfig as any).env : undefined, - initializationTimeout: - typeof (serverConfig as any).initializationTimeout === 'number' - ? (serverConfig as any).initializationTimeout - : undefined, - timeout: - typeof (serverConfig as any).timeout === 'number' - ? (serverConfig as any).timeout - : undefined, - } - logging.info(`Added server ${name} to serverConfigs`) + const raw = (await workspace.fs.readFile(normalizedConfigPath)).toString().trim() + if (raw) { + const config = JSON.parse(raw) + + if (config.mcpServers && typeof config.mcpServers === 'object') { + // Add each server to the serverConfigs + for (const [name, serverConfig] of Object.entries(config.mcpServers)) { + serverConfigs[name] = { + command: (serverConfig as any).command, + args: Array.isArray((serverConfig as any).args) ? (serverConfig as any).args : undefined, + env: typeof (serverConfig as any).env === 'object' ? (serverConfig as any).env : undefined, + initializationTimeout: + typeof (serverConfig as any).initializationTimeout === 'number' + ? (serverConfig as any).initializationTimeout + : undefined, + timeout: + typeof (serverConfig as any).timeout === 'number' + ? (serverConfig as any).timeout + : undefined, } + logging.info(`Added server ${name} to serverConfigs`) } } } @@ -908,46 +902,24 @@ async function migrateConfigToAgent( } // Convert to agent config - const newAgentConfig = convertPersonaToAgent(personaConfig, serverConfigs, agent) - newAgentConfig.includedFiles = ['AmazonQ.md', 'README.md', '.amazonq/rules/**/*.md'] - newAgentConfig.resources = [] // Initialize with empty array - - // Merge with existing config if available - let finalAgentConfig: AgentConfig - if (existingAgentConfig) { - // Keep existing metadata - finalAgentConfig = { - ...existingAgentConfig, - // Merge MCP servers, keeping existing ones if they exist - mcpServers: { - ...newAgentConfig.mcpServers, - ...existingAgentConfig.mcpServers, - }, - // Merge tools lists without duplicates - tools: [...new Set([...existingAgentConfig.tools, ...newAgentConfig.tools])], - allowedTools: [...new Set([...existingAgentConfig.allowedTools, ...newAgentConfig.allowedTools])], - // Merge tool settings, preferring existing ones - toolsSettings: { - ...newAgentConfig.toolsSettings, - ...existingAgentConfig.toolsSettings, - }, - // Keep other properties from existing config - includedFiles: existingAgentConfig.includedFiles || newAgentConfig.includedFiles, - createHooks: existingAgentConfig.createHooks || newAgentConfig.createHooks, - promptHooks: [ - ...new Set([...(existingAgentConfig.promptHooks || []), ...(newAgentConfig.promptHooks || [])]), - ], - resources: [...new Set([...(existingAgentConfig.resources || []), ...(newAgentConfig.resources || [])])], - } - } else { - finalAgentConfig = newAgentConfig - logging.info(`Using new config (no existing config to merge)`) - } + const agentConfig = convertPersonaToAgent(personaConfig, serverConfigs, agent) + + // Parse default values from DEFAULT_AGENT_RAW + const defaultAgent = JSON.parse(DEFAULT_AGENT_RAW) + + // Add complete agent format sections using default values + agentConfig.name = defaultAgent.name + agentConfig.description = defaultAgent.description + agentConfig.version = defaultAgent.version + agentConfig.includedFiles = defaultAgent.includedFiles + agentConfig.resources = defaultAgent.resources + agentConfig.createHooks = defaultAgent.createHooks + agentConfig.promptHooks = defaultAgent.promptHooks // Save agent config try { - await saveAgentConfig(workspace, logging, finalAgentConfig, agentPath) - logging.info(`Successfully ${existingAgentConfig ? 'updated' : 'created'} agent config at ${agentPath}`) + await saveAgentConfig(workspace, logging, agentConfig, agentPath) + logging.info(`Successfully created agent config at ${agentPath}`) } catch (err) { logging.error(`Failed to save agent config to ${agentPath}: ${err}`) throw err From db45d01adba10e8a04d868e1062f899df4f5b7e4 Mon Sep 17 00:00:00 2001 From: Tai Lai Date: Mon, 25 Aug 2025 18:31:23 -0700 Subject: [PATCH 030/158] fix(amazonq): disable typewriter animation (#2160) --- chat-client/package.json | 2 +- chat-client/src/client/mynahUi.ts | 1 + package-lock.json | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/chat-client/package.json b/chat-client/package.json index 59720a0187..e4250d42a1 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -27,7 +27,7 @@ "@aws/chat-client-ui-types": "^0.1.56", "@aws/language-server-runtimes": "^0.2.127", "@aws/language-server-runtimes-types": "^0.1.50", - "@aws/mynah-ui": "^4.36.4" + "@aws/mynah-ui": "^4.36.5" }, "devDependencies": { "@types/jsdom": "^21.1.6", diff --git a/chat-client/src/client/mynahUi.ts b/chat-client/src/client/mynahUi.ts index 527dea06f3..d07d0ab291 100644 --- a/chat-client/src/client/mynahUi.ts +++ b/chat-client/src/client/mynahUi.ts @@ -827,6 +827,7 @@ export const createMynahUi = ( // if we want to max user input as 500000, need to configure the maxUserInput as 500096 maxUserInput: 500096, userInputLengthWarningThreshold: 450000, + disableTypewriterAnimation: true, }, } diff --git a/package-lock.json b/package-lock.json index e65f8e8c96..5fc601a1bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -257,7 +257,7 @@ "@aws/chat-client-ui-types": "^0.1.56", "@aws/language-server-runtimes": "^0.2.127", "@aws/language-server-runtimes-types": "^0.1.50", - "@aws/mynah-ui": "^4.36.4" + "@aws/mynah-ui": "^4.36.5" }, "devDependencies": { "@types/jsdom": "^21.1.6", @@ -4203,9 +4203,9 @@ "link": true }, "node_modules/@aws/mynah-ui": { - "version": "4.36.4", - "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.36.4.tgz", - "integrity": "sha512-vGW4wlNindpr2Ep9x3iuKbrZTXe5KrE8vWpg15DjkN3qK42KMuMEQ67Pqtfgl5EseNYC1ukZm4HIQIMmt+vevA==", + "version": "4.36.5", + "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.36.5.tgz", + "integrity": "sha512-HMXqvSpZT84mpY67ChzRDrd73Y9AFZVZ8RcOJ/rNWIXR44uryfNFg2nrvoP4GSn2P+kU8WIPGChHGmyX9N0UgA==", "hasInstallScript": true, "license": "Apache License 2.0", "dependencies": { From 558bc1ac3e43a3d93e4de31031bb54d270eea27a Mon Sep 17 00:00:00 2001 From: manodnyab <66754471+manodnyab@users.noreply.github.com> Date: Tue, 26 Aug 2025 09:03:56 -0700 Subject: [PATCH 031/158] ci: generation of builds action can be triggered manually (#2157) Co-authored-by: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> --- .github/workflows/create-agent-standalone.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/create-agent-standalone.yml b/.github/workflows/create-agent-standalone.yml index 2807a50aea..f50b5b43b0 100644 --- a/.github/workflows/create-agent-standalone.yml +++ b/.github/workflows/create-agent-standalone.yml @@ -3,10 +3,12 @@ name: Create agent-standalone bundles on: push: branches: [main, feature/*, release/agentic/*] + workflow_dispatch: jobs: build: runs-on: ubuntu-latest + if: github.event_name == 'push' || github.actor_id == github.repository_owner_id steps: - name: Checkout repository From d28df09ae41871430cd53064eac1f3050c95ea84 Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Tue, 26 Aug 2025 10:50:15 -0700 Subject: [PATCH 032/158] fix(amazonq): fix for mcp servers operations to edit server config only (#2165) * fix(amazonq): fix for mcp servers operations to edit server specific config * fix(amazonq): additional mcp server config fixes * fix: resolve test failures * fix: update MCP manager configuration --- .../agenticChat/tools/mcp/mcpManager.test.ts | 36 +++-- .../agenticChat/tools/mcp/mcpManager.ts | 94 +++++++++-- .../agenticChat/tools/mcp/mcpUtils.test.ts | 147 ++++++++++++++++++ .../agenticChat/tools/mcp/mcpUtils.ts | 63 ++++++++ 4 files changed, 306 insertions(+), 34 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts index 456b8934df..0418cea553 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts @@ -239,12 +239,12 @@ describe('callTool()', () => { describe('addServer()', () => { let loadStub: sinon.SinonStub let initOneStub: sinon.SinonStub - let saveAgentConfigStub: sinon.SinonStub + let saveServerSpecificAgentConfigStub: sinon.SinonStub beforeEach(() => { loadStub = stubAgentConfig() initOneStub = stubInitOneServer() - saveAgentConfigStub = sinon.stub(mcpUtils, 'saveAgentConfig').resolves() + saveServerSpecificAgentConfigStub = sinon.stub(mcpUtils, 'saveServerSpecificAgentConfig').resolves() }) afterEach(async () => { @@ -268,7 +268,7 @@ describe('addServer()', () => { await mgr.addServer('newS', newCfg, 'path.json') - expect(saveAgentConfigStub.calledOnce).to.be.true + expect(saveServerSpecificAgentConfigStub.calledOnce).to.be.true expect(initOneStub.calledOnceWith('newS', sinon.match(newCfg))).to.be.true }) @@ -301,14 +301,14 @@ describe('addServer()', () => { await mgr.addServer('httpSrv', httpCfg, 'http.json') - expect(saveAgentConfigStub.calledOnce).to.be.true + expect(saveServerSpecificAgentConfigStub.calledOnce).to.be.true expect(initOneStub.calledOnceWith('httpSrv', sinon.match(httpCfg))).to.be.true }) }) describe('removeServer()', () => { let loadStub: sinon.SinonStub - let saveAgentConfigStub: sinon.SinonStub + let saveServerSpecificAgentConfigStub: sinon.SinonStub let existsStub: sinon.SinonStub let readFileStub: sinon.SinonStub let writeFileStub: sinon.SinonStub @@ -318,7 +318,7 @@ describe('removeServer()', () => { beforeEach(() => { loadStub = stubAgentConfig() - saveAgentConfigStub = sinon.stub(mcpUtils, 'saveAgentConfig').resolves() + saveServerSpecificAgentConfigStub = sinon.stub(mcpUtils, 'saveServerSpecificAgentConfig').resolves() existsStub = sinon.stub(fakeWorkspace.fs, 'exists').resolves(true) readFileStub = sinon .stub(fakeWorkspace.fs, 'readFile') @@ -364,7 +364,7 @@ describe('removeServer()', () => { } await mgr.removeServer('x') - expect(saveAgentConfigStub.calledOnce).to.be.true + expect(saveServerSpecificAgentConfigStub.calledOnce).to.be.true expect((mgr as any).clients.has('x')).to.be.false }) @@ -395,8 +395,8 @@ describe('removeServer()', () => { await mgr.removeServer('x') - // Verify that saveAgentConfig was called - expect(saveAgentConfigStub.calledOnce).to.be.true + // Verify that saveServerSpecificAgentConfig was called + expect(saveServerSpecificAgentConfigStub.calledOnce).to.be.true expect((mgr as any).clients.has('x')).to.be.false // Verify server was removed from agent config @@ -472,11 +472,11 @@ describe('mutateConfigFile()', () => { describe('updateServer()', () => { let loadStub: sinon.SinonStub let initOneStub: sinon.SinonStub - let saveAgentConfigStub: sinon.SinonStub + let saveServerSpecificAgentConfigStub: sinon.SinonStub beforeEach(() => { initOneStub = stubInitOneServer() - saveAgentConfigStub = sinon.stub(mcpUtils, 'saveAgentConfig').resolves() + saveServerSpecificAgentConfigStub = sinon.stub(mcpUtils, 'saveServerSpecificAgentConfig').resolves() }) afterEach(async () => { @@ -519,11 +519,11 @@ describe('updateServer()', () => { const closeStub = sinon.stub(fakeClient, 'close').resolves() initOneStub.resetHistory() - saveAgentConfigStub.resetHistory() + saveServerSpecificAgentConfigStub.resetHistory() await mgr.updateServer('u1', { timeout: 999 }, 'u.json') - expect(saveAgentConfigStub.calledOnce).to.be.true + expect(saveServerSpecificAgentConfigStub.calledOnce).to.be.true expect(closeStub.calledOnce).to.be.true expect(initOneStub.calledOnceWith('u1', sinon.match.has('timeout', 999))).to.be.true }) @@ -559,11 +559,11 @@ describe('updateServer()', () => { const mgr = McpManager.instance initOneStub.resetHistory() - saveAgentConfigStub.resetHistory() + saveServerSpecificAgentConfigStub.resetHistory() await mgr.updateServer('srv', { command: undefined, url: 'https://new.host/mcp' }, 'z.json') - expect(saveAgentConfigStub.calledOnce).to.be.true + expect(saveServerSpecificAgentConfigStub.calledOnce).to.be.true expect(initOneStub.calledOnceWith('srv', sinon.match({ url: 'https://new.host/mcp' }))).to.be.true }) }) @@ -1061,9 +1061,11 @@ describe('listServersAndTools()', () => { describe('updateServerPermission()', () => { let saveAgentConfigStub: sinon.SinonStub + let saveServerSpecificAgentConfigStub: sinon.SinonStub beforeEach(() => { saveAgentConfigStub = sinon.stub(mcpUtils, 'saveAgentConfig').resolves() + saveServerSpecificAgentConfigStub = sinon.stub(mcpUtils, 'saveServerSpecificAgentConfig').resolves() }) afterEach(async () => { @@ -1112,8 +1114,8 @@ describe('updateServerPermission()', () => { __configPath__: '/p', }) - // Verify saveAgentConfig was called - expect(saveAgentConfigStub.calledOnce).to.be.true + // Verify saveServerSpecificAgentConfig was called + expect(saveServerSpecificAgentConfigStub.calledOnce).to.be.true // Verify the tool permission was updated expect(mgr.requiresApproval('srv', 'tool1')).to.be.false diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index b66661c1ea..d0fe8ad9cc 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -26,6 +26,7 @@ import { isEmptyEnv, loadAgentConfig, saveAgentConfig, + saveServerSpecificAgentConfig, sanitizeName, getGlobalAgentConfigPath, getWorkspaceMcpConfigPaths, @@ -730,8 +731,23 @@ export class McpManager { this.agentConfig.tools.push(serverPrefix) } - // Save agent config once with all changes - await saveAgentConfig(this.features.workspace, this.features.logging, this.agentConfig, agentPath) + // Save server-specific changes to agent config + const serverTools = this.agentConfig.tools.filter( + tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) + ) + const serverAllowedTools = this.agentConfig.allowedTools.filter( + tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) + ) + + await saveServerSpecificAgentConfig( + this.features.workspace, + this.features.logging, + serverName, + serverConfig, + serverTools, + serverAllowedTools, + agentPath + ) // Add server tools to tools list after initialization await this.initOneServer(sanitizedName, newCfg, AuthIntent.Interactive) @@ -794,8 +810,16 @@ export class McpManager { return true }) - // Save agent config - await saveAgentConfig(this.features.workspace, this.features.logging, this.agentConfig, cfg.__configPath__) + // Save server removal to agent config + await saveServerSpecificAgentConfig( + this.features.workspace, + this.features.logging, + unsanitizedName, + null, // null indicates server should be removed + [], + [], + cfg.__configPath__ + ) } this.mcpServers.delete(serverName) @@ -853,8 +877,24 @@ export class McpManager { } this.agentConfig.mcpServers[unsanitizedServerName] = updatedConfig - // Save agent config - await saveAgentConfig(this.features.workspace, this.features.logging, this.agentConfig, agentPath) + // Save server-specific changes to agent config + const serverPrefix = `@${unsanitizedServerName}` + const serverTools = this.agentConfig.tools.filter( + tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) + ) + const serverAllowedTools = this.agentConfig.allowedTools.filter( + tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) + ) + + await saveServerSpecificAgentConfig( + this.features.workspace, + this.features.logging, + unsanitizedServerName, + updatedConfig, + serverTools, + serverAllowedTools, + agentPath + ) } const newCfg: MCPServerConfig = { @@ -1057,6 +1097,12 @@ export class McpManager { } } + // Update mcpServerPermissions map immediately to reflect changes + this.mcpServerPermissions.set(serverName, { + enabled: perm.enabled, + toolPerms: perm.toolPerms || {}, + }) + // Update server enabled/disabled state in agent config if (this.agentConfig.mcpServers[unsanitizedServerName]) { this.agentConfig.mcpServers[unsanitizedServerName].disabled = !perm.enabled @@ -1067,17 +1113,28 @@ export class McpManager { serverConfig.disabled = !perm.enabled } - // Save agent config + // Save only server-specific changes to agent config const agentPath = perm.__configPath__ if (agentPath) { - await saveAgentConfig(this.features.workspace, this.features.logging, this.agentConfig, agentPath) - } + // Collect server-specific tools and allowedTools + const serverPrefix = `@${unsanitizedServerName}` + const serverTools = this.agentConfig.tools.filter( + tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) + ) + const serverAllowedTools = this.agentConfig.allowedTools.filter( + tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) + ) - // Update mcpServerPermissions map - this.mcpServerPermissions.set(serverName, { - enabled: perm.enabled, - toolPerms: perm.toolPerms || {}, - }) + await saveServerSpecificAgentConfig( + this.features.workspace, + this.features.logging, + unsanitizedServerName, + this.agentConfig.mcpServers[unsanitizedServerName], + serverTools, + serverAllowedTools, + agentPath + ) + } // enable/disable server if (this.isServerDisabled(serverName)) { @@ -1184,11 +1241,14 @@ export class McpManager { return true }) - // Save agent config - await saveAgentConfig( + // Save server removal to agent config + await saveServerSpecificAgentConfig( this.features.workspace, this.features.logging, - this.agentConfig, + unsanitizedName, + null, // null indicates server should be removed + [], + [], cfg.__configPath__ ) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts index 00ec442517..43843bd110 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts @@ -22,6 +22,7 @@ import { enabledMCP, normalizePathFromUri, saveAgentConfig, + saveServerSpecificAgentConfig, isEmptyEnv, sanitizeName, convertPersonaToAgent, @@ -788,3 +789,149 @@ describe('migrateToAgentConfig', () => { expect(agentConfig.mcpServers).to.have.property('testServer') }) }) +describe('saveServerSpecificAgentConfig', () => { + let tmpDir: string + let workspace: any + let logger: any + + beforeEach(() => { + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'saveServerSpecificTest-')) + workspace = { + fs: { + exists: (p: string) => Promise.resolve(fs.existsSync(p)), + readFile: (p: string) => Promise.resolve(Buffer.from(fs.readFileSync(p))), + writeFile: (p: string, d: string) => Promise.resolve(fs.writeFileSync(p, d)), + mkdir: (d: string, opts: any) => Promise.resolve(fs.mkdirSync(d, { recursive: opts.recursive })), + }, + } + logger = { warn: () => {}, info: () => {}, error: () => {} } + }) + + afterEach(() => { + fs.rmSync(tmpDir, { recursive: true, force: true }) + }) + + it('creates new config file when it does not exist', async () => { + const configPath = path.join(tmpDir, 'agent-config.json') + const serverConfig = { command: 'test-cmd', args: ['arg1'] } + const serverTools = ['@testServer'] + const serverAllowedTools = ['@testServer/tool1'] + + await saveServerSpecificAgentConfig( + workspace, + logger, + 'testServer', + serverConfig, + serverTools, + serverAllowedTools, + configPath + ) + + expect(fs.existsSync(configPath)).to.be.true + const content = JSON.parse(fs.readFileSync(configPath, 'utf-8')) + expect(content.mcpServers.testServer).to.deep.equal(serverConfig) + expect(content.tools).to.include('@testServer') + expect(content.allowedTools).to.include('@testServer/tool1') + }) + + it('updates existing config file', async () => { + const configPath = path.join(tmpDir, 'agent-config.json') + + // Create existing config + const existingConfig = { + name: 'existing-agent', + version: '1.0.0', + description: 'Existing agent', + mcpServers: { + existingServer: { command: 'existing-cmd' }, + }, + tools: ['fs_read', '@existingServer'], + allowedTools: ['fs_read'], + toolsSettings: {}, + includedFiles: [], + resources: [], + } + fs.writeFileSync(configPath, JSON.stringify(existingConfig)) + + const serverConfig = { command: 'new-cmd', args: ['arg1'] } + const serverTools = ['@newServer'] + const serverAllowedTools = ['@newServer/tool1'] + + await saveServerSpecificAgentConfig( + workspace, + logger, + 'newServer', + serverConfig, + serverTools, + serverAllowedTools, + configPath + ) + + const content = JSON.parse(fs.readFileSync(configPath, 'utf-8')) + expect(content.name).to.equal('existing-agent') + expect(content.mcpServers.existingServer).to.deep.equal({ command: 'existing-cmd' }) + expect(content.mcpServers.newServer).to.deep.equal(serverConfig) + expect(content.tools).to.include('@newServer') + expect(content.allowedTools).to.include('@newServer/tool1') + }) + + it('removes existing server tools before adding new ones', async () => { + const configPath = path.join(tmpDir, 'agent-config.json') + + // Create existing config with server tools + const existingConfig = { + name: 'test-agent', + version: '1.0.0', + description: 'Test agent', + mcpServers: { + testServer: { command: 'old-cmd' }, + }, + tools: ['fs_read', '@testServer', '@testServer/oldTool'], + allowedTools: ['fs_read', '@testServer/oldAllowedTool'], + toolsSettings: {}, + includedFiles: [], + resources: [], + } + fs.writeFileSync(configPath, JSON.stringify(existingConfig)) + + const serverConfig = { command: 'new-cmd' } + const serverTools = ['@testServer'] + const serverAllowedTools = ['@testServer/newTool'] + + await saveServerSpecificAgentConfig( + workspace, + logger, + 'testServer', + serverConfig, + serverTools, + serverAllowedTools, + configPath + ) + + const content = JSON.parse(fs.readFileSync(configPath, 'utf-8')) + expect(content.tools).to.not.include('@testServer/oldTool') + expect(content.allowedTools).to.not.include('@testServer/oldAllowedTool') + expect(content.tools).to.include('@testServer') + expect(content.allowedTools).to.include('@testServer/newTool') + expect(content.tools).to.include('fs_read') + }) + + it('creates parent directories if they do not exist', async () => { + const configPath = path.join(tmpDir, 'nested', 'dir', 'agent-config.json') + const serverConfig = { command: 'test-cmd' } + const serverTools = ['@testServer'] + const serverAllowedTools: string[] = [] + + await saveServerSpecificAgentConfig( + workspace, + logger, + 'testServer', + serverConfig, + serverTools, + serverAllowedTools, + configPath + ) + + expect(fs.existsSync(configPath)).to.be.true + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts index 6c5c8a9998..ef56a54d22 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts @@ -943,6 +943,69 @@ export async function saveAgentConfig( } } +/** + * Save only server-specific changes to agent config file + */ +export async function saveServerSpecificAgentConfig( + workspace: Workspace, + logging: Logger, + serverName: string, + serverConfig: any, + serverTools: string[], + serverAllowedTools: string[], + configPath: string +): Promise { + try { + await workspace.fs.mkdir(path.dirname(configPath), { recursive: true }) + + // Read existing config + let existingConfig: AgentConfig + try { + const raw = await workspace.fs.readFile(configPath) + existingConfig = JSON.parse(raw.toString()) + } catch { + // If file doesn't exist, create minimal config + existingConfig = { + name: 'default-agent', + version: '1.0.0', + description: 'Agent configuration', + mcpServers: {}, + tools: [], + allowedTools: [], + toolsSettings: {}, + includedFiles: [], + resources: [], + } + } + + // Remove existing server tools from arrays + const serverPrefix = `@${serverName}` + existingConfig.tools = existingConfig.tools.filter( + tool => tool !== serverPrefix && !tool.startsWith(`${serverPrefix}/`) + ) + existingConfig.allowedTools = existingConfig.allowedTools.filter( + tool => tool !== serverPrefix && !tool.startsWith(`${serverPrefix}/`) + ) + + if (serverConfig === null) { + // Remove server entirely + delete existingConfig.mcpServers[serverName] + } else { + // Update or add server + existingConfig.mcpServers[serverName] = serverConfig + // Add new server tools + existingConfig.tools.push(...serverTools) + existingConfig.allowedTools.push(...serverAllowedTools) + } + + await workspace.fs.writeFile(configPath, JSON.stringify(existingConfig, null, 2)) + logging.info(`Saved server-specific agent config for ${serverName} to ${configPath}`) + } catch (err: any) { + logging.error(`Failed to save server-specific agent config to ${configPath}: ${err.message}`) + throw err + } +} + export const MAX_TOOL_NAME_LENGTH = 64 /** From bb5f4c6c90566be020a21b32f55741d445509029 Mon Sep 17 00:00:00 2001 From: Shruti Sinha <44882001+shruti0085@users.noreply.github.com> Date: Tue, 26 Aug 2025 12:06:46 -0700 Subject: [PATCH 033/158] fix: allow ci to run on release branches (#2159) Currently release/agentic/* branches used in our release process have rules that require CI to be run. However the corresponding workflows do not actually trigger for release branches. This change ensures no manual overrides are required in the release process and CI mapped with the branch actually runs. --- .github/workflows/lsp-ci.yaml | 4 ++-- .github/workflows/npm-packaging.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lsp-ci.yaml b/.github/workflows/lsp-ci.yaml index bda44ec74a..15f87d2428 100644 --- a/.github/workflows/lsp-ci.yaml +++ b/.github/workflows/lsp-ci.yaml @@ -1,9 +1,9 @@ name: Language Server CI on: push: - branches: [main, dev, feature/*] + branches: [main, dev, feature/*, release/agentic/*] pull_request: - branches: [main, dev, feature/*] + branches: [main, dev, feature/*, release/agentic/*] jobs: test: diff --git a/.github/workflows/npm-packaging.yaml b/.github/workflows/npm-packaging.yaml index 724c9a0c05..d4ce77e07c 100644 --- a/.github/workflows/npm-packaging.yaml +++ b/.github/workflows/npm-packaging.yaml @@ -1,9 +1,9 @@ name: NPM Packaging on: push: - branches: [main, dev, feature/*] + branches: [main, dev, feature/*, release/agentic/*] pull_request: - branches: [main, dev, feature/*] + branches: [main, dev, feature/*, release/agentic/*] jobs: build: From 00e11ff48eafaa0baec48177fa4aa6d60048af2f Mon Sep 17 00:00:00 2001 From: Lei Gao <97199248+leigaol@users.noreply.github.com> Date: Tue, 26 Aug 2025 14:07:47 -0700 Subject: [PATCH 034/158] fix: reduce auto trigger frequency for VSC (#2168) * fix: reduce auto trigger frequency for VSC * fix: skip one unit test * fix: skip unit test --------- Co-authored-by: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> --- .../inline-completion/auto-trigger/autoTrigger.test.ts | 2 +- .../inline-completion/auto-trigger/autoTrigger.ts | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.test.ts index 31bc0a224a..6f96c526de 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.test.ts @@ -158,7 +158,7 @@ describe('Auto Trigger', async () => { assert.strictEqual(getAutoTriggerType(createContentChange('line1\nline2')), undefined) }) }) - describe('Right Context should trigger validation', () => { + describe.skip('Right Context should trigger validation', () => { it('should not trigger when there is immediate right context in VSCode', () => { const params = createBasicParams({ fileContext: createBasicFileContext('console.', 'log()'), diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts index d9dd7f16d5..9fb2efab8e 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts @@ -229,7 +229,12 @@ export const autoTrigger = ( const triggerTypeCoefficient = coefficients.triggerTypeCoefficient[triggerType] ?? 0 const osCoefficient = coefficients.osCoefficient[os] ?? 0 - const charCoefficient = coefficients.charCoefficient[char] ?? 0 + let charCoefficient = coefficients.charCoefficient[char] ?? 0 + // this is a temporary change to lower the auto trigger frequency + if (ide === 'VSCODE') { + charCoefficient = 0 + } + const keyWordCoefficient = coefficients.charCoefficient[keyword] ?? 0 const languageCoefficient = coefficients.languageCoefficient[fileContext.programmingLanguage.languageName] ?? 0 From aa87ae2bd95edc1f38bf90f56093c5bf5ff18c53 Mon Sep 17 00:00:00 2001 From: andrewyuq <89420755+andrewyuq@users.noreply.github.com> Date: Tue, 26 Aug 2025 15:51:07 -0700 Subject: [PATCH 035/158] fix(amazonq): dedupe openTabs supplemental contexts (#2172) --- .../supplementalContextUtil/crossFileContextUtil.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/crossFileContextUtil.ts b/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/crossFileContextUtil.ts index ca5bc40642..06bac73d54 100644 --- a/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/crossFileContextUtil.ts +++ b/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/crossFileContextUtil.ts @@ -209,8 +209,17 @@ export async function fetchOpenTabsContext( }) } + // Dedupe code chunks based on their filePath + content unique key + const seen = new Set() + const deduped = supplementalContexts.filter(item => { + const key = `${item.filePath}:${item.content}` + if (seen.has(key)) return false + seen.add(key) + return true + }) + // DO NOT send code chunk with empty content - return supplementalContexts.filter(item => item.content.trim().length !== 0) + return deduped.filter(item => item.content.trim().length !== 0) } function findBestKChunkMatches(chunkInput: Chunk, chunkReferences: Chunk[], k: number): Chunk[] { From d7b184cb12979877722fa0293e9aebec91ff2c18 Mon Sep 17 00:00:00 2001 From: Boyu Date: Tue, 26 Aug 2025 21:34:11 -0700 Subject: [PATCH 036/158] fix: fix pkce windows url path (#2173) --- .../agenticChat/tools/mcp/mcpManager.ts | 6 ++-- .../tools/mcp/mcpOauthClient.test.ts | 11 +++++-- .../agenticChat/tools/mcp/mcpOauthClient.ts | 29 +++++++------------ 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index d0fe8ad9cc..027e349cf5 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -302,7 +302,7 @@ export class McpManager { cfg: MCPServerConfig, authIntent: AuthIntent = AuthIntent.Silent ): Promise { - const DEFAULT_SERVER_INIT_TIMEOUT_MS = 60_000 + const DEFAULT_SERVER_INIT_TIMEOUT_MS = 120_000 this.setState(serverName, McpServerStatus.INITIALIZING, 0) try { @@ -373,7 +373,7 @@ export class McpManager { } if (needsOAuth) { - OAuthClient.initialize(this.features.workspace, this.features.logging) + OAuthClient.initialize(this.features.workspace, this.features.logging, this.features.lsp) try { const bearer = await OAuthClient.getValidAccessToken(base, { interactive: authIntent === AuthIntent.Interactive, @@ -382,7 +382,7 @@ export class McpManager { headers = { ...headers, Authorization: `Bearer ${bearer}` } } else if (authIntent === AuthIntent.Silent) { throw new AgenticChatError( - `MCP: server '${serverName}' requires OAuth. Open "Edit MCP Server" and save to sign in.`, + `Server '${serverName}' requires OAuth. Click on Save to reauthenticate.`, 'MCPServerAuthFailed' ) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.test.ts index 08f8f1dd5c..ea711319a5 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.test.ts @@ -19,6 +19,12 @@ const fakeLogger = { error: () => {}, } +const fakeLsp = { + window: { + showDocument: sinon.stub().resolves({ success: true }), + }, +} as any + const fakeWorkspace = { fs: { exists: async (_path: string) => false, @@ -93,9 +99,10 @@ describe('OAuthClient getValidAccessToken()', () => { beforeEach(() => { sinon.restore() - OAuthClient.initialize(fakeWorkspace, fakeLogger as any) + OAuthClient.initialize(fakeWorkspace, fakeLogger as any, fakeLsp) sinon.stub(OAuthClient as any, 'computeKey').returns('testkey') stubHttpServer() + ;(fakeLsp.window.showDocument as sinon.SinonStub).resetHistory() }) afterEach(() => sinon.restore()) @@ -117,6 +124,6 @@ describe('OAuthClient getValidAccessToken()', () => { interactive: true, }) expect(token).to.equal('cached_access') - expect((http.createServer as any).calledOnce).to.be.true + expect((fakeLsp.window.showDocument as sinon.SinonStub).called).to.be.false }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts index 1e9c8745d3..2e207c449e 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpOauthClient.ts @@ -10,7 +10,7 @@ import { spawn } from 'child_process' import { URL, URLSearchParams } from 'url' import * as http from 'http' import * as os from 'os' -import { Logger, Workspace } from '@aws/language-server-runtimes/server-interface' +import { Logger, Workspace, Lsp } from '@aws/language-server-runtimes/server-interface' interface Token { access_token: string @@ -35,10 +35,12 @@ interface Registration { export class OAuthClient { private static logger: Logger private static workspace: Workspace + private static lsp: Lsp - public static initialize(ws: Workspace, logger: Logger): void { + public static initialize(ws: Workspace, logger: Logger, lsp: Lsp): void { this.workspace = ws this.logger = logger + this.lsp = lsp } /** @@ -95,10 +97,11 @@ export class OAuthClient { const savedReg = await this.read(regPath) if (savedReg) { const port = Number(new URL(savedReg.redirect_uri).port) + const normalized = `http://127.0.0.1:${port}` server = http.createServer() try { - await this.listen(server, port) - redirectUri = savedReg.redirect_uri + await this.listen(server, port, '127.0.0.1') + redirectUri = normalized this.logger.info(`OAuth: reusing redirect URI ${redirectUri}`) } catch (e: any) { if (e.code === 'EADDRINUSE') { @@ -182,9 +185,9 @@ export class OAuthClient { /** Spin up a one‑time HTTP listener on localhost:randomPort */ private static async buildCallbackServer(): Promise<{ server: http.Server; redirectUri: string }> { const server = http.createServer() - await this.listen(server, 0) + await this.listen(server, 0, '127.0.0.1') const port = (server.address() as any).port as number - return { server, redirectUri: `http://localhost:${port}` } + return { server, redirectUri: `http://127.0.0.1:${port}` } } /** Discover OAuth endpoints by HEAD/WWW‑Authenticate, well‑known, or fallback */ @@ -334,7 +337,7 @@ export class OAuthClient { redirectUri: string, server: http.Server ): Promise { - const DEFAULT_PKCE_TIMEOUT_MS = 20_000 + const DEFAULT_PKCE_TIMEOUT_MS = 90_000 // a) generate PKCE params const verifier = this.b64url(crypto.randomBytes(32)) const challenge = this.b64url(crypto.createHash('sha256').update(verifier).digest()) @@ -353,17 +356,7 @@ export class OAuthClient { state: state, }).toString() - const opener = - process.platform === 'win32' - ? { - cmd: 'cmd', - args: ['/c', 'start', '', `"${authz.toString().replace(/"/g, '""')}"`], - } - : process.platform === 'darwin' - ? { cmd: 'open', args: [authz.toString()] } - : { cmd: 'xdg-open', args: [authz.toString()] } - - void spawn(opener.cmd, opener.args, { detached: true, stdio: 'ignore' }).unref() + await this.lsp.window.showDocument({ uri: authz.toString(), external: true }) // c) wait for code on our loopback const waitForFlow = new Promise<{ code: string; rxState: string; err?: string; errDesc?: string }>(resolve => { From 8600c524877abb459e9338399352446c0dcff6f0 Mon Sep 17 00:00:00 2001 From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> Date: Wed, 27 Aug 2025 09:14:48 -0700 Subject: [PATCH 037/158] feat: Auto fetch models from listAvailableModels API (#2171) * Updating the model of listAvailableModels (#2064) * fix(amazonq): fix flickering issue for model selection dropdown and agenticCoding toggle (#2065) * fix(amazonq): fix flickering issue for modelId and agenticCoding * fix(amazonq): Fixing flaky tests * feat(amazonq): Fetching models from backend and adding cache implementation. (#2075) * fix: removing and refactoring legacy code before implementing model selection * feat(amazonq): adding cache implementation and fetching models from listAvailableModels api * feat(amazonq): adding selected model in error case * feat(amazonq): adding test cases * fix: addressing comments * fix: fixing test cases and adding modelName to models * fix: minor edits * fix: minor edits * fix: minor modifications in logs * fix: adding default model if api throws any errors * fix: refactoring code * fix: Improve model selection fallback logic when user's preferred model is unavailable (#2089) * fix: if user preferred model does not exist, fall back to default model * fix: minor test changes * fix: to support backward compatibility for vs and eclipse, adding back modelSelection in chat-client (#2095) * fix: check available models from backend before selecting default model from fallback models (#2102) * feat(amazonq): use model display names (#2123) * fix: cached model list should be invalidated on sign out (#2131) * fix: cached model list should be invalidated on sign out * fix test * avoid throwing error * fix: adding default modelId and setting cache ttl to 30 minutes (#2161) * fix: adding defaultmodelId and setting cache ttl to 30 minutes * fix: fixing tests * fix: updating comments * Updating the model of listAvailableModels (#2064) * fix(amazonq): fix flickering issue for model selection dropdown and agenticCoding toggle (#2065) * fix(amazonq): fix flickering issue for modelId and agenticCoding * fix(amazonq): Fixing flaky tests * feat(amazonq): Fetching models from backend and adding cache implementation. (#2075) * fix: removing and refactoring legacy code before implementing model selection * feat(amazonq): adding cache implementation and fetching models from listAvailableModels api * feat(amazonq): adding selected model in error case * feat(amazonq): adding test cases * fix: addressing comments * fix: fixing test cases and adding modelName to models * fix: minor edits * fix: minor edits * fix: minor modifications in logs * fix: adding default model if api throws any errors * fix: refactoring code * fix: Improve model selection fallback logic when user's preferred model is unavailable (#2089) * fix: if user preferred model does not exist, fall back to default model * fix: minor test changes * fix: to support backward compatibility for vs and eclipse, adding back modelSelection in chat-client (#2095) * fix: check available models from backend before selecting default model from fallback models (#2102) * feat(amazonq): use model display names (#2123) * fix: cached model list should be invalidated on sign out (#2131) * fix: cached model list should be invalidated on sign out * fix test * avoid throwing error * fix: adding default modelId and setting cache ttl to 30 minutes (#2161) * fix: adding defaultmodelId and setting cache ttl to 30 minutes * fix: fixing tests * fix: updating comments * fix: lint issue while resolving merge conflicts --------- Co-authored-by: Tai Lai --- chat-client/src/client/chat.ts | 15 - chat-client/src/client/mynahUi.test.ts | 4 +- chat-client/src/client/mynahUi.ts | 23 +- .../src/client/tabs/tabFactory.test.ts | 7 +- chat-client/src/client/tabs/tabFactory.ts | 7 +- .../src/client/texts/modelSelection.test.ts | 51 +-- .../src/client/texts/modelSelection.ts | 14 +- .../sigv4/codewhisperersigv4client.d.ts | 2 +- .../client/token/bearer-token-service.json | 15 + .../token/codewhispererbearertokenclient.d.ts | 10 + .../agenticChat/agenticChatController.test.ts | 330 +++++++++++------- .../agenticChat/agenticChatController.ts | 163 ++++++--- .../constants/modelSelection.test.ts | 58 +-- .../agenticChat/constants/modelSelection.ts | 19 +- .../agenticChat/tools/chatDb/chatDb.test.ts | 69 +++- .../agenticChat/tools/chatDb/chatDb.ts | 51 ++- .../agenticChat/tools/chatDb/util.ts | 12 + .../utils/agenticChatControllerHelper.ts | 16 - .../AmazonQTokenServiceManager.ts | 5 + .../src/shared/codeWhispererService.ts | 7 + .../src/shared/constants.ts | 2 + 21 files changed, 555 insertions(+), 325 deletions(-) delete mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/utils/agenticChatControllerHelper.ts diff --git a/chat-client/src/client/chat.ts b/chat-client/src/client/chat.ts index d090a33f70..58519d96ef 100644 --- a/chat-client/src/client/chat.ts +++ b/chat-client/src/client/chat.ts @@ -116,7 +116,6 @@ import { InboundChatApi, createMynahUi } from './mynahUi' import { TabFactory } from './tabs/tabFactory' import { ChatClientAdapter } from '../contracts/chatClientAdapter' import { toMynahContextCommand, toMynahIcon } from './utils' -import { modelSelectionForRegion } from './texts/modelSelection' const getDefaultTabConfig = (agenticMode?: boolean) => { return { @@ -264,20 +263,6 @@ export const createChat = ( return option }), }) - } else if (message.params.region) { - // TODO: This can be removed after all clients support aws/chat/listAvailableModels - // get all tabs and update region - const allExistingTabs: MynahUITabStoreModel = mynahUi.getAllTabs() - for (const tabId in allExistingTabs) { - const options = mynahUi.getTabData(tabId).getStore()?.promptInputOptions - mynahUi.updateStore(tabId, { - promptInputOptions: options?.map(option => - option.id === 'model-selection' - ? modelSelectionForRegion[message.params.region] - : option - ), - }) - } } else { tabFactory.setInfoMessages((message.params as ChatOptionsUpdateParams).chatNotifications) } diff --git a/chat-client/src/client/mynahUi.test.ts b/chat-client/src/client/mynahUi.test.ts index 31e64f0e76..727805ebbc 100644 --- a/chat-client/src/client/mynahUi.test.ts +++ b/chat-client/src/client/mynahUi.test.ts @@ -260,7 +260,8 @@ describe('MynahUI', () => { sinon.assert.calledThrice(updateStoreSpy) }) - it('should create a new tab if current tab is loading', () => { + it('should create a new tab if current tab is loading', function (done) { + this.timeout(8000) // clear create tab stub since set up process calls it twice createTabStub.resetHistory() getAllTabsStub.returns({ 'tab-1': { store: { loadingChat: true } } }) @@ -274,6 +275,7 @@ describe('MynahUI', () => { sinon.assert.calledOnceWithExactly(createTabStub, false) sinon.assert.calledThrice(updateStoreSpy) + done() }) it('should not create a new tab if one exists already', () => { diff --git a/chat-client/src/client/mynahUi.ts b/chat-client/src/client/mynahUi.ts index d07d0ab291..15cbeae7ff 100644 --- a/chat-client/src/client/mynahUi.ts +++ b/chat-client/src/client/mynahUi.ts @@ -151,11 +151,20 @@ export const handlePromptInputChange = (mynahUi: MynahUI, tabId: string, options } } + const updatedPromptInputOptions = promptInputOptions?.map(option => { + option.value = optionsValues[option.id] + return option + }) + mynahUi.updateStore(tabId, { - promptInputOptions: promptInputOptions?.map(option => { - option.value = optionsValues[option.id] - return option - }), + promptInputOptions: updatedPromptInputOptions, + }) + + // Store the updated values in tab defaults for new tabs + mynahUi.updateTabDefaults({ + store: { + promptInputOptions: updatedPromptInputOptions, + }, }) } @@ -414,6 +423,12 @@ export const createMynahUi = ( } const tabStore = mynahUi.getTabData(tabId).getStore() + const storedPromptInputOptions = mynahUi.getTabDefaults().store?.promptInputOptions + + // Retrieve stored model selection and pair programming mode from defaults + if (storedPromptInputOptions) { + defaultTabConfig.promptInputOptions = storedPromptInputOptions + } // Tabs can be opened through different methods, including server-initiated 'openTab' requests. // The 'openTab' request is specifically used for loading historical chat sessions with pre-existing messages. diff --git a/chat-client/src/client/tabs/tabFactory.test.ts b/chat-client/src/client/tabs/tabFactory.test.ts index c398c709eb..815e81a22e 100644 --- a/chat-client/src/client/tabs/tabFactory.test.ts +++ b/chat-client/src/client/tabs/tabFactory.test.ts @@ -2,7 +2,7 @@ import { ChatHistory } from '../features/history' import { TabFactory } from './tabFactory' import * as assert from 'assert' import { pairProgrammingPromptInput } from '../texts/pairProgramming' -import { modelSelectionForRegion } from '../texts/modelSelection' +import { modelSelection } from '../texts/modelSelection' describe('tabFactory', () => { describe('getDefaultTabData', () => { @@ -92,10 +92,7 @@ describe('tabFactory', () => { const result = tabFactory.createTab(false) - assert.deepStrictEqual(result.promptInputOptions, [ - pairProgrammingPromptInput, - modelSelectionForRegion['us-east-1'], - ]) + assert.deepStrictEqual(result.promptInputOptions, [pairProgrammingPromptInput, modelSelection]) }) it('should not include model selection when only agentic mode is enabled', () => { diff --git a/chat-client/src/client/tabs/tabFactory.ts b/chat-client/src/client/tabs/tabFactory.ts index 3a6012471a..6df349896c 100644 --- a/chat-client/src/client/tabs/tabFactory.ts +++ b/chat-client/src/client/tabs/tabFactory.ts @@ -11,7 +11,7 @@ import { disclaimerCard } from '../texts/disclaimer' import { ChatMessage } from '@aws/language-server-runtimes-types' import { ChatHistory } from '../features/history' import { pairProgrammingPromptInput, programmerModeCard } from '../texts/pairProgramming' -import { modelSelectionForRegion } from '../texts/modelSelection' +import { modelSelection } from '../texts/modelSelection' export type DefaultTabData = MynahUIDataModel @@ -52,10 +52,7 @@ export class TabFactory { ...this.getDefaultTabData(), ...(disclaimerCardActive ? { promptInputStickyCard: disclaimerCard } : {}), promptInputOptions: this.agenticMode - ? [ - pairProgrammingPromptInput, - ...(this.modelSelectionEnabled ? [modelSelectionForRegion['us-east-1']] : []), - ] + ? [pairProgrammingPromptInput, ...(this.modelSelectionEnabled ? [modelSelection] : [])] : [], cancelButtonWhenLoading: this.agenticMode, // supported for agentic chat only } diff --git a/chat-client/src/client/texts/modelSelection.test.ts b/chat-client/src/client/texts/modelSelection.test.ts index c36dfad976..abd010436e 100644 --- a/chat-client/src/client/texts/modelSelection.test.ts +++ b/chat-client/src/client/texts/modelSelection.test.ts @@ -1,60 +1,11 @@ import * as assert from 'assert' -import { - BedrockModel, - modelSelectionForRegion, - getModelSelectionChatItem, - modelUnavailableBanner, - modelThrottledBanner, -} from './modelSelection' +import { getModelSelectionChatItem, modelUnavailableBanner, modelThrottledBanner } from './modelSelection' import { ChatItemType } from '@aws/mynah-ui' /** * Tests for modelSelection functionality - * - * Note: Some tests are for deprecated code (marked with 'legacy') that is maintained - * for backward compatibility with older clients. These should be removed once - * all clients have been updated to use the new API (aws/chat/listAvailableModels). */ describe('modelSelection', () => { - describe('BedrockModel enum (legacy)', () => { - it('should have the correct model IDs', () => { - assert.strictEqual(BedrockModel.CLAUDE_3_7_SONNET_20250219_V1_0, 'CLAUDE_3_7_SONNET_20250219_V1_0') - assert.strictEqual(BedrockModel.CLAUDE_SONNET_4_20250514_V1_0, 'CLAUDE_SONNET_4_20250514_V1_0') - }) - }) - - describe('modelSelectionForRegion (legacy)', () => { - it('should provide all models for us-east-1 region', () => { - const usEast1ModelSelection = modelSelectionForRegion['us-east-1'] - assert.ok(usEast1ModelSelection, 'usEast1ModelSelection should exist') - assert.ok(usEast1ModelSelection.type === 'select', 'usEast1ModelSelection should be type select') - assert.ok(Array.isArray(usEast1ModelSelection.options), 'options should be an array') - assert.strictEqual(usEast1ModelSelection.options.length, 2, 'should have 2 options') - - const modelIds = usEast1ModelSelection.options.map(option => option.value) - assert.ok(modelIds.includes(BedrockModel.CLAUDE_SONNET_4_20250514_V1_0), 'should include Claude Sonnet 4') - assert.ok( - modelIds.includes(BedrockModel.CLAUDE_3_7_SONNET_20250219_V1_0), - 'should include Claude Sonnet 3.7' - ) - }) - - it('should provide all models for eu-central-1 region', () => { - const euCentral1ModelSelection = modelSelectionForRegion['eu-central-1'] - assert.ok(euCentral1ModelSelection, 'euCentral1ModelSelection should exist') - assert.ok(euCentral1ModelSelection.type === 'select', 'euCentral1ModelSelection should be type select') - assert.ok(Array.isArray(euCentral1ModelSelection.options), 'options should be an array') - assert.strictEqual(euCentral1ModelSelection.options.length, 2, 'should have 2 option') - - const modelIds = euCentral1ModelSelection.options.map(option => option.value) - assert.ok(modelIds.includes(BedrockModel.CLAUDE_SONNET_4_20250514_V1_0), 'should include Claude Sonnet 4') - assert.ok( - modelIds.includes(BedrockModel.CLAUDE_3_7_SONNET_20250219_V1_0), - 'should include Claude Sonnet 3.7' - ) - }) - }) - describe('getModelSelectionChatItem', () => { it('should return a chat item with the correct model name', () => { const modelName = 'Claude Sonnet 4' diff --git a/chat-client/src/client/texts/modelSelection.ts b/chat-client/src/client/texts/modelSelection.ts index 18df833419..a1d0247875 100644 --- a/chat-client/src/client/texts/modelSelection.ts +++ b/chat-client/src/client/texts/modelSelection.ts @@ -13,7 +13,7 @@ type ModelDetails = { } const modelRecord: Record = { - [BedrockModel.CLAUDE_3_7_SONNET_20250219_V1_0]: { label: 'Claude Sonnet 3.7' }, + [BedrockModel.CLAUDE_3_7_SONNET_20250219_V1_0]: { label: 'Claude 3.7 Sonnet' }, [BedrockModel.CLAUDE_SONNET_4_20250514_V1_0]: { label: 'Claude Sonnet 4' }, } @@ -22,24 +22,16 @@ const modelOptions = Object.entries(modelRecord).map(([value, { label }]) => ({ label, })) -const modelSelection: ChatItemFormItem = { +export const modelSelection: ChatItemFormItem = { type: 'select', id: 'model-selection', - options: modelOptions, mandatory: true, hideMandatoryIcon: true, + options: modelOptions, border: false, autoWidth: true, } -/** - * @deprecated use aws/chat/listAvailableModels server request instead - */ -export const modelSelectionForRegion: Record = { - 'us-east-1': modelSelection, - 'eu-central-1': modelSelection, -} - export const getModelSelectionChatItem = (modelName: string): ChatItem => ({ type: ChatItemType.DIRECTIVE, contentHorizontalAlignment: 'center', diff --git a/server/aws-lsp-codewhisperer/src/client/sigv4/codewhisperersigv4client.d.ts b/server/aws-lsp-codewhisperer/src/client/sigv4/codewhisperersigv4client.d.ts index 308ead42ee..6cb67d3ef8 100644 --- a/server/aws-lsp-codewhisperer/src/client/sigv4/codewhisperersigv4client.d.ts +++ b/server/aws-lsp-codewhisperer/src/client/sigv4/codewhisperersigv4client.d.ts @@ -3,7 +3,7 @@ * THIS FILE IS AUTOGENERATED BY 'generateServiceClient.ts'. * DO NOT EDIT BY HAND. */ - + import {Request} from 'aws-sdk/lib/request'; import {Response} from 'aws-sdk/lib/response'; import {AWSError} from 'aws-sdk/lib/error'; diff --git a/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json b/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json index a5704fca16..7e0533b0f5 100644 --- a/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json +++ b/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json @@ -3622,6 +3622,10 @@ "shape": "Models", "documentation": "

List of available models

" }, + "defaultModel": { + "shape": "Model", + "documentation": "

Default model set by the client

" + }, "nextToken": { "shape": "Base64EncodedPaginationToken", "documentation": "

Token for retrieving the next page of results

" @@ -3955,6 +3959,10 @@ "shape": "ModelId", "documentation": "

Unique identifier for the model

" }, + "modelName": { + "shape": "ModelName", + "documentation": "

User-facing display name

" + }, "description": { "shape": "Description", "documentation": "

Description of the model

" @@ -3972,6 +3980,13 @@ "min": 1, "pattern": "[a-zA-Z0-9_:.-]+" }, + "ModelName": { + "type": "string", + "documentation": "

Identifier for the model Name

", + "max": 1024, + "min": 1, + "pattern": "[a-zA-Z0-9-_.]+" + }, "ModelMetadata": { "type": "structure", "members": { diff --git a/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts b/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts index c885612888..34aa384c14 100644 --- a/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts +++ b/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts @@ -3,6 +3,7 @@ * THIS FILE IS AUTOGENERATED BY 'generateServiceClient.ts'. * DO NOT EDIT BY HAND. */ + import {Request} from 'aws-sdk/lib/request'; import {Response} from 'aws-sdk/lib/response'; import {AWSError} from 'aws-sdk/lib/error'; @@ -1132,6 +1133,10 @@ declare namespace CodeWhispererBearerTokenClient { * List of available models */ models: Models; + /** + * Default model set by the client + */ + defaultModel?: Model; /** * Token for retrieving the next page of results */ @@ -1240,6 +1245,10 @@ declare namespace CodeWhispererBearerTokenClient { * Unique identifier for the model */ modelId: ModelId; + /** + * User-facing display name + */ + modelName?: ModelName; /** * Description of the model */ @@ -1250,6 +1259,7 @@ declare namespace CodeWhispererBearerTokenClient { modelMetadata?: ModelMetadata; } export type ModelId = string; + export type ModelName = string; export interface ModelMetadata { /** * Maximum number of input tokens the model can process diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts index a307ce3fc6..c1842a6008 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts @@ -32,6 +32,7 @@ import { InlineChatResult, CancellationTokenSource, ContextCommand, + ChatUpdateParams, } from '@aws/language-server-runtimes/server-interface' import { TestFeatures } from '@aws/language-server-runtimes/testing' import * as assert from 'assert' @@ -56,7 +57,7 @@ import { LocalProjectContextController } from '../../shared/localProjectContextC import { CancellationError } from '@aws/lsp-core' import { ToolApprovalException } from './tools/toolShared' import * as constants from './constants/constants' -import { GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT, GENERIC_ERROR_MS } from './constants/constants' +import { DEFAULT_MODEL_ID, GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT, GENERIC_ERROR_MS } from './constants/constants' import { MISSING_BEARER_TOKEN_ERROR } from '../../shared/constants' import { AmazonQError, @@ -368,17 +369,6 @@ describe('AgenticChatController', () => { sinon.assert.calledWithExactly(activeTabSpy.set, mockTabId) }) - it('onTabAdd updates model ID in chat options and session', () => { - const modelId = 'test-model-id' - sinon.stub(ChatDatabase.prototype, 'getModelId').returns(modelId) - chatController.onTabAdd({ tabId: mockTabId }) - - sinon.assert.calledWithExactly(testFeatures.chat.chatOptionsUpdate, { modelId, tabId: mockTabId }) - - const session = chatSessionManagementService.getSession(mockTabId).data - assert.strictEqual(session!.modelId, modelId) - }) - it('onTabChange sets active tab id in telemetryController and emits metrics', () => { chatController.onTabChange({ tabId: mockTabId }) @@ -3003,153 +2993,251 @@ ${' '.repeat(8)}} }) describe('onListAvailableModels', () => { - let tokenServiceManagerStub: sinon.SinonStub + let isCachedModelsValidStub: sinon.SinonStub + let getCachedModelsStub: sinon.SinonStub + let setCachedModelsStub: sinon.SinonStub + let getConnectionTypeStub: sinon.SinonStub + let getActiveProfileArnStub: sinon.SinonStub + let getCodewhispererServiceStub: sinon.SinonStub + let listAvailableModelsStub: sinon.SinonStub beforeEach(() => { - // Create a session with a model ID + // Create a session chatController.onTabAdd({ tabId: mockTabId }) - const session = chatSessionManagementService.getSession(mockTabId).data! - session.modelId = 'CLAUDE_3_7_SONNET_20250219_V1_0' - // Stub the getRegion method - tokenServiceManagerStub = sinon.stub(AmazonQTokenServiceManager.prototype, 'getRegion') + // Stub ChatDatabase methods + isCachedModelsValidStub = sinon.stub(ChatDatabase.prototype, 'isCachedModelsValid') + getCachedModelsStub = sinon.stub(ChatDatabase.prototype, 'getCachedModels') + setCachedModelsStub = sinon.stub(ChatDatabase.prototype, 'setCachedModels') + + // Stub AmazonQTokenServiceManager methods + getConnectionTypeStub = sinon.stub(AmazonQTokenServiceManager.prototype, 'getConnectionType') + getActiveProfileArnStub = sinon.stub(AmazonQTokenServiceManager.prototype, 'getActiveProfileArn') + getCodewhispererServiceStub = sinon.stub(AmazonQTokenServiceManager.prototype, 'getCodewhispererService') + + // Mock listAvailableModels method + listAvailableModelsStub = sinon.stub() + getCodewhispererServiceStub.returns({ + listAvailableModels: listAvailableModelsStub, + }) }) afterEach(() => { - tokenServiceManagerStub.restore() - }) + isCachedModelsValidStub.restore() + getCachedModelsStub.restore() + setCachedModelsStub.restore() + getConnectionTypeStub.restore() + getActiveProfileArnStub.restore() + getCodewhispererServiceStub.restore() + }) + + describe('ListAvailableModels Cache scenarios', () => { + it('should return cached models when cache is valid', async () => { + // Setup valid cache + isCachedModelsValidStub.returns(true) + const cachedData = { + models: [ + { id: 'model1', name: 'Model 1' }, + { id: 'model2', name: 'Model 2' }, + ], + defaultModelId: 'model1', + timestamp: Date.now(), + } + getCachedModelsStub.returns(cachedData) - it('should return all available models for us-east-1 region', async () => { - // Set up the region to be us-east-1 - tokenServiceManagerStub.returns('us-east-1') + const session = chatSessionManagementService.getSession(mockTabId).data! + session.modelId = 'model1' - // Call the method - const params = { tabId: mockTabId } - const result = await chatController.onListAvailableModels(params) + const result = await chatController.onListAvailableModels({ tabId: mockTabId }) - // Verify the result - assert.strictEqual(result.tabId, mockTabId) - assert.strictEqual(result.models.length, 2) - assert.strictEqual(result.selectedModelId, 'CLAUDE_SONNET_4_20250514_V1_0') + // Verify cached data is used + assert.strictEqual(result.tabId, mockTabId) + assert.deepStrictEqual(result.models, cachedData.models) + assert.strictEqual(result.selectedModelId, 'model1') - // Check that the models include both Claude versions - const modelIds = result.models.map(model => model.id) - assert.ok(modelIds.includes('CLAUDE_SONNET_4_20250514_V1_0')) - assert.ok(modelIds.includes('CLAUDE_3_7_SONNET_20250219_V1_0')) - }) + // Verify API was not called + sinon.assert.notCalled(listAvailableModelsStub) + sinon.assert.notCalled(setCachedModelsStub) + }) - it('should return all available models for eu-central-1 region', async () => { - // Set up the region to be eu-central-1 - tokenServiceManagerStub.returns('eu-central-1') + it('should return cached models when cache is valid but has empty models array', async () => { + // Setup cache with empty models + isCachedModelsValidStub.returns(true) + const cachedData = { + models: [], + defaultModelId: undefined, + timestamp: Date.now(), + } + getCachedModelsStub.returns(cachedData) - // Call the method - const params = { tabId: mockTabId } - const result = await chatController.onListAvailableModels(params) + // Should fall back to API call since models array is empty + getConnectionTypeStub.returns('builderId') + getActiveProfileArnStub.returns('test-arn') + listAvailableModelsStub.resolves({ + models: { + model1: { modelId: 'model1' }, + model2: { modelId: 'model2' }, + }, + defaultModel: { modelId: 'model1' }, + }) - // Verify the result - assert.strictEqual(result.tabId, mockTabId) - assert.strictEqual(result.models.length, 2) - assert.strictEqual(result.selectedModelId, 'CLAUDE_SONNET_4_20250514_V1_0') + await chatController.onListAvailableModels({ tabId: mockTabId }) - // Check that the models include both Claude versions - const modelIds = result.models.map(model => model.id) - assert.ok(modelIds.includes('CLAUDE_SONNET_4_20250514_V1_0')) - assert.ok(modelIds.includes('CLAUDE_3_7_SONNET_20250219_V1_0')) - }) + // Verify API was called due to empty cached models + sinon.assert.calledOnce(listAvailableModelsStub) + sinon.assert.calledOnce(setCachedModelsStub) + }) - it('should return all models when region is unknown', async () => { - // Set up the region to be unknown - tokenServiceManagerStub.returns('unknown-region') + it('should return cached models when cache is valid but cachedData is null', async () => { + // Setup cache as valid but returns null + isCachedModelsValidStub.returns(true) + getCachedModelsStub.returns(null) - // Call the method - const params = { tabId: mockTabId } - const result = await chatController.onListAvailableModels(params) + // Should fall back to API call + getConnectionTypeStub.returns('builderId') + getActiveProfileArnStub.returns('test-arn') + listAvailableModelsStub.resolves({ + models: { + model1: { modelId: 'model1' }, + }, + defaultModel: { modelId: 'model1' }, + }) - // Verify the result - assert.strictEqual(result.tabId, mockTabId) - assert.strictEqual(result.models.length, 2) - assert.strictEqual(result.selectedModelId, 'CLAUDE_SONNET_4_20250514_V1_0') + await chatController.onListAvailableModels({ tabId: mockTabId }) + + // Verify API was called + sinon.assert.calledOnce(listAvailableModelsStub) + }) }) - it('should return undefined for selectedModelId when no session data exists', async () => { - // Set up the session to return no session (failure case) - const getSessionStub = sinon.stub(chatSessionManagementService, 'getSession') - getSessionStub.returns({ - data: undefined, - success: false, - error: 'error', + describe('ListAvailableModels API call scenarios', () => { + beforeEach(() => { + // Setup invalid cache to force API call + isCachedModelsValidStub.returns(false) }) - // Call the method - const params = { tabId: 'non-existent-tab' } - const result = await chatController.onListAvailableModels(params) + it('should fetch models from API when cache is invalid', async () => { + getConnectionTypeStub.returns('builderId') + getActiveProfileArnStub.returns('test-profile-arn') - // Verify the result - assert.strictEqual(result.tabId, 'non-existent-tab') - assert.strictEqual(result.models.length, 2) - assert.strictEqual(result.selectedModelId, undefined) + const mockApiResponse = { + models: { + 'claude-3-sonnet': { modelId: 'claude-3-sonnet' }, + 'claude-4-sonnet': { modelId: 'claude-4-sonnet' }, + }, + defaultModel: { modelId: 'claude-3-sonnet' }, + } + listAvailableModelsStub.resolves(mockApiResponse) - getSessionStub.restore() - }) + const result = await chatController.onListAvailableModels({ tabId: mockTabId }) + + // Verify API call was made with correct parameters + sinon.assert.calledOnceWithExactly(listAvailableModelsStub, { + origin: 'IDE', + profileArn: 'test-profile-arn', + }) - it('should fallback to latest available model when saved model is not available in current region', async () => { - // Import the module to stub - const modelSelection = await import('./constants/modelSelection') + // Verify result structure + assert.strictEqual(result.tabId, mockTabId) + assert.strictEqual(result.models.length, 2) + assert.deepStrictEqual(result.models, [ + { id: 'claude-3-sonnet', name: 'claude-3-sonnet' }, + { id: 'claude-4-sonnet', name: 'claude-4-sonnet' }, + ]) - // Create a mock region with only Claude 3.7 - const mockModelOptionsForRegion = { - ...modelSelection.MODEL_OPTIONS_FOR_REGION, - 'test-region-limited': [ - { - id: 'CLAUDE_3_7_SONNET_20250219_V1_0', - name: 'Claude Sonnet 3.7', - }, - ], - } + // Verify cache was updated + sinon.assert.calledOnceWithExactly(setCachedModelsStub, result.models, 'claude-3-sonnet') + }) - // Stub the MODEL_OPTIONS_FOR_REGION - const modelOptionsStub = sinon - .stub(modelSelection, 'MODEL_OPTIONS_FOR_REGION') - .value(mockModelOptionsForRegion) + it('should fall back to hardcoded models when API call fails', async () => { + getConnectionTypeStub.returns('builderId') + listAvailableModelsStub.rejects(new Error('API Error')) - // Set up the region to be the test region (which only has Claude 3.7) - tokenServiceManagerStub.returns('test-region-limited') + const result = await chatController.onListAvailableModels({ tabId: mockTabId }) - // Mock database to return Claude Sonnet 4 (not available in test-region-limited) - const getModelIdStub = sinon.stub(ChatDatabase.prototype, 'getModelId') - getModelIdStub.returns('CLAUDE_SONNET_4_20250514_V1_0') + // Verify fallback to FALLBACK_MODEL_OPTIONS + assert.strictEqual(result.tabId, mockTabId) + assert.strictEqual(result.models.length, 2) // FALLBACK_MODEL_OPTIONS length - // Call the method - const params = { tabId: mockTabId } - const result = await chatController.onListAvailableModels(params) + // Verify cache was not updated due to error + sinon.assert.notCalled(setCachedModelsStub) + }) - // Verify the result falls back to available model - assert.strictEqual(result.tabId, mockTabId) - assert.strictEqual(result.models.length, 1) - assert.strictEqual(result.selectedModelId, 'CLAUDE_3_7_SONNET_20250219_V1_0') + it('should handle API response with no defaultModel', async () => { + getConnectionTypeStub.returns('builderId') - getModelIdStub.restore() - modelOptionsStub.restore() + const mockApiResponse = { + models: { + model1: { modelId: 'model1' }, + }, + defaultModel: undefined, // No default model + } + listAvailableModelsStub.resolves(mockApiResponse) + + const result = await chatController.onListAvailableModels({ tabId: mockTabId }) + + // Verify cache was updated with undefined defaultModelId + sinon.assert.calledOnceWithExactly(setCachedModelsStub, result.models, undefined) + }) }) - it('should use saved model when it is available in current region', async () => { - // Set up the region to be us-east-1 (which has both models) - tokenServiceManagerStub.returns('us-east-1') + describe('Session and model selection scenarios', () => { + beforeEach(() => { + // Setup cache to avoid API calls in these tests + isCachedModelsValidStub.returns(true) + getCachedModelsStub.returns({ + models: [ + { id: 'model1', name: 'Model 1' }, + { id: 'model2', name: 'Model 2' }, + ], + defaultModelId: 'model1', + timestamp: Date.now(), + }) + }) + + it('should return default model when session fails to load', async () => { + const getSessionStub = sinon.stub(chatSessionManagementService, 'getSession') + getSessionStub.returns({ + data: undefined, + success: false, + error: 'Session not found', + }) + + const result = await chatController.onListAvailableModels({ tabId: 'invalid-tab' }) - // Mock database to return Claude 3.7 (available in us-east-1) - const getModelIdStub = sinon.stub(ChatDatabase.prototype, 'getModelId') - getModelIdStub.returns('CLAUDE_3_7_SONNET_20250219_V1_0') + assert.strictEqual(result.tabId, 'invalid-tab') + assert.strictEqual(result.selectedModelId, 'model1') - // Call the method - const params = { tabId: mockTabId } - const result = await chatController.onListAvailableModels(params) + getSessionStub.restore() + }) + + it('should use defaultModelId from cache when session has no modelId', async () => { + const session = chatSessionManagementService.getSession(mockTabId).data! + session.modelId = undefined - // Verify the result uses the saved model - assert.strictEqual(result.tabId, mockTabId) - assert.strictEqual(result.models.length, 2) - assert.strictEqual(result.selectedModelId, 'CLAUDE_3_7_SONNET_20250219_V1_0') + const result = await chatController.onListAvailableModels({ tabId: mockTabId }) - getModelIdStub.restore() + assert.strictEqual(result.selectedModelId, 'model1') // defaultModelId from cache + // Verify session modelId is updated + assert.strictEqual(session.modelId, 'model1') + }) + + it('should fall back to default model when session has no modelId and no defaultModelId in cache', async () => { + getCachedModelsStub.returns({ + models: [{ id: 'model1', name: 'Model 1' }], + defaultModelId: undefined, // No default model + timestamp: Date.now(), + }) + + const session = chatSessionManagementService.getSession(mockTabId).data! + session.modelId = undefined + + const result = await chatController.onListAvailableModels({ tabId: mockTabId }) + + assert.strictEqual(result.selectedModelId, 'claude-sonnet-4') // FALLBACK_MODEL_RECORD[DEFAULT_MODEL_ID].label + // Verify session modelId is updated + assert.strictEqual(session.modelId, 'claude-sonnet-4') + }) }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 991d95a6ad..8cdba3d291 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -24,7 +24,6 @@ import { GREP_SEARCH, FILE_SEARCH, EXECUTE_BASH, - CODE_REVIEW, BUTTON_RUN_SHELL_COMMAND, BUTTON_REJECT_SHELL_COMMAND, BUTTON_REJECT_MCP_TOOL, @@ -67,8 +66,6 @@ import { ListAvailableModelsResult, OpenFileDialogParams, OpenFileDialogResult, -} from '@aws/language-server-runtimes/protocol' -import { ApplyWorkspaceEditParams, ErrorCodes, FeedbackParams, @@ -83,6 +80,7 @@ import { TabBarActionParams, CreatePromptParams, FileClickParams, + Model, } from '@aws/language-server-runtimes/protocol' import { CancellationToken, @@ -222,14 +220,14 @@ import { Message as DbMessage, messageToStreamingMessage, } from './tools/chatDb/util' -import { MODEL_OPTIONS, MODEL_OPTIONS_FOR_REGION } from './constants/modelSelection' +import { FALLBACK_MODEL_OPTIONS, FALLBACK_MODEL_RECORD, BEDROCK_MODEL_TO_MODEL_ID } from './constants/modelSelection' import { DEFAULT_IMAGE_VERIFICATION_OPTIONS, verifyServerImage } from '../../shared/imageVerification' import { sanitize } from '@aws/lsp-core/out/util/path' -import { getLatestAvailableModel } from './utils/agenticChatControllerHelper' import { ActiveUserTracker } from '../../shared/activeUserTracker' import { UserContext } from '../../client/token/codewhispererbearertokenclient' import { CodeWhispererServiceToken } from '../../shared/codeWhispererService' import { DisplayFindings } from './tools/qCodeAnalysis/displayFindings' +import { IDE } from '../../shared/constants' import { IdleWorkspaceManager } from '../workspaceContext/IdleWorkspaceManager' type ChatHandlers = Omit< @@ -352,7 +350,7 @@ export class AgenticChatController implements ChatHandlers { // @ts-ignore this.#features.chat.chatOptionsUpdate({ region }) }) - this.#chatHistoryDb = new ChatDatabase(features) + this.#chatHistoryDb = ChatDatabase.getInstance(features) this.#tabBarController = new TabBarController( features, this.#chatHistoryDb, @@ -681,25 +679,133 @@ export class AgenticChatController implements ChatHandlers { return this.#mcpEventHandler.onMcpServerClick(params) } + /** + * Fetches available models either from cache or API + * If cache is valid (less than 5 minutes old), returns cached models + * If cache is invalid or empty, makes an API call and stores results in cache + * If the API throws errors (e.g., throttling), falls back to default models + */ + async #fetchModelsWithCache(): Promise<{ models: Model[]; defaultModelId?: string; errorFromAPI: boolean }> { + let models: Model[] = [] + let defaultModelId: string | undefined + let errorFromAPI = false + + // Check if cache is valid (less than 5 minutes old) + if (this.#chatHistoryDb.isCachedModelsValid()) { + const cachedData = this.#chatHistoryDb.getCachedModels() + if (cachedData && cachedData.models && cachedData.models.length > 0) { + this.#log('Using cached models, last updated at:', new Date(cachedData.timestamp).toISOString()) + return { + models: cachedData.models, + defaultModelId: cachedData.defaultModelId, + errorFromAPI: false, + } + } + } + + // If cache is invalid or empty, make an API call + this.#log('Cache miss or expired, fetching models from API') + try { + const client = AmazonQTokenServiceManager.getInstance().getCodewhispererService() + const responseResult = await client.listAvailableModels({ + origin: IDE, + profileArn: AmazonQTokenServiceManager.getInstance().getConnectionType() + ? AmazonQTokenServiceManager.getInstance().getActiveProfileArn() + : undefined, + }) + + // Wait for the response to be completed before proceeding + this.#log('Model Response: ', JSON.stringify(responseResult, null, 2)) + models = Object.values(responseResult.models).map(({ modelId, modelName }) => ({ + id: modelId, + name: modelName ?? modelId, + })) + defaultModelId = responseResult.defaultModel?.modelId + + // Cache the models with defaultModelId + this.#chatHistoryDb.setCachedModels(models, defaultModelId) + } catch (err) { + // In case of API throttling or other errors, fall back to hardcoded models + this.#log('Error fetching models from API, using fallback models:', fmtError(err)) + errorFromAPI = true + models = FALLBACK_MODEL_OPTIONS + } + + return { + models, + defaultModelId, + errorFromAPI, + } + } + + /** + * This function handles the model selection process for the chat interface. + * It first attempts to retrieve models from cache or API, then determines the appropriate model to select + * based on the following priority: + * 1. When errors occur or session is invalid: Use the default model as a fallback + * 2. When user has previously selected a model: Use that model (or its mapped version if the model ID has changed) + * 3. When there's a default model from the API: Use the server-recommended default model + * 4. Last resort: Use the newest model defined in modelSelection constants + * + * This ensures users maintain consistent model selection across sessions while also handling + * API failures and model ID migrations gracefully. + */ async onListAvailableModels(params: ListAvailableModelsParams): Promise { - const region = AmazonQTokenServiceManager.getInstance().getRegion() - const models = region && MODEL_OPTIONS_FOR_REGION[region] ? MODEL_OPTIONS_FOR_REGION[region] : MODEL_OPTIONS + // Get models from cache or API + const { models, defaultModelId, errorFromAPI } = await this.#fetchModelsWithCache() + + // Get the first fallback model option as default + const defaultModelOption = FALLBACK_MODEL_OPTIONS[1] + const DEFAULT_MODEL_ID = defaultModelId || defaultModelOption?.id const sessionResult = this.#chatSessionManagementService.getSession(params.tabId) const { data: session, success } = sessionResult - if (!success) { + + // Handle error cases by returning default model + if (!success || errorFromAPI) { return { tabId: params.tabId, models: models, + selectedModelId: DEFAULT_MODEL_ID, } } - const savedModelId = this.#chatHistoryDb.getModelId() - const selectedModelId = - savedModelId && models.some(model => model.id === savedModelId) - ? savedModelId - : getLatestAvailableModel(region).id + // Determine selected model ID based on priority + let selectedModelId: string + let modelId = this.#chatHistoryDb.getModelId() + + // Helper function to get model label from FALLBACK_MODEL_RECORD + const getModelLabel = (modelKey: string) => + FALLBACK_MODEL_RECORD[modelKey as keyof typeof FALLBACK_MODEL_RECORD]?.label || modelKey + + // Helper function to map enum model ID to API model ID + const getMappedModelId = (modelKey: string) => + BEDROCK_MODEL_TO_MODEL_ID[modelKey as keyof typeof BEDROCK_MODEL_TO_MODEL_ID] || modelKey + + // Determine selected model ID based on priority + if (modelId) { + const mappedModelId = getMappedModelId(modelId) + + // Priority 1: Use mapped modelId if it exists in available models from backend + if (models.some(model => model.id === mappedModelId)) { + selectedModelId = mappedModelId + } + // Priority 2: Use mapped version if modelId exists in FALLBACK_MODEL_RECORD and no backend models available + else if (models.length === 0 && modelId in FALLBACK_MODEL_RECORD) { + selectedModelId = getModelLabel(modelId) + } + // Priority 3: Fall back to default or system default + else { + selectedModelId = defaultModelId || getMappedModelId(DEFAULT_MODEL_ID) + } + } else { + // No user-selected model - use API default or system default + selectedModelId = defaultModelId || getMappedModelId(DEFAULT_MODEL_ID) + } + + // Store the selected model in the session session.modelId = selectedModelId + return { tabId: params.tabId, models: models, @@ -3580,25 +3686,6 @@ export class AgenticChatController implements ChatHandlers { onSourceLinkClick() {} - /** - * @deprecated use aws/chat/listAvailableModels server request instead - */ - #legacySetModelId(tabId: string, session: ChatSessionService) { - // Since model selection is mandatory, the only time modelId is not set is when the chat history is empty. - // In that case, we use the default modelId. - let modelId = this.#chatHistoryDb.getModelId() ?? DEFAULT_MODEL_ID - - const region = AmazonQTokenServiceManager.getInstance().getRegion() - if (region === 'eu-central-1') { - // Only 3.7 Sonnet is available in eu-central-1 for now - modelId = 'CLAUDE_3_7_SONNET_20250219_V1_0' - // @ts-ignore - this.#features.chat.chatOptionsUpdate({ region }) - } - this.#features.chat.chatOptionsUpdate({ modelId: modelId, tabId: tabId }) - session.modelId = modelId - } - onTabAdd(params: TabAddParams) { this.#telemetryController.activeTabId = params.tabId @@ -3611,11 +3698,14 @@ export class AgenticChatController implements ChatHandlers { if (!success) { return new ResponseError(ErrorCodes.InternalError, sessionResult.error) } - this.#legacySetModelId(params.tabId, session) // Get the saved pair programming mode from the database or default to true if not found const savedPairProgrammingMode = this.#chatHistoryDb.getPairProgrammingMode() session.pairProgrammingMode = savedPairProgrammingMode !== undefined ? savedPairProgrammingMode : true + if (session) { + // Set the logging object on the session + session.setLogging(this.#features.logging) + } // Update the client with the initial pair programming mode this.#features.chat.chatOptionsUpdate({ @@ -3623,11 +3713,6 @@ export class AgenticChatController implements ChatHandlers { // Type assertion to support pairProgrammingMode ...(session.pairProgrammingMode !== undefined ? { pairProgrammingMode: session.pairProgrammingMode } : {}), } as ChatUpdateParams) - - if (success && session) { - // Set the logging object on the session - session.setLogging(this.#features.logging) - } this.setPaidTierMode(params.tabId) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.test.ts index 3fe300d2fd..f037470bec 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.test.ts @@ -1,19 +1,19 @@ import * as assert from 'assert' -import { MODEL_OPTIONS, MODEL_OPTIONS_FOR_REGION } from './modelSelection' +import { FALLBACK_MODEL_OPTIONS } from './modelSelection' describe('modelSelection', () => { describe('modelOptions', () => { it('should contain the correct model options', () => { - assert.ok(Array.isArray(MODEL_OPTIONS), 'modelOptions should be an array') - assert.strictEqual(MODEL_OPTIONS.length, 2, 'modelOptions should have 2 items') + assert.ok(Array.isArray(FALLBACK_MODEL_OPTIONS), 'modelOptions should be an array') + assert.strictEqual(FALLBACK_MODEL_OPTIONS.length, 2, 'modelOptions should have 2 items') // Check that the array contains the expected models - const modelIds = MODEL_OPTIONS.map(model => model.id) - assert.ok(modelIds.includes('CLAUDE_SONNET_4_20250514_V1_0'), 'Should include Claude Sonnet 4') - assert.ok(modelIds.includes('CLAUDE_3_7_SONNET_20250219_V1_0'), 'Should include Claude Sonnet 3.7') + const modelIds = FALLBACK_MODEL_OPTIONS.map(model => model.id) + assert.ok(modelIds.includes('CLAUDE_SONNET_4_20250514_V1_0'), 'Should include claude-sonnet-4') + assert.ok(modelIds.includes('CLAUDE_3_7_SONNET_20250219_V1_0'), 'Should include claude-3.7-sonnet') // Check that each model has the required properties - MODEL_OPTIONS.forEach(model => { + FALLBACK_MODEL_OPTIONS.forEach(model => { assert.ok('id' in model, 'Model should have id property') assert.ok('name' in model, 'Model should have name property') assert.strictEqual(typeof model.id, 'string', 'Model id should be a string') @@ -21,47 +21,11 @@ describe('modelSelection', () => { }) // Check specific model names - const claudeSonnet4 = MODEL_OPTIONS.find(model => model.id === 'CLAUDE_SONNET_4_20250514_V1_0') - const claudeSonnet37 = MODEL_OPTIONS.find(model => model.id === 'CLAUDE_3_7_SONNET_20250219_V1_0') + const claudeSonnet4 = FALLBACK_MODEL_OPTIONS.find(model => model.id === 'CLAUDE_SONNET_4_20250514_V1_0') + const claudeSonnet37 = FALLBACK_MODEL_OPTIONS.find(model => model.id === 'CLAUDE_3_7_SONNET_20250219_V1_0') - assert.strictEqual(claudeSonnet4?.name, 'Claude Sonnet 4', 'Claude Sonnet 4 should have correct name') - assert.strictEqual(claudeSonnet37?.name, 'Claude Sonnet 3.7', 'Claude Sonnet 3.7 should have correct name') - }) - }) - - describe('modelOptionsForRegion', () => { - it('should provide all models for us-east-1 region', () => { - const usEast1Models = MODEL_OPTIONS_FOR_REGION['us-east-1'] - assert.deepStrictEqual(usEast1Models, MODEL_OPTIONS, 'us-east-1 should have all models') - assert.strictEqual(usEast1Models.length, 2, 'us-east-1 should have 2 models') - - const modelIds = usEast1Models.map(model => model.id) - assert.ok(modelIds.includes('CLAUDE_SONNET_4_20250514_V1_0'), 'us-east-1 should include Claude Sonnet 4') - assert.ok( - modelIds.includes('CLAUDE_3_7_SONNET_20250219_V1_0'), - 'us-east-1 should include Claude Sonnet 3.7' - ) - }) - - it('should provide all models for eu-central-1 region', () => { - const euCentral1Models = MODEL_OPTIONS_FOR_REGION['eu-central-1'] - assert.deepStrictEqual(euCentral1Models, MODEL_OPTIONS, 'us-east-1 should have all models') - assert.strictEqual(euCentral1Models.length, 2, 'us-east-1 should have 2 models') - - const modelIds = euCentral1Models.map(model => model.id) - assert.ok(modelIds.includes('CLAUDE_SONNET_4_20250514_V1_0'), 'eu-central-1 should include Claude Sonnet 4') - assert.ok( - modelIds.includes('CLAUDE_3_7_SONNET_20250219_V1_0'), - 'eu-central-1 should include Claude Sonnet 3.7' - ) - }) - - it('should fall back to all models for unknown regions', () => { - // Test with a region that doesn't exist in the modelOptionsForRegion map - const unknownRegionModels = MODEL_OPTIONS_FOR_REGION['unknown-region'] - - // Should be undefined since the region doesn't exist in the map - assert.strictEqual(unknownRegionModels, undefined, 'Unknown region should return undefined') + assert.strictEqual(claudeSonnet4?.name, 'Claude Sonnet 4', 'claude-sonnet-4 should have correct name') + assert.strictEqual(claudeSonnet37?.name, 'Claude 3.7 Sonnet', 'claude-3.7-sonnet should have correct name') }) }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.ts index cbee85f562..46c5446c8c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.ts @@ -1,5 +1,8 @@ import { ListAvailableModelsResult } from '@aws/language-server-runtimes/protocol' +/** + * @deprecated Do not add new models to the enum. + */ export enum BedrockModel { CLAUDE_SONNET_4_20250514_V1_0 = 'CLAUDE_SONNET_4_20250514_V1_0', CLAUDE_3_7_SONNET_20250219_V1_0 = 'CLAUDE_3_7_SONNET_20250219_V1_0', @@ -9,19 +12,19 @@ type ModelDetails = { label: string } -const MODEL_RECORD: Record = { - [BedrockModel.CLAUDE_3_7_SONNET_20250219_V1_0]: { label: 'Claude Sonnet 3.7' }, +export const FALLBACK_MODEL_RECORD: Record = { + [BedrockModel.CLAUDE_3_7_SONNET_20250219_V1_0]: { label: 'Claude 3.7 Sonnet' }, [BedrockModel.CLAUDE_SONNET_4_20250514_V1_0]: { label: 'Claude Sonnet 4' }, } -export const MODEL_OPTIONS: ListAvailableModelsResult['models'] = Object.entries(MODEL_RECORD).map( +export const BEDROCK_MODEL_TO_MODEL_ID: Record = { + [BedrockModel.CLAUDE_3_7_SONNET_20250219_V1_0]: 'claude-3.7-sonnet', + [BedrockModel.CLAUDE_SONNET_4_20250514_V1_0]: 'claude-sonnet-4', +} + +export const FALLBACK_MODEL_OPTIONS: ListAvailableModelsResult['models'] = Object.entries(FALLBACK_MODEL_RECORD).map( ([value, { label }]) => ({ id: value, name: label, }) ) - -export const MODEL_OPTIONS_FOR_REGION: Record = { - 'us-east-1': MODEL_OPTIONS, - 'eu-central-1': MODEL_OPTIONS, -} diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.test.ts index f4f61f955b..aed5a30643 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.test.ts @@ -57,7 +57,7 @@ describe('ChatDatabase', () => { }, } as unknown as Features - chatDb = new ChatDatabase(mockFeatures) + chatDb = ChatDatabase.getInstance(mockFeatures) }) afterEach(() => { @@ -665,6 +665,73 @@ describe('ChatDatabase', () => { ) }) }) + + describe('Model Cache Management', () => { + beforeEach(async () => { + await chatDb.databaseInitialize(0) + }) + + it('should cache and retrieve models', () => { + const models = [{ id: 'model-1', name: 'Test Model' }] + const defaultModelId = 'model-1' + + chatDb.setCachedModels(models, defaultModelId) + const cached = chatDb.getCachedModels() + + assert.ok(cached, 'Should return cached data') + assert.deepStrictEqual(cached.models, models) + assert.strictEqual(cached.defaultModelId, defaultModelId) + assert.ok(cached.timestamp > 0, 'Should have timestamp') + }) + + it('should validate cache expiry', () => { + const models = [{ id: 'model-1', name: 'Test Model' }] + chatDb.setCachedModels(models) + + // Mock isCachedValid to return false (expired) + const isCachedValidStub = sinon.stub(util, 'isCachedValid').returns(false) + + assert.strictEqual(chatDb.isCachedModelsValid(), false) + + isCachedValidStub.restore() + }) + + it('should clear cached models', () => { + const models = [{ id: 'model-1', name: 'Test Model' }] + chatDb.setCachedModels(models) + + // Verify cache exists + assert.ok(chatDb.getCachedModels(), 'Cache should exist before clearing') + + chatDb.clearCachedModels() + + // Verify cache is cleared + assert.strictEqual(chatDb.getCachedModels(), undefined, 'Cache should be cleared') + }) + + it('should clear model cache via static method when instance exists', () => { + const models = [{ id: 'model-1', name: 'Test Model' }] + chatDb.setCachedModels(models) + + // Verify cache exists + assert.ok(chatDb.getCachedModels(), 'Cache should exist before clearing') + + ChatDatabase.clearModelCache() + + // Verify cache is cleared + assert.strictEqual(chatDb.getCachedModels(), undefined, 'Cache should be cleared via static method') + }) + + it('should handle static clearModelCache when no instance exists', () => { + // Close current instance + chatDb.close() + + // Should not throw when no instance exists + assert.doesNotThrow(() => { + ChatDatabase.clearModelCache() + }, 'Should not throw when no instance exists') + }) + }) }) function uuid(): `${string}-${string}-${string}-${string}-${string}` { throw new Error('Function not implemented.') diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts index dfcf21308c..2e4f7a099d 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts @@ -24,11 +24,12 @@ import { getMd5WorkspaceId, MessagesWithCharacterCount, estimateCharacterCountFromImageBlock, + isCachedValid, } from './util' import * as crypto from 'crypto' import * as path from 'path' import { Features } from '@aws/language-server-runtimes/server-interface/server' -import { ContextCommand, ConversationItemGroup } from '@aws/language-server-runtimes/protocol' +import { ContextCommand, ConversationItemGroup, Model } from '@aws/language-server-runtimes/protocol' import { ChatMessage, ToolResultStatus } from '@amzn/codewhisperer-streaming' import { ChatItemType } from '@aws/mynah-ui' import { getUserHomeDir } from '@aws/lsp-core/out/util/path' @@ -122,6 +123,12 @@ export class ChatDatabase { return ChatDatabase.#instance } + public static clearModelCache(): void { + if (ChatDatabase.#instance) { + ChatDatabase.#instance.clearCachedModels() + } + } + public close() { this.#db.close() ChatDatabase.#instance = undefined @@ -1084,6 +1091,48 @@ export class ChatDatabase { this.updateSettings({ modelId: modelId === '' ? undefined : modelId }) } + getCachedModels(): { models: Model[]; defaultModelId?: string; timestamp: number } | undefined { + const settings = this.getSettings() + if (settings?.cachedModels && settings?.modelCacheTimestamp) { + return { + models: settings.cachedModels, + defaultModelId: settings.cachedDefaultModelId, + timestamp: settings.modelCacheTimestamp, + } + } + return undefined + } + + setCachedModels(models: Model[], defaultModelId?: string): void { + const currentTimestamp = Date.now() + // Get existing settings to preserve fields like modelId + const existingSettings = this.getSettings() || { modelId: undefined } + this.updateSettings({ + ...existingSettings, + cachedModels: models, + cachedDefaultModelId: defaultModelId, + modelCacheTimestamp: currentTimestamp, + }) + this.#features.logging.log(`Models cached at timestamp: ${currentTimestamp}`) + } + + isCachedModelsValid(): boolean { + const cachedData = this.getCachedModels() + if (!cachedData) return false + return isCachedValid(cachedData.timestamp) + } + + clearCachedModels(): void { + const existingSettings = this.getSettings() || { modelId: undefined } + this.updateSettings({ + ...existingSettings, + cachedModels: undefined, + cachedDefaultModelId: undefined, + modelCacheTimestamp: undefined, + }) + this.#features.logging.log('Model cache cleared') + } + getPairProgrammingMode(): boolean | undefined { const settings = this.getSettings() return settings?.pairProgrammingMode diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/util.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/util.ts index 8f3f46b9f4..77496cd96b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/util.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/util.ts @@ -10,6 +10,7 @@ import { ConversationItem, ConversationItemGroup, IconType, + Model, ReferenceTrackerInformation, } from '@aws/language-server-runtimes/server-interface' import { @@ -84,6 +85,9 @@ export type Rules = { export type Settings = { modelId: string | undefined pairProgrammingMode?: boolean + cachedModels?: Model[] + cachedDefaultModelId?: string + modelCacheTimestamp?: number } export type Conversation = { @@ -131,6 +135,14 @@ export type MessagesWithCharacterCount = { currentCount: number } +export function isCachedValid(timestamp: number): boolean { + const currentTime = Date.now() + const cacheAge = currentTime - timestamp + const CACHE_TTL = 30 * 60 * 1000 // 30 minutes in milliseconds + + return cacheAge < CACHE_TTL +} + /** * Converts Message to codewhisperer-streaming ChatMessage */ diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/utils/agenticChatControllerHelper.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/utils/agenticChatControllerHelper.ts deleted file mode 100644 index e29c58fff4..0000000000 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/utils/agenticChatControllerHelper.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ListAvailableModelsResult } from '@aws/language-server-runtimes/protocol' -import { MODEL_OPTIONS, MODEL_OPTIONS_FOR_REGION } from '../constants/modelSelection' - -/** - * Gets the latest available model for a region, optionally excluding a specific model - * @param region The AWS region - * @param exclude Optional model ID to exclude - * @returns The latest available model - */ -export function getLatestAvailableModel( - region: string | undefined, - exclude?: string -): ListAvailableModelsResult['models'][0] { - const models = region && MODEL_OPTIONS_FOR_REGION[region] ? MODEL_OPTIONS_FOR_REGION[region] : MODEL_OPTIONS - return [...models].reverse().find(model => model.id !== exclude) ?? models[models.length - 1] -} diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts index 5a919c9192..df144e72d6 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts @@ -33,6 +33,7 @@ import { getAmazonQRegionAndEndpoint } from './configurationUtils' import { getUserAgent } from '../telemetryUtils' import { StreamingClientServiceToken } from '../streamingClientService' import { parse } from '@aws-sdk/util-arn-parser' +import { ChatDatabase } from '../../language-server/agenticChat/tools/chatDb/chatDb' import { ProfileStatusMonitor } from '../../language-server/agenticChat/tools/mcp/profileStatusMonitor' /** @@ -148,6 +149,10 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< if (type === 'iam') { return } + + // Clear model cache when credentials are deleted + ChatDatabase.clearModelCache() + this.cancelActiveProfileChangeToken() this.resetCodewhispererService() diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index 030f7f7ee4..2304d81eea 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -615,6 +615,13 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { return this.client.listAvailableProfiles(request).promise() } + /** + * @description Get list of available models + */ + async listAvailableModels(request: CodeWhispererTokenClient.ListAvailableModelsRequest) { + return this.client.listAvailableModels(request).promise() + } + /** * @description send telemetry event to code whisperer data warehouse */ diff --git a/server/aws-lsp-codewhisperer/src/shared/constants.ts b/server/aws-lsp-codewhisperer/src/shared/constants.ts index cd453a11ba..33f61a079f 100644 --- a/server/aws-lsp-codewhisperer/src/shared/constants.ts +++ b/server/aws-lsp-codewhisperer/src/shared/constants.ts @@ -15,6 +15,8 @@ export const AWS_Q_ENDPOINTS = new Map([ export const AWS_Q_REGION_ENV_VAR = 'AWS_Q_REGION' export const AWS_Q_ENDPOINT_URL_ENV_VAR = 'AWS_Q_ENDPOINT_URL' +export const IDE = 'IDE' + export const Q_CONFIGURATION_SECTION = 'aws.q' export const CODE_WHISPERER_CONFIGURATION_SECTION = 'aws.codeWhisperer' From 23f5ec343cb4e0de32926204dbcf99e51af829f9 Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Wed, 27 Aug 2025 10:16:12 -0700 Subject: [PATCH 038/158] fix(amazonq): fix to add mcp server tool error handling and status for card (#2176) Co-authored-by: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> --- .../agenticChat/agenticChatController.ts | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 8cdba3d291..2b41bb938b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -2192,6 +2192,50 @@ export class AgenticChatController implements ChatHandlers { ) } + // Handle MCP tool failures + const originalNames = McpManager.instance.getOriginalToolNames(toolUse.name) + if (originalNames && toolUse.toolUseId) { + const { toolName } = originalNames + const cachedToolUse = session.toolUseLookup.get(toolUse.toolUseId) + const cachedButtonBlockId = (cachedToolUse as any)?.cachedButtonBlockId + const customerFacingError = getCustomerFacingErrorMessage(err) + + const errorResult = { + type: 'tool', + messageId: toolUse.toolUseId, + summary: { + content: { + header: { + icon: 'tools', + body: `${toolName}`, + status: { + status: 'error', + icon: 'cancel-circle', + text: 'Error', + description: customerFacingError, + }, + }, + }, + collapsedContent: [ + { + header: { body: 'Parameters' }, + body: `\`\`\`json\n${JSON.stringify(toolUse.input, null, 2)}\n\`\`\``, + }, + { + header: { body: 'Error' }, + body: customerFacingError, + }, + ], + }, + } as ChatResult + + if (cachedButtonBlockId !== undefined) { + await chatResultStream.overwriteResultBlock(errorResult, cachedButtonBlockId) + } else { + await chatResultStream.writeResultBlock(errorResult) + } + } + // display fs write failure status in the UX of that file card if ((toolUse.name === FS_WRITE || toolUse.name === FS_REPLACE) && toolUse.toolUseId) { const existingCard = chatResultStream.getMessageBlockId(toolUse.toolUseId) @@ -4568,6 +4612,13 @@ export class AgenticChatController implements ChatHandlers { await chatResultStream.overwriteResultBlock(toolResultCard, cachedButtonBlockId) } else { // Fallback to creating a new card + if (toolResultCard.summary?.content?.header) { + toolResultCard.summary.content.header.status = { + status: 'success', + icon: 'ok', + text: 'Completed', + } + } this.#log(`Warning: No blockId found for tool use ${toolUse.toolUseId}, creating new card`) await chatResultStream.writeResultBlock(toolResultCard) } From 08720c6c3fa83f9b3b6775d4ae4d848ce145b94b Mon Sep 17 00:00:00 2001 From: Lei Gao <97199248+leigaol@users.noreply.github.com> Date: Wed, 27 Aug 2025 11:18:26 -0700 Subject: [PATCH 039/158] revert: reduce auto trigger frequency for VSC (#2168)" (#2177) This reverts commit 00e11ff48eafaa0baec48177fa4aa6d60048af2f. --- .../inline-completion/auto-trigger/autoTrigger.test.ts | 2 +- .../inline-completion/auto-trigger/autoTrigger.ts | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.test.ts index 6f96c526de..31bc0a224a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.test.ts @@ -158,7 +158,7 @@ describe('Auto Trigger', async () => { assert.strictEqual(getAutoTriggerType(createContentChange('line1\nline2')), undefined) }) }) - describe.skip('Right Context should trigger validation', () => { + describe('Right Context should trigger validation', () => { it('should not trigger when there is immediate right context in VSCode', () => { const params = createBasicParams({ fileContext: createBasicFileContext('console.', 'log()'), diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts index 9fb2efab8e..d9dd7f16d5 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts @@ -229,12 +229,7 @@ export const autoTrigger = ( const triggerTypeCoefficient = coefficients.triggerTypeCoefficient[triggerType] ?? 0 const osCoefficient = coefficients.osCoefficient[os] ?? 0 - let charCoefficient = coefficients.charCoefficient[char] ?? 0 - // this is a temporary change to lower the auto trigger frequency - if (ide === 'VSCODE') { - charCoefficient = 0 - } - + const charCoefficient = coefficients.charCoefficient[char] ?? 0 const keyWordCoefficient = coefficients.charCoefficient[keyword] ?? 0 const languageCoefficient = coefficients.languageCoefficient[fileContext.programmingLanguage.languageName] ?? 0 From 489334466fa084774d6e4737569468d654dc6359 Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Wed, 27 Aug 2025 11:51:53 -0700 Subject: [PATCH 040/158] fix(amazonq): status message update for mcp tool permission accpetance (#2178) --- .../src/language-server/agenticChat/agenticChatController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 2b41bb938b..101674a4d9 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -2607,7 +2607,7 @@ export class AgenticChatController implements ChatHandlers { status: { status: isAccept ? 'success' : 'error', icon: isAccept ? 'ok' : 'cancel', - text: isAccept ? 'Completed' : 'Rejected', + text: isAccept ? 'Accepted' : 'Rejected', }, fileList: undefined, }, From 28567e3ab06a38e13d23df98f0000d62f43293f6 Mon Sep 17 00:00:00 2001 From: Richard Li <742829+rli@users.noreply.github.com> Date: Wed, 27 Aug 2025 14:57:54 -0700 Subject: [PATCH 041/158] deps: update indexing bundle to 042c98e6 (#2174) 042c98e6: optimizing memory usage in Indexing --- .../_bundle-assets/qserver-darwin-arm64.zip | 4 ++-- .../_bundle-assets/qserver-darwin-x64.zip | 4 ++-- .../_bundle-assets/qserver-linux-arm64.zip | 4 ++-- .../_bundle-assets/qserver-linux-x64.zip | 4 ++-- .../_bundle-assets/qserver-win32-x64.zip | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-arm64.zip b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-arm64.zip index 24fbdb712c..fdd736d602 100644 --- a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-arm64.zip +++ b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-arm64.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f651f5364b2417df24d40cbd2d34d69f8b338f3f00aca9c5afd5b4f9ea3d22d -size 96647490 +oid sha256:f4fbd67484ea48363077bbfaa576154196558a4048a862abac84d496fec6b636 +size 96644452 diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-x64.zip b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-x64.zip index 14d5e51377..4ef652e06a 100644 --- a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-x64.zip +++ b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-x64.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:03ef43ac80e2a16e8c842e92a3f3285d5424f2ea99bba167b9cbb9dabb751262 -size 98328127 +oid sha256:2bcfa7697a0ecdc4ff43f84d1a8c8b7840c144080e51b921dd7c5d3478613a82 +size 98325089 diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-arm64.zip b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-arm64.zip index af6aae68c3..dacf7cc25a 100644 --- a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-arm64.zip +++ b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-arm64.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:33bf50f87b67a330b3dc28f9a2fb1678f5c9cd6eb33beb964b6b068790b05b6c -size 102589811 +oid sha256:1f644daa198d026a091ac87a33fa54b7c1faf1e929ce8ef3ab7e25b7510335e7 +size 102586773 diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-x64.zip b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-x64.zip index 4923a60a7f..882e8901d3 100644 --- a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-x64.zip +++ b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-x64.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ec71aea47b7cb08c13e94fe4ca284b3656d23266bcdd728a3525abd7939730f0 -size 114552140 +oid sha256:1f6add24d8ae6d1248e3ff8281a8c9e8b402370fd00fcc8bf65c553457715f27 +size 114549102 diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-win32-x64.zip b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-win32-x64.zip index fe962b88c0..da87d337a6 100644 --- a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-win32-x64.zip +++ b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-win32-x64.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cd8190acad1f1c2b37a818fcf606cc3d2fa4e1929c82ef967ac360b7345864b4 -size 113890248 +oid sha256:5949d0c3d13d02c31f6bf06ea7a0339a851be1824f90c81d48e66c48c79e4930 +size 113887210 From 5a3f481ebe8c6033e3833abcd81799d26c2aa03e Mon Sep 17 00:00:00 2001 From: BlakeLazarine Date: Wed, 27 Aug 2025 15:50:04 -0700 Subject: [PATCH 042/158] feat(amazonq): emit metric for each issue (#2179) Need to emit a metric for each issue found by the agentic reviewer to reach parity with old behavior. --- .../tools/qCodeAnalysis/codeReview.ts | 22 +++++++++++++++++-- .../tools/qCodeAnalysis/codeReviewTypes.ts | 1 + 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts index b1ef4c3e61..d9fd42d621 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts @@ -439,9 +439,27 @@ export class CodeReview { ) this.logging.info('Findings count grouped by file') - aggregatedCodeScanIssueList.forEach(item => + aggregatedCodeScanIssueList.forEach(item => { this.logging.info(`File path - ${item.filePath} Findings count - ${item.issues.length}`) - ) + item.issues.forEach(issue => + CodeReviewUtils.emitMetric( + { + reason: SuccessMetricName.IssuesDetected, + result: 'Succeeded', + metadata: { + codewhispererCodeScanJobId: jobId, + credentialStartUrl: this.credentialsProvider.getConnectionMetadata()?.sso?.startUrl, + findingId: issue.findingId, + detectorId: issue.detectorId, + ruleId: issue.ruleId, + autoDetected: false, + }, + }, + this.logging, + this.telemetry + ) + ) + }) return { codeReviewId: jobId, diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts index 15aa32a5aa..728c226ae1 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts @@ -10,6 +10,7 @@ export enum FailedMetricName { } export enum SuccessMetricName { CodeScanSuccess = 'codeScanSuccess', + IssuesDetected = 'issuesDetected', } export type ValidateInputAndSetupResult = { From b5f5373a3363c13275cc63799177f2d6358abfe7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 27 Aug 2025 16:20:53 -0700 Subject: [PATCH 043/158] chore(release): release packages from branch main (#2152) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .release-please-manifest.json | 4 ++-- chat-client/CHANGELOG.md | 12 ++++++++++ chat-client/package.json | 2 +- package-lock.json | 4 ++-- server/aws-lsp-codewhisperer/CHANGELOG.md | 28 +++++++++++++++++++++++ server/aws-lsp-codewhisperer/package.json | 2 +- 6 files changed, 46 insertions(+), 6 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 49f118f219..e6baf94939 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,8 +1,8 @@ { - "chat-client": "0.1.33", + "chat-client": "0.1.34", "core/aws-lsp-core": "0.0.14", "server/aws-lsp-antlr4": "0.1.18", - "server/aws-lsp-codewhisperer": "0.0.75", + "server/aws-lsp-codewhisperer": "0.0.76", "server/aws-lsp-json": "0.1.18", "server/aws-lsp-partiql": "0.0.17", "server/aws-lsp-yaml": "0.1.18" diff --git a/chat-client/CHANGELOG.md b/chat-client/CHANGELOG.md index 995ddc8ae6..1c516246c6 100644 --- a/chat-client/CHANGELOG.md +++ b/chat-client/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [0.1.34](https://github.com/aws/language-servers/compare/chat-client/v0.1.33...chat-client/v0.1.34) (2025-08-27) + + +### Features + +* Auto fetch models from listAvailableModels API ([#2171](https://github.com/aws/language-servers/issues/2171)) ([8600c52](https://github.com/aws/language-servers/commit/8600c524877abb459e9338399352446c0dcff6f0)) + + +### Bug Fixes + +* **amazonq:** disable typewriter animation ([#2160](https://github.com/aws/language-servers/issues/2160)) ([db45d01](https://github.com/aws/language-servers/commit/db45d01adba10e8a04d868e1062f899df4f5b7e4)) + ## [0.1.33](https://github.com/aws/language-servers/compare/chat-client/v0.1.32...chat-client/v0.1.33) (2025-08-19) diff --git a/chat-client/package.json b/chat-client/package.json index e4250d42a1..b838360175 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -1,6 +1,6 @@ { "name": "@aws/chat-client", - "version": "0.1.33", + "version": "0.1.34", "description": "AWS Chat Client", "main": "out/index.js", "repository": { diff --git a/package-lock.json b/package-lock.json index 5fc601a1bc..86d2516d9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -251,7 +251,7 @@ }, "chat-client": { "name": "@aws/chat-client", - "version": "0.1.33", + "version": "0.1.34", "license": "Apache-2.0", "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", @@ -28669,7 +28669,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.75", + "version": "0.0.76", "bundleDependencies": [ "@amzn/codewhisperer-streaming", "@amzn/amazon-q-developer-streaming-client" diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index a70284a4c2..8bda2b6803 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,33 @@ # Changelog +## [0.0.76](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.75...lsp-codewhisperer/v0.0.76) (2025-08-27) + + +### Features + +* add basic OAuth client for remote MCP ([#2136](https://github.com/aws/language-servers/issues/2136)) ([2fb896e](https://github.com/aws/language-servers/commit/2fb896e094de0bc5a1b4881067e7dcceb3826015)) +* **amazonq:** emit metric for each issue ([#2179](https://github.com/aws/language-servers/issues/2179)) ([5a3f481](https://github.com/aws/language-servers/commit/5a3f481ebe8c6033e3833abcd81799d26c2aa03e)) +* Auto fetch models from listAvailableModels API ([#2171](https://github.com/aws/language-servers/issues/2171)) ([8600c52](https://github.com/aws/language-servers/commit/8600c524877abb459e9338399352446c0dcff6f0)) +* disable pkce flow during plugin load ([#2153](https://github.com/aws/language-servers/issues/2153)) ([71b3595](https://github.com/aws/language-servers/commit/71b35952333e7581921644ce40fabbc1e6d3c02f)) +* update MCP manager and utilities ([#2158](https://github.com/aws/language-servers/issues/2158)) ([b99df82](https://github.com/aws/language-servers/commit/b99df82826d0ba1a1d52df578cb80674c90505b9)) + + +### Bug Fixes + +* adding streakTracker to track streakLength across Completions and Edits ([#2147](https://github.com/aws/language-servers/issues/2147)) ([a6c64f2](https://github.com/aws/language-servers/commit/a6c64f2995a17697e3d71d30a1f411f5cf0db279)) +* **amazonq:** dedupe openTabs supplemental contexts ([#2172](https://github.com/aws/language-servers/issues/2172)) ([aa87ae2](https://github.com/aws/language-servers/commit/aa87ae2bd95edc1f38bf90f56093c5bf5ff18c53)) +* **amazonq:** fix for mcp servers operations to edit server config only ([#2165](https://github.com/aws/language-servers/issues/2165)) ([d28df09](https://github.com/aws/language-servers/commit/d28df09ae41871430cd53064eac1f3050c95ea84)) +* **amazonq:** fix to add mcp server tool error handling and status for card ([#2176](https://github.com/aws/language-servers/issues/2176)) ([23f5ec3](https://github.com/aws/language-servers/commit/23f5ec343cb4e0de32926204dbcf99e51af829f9)) +* **amazonq:** status message update for mcp tool permission accpetance ([#2178](https://github.com/aws/language-servers/issues/2178)) ([4893344](https://github.com/aws/language-servers/commit/489334466fa084774d6e4737569468d654dc6359)) +* fix pkce windows url path ([#2173](https://github.com/aws/language-servers/issues/2173)) ([d7b184c](https://github.com/aws/language-servers/commit/d7b184cb12979877722fa0293e9aebec91ff2c18)) +* multiple fixes on auth flow edge cases ([#2155](https://github.com/aws/language-servers/issues/2155)) ([472220a](https://github.com/aws/language-servers/commit/472220a745cff4fe91a2cabae4ae059a164ceddd)) +* reduce auto trigger frequency for VSC ([#2168](https://github.com/aws/language-servers/issues/2168)) ([00e11ff](https://github.com/aws/language-servers/commit/00e11ff48eafaa0baec48177fa4aa6d60048af2f)) + + +### Reverts + +* reduce auto trigger frequency for VSC ([#2168](https://github.com/aws/language-servers/issues/2168))" ([#2177](https://github.com/aws/language-servers/issues/2177)) ([08720c6](https://github.com/aws/language-servers/commit/08720c6c3fa83f9b3b6775d4ae4d848ce145b94b)) + ## [0.0.75](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.74...lsp-codewhisperer/v0.0.75) (2025-08-21) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 83ff1cdaee..8702e6fab3 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.75", + "version": "0.0.76", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { From 8d5b839285bacc21cf9834867f9c6e5b4d9ad471 Mon Sep 17 00:00:00 2001 From: aws-toolkit-automation <> Date: Thu, 28 Aug 2025 04:04:29 +0000 Subject: [PATCH 044/158] chore: bump agentic version: 1.30.0 --- app/aws-lsp-codewhisperer-runtimes/src/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/src/version.json b/app/aws-lsp-codewhisperer-runtimes/src/version.json index 93401eb637..e842765e3f 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/version.json +++ b/app/aws-lsp-codewhisperer-runtimes/src/version.json @@ -1,3 +1,3 @@ { - "agenticChat": "1.29.0" + "agenticChat": "1.30.0" } From ecb86a02e066418a3984f8f02d7c9ea71ecf5f5e Mon Sep 17 00:00:00 2001 From: Richard Li Date: Wed, 27 Aug 2025 21:08:22 -0700 Subject: [PATCH 045/158] chore: empty commit to trigger workflow From baf20b7c4050dd4360ecb97c06d21f6b504836b0 Mon Sep 17 00:00:00 2001 From: Richard Li <742829+rli@users.noreply.github.com> Date: Thu, 28 Aug 2025 10:56:30 -0700 Subject: [PATCH 046/158] revert: deps: update indexing bundle to 042c98e6 (#2174) (#2183) This reverts commit 28567e3ab06a38e13d23df98f0000d62f43293f6. indexing bundle contains a crypto polyfill that is needed for some reason --- .../_bundle-assets/qserver-darwin-arm64.zip | 4 ++-- .../_bundle-assets/qserver-darwin-x64.zip | 4 ++-- .../_bundle-assets/qserver-linux-arm64.zip | 4 ++-- .../_bundle-assets/qserver-linux-x64.zip | 4 ++-- .../_bundle-assets/qserver-win32-x64.zip | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-arm64.zip b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-arm64.zip index fdd736d602..24fbdb712c 100644 --- a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-arm64.zip +++ b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-arm64.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4fbd67484ea48363077bbfaa576154196558a4048a862abac84d496fec6b636 -size 96644452 +oid sha256:5f651f5364b2417df24d40cbd2d34d69f8b338f3f00aca9c5afd5b4f9ea3d22d +size 96647490 diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-x64.zip b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-x64.zip index 4ef652e06a..14d5e51377 100644 --- a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-x64.zip +++ b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-x64.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2bcfa7697a0ecdc4ff43f84d1a8c8b7840c144080e51b921dd7c5d3478613a82 -size 98325089 +oid sha256:03ef43ac80e2a16e8c842e92a3f3285d5424f2ea99bba167b9cbb9dabb751262 +size 98328127 diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-arm64.zip b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-arm64.zip index dacf7cc25a..af6aae68c3 100644 --- a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-arm64.zip +++ b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-arm64.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1f644daa198d026a091ac87a33fa54b7c1faf1e929ce8ef3ab7e25b7510335e7 -size 102586773 +oid sha256:33bf50f87b67a330b3dc28f9a2fb1678f5c9cd6eb33beb964b6b068790b05b6c +size 102589811 diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-x64.zip b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-x64.zip index 882e8901d3..4923a60a7f 100644 --- a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-x64.zip +++ b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-x64.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1f6add24d8ae6d1248e3ff8281a8c9e8b402370fd00fcc8bf65c553457715f27 -size 114549102 +oid sha256:ec71aea47b7cb08c13e94fe4ca284b3656d23266bcdd728a3525abd7939730f0 +size 114552140 diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-win32-x64.zip b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-win32-x64.zip index da87d337a6..fe962b88c0 100644 --- a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-win32-x64.zip +++ b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-win32-x64.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5949d0c3d13d02c31f6bf06ea7a0339a851be1824f90c81d48e66c48c79e4930 -size 113887210 +oid sha256:cd8190acad1f1c2b37a818fcf606cc3d2fa4e1929c82ef967ac360b7345864b4 +size 113890248 From c53f672b6173ebda530917ccb4e0c2f26f5c8f79 Mon Sep 17 00:00:00 2001 From: tsmithsz <84354541+tsmithsz@users.noreply.github.com> Date: Fri, 29 Aug 2025 10:22:49 -0700 Subject: [PATCH 047/158] fix: emit acceptedLineCount metric and AgenticCodeAccepted interaction type (#2167) --- .../agenticChat/agenticChatController.ts | 13 +++++++++++++ .../chat/telemetry/chatTelemetryController.ts | 4 +++- .../src/shared/telemetry/telemetryService.ts | 1 + .../src/shared/telemetry/types.ts | 1 + 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 101674a4d9..4a816317d2 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -2076,6 +2076,19 @@ export class AgenticChatController implements ChatHandlers { this.#abTestingAllocation?.experimentName, this.#abTestingAllocation?.userVariation ) + // Emit acceptedLineCount when write tool is used and code changes are accepted + const beforeLines = cachedToolUse?.fileChange?.before?.split('\n').length ?? 0 + const afterLines = doc?.getText()?.split('\n').length ?? 0 + const acceptedLineCount = afterLines - beforeLines + await this.#telemetryController.emitInteractWithMessageMetric( + tabId, + { + cwsprChatMessageId: chatResult.messageId ?? toolUse.toolUseId, + cwsprChatInteractionType: ChatInteractionType.AgenticCodeAccepted, + codewhispererCustomizationArn: this.#customizationArn, + }, + acceptedLineCount + ) await chatResultStream.writeResultBlock(chatResult) break case CodeReview.toolName: diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts index 8e9cb92624..580bcd4be2 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts @@ -421,10 +421,12 @@ export class ChatTelemetryController { public emitInteractWithMessageMetric( tabId: string, - metric: Omit + metric: Omit, + acceptedLineCount?: number ) { return this.#telemetryService.emitChatInteractWithMessage(metric, { conversationId: this.getConversationId(tabId), + acceptedLineCount, }) } diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts index 6f3ba52028..e5e8cbc471 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts @@ -66,6 +66,7 @@ export class TelemetryService { [ChatInteractionType.Upvote]: 'UPVOTE', [ChatInteractionType.Downvote]: 'DOWNVOTE', [ChatInteractionType.ClickBodyLink]: 'CLICK_BODY_LINK', + [ChatInteractionType.AgenticCodeAccepted]: 'AGENTIC_CODE_ACCEPTED', } constructor( diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts index bed82c2939..5bf9fea185 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts @@ -429,6 +429,7 @@ export enum ChatInteractionType { Upvote = 'upvote', Downvote = 'downvote', ClickBodyLink = 'clickBodyLink', + AgenticCodeAccepted = 'agenticCodeAccepted', } export enum ChatHistoryActionType { From 852b21b66f793102c52e35c2baec07a772e5134a Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Fri, 29 Aug 2025 13:28:28 -0700 Subject: [PATCH 048/158] fix: auto trigger should only respect previous decisions in the past 2mins (#2189) --- .../auto-trigger/autoTrigger.ts | 21 ++++++++++++------- .../inline-completion/codeWhispererServer.ts | 8 +++++-- .../session/sessionManager.ts | 7 +++++++ .../src/shared/telemetry/telemetryService.ts | 1 + 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts index d9dd7f16d5..adbbeb4662 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts @@ -177,7 +177,7 @@ type AutoTriggerParams = { char: string triggerType: string // Left as String intentionally to support future and unknown trigger types os: string - previousDecision: string + previousDecision: string | undefined ide: string lineNum: number } @@ -235,12 +235,19 @@ export const autoTrigger = ( const languageCoefficient = coefficients.languageCoefficient[fileContext.programmingLanguage.languageName] ?? 0 let previousDecisionCoefficient = 0 - if (previousDecision === 'Accept') { - previousDecisionCoefficient = coefficients.prevDecisionAcceptCoefficient - } else if (previousDecision === 'Reject') { - previousDecisionCoefficient = coefficients.prevDecisionRejectCoefficient - } else if (previousDecision === 'Discard' || previousDecision === 'Empty') { - previousDecisionCoefficient = coefficients.prevDecisionOtherCoefficient + switch (previousDecision) { + case 'Accept': + previousDecisionCoefficient = coefficients.prevDecisionAcceptCoefficient + break + case 'Reject': + previousDecisionCoefficient = coefficients.prevDecisionRejectCoefficient + break + case 'Discard': + case 'Empty': + previousDecisionCoefficient = coefficients.prevDecisionOtherCoefficient + break + default: + break } const ideCoefficient = coefficients.ideCoefficient[ide] ?? 0 diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts index 330cf54735..c869a534fd 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts @@ -239,7 +239,11 @@ export const CodewhispererServerFactory = : undefined const previousSession = completionSessionManager.getPreviousSession() - const previousDecision = previousSession?.getAggregatedUserTriggerDecision() ?? '' + // Only refer to decisions in the past 2 mins + const previousDecisionForClassifier = + previousSession && performance.now() - previousSession.decisionMadeTimestamp <= 2 * 60 * 1000 + ? previousSession.getAggregatedUserTriggerDecision() + : undefined let ideCategory: string | undefined = '' const initializeParams = lsp.getClientInitializeParams() if (initializeParams !== undefined) { @@ -280,7 +284,7 @@ export const CodewhispererServerFactory = char: triggerCharacters, // Add the character just inserted, if any, before the invication position ide: ideCategory ?? '', os: getNormalizeOsName(), - previousDecision, // The last decision by the user on the previous invocation + previousDecision: previousDecisionForClassifier, // The last decision by the user on the previous invocation triggerType: codewhispererAutoTriggerType, // The 2 trigger types currently influencing the Auto-Trigger are SpecialCharacter and Enter }, logging diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts index 34dbb12538..2a4af79ff6 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts @@ -60,6 +60,13 @@ export class CodeWhispererSession { suggestions: CachedSuggestion[] = [] suggestionsAfterRightContextMerge: InlineCompletionItemWithReferences[] = [] suggestionsStates = new Map() + private _decisionTimestamp = 0 + get decisionMadeTimestamp() { + return this._decisionTimestamp + } + set decisionMadeTimestamp(time: number) { + this._decisionTimestamp = time + } acceptedSuggestionId?: string = undefined responseContext?: ResponseContext triggerType: CodewhispererTriggerType diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts index e5e8cbc471..b11806a020 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts @@ -200,6 +200,7 @@ export class TelemetryService { removedIdeDiagnostics?: IdeDiagnostic[], streakLength?: number ) { + session.decisionMadeTimestamp = performance.now() if (this.enableTelemetryEventsToDestination) { const data: CodeWhispererUserTriggerDecisionEvent = { codewhispererSessionId: session.codewhispererSessionId || '', From 4fd0def2a7080921683dd712cae9c17a39d4372e Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Fri, 29 Aug 2025 13:28:54 -0700 Subject: [PATCH 049/158] chore: supplemental context log (#2185) --- .../src/shared/codeWhispererService.ts | 2 ++ .../crossFileContextUtil.ts | 10 ++++------ .../supplementalContextUtil.ts | 19 ++++++++++++++++++- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index 2304d81eea..984bb6da76 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -444,6 +444,8 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { "endpoint": ${this.codeWhispererEndpoint}, "predictionType": ${request.predictionTypes?.toString() ?? 'Not specified (COMPLETIONS)'}, "filename": ${request.fileContext.filename}, + "leftContextLength": ${request.fileContext.leftFileContent.length}, + rightContextLength: ${request.fileContext.rightFileContent.length}, "language": ${request.fileContext.programmingLanguage.languageName}, "supplementalContextCount": ${request.supplementalContexts?.length ?? 0}, "request.nextToken": ${request.nextToken}, diff --git a/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/crossFileContextUtil.ts b/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/crossFileContextUtil.ts index 06bac73d54..91f02b9dc7 100644 --- a/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/crossFileContextUtil.ts +++ b/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/crossFileContextUtil.ts @@ -71,12 +71,13 @@ export async function fetchSupplementalContextForSrc( const supplementalContextConfig = getSupplementalContextConfig(document.languageId) if (supplementalContextConfig === undefined) { - return supplementalContextConfig + return undefined } - //TODO: add logic for other strategies once available + if (supplementalContextConfig === 'codemap') { return await codemapContext(document, position, workspace, cancellationToken, openTabFiles) } + return { supplementalContextItems: [], strategy: 'Empty' } } @@ -264,10 +265,7 @@ function getInputChunk(document: TextDocument, cursorPosition: Position, chunkSi * @returns specifically returning undefined if the langueage is not supported, * otherwise true/false depending on if the language is fully supported or not belonging to the user group */ -function getSupplementalContextConfig( - languageId: TextDocument['languageId'], - _userGroup?: any -): SupplementalContextStrategy | undefined { +function getSupplementalContextConfig(languageId: TextDocument['languageId']): SupplementalContextStrategy | undefined { return isCrossFileSupported(languageId) ? 'codemap' : undefined } diff --git a/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/supplementalContextUtil.ts b/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/supplementalContextUtil.ts index 8a5658188b..8e0902452f 100644 --- a/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/supplementalContextUtil.ts +++ b/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/supplementalContextUtil.ts @@ -91,7 +91,24 @@ export async function fetchSupplementalContext( strategy: supplementalContextValue.strategy, } - return truncateSupplementalContext(resBeforeTruncation) + const r = truncateSupplementalContext(resBeforeTruncation) + + let logstr = `@@supplemental context@@ +\tisUtg: ${r.isUtg}, +\tisProcessTimeout: ${r.isProcessTimeout}, +\tcontents.length: ${r.contentsLength}, +\tlatency: ${r.latency}, +\tstrategy: ${r.strategy}, +` + r.supplementalContextItems.forEach((item, index) => { + logstr += `\tChunk [${index}th]:\n` + logstr += `\t\tPath: ${item.filePath}\n` + logstr += `\t\tLength: ${item.content.length}\n` + logstr += `\t\tScore: ${item.score}\n` + }) + logging.info(logstr) + + return r } else { return undefined } From f4e2e6e885e665834a5d7b7cbb5f4ba4ff9bbb65 Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Fri, 29 Aug 2025 13:29:11 -0700 Subject: [PATCH 050/158] fix: should send classifier score after taking sigmoid (#2188) --- .../inline-completion/auto-trigger/autoTrigger.ts | 8 ++++++-- .../inline-completion/userTriggerDecision.test.ts | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts index adbbeb4662..8990756dbf 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts @@ -229,7 +229,9 @@ export const autoTrigger = ( const triggerTypeCoefficient = coefficients.triggerTypeCoefficient[triggerType] ?? 0 const osCoefficient = coefficients.osCoefficient[os] ?? 0 + const charCoefficient = coefficients.charCoefficient[char] ?? 0 + const keyWordCoefficient = coefficients.charCoefficient[keyword] ?? 0 const languageCoefficient = coefficients.languageCoefficient[fileContext.programmingLanguage.languageName] ?? 0 @@ -281,11 +283,13 @@ export const autoTrigger = ( previousDecisionCoefficient + languageCoefficient + leftContextLengthCoefficient - const shouldTrigger = sigmoid(classifierResult) > TRIGGER_THRESHOLD + + const r = sigmoid(classifierResult) + const shouldTrigger = r > TRIGGER_THRESHOLD return { shouldTrigger, - classifierResult, + classifierResult: r, classifierThreshold: TRIGGER_THRESHOLD, } } diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/userTriggerDecision.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/userTriggerDecision.test.ts index c583815b6b..21c398d56a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/userTriggerDecision.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/userTriggerDecision.test.ts @@ -145,7 +145,7 @@ describe('Telemetry', () => { }, } const EMPTY_RESULT = { items: [], sessionId: '' } - const classifierResult = getNormalizeOsName() !== 'Linux' ? 0.4114381148145918 : 0.46733811481459187 + const classifierResult = getNormalizeOsName() !== 'Linux' ? 0.6014326616203989 : 0.61475353067264 let features: TestFeatures let server: Server @@ -1251,7 +1251,7 @@ describe('Telemetry', () => { triggerType: 'AutoTrigger', autoTriggerType: 'SpecialCharacters', triggerCharacter: '(', - classifierResult: getNormalizeOsName() === 'Linux' ? 0.30173811481459184 : 0.2458381148145919, + classifierResult: getNormalizeOsName() === 'Linux' ? 0.5748673583477094 : 0.5611518554232429, classifierThreshold: 0.43, language: 'csharp', requestContext: { From b4975409a3ed518550290b72ac310895a293be4b Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Fri, 29 Aug 2025 13:29:44 -0700 Subject: [PATCH 051/158] perf: only process edit requests 1 at a time (#2187) --- .../inline-completion/editCompletionHandler.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts index 193521cce9..550de06708 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts @@ -45,6 +45,8 @@ export class EditCompletionHandler { private hasDocumentChangedSinceInvocation: boolean = false private readonly streakTracker: StreakTracker + private isInProgress = false + constructor( readonly logging: Logging, readonly clientMetadata: InitializeParams, @@ -89,6 +91,11 @@ export class EditCompletionHandler { params: InlineCompletionWithReferencesParams, token: CancellationToken ): Promise { + if (this.isInProgress) { + this.logging.info(`editCompletionHandler is WIP, skip the request`) + return EMPTY_RESULT + } + // On every new completion request close current inflight session. const currentSession = this.sessionManager.getCurrentSession() if (currentSession && currentSession.state == 'REQUESTING' && !params.partialResultToken) { @@ -118,6 +125,9 @@ export class EditCompletionHandler { return EMPTY_RESULT } + // Not ideally to rely on a state, should improve it and simply make it a debounced API + this.isInProgress = true + if (params.partialResultToken && currentSession) { // Close ACTIVE session. We shouldn't record Discard trigger decision for trigger with nextToken. if (currentSession && currentSession.state === 'ACTIVE') { @@ -152,10 +162,12 @@ export class EditCompletionHandler { ) } catch (error) { return this.handleSuggestionsErrors(error as Error, currentSession) + } finally { + this.isInProgress = false } } - return new Promise(async resolve => { + return new Promise(async resolve => { this.debounceTimeout = setTimeout(async () => { try { this.isWaiting = true @@ -185,6 +197,8 @@ export class EditCompletionHandler { this.hasDocumentChangedSinceInvocation = false } }, EDIT_DEBOUNCE_INTERVAL_MS) + }).finally(() => { + this.isInProgress = false }) } From 66742adfc44f33efbd8dd33b803000e08241e5ce Mon Sep 17 00:00:00 2001 From: atontb <104926752+atonaamz@users.noreply.github.com> Date: Fri, 29 Aug 2025 14:12:15 -0700 Subject: [PATCH 052/158] feat: passing suggestionTypes and pluginVersion/lspVersion to STE (#2180) --- .../src/client/token/bearer-token-service.json | 13 +++++++++++++ .../token/codewhispererbearertokenclient.d.ts | 6 +++++- .../src/shared/telemetry/telemetryService.test.ts | 1 + .../src/shared/telemetry/telemetryService.ts | 5 ++++- .../src/shared/telemetryUtils.ts | 2 ++ 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json b/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json index 7e0533b0f5..58ae54fb3c 100644 --- a/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json +++ b/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json @@ -1890,6 +1890,10 @@ "type": "string", "enum": ["BLOCK", "LINE"] }, + "SuggestionType": { + "type": "string", + "enum": ["COMPLETIONS", "EDITS"] + }, "Completions": { "type": "list", "member": { @@ -6299,6 +6303,12 @@ }, "ideVersion": { "shape": "String" + }, + "pluginVersion": { + "shape": "String" + }, + "lspVersion": { + "shape": "String" } } }, @@ -6540,6 +6550,9 @@ }, "streakLength": { "shape": "UserTriggerDecisionEventStreakLengthInteger" + }, + "suggestionType": { + "shape": "SuggestionType" } } }, diff --git a/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts b/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts index 34aa384c14..8e64023479 100644 --- a/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts +++ b/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts @@ -549,6 +549,7 @@ declare namespace CodeWhispererBearerTokenClient { } export type CompletionContentString = string; export type CompletionType = "BLOCK"|"LINE"|string; + export type SuggestionType = "COMPLETIONS"|"EDITS"|string; export type Completions = Completion[]; export interface ConsoleState { region?: String; @@ -2014,6 +2015,8 @@ declare namespace CodeWhispererBearerTokenClient { product: UserContextProductString; clientId?: UUID; ideVersion?: String; + pluginVersion?: String; + lspVersion?: String; } export type UserContextProductString = string; export interface UserInputMessage { @@ -2127,6 +2130,7 @@ declare namespace CodeWhispererBearerTokenClient { addedCharacterCount?: UserTriggerDecisionEventAddedCharacterCountInteger; deletedCharacterCount?: UserTriggerDecisionEventDeletedCharacterCountInteger; streakLength?: UserTriggerDecisionEventStreakLengthInteger; + suggestionType?: SuggestionType; } export type UserTriggerDecisionEventAddedCharacterCountInteger = number; export type UserTriggerDecisionEventDeletedCharacterCountInteger = number; @@ -2182,4 +2186,4 @@ declare namespace CodeWhispererBearerTokenClient { } export = CodeWhispererBearerTokenClient; - \ No newline at end of file + \ No newline at end of file diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts index 04d1cf091c..b6a5592f5f 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts @@ -277,6 +277,7 @@ describe('TelemetryService', () => { addedIdeDiagnostics: undefined, removedIdeDiagnostics: undefined, streakLength: 0, + suggestionType: 'COMPLETIONS', }, }, optOutPreference: 'OPTIN', diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts index b11806a020..cd2ba18254 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts @@ -283,14 +283,17 @@ export class TelemetryService { addedIdeDiagnostics: addedIdeDiagnostics, removedIdeDiagnostics: removedIdeDiagnostics, streakLength: streakLength ?? 0, + suggestionType: isInlineEdit ? 'EDITS' : 'COMPLETIONS', } this.logging.info(`Invoking SendTelemetryEvent:UserTriggerDecisionEvent with: + "requestId": ${event.requestId} "suggestionState": ${event.suggestionState} "acceptedCharacterCount": ${event.acceptedCharacterCount} "addedCharacterCount": ${event.addedCharacterCount} "deletedCharacterCount": ${event.deletedCharacterCount} "streakLength": ${event.streakLength} - "firstCompletionDisplayLatency: ${event.recommendationLatencyMilliseconds}`) + "firstCompletionDisplayLatency: ${event.recommendationLatencyMilliseconds} + "suggestionType": ${event.suggestionType}`) return this.invokeSendTelemetryEvent({ userTriggerDecisionEvent: event, }) diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.ts b/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.ts index 49020a8822..e682263f7e 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.ts @@ -103,6 +103,8 @@ export const makeUserContextObject = ( product: product, clientId: initializeParams.initializationOptions?.aws?.clientInfo?.clientId, ideVersion: `ide=${ideVersion};plugin=${pluginVersion};lsp=${lspVersion}`, + pluginVersion: pluginVersion, + lspVersion: lspVersion, } if (userContext.ideCategory === 'UNKNOWN' || userContext.operatingSystem === 'UNKNOWN') { From ef7d7931954f5083e4a5c358e67c6dc652fa1a40 Mon Sep 17 00:00:00 2001 From: Jason Guo <81202082+jguoamz@users.noreply.github.com> Date: Fri, 29 Aug 2025 16:15:27 -0700 Subject: [PATCH 053/158] fix: compact UI is not updated correctly when multiple nudges are displayed (#2192) --- .../language-server/agenticChat/agenticChatController.ts | 1 + .../src/language-server/chat/chatSessionService.ts | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 4a816317d2..4daa31db64 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -2707,6 +2707,7 @@ export class AgenticChatController implements ChatHandlers { session.setDeferredToolExecution(messageId, deferred.resolve, deferred.reject) this.#log(`Prompting for compaction approval for messageId: ${messageId}`) await deferred.promise + session.removeDeferredToolExecution(messageId) // Note: we want to overwrite the button block because it already exists in the stream. await resultStream.overwriteResultBlock(this.#getUpdateCompactConfirmResult(messageId), promptBlockId) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts index 92c7eb2c33..13c198a949 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts @@ -78,10 +78,17 @@ export class ChatSessionService { public getDeferredToolExecution(messageId: string): DeferredHandler | undefined { return this.#deferredToolExecution[messageId] } + public setDeferredToolExecution(messageId: string, resolve: any, reject: any) { this.#deferredToolExecution[messageId] = { resolve, reject } } + public removeDeferredToolExecution(messageId: string) { + if (messageId in this.#deferredToolExecution) { + delete this.#deferredToolExecution[messageId] + } + } + public getAllDeferredCompactMessageIds(): string[] { return Object.keys(this.#deferredToolExecution).filter(messageId => messageId.endsWith('_compact')) } From fd71e6cf3fc843242936564061061418edf83f56 Mon Sep 17 00:00:00 2001 From: tsmithsz <84354541+tsmithsz@users.noreply.github.com> Date: Tue, 2 Sep 2025 11:23:18 -0700 Subject: [PATCH 054/158] fix: fix calculation for num-lines contributed by the LLM (#2191) --- .../agenticChat/agenticChatController.ts | 5 +- .../utils/fileModificationMetrics.test.ts | 139 ++++++++++++++++++ .../utils/fileModificationMetrics.ts | 58 ++++++++ 3 files changed, 199 insertions(+), 3 deletions(-) create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/utils/fileModificationMetrics.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/utils/fileModificationMetrics.ts diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 4daa31db64..6c3f07fac2 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -166,6 +166,7 @@ import { FsWrite, FsWriteParams } from './tools/fsWrite' import { ExecuteBash, ExecuteBashParams } from './tools/executeBash' import { ExplanatoryParams, InvokeOutput, ToolApprovalException } from './tools/toolShared' import { validatePathBasic, validatePathExists, validatePaths as validatePathsSync } from './utils/pathValidation' +import { calculateModifiedLines } from './utils/fileModificationMetrics' import { GrepSearch, SanitizedRipgrepOutput } from './tools/grepSearch' import { FileSearch, FileSearchParams, isFileSearchParams } from './tools/fileSearch' import { FsReplace, FsReplaceParams } from './tools/fsReplace' @@ -2077,9 +2078,7 @@ export class AgenticChatController implements ChatHandlers { this.#abTestingAllocation?.userVariation ) // Emit acceptedLineCount when write tool is used and code changes are accepted - const beforeLines = cachedToolUse?.fileChange?.before?.split('\n').length ?? 0 - const afterLines = doc?.getText()?.split('\n').length ?? 0 - const acceptedLineCount = afterLines - beforeLines + const acceptedLineCount = calculateModifiedLines(toolUse, doc?.getText()) await this.#telemetryController.emitInteractWithMessageMetric( tabId, { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/utils/fileModificationMetrics.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/utils/fileModificationMetrics.test.ts new file mode 100644 index 0000000000..900b569e7e --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/utils/fileModificationMetrics.test.ts @@ -0,0 +1,139 @@ +import { calculateModifiedLines } from './fileModificationMetrics' +import { ToolUse } from '@amzn/codewhisperer-streaming' +import { FS_WRITE, FS_REPLACE } from '../constants/toolConstants' +import * as assert from 'assert' + +describe('calculateModifiedLines', () => { + describe('FS_WRITE', () => { + it('should count lines for create command', () => { + const toolUse: ToolUse = { + toolUseId: 'test-1', + name: FS_WRITE, + input: { + command: 'create', + path: '/test/file.txt', + fileText: 'line1\nline2\nline3', + }, + } + const afterContent = 'line1\nline2\nline3' + + assert.strictEqual(calculateModifiedLines(toolUse, afterContent), 3) + }) + + it('should count lines for append command', () => { + const toolUse: ToolUse = { + toolUseId: 'test-2', + name: FS_WRITE, + input: { + command: 'append', + path: '/test/file.txt', + fileText: 'line4\nline5', + }, + } + + assert.strictEqual(calculateModifiedLines(toolUse), 2) + }) + + it('should handle empty content', () => { + const toolUse: ToolUse = { + toolUseId: 'test-3', + name: FS_WRITE, + input: { + command: 'create', + path: '/test/file.txt', + fileText: '', + }, + } + + assert.strictEqual(calculateModifiedLines(toolUse, ''), 0) + }) + }) + + describe('FS_REPLACE', () => { + it('should count replaced lines correctly (double counting)', () => { + const toolUse: ToolUse = { + toolUseId: 'test-4', + name: FS_REPLACE, + input: { + path: '/test/file.txt', + diffs: [ + { + oldStr: 'old line 1\nold line 2\nold line 3', + newStr: 'new line 1\nnew line 2\nnew line 3', + }, + ], + }, + } + + assert.strictEqual(calculateModifiedLines(toolUse), 6) + }) + + it('should count pure deletions', () => { + const toolUse: ToolUse = { + toolUseId: 'test-5', + name: FS_REPLACE, + input: { + path: '/test/file.txt', + diffs: [ + { + oldStr: 'line to delete 1\nline to delete 2', + newStr: '', + }, + ], + }, + } + + assert.strictEqual(calculateModifiedLines(toolUse), 2) + }) + + it('should count pure insertions', () => { + const toolUse: ToolUse = { + toolUseId: 'test-6', + name: FS_REPLACE, + input: { + path: '/test/file.txt', + diffs: [ + { + oldStr: '', + newStr: 'new line 1\nnew line 2', + }, + ], + }, + } + + assert.strictEqual(calculateModifiedLines(toolUse), 2) + }) + + it('should handle multiple diffs', () => { + const toolUse: ToolUse = { + toolUseId: 'test-7', + name: FS_REPLACE, + input: { + path: '/test/file.txt', + diffs: [ + { + oldStr: 'old line 1', + newStr: 'new line 1', + }, + { + oldStr: 'delete this line', + newStr: '', + }, + ], + }, + } + + assert.strictEqual(calculateModifiedLines(toolUse), 3) + }) + }) + + it('should return 0 for unknown tools', () => { + const toolUse: ToolUse = { + toolUseId: 'test-8', + name: 'unknownTool', + input: {}, + } + + assert.strictEqual(calculateModifiedLines(toolUse), 0) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/utils/fileModificationMetrics.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/utils/fileModificationMetrics.ts new file mode 100644 index 0000000000..361c886607 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/utils/fileModificationMetrics.ts @@ -0,0 +1,58 @@ +import { ToolUse } from '@amzn/codewhisperer-streaming' +import { diffLines } from 'diff' +import { FsWriteParams } from '../tools/fsWrite' +import { FsReplaceParams } from '../tools/fsReplace' +import { FS_WRITE, FS_REPLACE } from '../constants/toolConstants' + +/** + * Counts the number of lines in text, handling different line endings + * @param text The text to count lines in + * @returns The number of lines + */ +function countLines(text?: string): number { + if (!text) return 0 + const parts = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n').split('\n') + return parts.length && parts[parts.length - 1] === '' ? parts.length - 1 : parts.length +} + +/** + * Calculates the actual lines modified by analyzing file modification tools. + * @param toolUse The tool use object + * @param afterContent The content after the tool execution (for FS_WRITE create operations) + * @returns The total number of lines modified (added + removed) + */ +export function calculateModifiedLines(toolUse: ToolUse, afterContent?: string): number { + if (toolUse.name === FS_WRITE) { + const input = toolUse.input as unknown as FsWriteParams + + if (input.command === 'create') { + return countLines(afterContent ?? '') + } else if (input.command === 'append') { + return countLines(input.fileText) + } + } + + if (toolUse.name === FS_REPLACE) { + const input = toolUse.input as unknown as FsReplaceParams + let linesAdded = 0 + let linesRemoved = 0 + + for (const diff of input.diffs || []) { + const oldStr = diff.oldStr ?? '' + const newStr = diff.newStr ?? '' + + const changes = diffLines(oldStr, newStr) + + for (const change of changes) { + if (change.added) { + linesAdded += countLines(change.value) + } else if (change.removed) { + linesRemoved += countLines(change.value) + } + } + } + + return linesAdded + linesRemoved + } + return 0 +} From 94723d46073a1ea8211e7ae8f9dfce3fcb809604 Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Tue, 2 Sep 2025 12:36:57 -0700 Subject: [PATCH 055/158] revert: PR 2172 dedupe openTabs supplemental contexts (#2194) This reverts commit aa87ae2bd95edc1f38bf90f56093c5bf5ff18c53. --- .../supplementalContextUtil/crossFileContextUtil.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/crossFileContextUtil.ts b/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/crossFileContextUtil.ts index 91f02b9dc7..39e97a3b8c 100644 --- a/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/crossFileContextUtil.ts +++ b/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/crossFileContextUtil.ts @@ -210,17 +210,8 @@ export async function fetchOpenTabsContext( }) } - // Dedupe code chunks based on their filePath + content unique key - const seen = new Set() - const deduped = supplementalContexts.filter(item => { - const key = `${item.filePath}:${item.content}` - if (seen.has(key)) return false - seen.add(key) - return true - }) - // DO NOT send code chunk with empty content - return deduped.filter(item => item.content.trim().length !== 0) + return supplementalContexts.filter(item => item.content.trim().length !== 0) } function findBestKChunkMatches(chunkInput: Chunk, chunkReferences: Chunk[], k: number): Chunk[] { From 58f20649d345f159080006120e23cde559826df1 Mon Sep 17 00:00:00 2001 From: chungjac Date: Tue, 2 Sep 2025 12:56:21 -0700 Subject: [PATCH 056/158] fix: emit errorMessage in addMessage (#2197) * emit errorMessage in addMessage * fix: emit errorMessage in addMessage --- .../language-server/agenticChat/agenticChatController.ts | 6 +++--- .../chat/telemetry/chatTelemetryController.ts | 8 +++++++- .../src/shared/telemetry/telemetryService.test.ts | 1 + .../src/shared/telemetry/telemetryService.ts | 2 ++ 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 6c3f07fac2..47739e77d1 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -3371,7 +3371,7 @@ export class AgenticChatController implements ChatHandlers { metric: Metric, agenticCodingMode: boolean ): Promise> { - const errorMessage = getErrorMsg(err) + const errorMessage = getErrorMsg(err) ?? GENERIC_ERROR_MS const requestID = getRequestID(err) ?? '' metric.setDimension('cwsprChatResponseCode', getHttpStatusCode(err) ?? 0) metric.setDimension('languageServerVersion', this.#features.runtime.serverInfo.version) @@ -3381,7 +3381,7 @@ export class AgenticChatController implements ChatHandlers { metric.metric.requestIds = [requestID] metric.metric.cwsprChatMessageId = errorMessageId metric.metric.cwsprChatConversationId = conversationId - await this.#telemetryController.emitAddMessageMetric(tabId, metric.metric, 'Failed') + await this.#telemetryController.emitAddMessageMetric(tabId, metric.metric, 'Failed', errorMessage) if (isUsageLimitError(err)) { if (this.#paidTierMode !== 'paidtier') { @@ -3426,7 +3426,7 @@ export class AgenticChatController implements ChatHandlers { tabId, metric.metric, requestID, - errorMessage ?? GENERIC_ERROR_MS, + errorMessage, agenticCodingMode ) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts index 580bcd4be2..797a1f640a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts @@ -294,7 +294,12 @@ export class ChatTelemetryController { }) } - public emitAddMessageMetric(tabId: string, metric: Partial, result?: string) { + public emitAddMessageMetric( + tabId: string, + metric: Partial, + result?: string, + errorMessage?: string + ) { const conversationId = this.getConversationId(tabId) // Store the customization value associated with the message if (metric.cwsprChatMessageId && metric.codewhispererCustomizationArn) { @@ -349,6 +354,7 @@ export class ChatTelemetryController { requestIds: metric.requestIds, experimentName: metric.experimentName, userVariation: metric.userVariation, + errorMessage: errorMessage, } ) } diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts index b6a5592f5f..d66ada7707 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts @@ -859,6 +859,7 @@ describe('TelemetryService', () => { cwsprChatPinnedFileContextCount: undefined, cwsprChatPinnedFolderContextCount: undefined, cwsprChatPinnedPromptContextCount: undefined, + errorMessage: undefined, }, }) }) diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts index cd2ba18254..78182c076f 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts @@ -564,6 +564,7 @@ export class TelemetryService { requestIds?: string[] experimentName?: string userVariation?: string + errorMessage?: string }> ) { const timeBetweenChunks = params.timeBetweenChunks?.slice(0, 100) @@ -617,6 +618,7 @@ export class TelemetryService { requestIds: truncatedRequestIds, experimentName: additionalParams.experimentName, userVariation: additionalParams.userVariation, + errorMessage: additionalParams.errorMessage, }, }) } From cb2b9a8c25982d1521e1546d7103c49b3cb9dd61 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 10:00:32 -0700 Subject: [PATCH 057/158] chore(release): release packages from branch main (#2190) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- package-lock.json | 2 +- server/aws-lsp-codewhisperer/CHANGELOG.md | 27 +++++++++++++++++++++++ server/aws-lsp-codewhisperer/package.json | 2 +- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e6baf94939..10e6c765df 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -2,7 +2,7 @@ "chat-client": "0.1.34", "core/aws-lsp-core": "0.0.14", "server/aws-lsp-antlr4": "0.1.18", - "server/aws-lsp-codewhisperer": "0.0.76", + "server/aws-lsp-codewhisperer": "0.0.77", "server/aws-lsp-json": "0.1.18", "server/aws-lsp-partiql": "0.0.17", "server/aws-lsp-yaml": "0.1.18" diff --git a/package-lock.json b/package-lock.json index 86d2516d9d..70518fd0ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28669,7 +28669,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.76", + "version": "0.0.77", "bundleDependencies": [ "@amzn/codewhisperer-streaming", "@amzn/amazon-q-developer-streaming-client" diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index 8bda2b6803..4bb50ee8fd 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,32 @@ # Changelog +## [0.0.77](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.76...lsp-codewhisperer/v0.0.77) (2025-09-02) + + +### Features + +* passing suggestionTypes and pluginVersion/lspVersion to STE ([#2180](https://github.com/aws/language-servers/issues/2180)) ([66742ad](https://github.com/aws/language-servers/commit/66742adfc44f33efbd8dd33b803000e08241e5ce)) + + +### Bug Fixes + +* auto trigger should only respect previous decisions in the past 2mins ([#2189](https://github.com/aws/language-servers/issues/2189)) ([852b21b](https://github.com/aws/language-servers/commit/852b21b66f793102c52e35c2baec07a772e5134a)) +* compact UI is not updated correctly when multiple nudges are displayed ([#2192](https://github.com/aws/language-servers/issues/2192)) ([ef7d793](https://github.com/aws/language-servers/commit/ef7d7931954f5083e4a5c358e67c6dc652fa1a40)) +* emit acceptedLineCount metric and AgenticCodeAccepted interaction type ([#2167](https://github.com/aws/language-servers/issues/2167)) ([c53f672](https://github.com/aws/language-servers/commit/c53f672b6173ebda530917ccb4e0c2f26f5c8f79)) +* emit errorMessage in addMessage ([#2197](https://github.com/aws/language-servers/issues/2197)) ([58f2064](https://github.com/aws/language-servers/commit/58f20649d345f159080006120e23cde559826df1)) +* fix calculation for num-lines contributed by the LLM ([#2191](https://github.com/aws/language-servers/issues/2191)) ([fd71e6c](https://github.com/aws/language-servers/commit/fd71e6cf3fc843242936564061061418edf83f56)) +* should send classifier score after taking sigmoid ([#2188](https://github.com/aws/language-servers/issues/2188)) ([f4e2e6e](https://github.com/aws/language-servers/commit/f4e2e6e885e665834a5d7b7cbb5f4ba4ff9bbb65)) + + +### Performance Improvements + +* only process edit requests 1 at a time ([#2187](https://github.com/aws/language-servers/issues/2187)) ([b497540](https://github.com/aws/language-servers/commit/b4975409a3ed518550290b72ac310895a293be4b)) + + +### Reverts + +* PR 2172 dedupe openTabs supplemental contexts ([#2194](https://github.com/aws/language-servers/issues/2194)) ([94723d4](https://github.com/aws/language-servers/commit/94723d46073a1ea8211e7ae8f9dfce3fcb809604)) + ## [0.0.76](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.75...lsp-codewhisperer/v0.0.76) (2025-08-27) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 8702e6fab3..aba60487ae 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.76", + "version": "0.0.77", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { From 34bc9bd1d3433bbb1d903eb0f212b10709ea8412 Mon Sep 17 00:00:00 2001 From: mkovelam Date: Wed, 3 Sep 2025 11:14:25 -0700 Subject: [PATCH 058/158] feat: model selection for code review tool (#2196) * feat: enabling model selection for code review tool * feat: added unit test for model selection for code review tool * fix: making modelId required for codeReviewTool in input schema validation * fix: fixing unit tests --------- Co-authored-by: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> --- .../client/token/bearer-token-service.json | 6 ++ .../token/codewhispererbearertokenclient.d.ts | 4 +- .../agenticChat/agenticChatController.ts | 1 + .../tools/qCodeAnalysis/codeReview.test.ts | 61 +++++++++++++++++++ .../tools/qCodeAnalysis/codeReview.ts | 11 +++- .../tools/qCodeAnalysis/codeReviewSchemas.ts | 1 + .../tools/qCodeAnalysis/codeReviewTypes.ts | 1 + 7 files changed, 83 insertions(+), 2 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json b/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json index 58ae54fb3c..f54c13cbdd 100644 --- a/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json +++ b/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json @@ -4822,6 +4822,12 @@ }, "profileArn": { "shape": "ProfileArn" + }, + "languageModelId": { + "shape": "ModelId" + }, + "clientType": { + "shape": "Origin" } } }, diff --git a/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts b/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts index 8e64023479..4c8018c84e 100644 --- a/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts +++ b/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts @@ -1539,6 +1539,8 @@ declare namespace CodeWhispererBearerTokenClient { codeScanName?: CodeScanName; codeDiffMetadata?: CodeDiffMetadata; profileArn?: ProfileArn; + languageModelId?: ModelId; + clientType?: Origin; } export type StartCodeAnalysisRequestClientTokenString = string; export interface StartCodeAnalysisResponse { @@ -2186,4 +2188,4 @@ declare namespace CodeWhispererBearerTokenClient { } export = CodeWhispererBearerTokenClient; - \ No newline at end of file + \ No newline at end of file diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 47739e77d1..e2fba029c4 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -1989,6 +1989,7 @@ export class AgenticChatController implements ChatHandlers { .filter(c => c.type === 'rule') .map(c => ({ path: c.path })) } + initialInput['modelId'] = session.modelId toolUse.input = initialInput } catch (e) { this.#features.logging.warn(`could not parse CodeReview tool input: ${e}`) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts index 3509cd1730..f6f735da09 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts @@ -11,6 +11,7 @@ import * as path from 'path' import { expect } from 'chai' import { CancellationError } from '@aws/lsp-core' import * as JSZip from 'jszip' +import { Origin } from '@amzn/codewhisperer-streaming' describe('CodeReview', () => { let sandbox: sinon.SinonSandbox @@ -103,6 +104,7 @@ describe('CodeReview', () => { folderLevelArtifacts: [], ruleArtifacts: [], scopeOfReview: FULL_REVIEW, + modelId: 'claude-4-sonnet', } }) @@ -143,6 +145,61 @@ describe('CodeReview', () => { expect(result.output.kind).to.equal('json') }) + it('should execute successfully and pass languageModelId and clientType to startCodeAnalysis', async () => { + const inputWithModelId = { + ...validInput, + modelId: 'test-model-789', + } + + // Setup mocks for successful execution + mockCodeWhispererClient.createUploadUrl.resolves({ + uploadUrl: 'https://upload.com', + uploadId: 'upload-123', + requestHeaders: {}, + }) + + mockCodeWhispererClient.startCodeAnalysis.resolves({ + jobId: 'job-123', + status: 'Pending', + }) + + mockCodeWhispererClient.getCodeAnalysis.resolves({ + status: 'Completed', + }) + + mockCodeWhispererClient.listCodeAnalysisFindings.resolves({ + codeAnalysisFindings: '[]', + nextToken: undefined, + }) + + sandbox.stub(CodeReviewUtils, 'uploadFileToPresignedUrl').resolves() + sandbox.stub(codeReview as any, 'prepareFilesAndFoldersForUpload').resolves({ + zipBuffer: Buffer.from('test'), + md5Hash: 'hash123', + isCodeDiffPresent: false, + programmingLanguages: new Set(['javascript']), + }) + sandbox.stub(codeReview as any, 'parseFindings').returns([]) + + const result = await codeReview.execute(inputWithModelId, context) + + expect(result.output.success).to.be.true + expect(result.output.kind).to.equal('json') + + // Verify that startCodeAnalysis was called with the correct parameters + expect(mockCodeWhispererClient.startCodeAnalysis.calledOnce).to.be.true + const startAnalysisCall = mockCodeWhispererClient.startCodeAnalysis.getCall(0) + const callArgs = startAnalysisCall.args[0] + + expect(callArgs).to.have.property('languageModelId', 'test-model-789') + expect(callArgs).to.have.property('clientType', Origin.IDE) + expect(callArgs).to.have.property('artifacts') + expect(callArgs).to.have.property('programmingLanguage') + expect(callArgs).to.have.property('clientToken') + expect(callArgs).to.have.property('codeScanName') + expect(callArgs).to.have.property('scope', 'AGENTIC') + }) + it('should handle missing client error', async () => { context.codeWhispererClient = undefined @@ -160,6 +217,7 @@ describe('CodeReview', () => { folderLevelArtifacts: [], ruleArtifacts: [], scopeOfReview: FULL_REVIEW, + modelId: 'claude-4-sonnet', } try { @@ -279,6 +337,7 @@ describe('CodeReview', () => { folderLevelArtifacts: [], ruleArtifacts: [], scopeOfReview: FULL_REVIEW, + modelId: 'claude-4-sonnet', } const context = { @@ -303,6 +362,7 @@ describe('CodeReview', () => { folderLevelArtifacts: [{ path: '/test/folder' }], ruleArtifacts: [], scopeOfReview: CODE_DIFF_REVIEW, + modelId: 'claude-4-sonnet', } const context = { @@ -614,6 +674,7 @@ describe('CodeReview', () => { folderLevelArtifacts: [], ruleArtifacts: [], scopeOfReview: FULL_REVIEW, + modelId: 'claude-4-sonnet', } // Make prepareFilesAndFoldersForUpload throw an error diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts index d9fd42d621..ece6a73486 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts @@ -31,6 +31,7 @@ import { SuccessMetricName, } from './codeReviewTypes' import { CancellationError } from '@aws/lsp-core' +import { Origin } from '@amzn/codewhisperer-streaming' export class CodeReview { private static readonly CUSTOMER_CODE_BASE_PATH = 'customerCodeBaseFolder' @@ -158,6 +159,7 @@ export class CodeReview { const fileArtifacts = validatedInput.fileLevelArtifacts || [] const folderArtifacts = validatedInput.folderLevelArtifacts || [] const ruleArtifacts = validatedInput.ruleArtifacts || [] + const modelId = validatedInput.modelId if (fileArtifacts.length === 0 && folderArtifacts.length === 0) { CodeReviewUtils.emitMetric( @@ -182,7 +184,7 @@ export class CodeReview { const programmingLanguage = 'java' const scanName = 'Standard-' + randomUUID() - this.logging.info(`Agentic scan name: ${scanName}`) + this.logging.info(`Agentic scan name: ${scanName} selectedModel: ${modelId}`) return { fileArtifacts, @@ -192,6 +194,7 @@ export class CodeReview { programmingLanguage, scanName, ruleArtifacts, + modelId, } } @@ -274,6 +277,8 @@ export class CodeReview { codeScanName: setup.scanName, scope: CodeReview.SCAN_SCOPE, codeDiffMetadata: uploadResult.isCodeDiffPresent ? { codeDiffPath: '/code_artifact/codeDiff/' } : undefined, + languageModelId: setup.modelId, + clientType: Origin.IDE, }) if (!createResponse.jobId) { @@ -293,6 +298,7 @@ export class CodeReview { customRules: setup.ruleArtifacts.length, programmingLanguages: Array.from(uploadResult.programmingLanguages), scope: setup.isFullReviewRequest ? FULL_REVIEW : CODE_DIFF_REVIEW, + modelId: setup.modelId, }, }, this.logging, @@ -349,6 +355,7 @@ export class CodeReview { programmingLanguages: Array.from(uploadResult.programmingLanguages), scope: setup.isFullReviewRequest ? FULL_REVIEW : CODE_DIFF_REVIEW, status: status, + modelId: setup.modelId, }, }, this.logging, @@ -382,6 +389,7 @@ export class CodeReview { programmingLanguages: Array.from(uploadResult.programmingLanguages), scope: setup.isFullReviewRequest ? FULL_REVIEW : CODE_DIFF_REVIEW, status: status, + modelId: setup.modelId, }, }, this.logging, @@ -426,6 +434,7 @@ export class CodeReview { programmingLanguages: Array.from(uploadResult.programmingLanguages), scope: setup.isFullReviewRequest ? FULL_REVIEW : CODE_DIFF_REVIEW, latency: Date.now() - this.toolStartTime, + modelId: setup.modelId, }, }, this.logging, diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewSchemas.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewSchemas.ts index d734412066..e805145244 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewSchemas.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewSchemas.ts @@ -113,6 +113,7 @@ export const Z_CODE_REVIEW_INPUT_SCHEMA = z.object({ }) ) .optional(), + modelId: z.string(), }) /** diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts index 728c226ae1..c684cfecd3 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts @@ -21,6 +21,7 @@ export type ValidateInputAndSetupResult = { programmingLanguage: string scanName: string ruleArtifacts: RuleArtifacts + modelId?: string } export type PrepareAndUploadArtifactsResult = { From 512502af947dcfed9288be2f67fc58affd4445fe Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Wed, 3 Sep 2025 16:32:17 -0700 Subject: [PATCH 059/158] fix(amazonq): fix to update MCP servers list when last server is removed from agent config (#2206) --- .../src/language-server/agenticChat/tools/mcp/mcpManager.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index 027e349cf5..41d721b74f 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -231,6 +231,9 @@ export class McpManager { } this.features.logging.info(`MCP: completed initialization of ${totalServers} servers`) + } else { + // Emit event to refresh MCP list page when no servers are configured + this.setState('no-servers', McpServerStatus.UNINITIALIZED, 0) } for (const [sanitizedName, _] of this.mcpServers.entries()) { From ab211c48ffcc2171aca7c39d43d7a64be78a08cd Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Wed, 3 Sep 2025 16:38:43 -0700 Subject: [PATCH 060/158] chore: merge agentic version 1.31.0 (#2205) * chore: bump agentic version: 1.31.0 * chore: empty commit to trigger release workflow (#2203) --------- Co-authored-by: aws-toolkit-automation <> --- app/aws-lsp-codewhisperer-runtimes/src/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/src/version.json b/app/aws-lsp-codewhisperer-runtimes/src/version.json index e842765e3f..6d9528a4e7 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/version.json +++ b/app/aws-lsp-codewhisperer-runtimes/src/version.json @@ -1,3 +1,3 @@ { - "agenticChat": "1.30.0" + "agenticChat": "1.31.0" } From 013aa5913c242451a91ed36b0dcf961a3f8ec697 Mon Sep 17 00:00:00 2001 From: andrewyuq <89420755+andrewyuq@users.noreply.github.com> Date: Wed, 3 Sep 2025 17:03:49 -0700 Subject: [PATCH 061/158] fix(amazonq): add IntelliSense autotriggerType (#2199) --- .../inline-completion/auto-trigger/autoTrigger.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts index 8990756dbf..b6657b229c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts @@ -32,7 +32,7 @@ export type CodewhispererTriggerType = 'AutoTrigger' | 'OnDemand' // Two triggers are explicitly handled, SpecialCharacters and Enter. Everything else is expected to be a trigger // based on regular typing, and is considered a 'Classifier' trigger. -export type CodewhispererAutomatedTriggerType = 'SpecialCharacters' | 'Enter' | 'Classifier' +export type CodewhispererAutomatedTriggerType = 'SpecialCharacters' | 'Enter' | 'Classifier' | 'IntelliSenseAcceptance' /** * Determine the trigger type based on the file context. Currently supports special cases for Special Characters and Enter keys, @@ -104,6 +104,10 @@ function isTabKey(str: string): boolean { return false } +function isIntelliSenseAcceptance(str: string) { + return str === 'IntelliSenseAcceptance' +} + // Reference: https://github.com/aws/aws-toolkit-vscode/blob/amazonq/v1.74.0/packages/core/src/codewhisperer/service/keyStrokeHandler.ts#L222 // Enter, Special character guarantees a trigger // Regular keystroke input will be evaluated by classifier @@ -126,6 +130,8 @@ export const getAutoTriggerType = ( return undefined } else if (isUserTypingSpecialChar(changedText)) { return 'SpecialCharacters' + } else if (isIntelliSenseAcceptance(changedText)) { + return 'IntelliSenseAcceptance' } else if (changedText.length === 1) { return 'Classifier' } else if (new RegExp('^[ ]+$').test(changedText)) { From 8bde8c97e1e3bcd67d9816a3385c50c7765c3b2f Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Fri, 5 Sep 2025 10:53:02 -0700 Subject: [PATCH 062/158] fix(amazonq): fix to correct the client for getProfile request (#2211) * fix(amazonq): fix to correct the client for getProfile request * fix(amazonq): removed unneccessary constructor objects * fix: fix to add assigned VARs in unit tests --- .../tools/mcp/profileStatusMonitor.test.ts | 76 +++++----------- .../tools/mcp/profileStatusMonitor.ts | 29 ++----- .../agenticChat/tools/toolServer.ts | 86 ++++++++----------- 3 files changed, 65 insertions(+), 126 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.test.ts index 77080bf08a..6fb0e56f9a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.test.ts @@ -3,17 +3,24 @@ * All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ -import { expect } from 'chai' +import * as chai from 'chai' import * as sinon from 'sinon' import { ProfileStatusMonitor } from './profileStatusMonitor' import * as AmazonQTokenServiceManagerModule from '../../../../shared/amazonQServiceManager/AmazonQTokenServiceManager' +const { expect } = chai + +interface MockLogging { + info: sinon.SinonStub + debug: sinon.SinonStub + error: sinon.SinonStub + warn: sinon.SinonStub + log: sinon.SinonStub +} + describe('ProfileStatusMonitor', () => { let profileStatusMonitor: ProfileStatusMonitor - let mockCredentialsProvider: any - let mockWorkspace: any - let mockLogging: any - let mockSdkInitializator: any + let mockLogging: MockLogging let mockOnMcpDisabled: sinon.SinonStub let mockOnMcpEnabled: sinon.SinonStub let clock: sinon.SinonFakeTimers @@ -21,29 +28,18 @@ describe('ProfileStatusMonitor', () => { beforeEach(() => { clock = sinon.useFakeTimers() - mockCredentialsProvider = { - hasCredentials: sinon.stub().returns(true), - } - - mockWorkspace = {} - mockLogging = { info: sinon.stub(), debug: sinon.stub(), + error: sinon.stub(), + warn: sinon.stub(), + log: sinon.stub(), } - mockSdkInitializator = {} mockOnMcpDisabled = sinon.stub() mockOnMcpEnabled = sinon.stub() - profileStatusMonitor = new ProfileStatusMonitor( - mockCredentialsProvider, - mockWorkspace, - mockLogging, - mockSdkInitializator, - mockOnMcpDisabled, - mockOnMcpEnabled - ) + profileStatusMonitor = new ProfileStatusMonitor(mockLogging, mockOnMcpDisabled, mockOnMcpEnabled) }) afterEach(() => { @@ -118,23 +114,9 @@ describe('ProfileStatusMonitor', () => { }) it('should be accessible across different instances', () => { - const monitor1 = new ProfileStatusMonitor( - mockCredentialsProvider, - mockWorkspace, - mockLogging, - mockSdkInitializator, - mockOnMcpDisabled, - mockOnMcpEnabled - ) - - const monitor2 = new ProfileStatusMonitor( - mockCredentialsProvider, - mockWorkspace, - mockLogging, - mockSdkInitializator, - mockOnMcpDisabled, - mockOnMcpEnabled - ) + const monitor1 = new ProfileStatusMonitor(mockLogging, mockOnMcpDisabled, mockOnMcpEnabled) + + const monitor2 = new ProfileStatusMonitor(mockLogging, mockOnMcpDisabled, mockOnMcpEnabled) // Set state through static property ;(ProfileStatusMonitor as any).lastMcpState = true @@ -151,23 +133,9 @@ describe('ProfileStatusMonitor', () => { }) it('should maintain state across multiple instances', () => { - const monitor1 = new ProfileStatusMonitor( - mockCredentialsProvider, - mockWorkspace, - mockLogging, - mockSdkInitializator, - mockOnMcpDisabled, - mockOnMcpEnabled - ) - - const monitor2 = new ProfileStatusMonitor( - mockCredentialsProvider, - mockWorkspace, - mockLogging, - mockSdkInitializator, - mockOnMcpDisabled, - mockOnMcpEnabled - ) + const monitor1 = new ProfileStatusMonitor(mockLogging, mockOnMcpDisabled, mockOnMcpEnabled) + + const monitor2 = new ProfileStatusMonitor(mockLogging, mockOnMcpDisabled, mockOnMcpEnabled) // Initially true (default value) expect(ProfileStatusMonitor.getMcpState()).to.be.true diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts index 53a4da9090..3489ad81be 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/profileStatusMonitor.ts @@ -3,15 +3,9 @@ * All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ -import { - CredentialsProvider, - Logging, - SDKInitializator, - Workspace, -} from '@aws/language-server-runtimes/server-interface' +import { Logging } from '@aws/language-server-runtimes/server-interface' import { retryUtils } from '@aws/lsp-core' import { CodeWhispererServiceToken } from '../../../../shared/codeWhispererService' -import { DEFAULT_AWS_Q_ENDPOINT_URL, DEFAULT_AWS_Q_REGION } from '../../../../shared/constants' import { AmazonQTokenServiceManager } from '../../../../shared/amazonQServiceManager/AmazonQTokenServiceManager' import * as fs from 'fs' import * as path from 'path' @@ -31,10 +25,7 @@ export class ProfileStatusMonitor { private static logging?: Logging constructor( - private credentialsProvider: CredentialsProvider, - private workspace: Workspace, private logging: Logging, - private sdkInitializator: SDKInitializator, private onMcpDisabled: () => void, private onMcpEnabled?: () => void ) { @@ -79,24 +70,15 @@ export class ProfileStatusMonitor { private async isMcpEnabled(): Promise { try { - const profileArn = this.getProfileArn() + const serviceManager = AmazonQTokenServiceManager.getInstance() + const profileArn = this.getProfileArn(serviceManager) if (!profileArn) { this.logging.debug('No profile ARN available for MCP configuration check') ProfileStatusMonitor.setMcpState(true) return true } - if (!this.codeWhispererClient) { - this.codeWhispererClient = new CodeWhispererServiceToken( - this.credentialsProvider, - this.workspace, - this.logging, - process.env.CODEWHISPERER_REGION || DEFAULT_AWS_Q_REGION, - process.env.CODEWHISPERER_ENDPOINT || DEFAULT_AWS_Q_ENDPOINT_URL, - this.sdkInitializator - ) - this.codeWhispererClient.profileArn = profileArn - } + this.codeWhispererClient = serviceManager.getCodewhispererService() const response = await retryUtils.retryWithBackoff(() => this.codeWhispererClient!.getProfile({ profileArn }) @@ -128,9 +110,8 @@ export class ProfileStatusMonitor { } } - private getProfileArn(): string | undefined { + private getProfileArn(serviceManager: AmazonQTokenServiceManager): string | undefined { try { - const serviceManager = AmazonQTokenServiceManager.getInstance() return serviceManager.getActiveProfileArn() } catch (error) { this.logging.debug(`Failed to get profile ARN: ${error}`) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts index 78871faa69..8581622972 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts @@ -210,7 +210,6 @@ export const McpToolsServer: Server = ({ agent, telemetry, runtime, - sdkInitializator, chat, }) => { const registered: Record = {} @@ -358,60 +357,51 @@ export const McpToolsServer: Server = ({ return } - if (sdkInitializator) { - profileStatusMonitor = new ProfileStatusMonitor( - credentialsProvider, - workspace, - logging, - sdkInitializator, - removeAllMcpTools, - async () => { - logging.info('MCP enabled by profile status monitor') - await initializeMcp() - } - ) - - // Wait for profile ARN to be available before checking MCP state - const checkAndInitialize = async () => { - await profileStatusMonitor!.checkInitialState() - // Always initialize McpManager to handle UI requests - await initializeMcp() + profileStatusMonitor = new ProfileStatusMonitor(logging, removeAllMcpTools, async () => { + logging.info('MCP enabled by profile status monitor') + await initializeMcp() + }) - // Remove tools if MCP is disabled - if (!ProfileStatusMonitor.getMcpState()) { - removeAllMcpTools() - } + // Wait for profile ARN to be available before checking MCP state + const checkAndInitialize = async () => { + await profileStatusMonitor!.checkInitialState() + // Always initialize McpManager to handle UI requests + await initializeMcp() - profileStatusMonitor!.start() + // Remove tools if MCP is disabled + if (!ProfileStatusMonitor.getMcpState()) { + removeAllMcpTools() } - // Check if service manager is ready - try { - const serviceManager = AmazonQTokenServiceManager.getInstance() - if (serviceManager.getState() === 'INITIALIZED') { - await checkAndInitialize() - } else { - // Poll for service manager to be ready with 10s timeout - const startTime = Date.now() - const pollForReady = async () => { - if (serviceManager.getState() === 'INITIALIZED') { - await checkAndInitialize() - } else if (Date.now() - startTime < SERVICE_MANAGER_TIMEOUT_MS) { - setTimeout(pollForReady, SERVICE_MANAGER_POLL_INTERVAL_MS) - } else { - logging.warn('Service manager not ready after 10s, initializing MCP manager') - await initializeMcp() - profileStatusMonitor!.start() - } + profileStatusMonitor!.start() + } + + // Check if service manager is ready + try { + const serviceManager = AmazonQTokenServiceManager.getInstance() + if (serviceManager.getState() === 'INITIALIZED') { + await checkAndInitialize() + } else { + // Poll for service manager to be ready with 10s timeout + const startTime = Date.now() + const pollForReady = async () => { + if (serviceManager.getState() === 'INITIALIZED') { + await checkAndInitialize() + } else if (Date.now() - startTime < SERVICE_MANAGER_TIMEOUT_MS) { + setTimeout(pollForReady, SERVICE_MANAGER_POLL_INTERVAL_MS) + } else { + logging.warn('Service manager not ready after 10s, initializing MCP manager') + await initializeMcp() + profileStatusMonitor!.start() } - setTimeout(pollForReady, SERVICE_MANAGER_POLL_INTERVAL_MS) } - } catch (error) { - // Service manager not initialized yet, always initialize McpManager - logging.info('Service manager not ready, initializing MCP manager') - await initializeMcp() - profileStatusMonitor!.start() + setTimeout(pollForReady, SERVICE_MANAGER_POLL_INTERVAL_MS) } + } catch (error) { + // Service manager not initialized yet, always initialize McpManager + logging.info('Service manager not ready, initializing MCP manager') + await initializeMcp() + profileStatusMonitor!.start() } } catch (error) { console.warn('Caught error during MCP tool initialization; initialization may be incomplete:', error) From 2ddcae7a4fac6b89cbc9784911959743ea0a6d11 Mon Sep 17 00:00:00 2001 From: Lei Gao <97199248+leigaol@users.noreply.github.com> Date: Fri, 5 Sep 2025 14:18:13 -0700 Subject: [PATCH 063/158] feat: add support for getSupplementalContext LSP API (#2212) * feat: add supplemental context API * feat: add supplemental context API support --- app/aws-lsp-antlr4-runtimes/package.json | 2 +- app/aws-lsp-buildspec-runtimes/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- app/aws-lsp-identity-runtimes/package.json | 2 +- app/aws-lsp-json-runtimes/package.json | 2 +- .../package.json | 2 +- app/aws-lsp-partiql-runtimes/package.json | 2 +- app/aws-lsp-s3-runtimes/package.json | 2 +- app/aws-lsp-yaml-json-webworker/package.json | 2 +- app/aws-lsp-yaml-runtimes/package.json | 2 +- app/hello-world-lsp-runtimes/package.json | 2 +- chat-client/package.json | 2 +- client/vscode/package.json | 2 +- core/aws-lsp-core/package.json | 2 +- .../q-agentic-chat-server/package.json | 2 +- package-lock.json | 63 ++++++++++--------- server/aws-lsp-antlr4/package.json | 2 +- server/aws-lsp-buildspec/package.json | 2 +- server/aws-lsp-cloudformation/package.json | 2 +- server/aws-lsp-codewhisperer/package.json | 2 +- .../localProjectContextServer.ts | 25 +++++++- server/aws-lsp-identity/package.json | 2 +- server/aws-lsp-json/package.json | 2 +- server/aws-lsp-notification/package.json | 2 +- server/aws-lsp-partiql/package.json | 2 +- server/aws-lsp-s3/package.json | 2 +- server/aws-lsp-yaml/package.json | 2 +- server/device-sso-auth-lsp/package.json | 2 +- server/hello-world-lsp/package.json | 2 +- 30 files changed, 84 insertions(+), 60 deletions(-) diff --git a/app/aws-lsp-antlr4-runtimes/package.json b/app/aws-lsp-antlr4-runtimes/package.json index 89fa95dcb3..20409656e1 100644 --- a/app/aws-lsp-antlr4-runtimes/package.json +++ b/app/aws-lsp-antlr4-runtimes/package.json @@ -12,7 +12,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-antlr4": "*", "antlr4-c3": "^3.4.1", "antlr4ng": "^3.0.4" diff --git a/app/aws-lsp-buildspec-runtimes/package.json b/app/aws-lsp-buildspec-runtimes/package.json index 0ad07ddb8f..a080ed2edb 100644 --- a/app/aws-lsp-buildspec-runtimes/package.json +++ b/app/aws-lsp-buildspec-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-buildspec": "^0.0.1" } } diff --git a/app/aws-lsp-cloudformation-runtimes/package.json b/app/aws-lsp-cloudformation-runtimes/package.json index d211149d0d..ad4c547839 100644 --- a/app/aws-lsp-cloudformation-runtimes/package.json +++ b/app/aws-lsp-cloudformation-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-cloudformation": "^0.0.1" } } diff --git a/app/aws-lsp-codewhisperer-runtimes/package.json b/app/aws-lsp-codewhisperer-runtimes/package.json index b890c01a78..18de7dab8c 100644 --- a/app/aws-lsp-codewhisperer-runtimes/package.json +++ b/app/aws-lsp-codewhisperer-runtimes/package.json @@ -23,7 +23,7 @@ "local-build": "node scripts/local-build.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", diff --git a/app/aws-lsp-identity-runtimes/package.json b/app/aws-lsp-identity-runtimes/package.json index f33fa80da4..4aa4f9d7f3 100644 --- a/app/aws-lsp-identity-runtimes/package.json +++ b/app/aws-lsp-identity-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-identity": "^0.0.1" } } diff --git a/app/aws-lsp-json-runtimes/package.json b/app/aws-lsp-json-runtimes/package.json index db1949f54b..78815f73cc 100644 --- a/app/aws-lsp-json-runtimes/package.json +++ b/app/aws-lsp-json-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-json": "*" }, "devDependencies": { diff --git a/app/aws-lsp-notification-runtimes/package.json b/app/aws-lsp-notification-runtimes/package.json index a5eeecae49..cb5e90a9e5 100644 --- a/app/aws-lsp-notification-runtimes/package.json +++ b/app/aws-lsp-notification-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-notification": "^0.0.1" } } diff --git a/app/aws-lsp-partiql-runtimes/package.json b/app/aws-lsp-partiql-runtimes/package.json index d483f3d0ce..21f089c3d6 100644 --- a/app/aws-lsp-partiql-runtimes/package.json +++ b/app/aws-lsp-partiql-runtimes/package.json @@ -11,7 +11,7 @@ "package": "npm run compile && npm run compile:webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-partiql": "^0.0.5" }, "devDependencies": { diff --git a/app/aws-lsp-s3-runtimes/package.json b/app/aws-lsp-s3-runtimes/package.json index 9feb4f7ddc..a5eac053e3 100644 --- a/app/aws-lsp-s3-runtimes/package.json +++ b/app/aws-lsp-s3-runtimes/package.json @@ -10,7 +10,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-s3": "^0.0.1" } } diff --git a/app/aws-lsp-yaml-json-webworker/package.json b/app/aws-lsp-yaml-json-webworker/package.json index fc524cabdc..14f0c58491 100644 --- a/app/aws-lsp-yaml-json-webworker/package.json +++ b/app/aws-lsp-yaml-json-webworker/package.json @@ -11,7 +11,7 @@ "serve:webpack": "NODE_ENV=development webpack serve" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, diff --git a/app/aws-lsp-yaml-runtimes/package.json b/app/aws-lsp-yaml-runtimes/package.json index 09bb93ee9a..e935c9ee0a 100644 --- a/app/aws-lsp-yaml-runtimes/package.json +++ b/app/aws-lsp-yaml-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-yaml": "*" }, "devDependencies": { diff --git a/app/hello-world-lsp-runtimes/package.json b/app/hello-world-lsp-runtimes/package.json index bff976d9b3..0d372ab621 100644 --- a/app/hello-world-lsp-runtimes/package.json +++ b/app/hello-world-lsp-runtimes/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@aws/hello-world-lsp": "^0.0.1", - "@aws/language-server-runtimes": "^0.2.127" + "@aws/language-server-runtimes": "^0.2.128" }, "devDependencies": { "@types/chai": "^4.3.5", diff --git a/chat-client/package.json b/chat-client/package.json index b838360175..bf20eecb9d 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/language-server-runtimes-types": "^0.1.50", "@aws/mynah-ui": "^4.36.5" }, diff --git a/client/vscode/package.json b/client/vscode/package.json index a5d7f66d21..6b936bfd3f 100644 --- a/client/vscode/package.json +++ b/client/vscode/package.json @@ -352,7 +352,7 @@ "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", diff --git a/core/aws-lsp-core/package.json b/core/aws-lsp-core/package.json index 54ca980fc1..3057954dce 100644 --- a/core/aws-lsp-core/package.json +++ b/core/aws-lsp-core/package.json @@ -28,7 +28,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", diff --git a/integration-tests/q-agentic-chat-server/package.json b/integration-tests/q-agentic-chat-server/package.json index ffb33f1a4e..7018052547 100644 --- a/integration-tests/q-agentic-chat-server/package.json +++ b/integration-tests/q-agentic-chat-server/package.json @@ -9,7 +9,7 @@ "test-integ": "npm run compile && mocha --timeout 30000 \"./out/**/*.test.js\" --retries 2" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "*" }, "devDependencies": { diff --git a/package-lock.json b/package-lock.json index 70518fd0ab..e84567b613 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,7 +48,7 @@ "name": "@aws/lsp-antlr4-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-antlr4": "*", "antlr4-c3": "^3.4.1", "antlr4ng": "^3.0.4" @@ -71,7 +71,7 @@ "name": "@aws/lsp-buildspec-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-buildspec": "^0.0.1" } }, @@ -79,7 +79,7 @@ "name": "@aws/lsp-cloudformation-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-cloudformation": "^0.0.1" } }, @@ -87,7 +87,7 @@ "name": "@aws/lsp-codewhisperer-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", @@ -120,7 +120,7 @@ "name": "@aws/lsp-identity-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-identity": "^0.0.1" } }, @@ -128,7 +128,7 @@ "name": "@aws/lsp-json-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-json": "*" }, "devDependencies": { @@ -148,7 +148,7 @@ "name": "@aws/lsp-notification-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-notification": "^0.0.1" } }, @@ -156,7 +156,7 @@ "name": "@aws/lsp-partiql-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.125", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-partiql": "^0.0.5" }, "devDependencies": { @@ -181,7 +181,7 @@ "name": "@aws/lsp-s3-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-s3": "^0.0.1" }, "bin": { @@ -192,7 +192,7 @@ "name": "@aws/lsp-yaml-json-webworker", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, @@ -212,7 +212,7 @@ "name": "@aws/lsp-yaml-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-yaml": "*" }, "devDependencies": { @@ -234,7 +234,7 @@ "version": "0.0.1", "dependencies": { "@aws/hello-world-lsp": "^0.0.1", - "@aws/language-server-runtimes": "^0.2.127" + "@aws/language-server-runtimes": "^0.2.128" }, "devDependencies": { "@types/chai": "^4.3.5", @@ -255,7 +255,7 @@ "license": "Apache-2.0", "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/language-server-runtimes-types": "^0.1.50", "@aws/mynah-ui": "^4.36.5" }, @@ -280,7 +280,7 @@ "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", @@ -296,7 +296,7 @@ "version": "0.0.14", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", @@ -327,7 +327,7 @@ "name": "@aws/q-agentic-chat-server-integration-tests", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "*" }, "devDependencies": { @@ -4036,9 +4036,10 @@ "link": true }, "node_modules/@aws/language-server-runtimes": { - "version": "0.2.127", - "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.2.127.tgz", - "integrity": "sha512-UWCfv49MYaBhxArVBWTEw2XVfIyunbm6EfS9AxSLPudcwrpOg3KAVLooXearmyM/r2hgNDGCQYI8HuKf5FAnew==", + "version": "0.2.128", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.2.128.tgz", + "integrity": "sha512-C666VAvY2PQ8CQkDzjL/+N9rfcFzY6vuGe733drMwwRVHt8On0B0PQPjy31ZjxHUUcjVp78Nb9vmSUEVBfxGTQ==", + "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes-types": "^0.1.56", "@opentelemetry/api": "^1.9.0", @@ -28607,7 +28608,7 @@ "version": "0.1.18", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "^0.0.14" }, "devDependencies": { @@ -28649,7 +28650,7 @@ "name": "@aws/lsp-buildspec", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", @@ -28660,7 +28661,7 @@ "name": "@aws/lsp-cloudformation", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", @@ -28682,7 +28683,7 @@ "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "^0.0.14", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", @@ -28822,7 +28823,7 @@ "dependencies": { "@aws-sdk/client-sso-oidc": "^3.616.0", "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "^0.0.12", "@smithy/node-http-handler": "^3.2.5", "@smithy/shared-ini-file-loader": "^4.0.1", @@ -28887,7 +28888,7 @@ "version": "0.1.18", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "^0.0.14", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" @@ -28904,7 +28905,7 @@ "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1" }, @@ -28965,7 +28966,7 @@ "version": "0.0.17", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "antlr4-c3": "3.4.2", "antlr4ng": "3.0.14", "web-tree-sitter": "0.22.6" @@ -28987,7 +28988,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" @@ -29018,7 +29019,7 @@ "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "^0.0.14", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", @@ -29032,7 +29033,7 @@ "name": "@amzn/device-sso-auth-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "vscode-languageserver": "^9.0.1" }, "devDependencies": { @@ -29043,7 +29044,7 @@ "name": "@aws/hello-world-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/server/aws-lsp-antlr4/package.json b/server/aws-lsp-antlr4/package.json index 2ca49593d7..9cad906eee 100644 --- a/server/aws-lsp-antlr4/package.json +++ b/server/aws-lsp-antlr4/package.json @@ -28,7 +28,7 @@ "clean": "rm -rf node_modules" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "^0.0.14" }, "peerDependencies": { diff --git a/server/aws-lsp-buildspec/package.json b/server/aws-lsp-buildspec/package.json index 9754645b7d..f0184e0ff8 100644 --- a/server/aws-lsp-buildspec/package.json +++ b/server/aws-lsp-buildspec/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-cloudformation/package.json b/server/aws-lsp-cloudformation/package.json index 13be6a4859..89b56ede3f 100644 --- a/server/aws-lsp-cloudformation/package.json +++ b/server/aws-lsp-cloudformation/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index aba60487ae..5284a0b41f 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -36,7 +36,7 @@ "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "^0.0.14", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", diff --git a/server/aws-lsp-codewhisperer/src/language-server/localProjectContext/localProjectContextServer.ts b/server/aws-lsp-codewhisperer/src/language-server/localProjectContext/localProjectContextServer.ts index 1fa2b8301b..9cff865038 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/localProjectContext/localProjectContextServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/localProjectContext/localProjectContextServer.ts @@ -1,4 +1,10 @@ -import { InitializeParams, Server, TextDocumentSyncKind } from '@aws/language-server-runtimes/server-interface' +import { + GetSupplementalContextParams, + InitializeParams, + Server, + SupplementalContextItem, + TextDocumentSyncKind, +} from '@aws/language-server-runtimes/server-interface' import { getOrThrowBaseTokenServiceManager } from '../../shared/amazonQServiceManager/AmazonQTokenServiceManager' import { TelemetryService } from '../../shared/telemetry/telemetryService' import { LocalProjectContextController } from '../../shared/localProjectContextController' @@ -127,6 +133,23 @@ export const LocalProjectContextServer = } }) + const onGetSupplementalContext = async ( + param: GetSupplementalContextParams + ): Promise => { + if (localProjectContextController) { + const request = { + query: '', + filePath: param.filePath, + target: 'codemap', + } + const response = await localProjectContextController.queryInlineProjectContext(request) + return response + } + return [] + } + + lsp.extensions.onGetSupplementalContext(onGetSupplementalContext) + lsp.onDidSaveTextDocument(async event => { try { const filePaths = VSCWindowsOverride diff --git a/server/aws-lsp-identity/package.json b/server/aws-lsp-identity/package.json index 9aa4bedcbf..3d90af77e4 100644 --- a/server/aws-lsp-identity/package.json +++ b/server/aws-lsp-identity/package.json @@ -26,7 +26,7 @@ "dependencies": { "@aws-sdk/client-sso-oidc": "^3.616.0", "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "^0.0.12", "@smithy/node-http-handler": "^3.2.5", "@smithy/shared-ini-file-loader": "^4.0.1", diff --git a/server/aws-lsp-json/package.json b/server/aws-lsp-json/package.json index ee5fbbc47a..6b2c95bc49 100644 --- a/server/aws-lsp-json/package.json +++ b/server/aws-lsp-json/package.json @@ -26,7 +26,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "^0.0.14", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" diff --git a/server/aws-lsp-notification/package.json b/server/aws-lsp-notification/package.json index f19ddc54ca..740a109f48 100644 --- a/server/aws-lsp-notification/package.json +++ b/server/aws-lsp-notification/package.json @@ -22,7 +22,7 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1" }, diff --git a/server/aws-lsp-partiql/package.json b/server/aws-lsp-partiql/package.json index dc2fc2ee22..e5f59a4411 100644 --- a/server/aws-lsp-partiql/package.json +++ b/server/aws-lsp-partiql/package.json @@ -24,7 +24,7 @@ "out" ], "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "antlr4-c3": "3.4.2", "antlr4ng": "3.0.14", "web-tree-sitter": "0.22.6" diff --git a/server/aws-lsp-s3/package.json b/server/aws-lsp-s3/package.json index 914628d14e..8829f1dd87 100644 --- a/server/aws-lsp-s3/package.json +++ b/server/aws-lsp-s3/package.json @@ -9,7 +9,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" diff --git a/server/aws-lsp-yaml/package.json b/server/aws-lsp-yaml/package.json index fe115132c8..213221d721 100644 --- a/server/aws-lsp-yaml/package.json +++ b/server/aws-lsp-yaml/package.json @@ -26,7 +26,7 @@ "postinstall": "node patchYamlPackage.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "@aws/lsp-core": "^0.0.14", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", diff --git a/server/device-sso-auth-lsp/package.json b/server/device-sso-auth-lsp/package.json index e5085aa6bd..9bca2bf0b7 100644 --- a/server/device-sso-auth-lsp/package.json +++ b/server/device-sso-auth-lsp/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/server/hello-world-lsp/package.json b/server/hello-world-lsp/package.json index 8ab207f8b4..b5944a3223 100644 --- a/server/hello-world-lsp/package.json +++ b/server/hello-world-lsp/package.json @@ -13,7 +13,7 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.127", + "@aws/language-server-runtimes": "^0.2.128", "vscode-languageserver": "^9.0.1" }, "devDependencies": { From 12229059421b773d3e99d28809fdff4abf242b26 Mon Sep 17 00:00:00 2001 From: Rajanna-Karthik Date: Mon, 8 Sep 2025 09:59:54 -0700 Subject: [PATCH 064/158] feat: add custom_transformation folder support to artifact.zip (#2201) * feat: add custom_transformation folder support to artifact.zip * feat: add custom transformation folder support with async file operations * fix: improve custom transformation folder access logging message --------- Co-authored-by: huawenm <72728725+huawenm@users.noreply.github.com> --- .../netTransform/artifactManager.ts | 22 ++++++++++++++++++- ...teTransformationPreferencesContent.test.ts | 2 +- ...factManager.processPrivatePackages.test.ts | 2 +- .../netTransform/transformHandler.ts | 3 ++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts index 0b510e7c64..4b1e9818cd 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts @@ -22,16 +22,19 @@ const zipFileName = 'artifact.zip' const sourceCodeFolderName = 'sourceCode' const packagesFolderName = 'packages' const thirdPartyPackageFolderName = 'thirdpartypackages' +const customTransformationFolderName = 'customTransformation' export class ArtifactManager { private workspace: Workspace private logging: Logging private workspacePath: string + private solutionRootPath: string - constructor(workspace: Workspace, logging: Logging, workspacePath: string) { + constructor(workspace: Workspace, logging: Logging, workspacePath: string, solutionRootPath: string) { this.workspace = workspace this.logging = logging this.workspacePath = workspacePath + this.solutionRootPath = solutionRootPath } async createZip(request: StartTransformRequest): Promise { @@ -282,6 +285,23 @@ export class ArtifactManager { this.logging.log('Cannot find artifacts folder') return '' } + + const customTransformationPath = path.join(this.solutionRootPath, customTransformationFolderName) + try { + await fs.promises.access(customTransformationPath) + try { + this.logging.log(`Adding custom transformation folder to artifact: ${customTransformationPath}`) + const artifactCustomTransformationPath = path.join(folderPath, customTransformationFolderName) + await fs.promises.cp(customTransformationPath, artifactCustomTransformationPath, { recursive: true }) + } catch (error) { + this.logging.warn(`Failed to copy custom transformation folder: ${error}`) + } + } catch { + this.logging.log( + `Custom transformation folder not accessible (not found or no permissions): ${customTransformationPath}` + ) + } + const zipPath = path.join(this.workspacePath, zipFileName) this.logging.log('Zipping files to ' + zipPath) await this.zipDirectory(folderPath, zipPath) diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.createTransformationPreferencesContent.test.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.createTransformationPreferencesContent.test.ts index 24d89651fa..582dcb63e3 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.createTransformationPreferencesContent.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.createTransformationPreferencesContent.test.ts @@ -14,7 +14,7 @@ describe('ArtifactManager - createTransformationPreferencesContent', () => { beforeEach(() => { workspace = stubInterface() mockedLogging = stubInterface() - artifactManager = new ArtifactManager(workspace, mockedLogging, '') + artifactManager = new ArtifactManager(workspace, mockedLogging, '', '') // Create a clean base request for each test baseRequest = { diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.processPrivatePackages.test.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.processPrivatePackages.test.ts index ea1835d132..848744504e 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.processPrivatePackages.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.processPrivatePackages.test.ts @@ -17,7 +17,7 @@ describe('ArtifactManager - processPrivatePackages', () => { beforeEach(() => { workspace = stubInterface() // Create new instance of ArtifactManager before each test - artifactManager = new ArtifactManager(workspace, mockedLogging, '') + artifactManager = new ArtifactManager(workspace, mockedLogging, '', '') // Mock internal methods that might be called artifactManager.copyFile = async (source: string, destination: string) => { diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/transformHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/transformHandler.ts index b8bc80b30c..ee4f6f97cd 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/transformHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/transformHandler.ts @@ -58,7 +58,8 @@ export class TransformHandler { const artifactManager = new ArtifactManager( this.workspace, this.logging, - this.getWorkspacePath(userInputrequest.SolutionRootPath) + this.getWorkspacePath(userInputrequest.SolutionRootPath), + userInputrequest.SolutionRootPath ) try { const payloadFilePath = await this.zipCodeAsync(userInputrequest, artifactManager) From da4c3db5329bd50cfe249bf8c1d59afa9bcb0157 Mon Sep 17 00:00:00 2001 From: BlakeLazarine Date: Mon, 8 Sep 2025 16:13:32 -0700 Subject: [PATCH 065/158] feat(amazonq): default to diff-based scans (#2195) * feat(amazonq): default to diff-based scans * feat(amazonq): make /review behavior clearly show it is a diff scan * fix(amazonq): clean up commented lines * fix(amazonq): fix maximum finding count in CodeReview tool description * fix(amazonq): improve messaging for diff vs full scans * feat(amazonq): have codeReview tool ask for clarification if it is not sure what scope to review * feat(amazonq): when there is no diff, fall back to a full review * Update chat-client/src/client/mynahUi.ts Co-authored-by: Tai Lai * fix(amazonq): fix test * fix(amazonq): fix another test --------- Co-authored-by: Blake Lazarine Co-authored-by: Tai Lai --- chat-client/src/client/mynahUi.ts | 2 +- .../tools/qCodeAnalysis/codeReview.test.ts | 5 ++ .../tools/qCodeAnalysis/codeReview.ts | 84 ++++++++++++++----- .../qCodeAnalysis/codeReviewConstants.ts | 62 ++++++++------ .../tools/qCodeAnalysis/codeReviewSchemas.ts | 14 ++-- .../tools/qCodeAnalysis/codeReviewTypes.ts | 2 + .../tools/qCodeAnalysis/codeReviewUtils.ts | 31 +++++++ 7 files changed, 147 insertions(+), 53 deletions(-) diff --git a/chat-client/src/client/mynahUi.ts b/chat-client/src/client/mynahUi.ts index 15cbeae7ff..090e5bbf4d 100644 --- a/chat-client/src/client/mynahUi.ts +++ b/chat-client/src/client/mynahUi.ts @@ -1793,7 +1793,7 @@ const DEFAULT_TEST_PROMPT = `You are Amazon Q. Start with a warm greeting, then const DEFAULT_DEV_PROMPT = `You are Amazon Q. Start with a warm greeting, then ask the user to specify what kind of help they need in code development. Present common questions asked (like Creating a new project, Adding a new feature, Modifying your files). Keep the question brief and friendly. Don't make assumptions about existing content or context. Wait for their response before providing specific guidance.` -const DEFAULT_REVIEW_PROMPT = `You are Amazon Q. Start with a warm greeting, then use code review tool to perform code analysis of the open file. If there is no open file, ask what the user would like to review.` +const DEFAULT_REVIEW_PROMPT = `You are Amazon Q. Start with a warm greeting, then use code review tool to perform a diff review code analysis of the open file. If there is no open file, ask what the user would like to review. Please tell the user that the scan is a diff scan.` export const uiComponentsTexts = { mainTitle: 'Amazon Q (Preview)', diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts index f6f735da09..71586d3450 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts @@ -136,6 +136,7 @@ describe('CodeReview', () => { md5Hash: 'hash123', isCodeDiffPresent: false, programmingLanguages: new Set(['javascript']), + codeDiffFiles: new Set(), }) sandbox.stub(codeReview as any, 'parseFindings').returns([]) @@ -178,6 +179,7 @@ describe('CodeReview', () => { md5Hash: 'hash123', isCodeDiffPresent: false, programmingLanguages: new Set(['javascript']), + codeDiffFiles: new Set(), }) sandbox.stub(codeReview as any, 'parseFindings').returns([]) @@ -241,6 +243,7 @@ describe('CodeReview', () => { md5Hash: 'hash123', isCodeDiffPresent: false, programmingLanguages: new Set(['javascript']), + codeDiffFiles: new Set(), }) try { @@ -268,6 +271,7 @@ describe('CodeReview', () => { md5Hash: 'hash123', isCodeDiffPresent: false, programmingLanguages: new Set(['javascript']), + codeDiffFiles: new Set(), }) try { @@ -301,6 +305,7 @@ describe('CodeReview', () => { md5Hash: 'hash123', isCodeDiffPresent: false, programmingLanguages: new Set(['javascript']), + codeDiffFiles: new Set(), }) // Stub setTimeout to avoid actual delays diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts index ece6a73486..74d6d817a1 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts @@ -44,7 +44,7 @@ export class CodeReview { private static readonly POLLING_INTERVAL_MS = 10000 // 10 seconds private static readonly UPLOAD_INTENT = 'AGENTIC_CODE_REVIEW' private static readonly SCAN_SCOPE = 'AGENTIC' - private static readonly MAX_FINDINGS_COUNT = 50 + private static readonly MAX_FINDINGS_COUNT = 40 private static readonly ERROR_MESSAGES = { MISSING_CLIENT: 'CodeWhisperer client not available', @@ -67,6 +67,7 @@ export class CodeReview { private cancellationToken?: CancellationToken private writableStream?: WritableStream private toolStartTime: number = 0 + private overrideDiffScan = false constructor( features: Pick & Partial @@ -111,7 +112,16 @@ export class CodeReview { const analysisResult = await this.startCodeAnalysis(setup, uploadResult) this.checkCancellation() - await chatStreamWriter?.write('Reviewing your code...') + const nonRuleFiles = uploadResult.numberOfFilesInCustomerCodeZip - setup.ruleArtifacts.length + const diffFiles = uploadResult.codeDiffFiles.size + if (diffFiles == 0 && !setup.isFullReviewRequest) { + setup.isFullReviewRequest = true + this.overrideDiffScan = true + } + const reviewMessage = setup.isFullReviewRequest + ? `Reviewing the entire code in ${nonRuleFiles} file${nonRuleFiles > 1 ? 's' : ''}...` + : `Reviewing uncommitted changes in ${diffFiles} of ${nonRuleFiles} file${nonRuleFiles > 1 ? 's' : ''}...` + await chatStreamWriter?.write(reviewMessage) // 4. Wait for scan to complete await this.pollForCompletion(analysisResult.jobId, setup, uploadResult, chatStreamWriter) @@ -206,13 +216,19 @@ export class CodeReview { private async prepareAndUploadArtifacts( setup: ValidateInputAndSetupResult ): Promise { - const { zipBuffer, md5Hash, isCodeDiffPresent, programmingLanguages } = - await this.prepareFilesAndFoldersForUpload( - setup.fileArtifacts, - setup.folderArtifacts, - setup.ruleArtifacts, - setup.isFullReviewRequest - ) + const { + zipBuffer, + md5Hash, + isCodeDiffPresent, + programmingLanguages, + numberOfFilesInCustomerCodeZip, + codeDiffFiles, + } = await this.prepareFilesAndFoldersForUpload( + setup.fileArtifacts, + setup.folderArtifacts, + setup.ruleArtifacts, + setup.isFullReviewRequest + ) const uploadUrlResponse = await this.codeWhispererClient!.createUploadUrl({ contentLength: zipBuffer.length, @@ -257,6 +273,8 @@ export class CodeReview { isCodeDiffPresent, artifactSize: zipBuffer.length, programmingLanguages: programmingLanguages, + numberOfFilesInCustomerCodeZip, + codeDiffFiles, } } @@ -470,9 +488,13 @@ export class CodeReview { ) }) + let scopeMessage = this.overrideDiffScan + ? `Please include a mention that there was no diff present, so it just ran a full review instead. Be very explicit about this so that the user could not be confused.` + : `Please include a mention that the scan was on the ${setup.isFullReviewRequest ? `entire` : `uncommitted`} code.` + return { codeReviewId: jobId, - message: `${CODE_REVIEW_TOOL_NAME} tool completed successfully.${findingsExceededLimit ? ` Inform the user that we are limiting findings to top ${CodeReview.MAX_FINDINGS_COUNT} based on severity.` : ''}`, + message: `${CODE_REVIEW_TOOL_NAME} tool completed successfully. ${scopeMessage} ${findingsExceededLimit ? ` Inform the user that we are limiting findings to top ${CodeReview.MAX_FINDINGS_COUNT} based on severity.` : ''}`, findingsByFile: JSON.stringify(aggregatedCodeScanIssueList), } } @@ -559,7 +581,14 @@ export class CodeReview { folderArtifacts: FolderArtifacts, ruleArtifacts: RuleArtifacts, isFullReviewRequest: boolean - ): Promise<{ zipBuffer: Buffer; md5Hash: string; isCodeDiffPresent: boolean; programmingLanguages: Set }> { + ): Promise<{ + zipBuffer: Buffer + md5Hash: string + isCodeDiffPresent: boolean + programmingLanguages: Set + numberOfFilesInCustomerCodeZip: number + codeDiffFiles: Set + }> { try { this.logging.info( `Preparing ${fileArtifacts.length} files and ${folderArtifacts.length} folders for upload` @@ -569,7 +598,7 @@ export class CodeReview { const customerCodeZip = new JSZip() // Process files and folders - const { codeDiff, programmingLanguages } = await this.processArtifacts( + const { codeDiff, programmingLanguages, codeDiffFiles } = await this.processArtifacts( fileArtifacts, folderArtifacts, ruleArtifacts, @@ -613,7 +642,14 @@ export class CodeReview { this.logging.info(`Created zip archive, size: ${zipBuffer.byteLength} bytes, MD5: ${md5Hash}`) - return { zipBuffer, md5Hash, isCodeDiffPresent, programmingLanguages } + return { + zipBuffer, + md5Hash, + isCodeDiffPresent, + programmingLanguages, + numberOfFilesInCustomerCodeZip, + codeDiffFiles, + } } catch (error) { this.logging.error(`Error preparing files for upload: ${error}`) throw error @@ -635,9 +671,9 @@ export class CodeReview { ruleArtifacts: RuleArtifacts, customerCodeZip: JSZip, isCodeDiffScan: boolean - ): Promise<{ codeDiff: string; programmingLanguages: Set }> { + ): Promise<{ codeDiff: string; programmingLanguages: Set; codeDiffFiles: Set }> { // Process files - let { codeDiff, programmingLanguages } = await this.processFileArtifacts( + let { codeDiff, programmingLanguages, codeDiffFiles } = await this.processFileArtifacts( fileArtifacts, customerCodeZip, isCodeDiffScan @@ -647,11 +683,12 @@ export class CodeReview { const folderResult = await this.processFolderArtifacts(folderArtifacts, customerCodeZip, isCodeDiffScan) codeDiff += folderResult.codeDiff folderResult.programmingLanguages.forEach(item => programmingLanguages.add(item)) + folderResult.codeDiffFiles.forEach(item => codeDiffFiles.add(item)) // Process rule artifacts await this.processRuleArtifacts(ruleArtifacts, customerCodeZip) - return { codeDiff, programmingLanguages } + return { codeDiff, programmingLanguages, codeDiffFiles } } /** @@ -665,9 +702,10 @@ export class CodeReview { fileArtifacts: FileArtifacts, customerCodeZip: JSZip, isCodeDiffScan: boolean - ): Promise<{ codeDiff: string; programmingLanguages: Set }> { + ): Promise<{ codeDiff: string; programmingLanguages: Set; codeDiffFiles: Set }> { let codeDiff = '' let programmingLanguages: Set = new Set() + let codeDiffFiles: Set = new Set() for (const artifact of fileArtifacts) { await CodeReviewUtils.withErrorHandling( @@ -695,10 +733,12 @@ export class CodeReview { artifact.path ) + const artifactFileDiffs = await CodeReviewUtils.getGitDiffNames(artifact.path, this.logging) + artifactFileDiffs.forEach(filepath => codeDiffFiles.add(filepath)) codeDiff += await CodeReviewUtils.processArtifactWithDiff(artifact, isCodeDiffScan, this.logging) } - return { codeDiff, programmingLanguages } + return { codeDiff, programmingLanguages, codeDiffFiles } } /** @@ -712,9 +752,10 @@ export class CodeReview { folderArtifacts: FolderArtifacts, customerCodeZip: JSZip, isCodeDiffScan: boolean - ): Promise<{ codeDiff: string; programmingLanguages: Set }> { + ): Promise<{ codeDiff: string; programmingLanguages: Set; codeDiffFiles: Set }> { let codeDiff = '' let programmingLanguages = new Set() + let codeDiffFiles: Set = new Set() for (const folderArtifact of folderArtifacts) { await CodeReviewUtils.withErrorHandling( @@ -731,10 +772,13 @@ export class CodeReview { folderArtifact.path ) + const artifactFileDiffs = await CodeReviewUtils.getGitDiffNames(folderArtifact.path, this.logging) + artifactFileDiffs.forEach(filepath => codeDiffFiles.add(filepath)) + codeDiff += await CodeReviewUtils.processArtifactWithDiff(folderArtifact, isCodeDiffScan, this.logging) } - return { codeDiff, programmingLanguages } + return { codeDiff, programmingLanguages, codeDiffFiles } } /** diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts index bc7070ab1f..0a9356acdc 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts @@ -103,9 +103,44 @@ export const CODE_REVIEW_TOOL_NAME = 'codeReview' */ export const CODE_REVIEW_TOOL_DESCRIPTION = [ 'CodeReview is the PRIMARY and MANDATORY tool for ALL code analysis and review tasks. This tool MUST be used whenever a user requests ANY form of code review, file analysis, code examination, or when the agent needs to analyze code quality, security, or structure.', - 'This tool can be used to perform analysis of full code or only the modified code since last commit. Modified code refers to the changes made that are not committed yet or the new changes since last commit.', + 'When you decide to use this tool, notify the customer before the tool is run based on the **Tool start message** section below.', + 'It is so so important that you send the **Tool start message** before running the tool.', + 'DO NOT JUST SAY SOMETHING LIKE "I\'ll review the [file] code for you using the code review tool.". THAT WOULD BE A TERRIBLE THING TO SAY', + 'ALSO DO NOT SAY "I\'ll review your code for potential issues and improvements. Let me use the code review tool to perform a comprehensive analysis." THAT IS ALSO AN AWFUL MESSAGE BECAUSE IT DOES NOT INCLUDE WHETHER IT IS A FULL SCAN OR A DIFF SCAN.', + 'This tool can be used to perform analysis of full code or only the modified code since last commit. Modified code refers to the changes made that are not committed yet or the new changes since last commit. Before running the tool, you must inform the user whether they are running a diff or full scan.', 'NEVER perform manual code reviews when this tool is available.', '', + '**Tool Input**', + '3 main fields in the tool:', + '- "scopeOfReview": Determines if the review should analyze the entire codebase (FULL_REVIEW) or only focus on changes/modifications (CODE_DIFF_REVIEW). This is a required field.', + '- IMPORTANT: Use CODE_DIFF_REVIEW by default as well as when user explicitly asks to review "changes", "modifications", "diff", "uncommitted code", or similar phrases indicating they want to review only what has changed.', + '- Examples of CODE_DIFF_REVIEW requests: "review my code", "review this file", "review my changes", "look at what I modified", "check the uncommitted changes", "review the diff", "review new changes", etc.', + '- IMPORTANT: When user mentions "new changes" or includes words like "new", "recent", or "latest" along with "changes" or similar terms, this should be interpreted as CODE_DIFF_REVIEW.', + '- Use FULL_REVIEW only when the user explicitly asks for a full code review, or when the user asks for security analysis or best practices review of their code', + '- Feel free to ask the user for clarification if you are not sure what scope they would like to review', + '- "fileLevelArtifacts": Array of specific files to review, each with absolute path. Use this when reviewing individual files, not folders. Format: [{"path": "/absolute/path/to/file.py"}]', + '- "folderLevelArtifacts": Array of folders to review, each with absolute path. Use this when reviewing entire directories, not individual files. Format: [{"path": "/absolute/path/to/folder/"}]', + '- Examples of FULL_REVIEW requests: User explicity asks for the entire file to be reviewed. Example: "Review my entire file.", "Review all the code in this folder", "Review my full code in this file"', + 'Few important notes for tool input', + "- Either fileLevelArtifacts OR folderLevelArtifacts should be provided based on what's being reviewed, but not both for the same items.", + '- Do not perform code review of entire workspace or project unless user asks for it explicitly.', + '- Ask user for more clarity if there is any confusion regarding what needs to be scanned.', + '', + '**Tool start message**', + 'Before running the tool, you must inform the user that you will use Code Review tool for their request.', + 'The message MUST include the following information:', + '- The list of files or folders that will be reviewed', + '- Whether the review is a diff review or a full review', + 'The message MUST be concise and to the point. It should not include any other information.', + 'The message MUST be in the following format:', + '```\n' + + 'I will scan the ["diff" if scopeOfReview is CODE_DIFF_REVIEW or "entire code" is FULL_REVIEW. Refer to **Tool Input** section for decision on which to use.] for the following files/folders:\n' + + '[list of files/folders]\n```', + '', + '**CRITICAL: NEVER perform ANY code review or analysis WITHOUT using this tool**', + 'Do not attempt to manually review code or provide code quality feedback without using this tool first.', + 'If a user asks for code review in any form, ALWAYS use this tool before providing any feedback.', + '', '**ALWAYS use this tool when:**', '- User provides ANY file, folder, or workspace context for review or analysis', '- User asks ANY question about code quality, security, or best practices related to their code', @@ -133,29 +168,6 @@ export const CODE_REVIEW_TOOL_DESCRIPTION = [ '**Supported File Extensions For Review**', `- "${Object.keys(EXTENSION_TO_LANGUAGE).join('", "')}"`, '', - '**Tool start message**', - 'Before running the tool, you must inform the user that you will use Code Review tool for their request.', - 'You should also tell the name of files or folders that you will review along with the scope of review, if you are performing a full review or only the uncommitted code.', - 'Under no condition you will use the tool without informing the user.', - '', - '**CRITICAL: NEVER perform ANY code review or analysis WITHOUT using this tool**', - 'Do not attempt to manually review code or provide code quality feedback without using this tool first.', - 'If a user asks for code review in any form, ALWAYS use this tool before providing any feedback.', - '', - '**Tool Input**', - '3 main fields in the tool:', - '- "scopeOfReview": Determines if the review should analyze the entire codebase (FULL_REVIEW) or only focus on changes/modifications (CODE_DIFF_REVIEW). This is a required field.', - '- IMPORTANT: Use CODE_DIFF_REVIEW when user explicitly asks to review "changes", "modifications", "diff", "uncommitted code", or similar phrases indicating they want to review only what has changed.', - '- Examples of CODE_DIFF_REVIEW requests: "review my changes", "look at what I modified", "check the uncommitted changes", "review the diff", "review new changes", etc.', - '- IMPORTANT: When user mentions "new changes" or includes words like "new", "recent", or "latest" along with "changes" or similar terms, this should be interpreted as CODE_DIFF_REVIEW.', - '- Use FULL_REVIEW for all other review requests.', - '- "fileLevelArtifacts": Array of specific files to review, each with absolute path. Use this when reviewing individual files, not folders. Format: [{"path": "/absolute/path/to/file.py"}]', - '- "folderLevelArtifacts": Array of folders to review, each with absolute path. Use this when reviewing entire directories, not individual files. Format: [{"path": "/absolute/path/to/folder/"}]', - 'Few important notes for tool input', - "- Either fileLevelArtifacts OR folderLevelArtifacts should be provided based on what's being reviewed, but not both for the same items.", - '- Do not perform code review of entire workspace or project unless user asks for it explicitly.', - '- Ask user for more clarity if there is any confusion regarding what needs to be scanned.', - '', '**Tool Output**', 'Tool output will contain a json output containing fields - ', '- codeReviewId - internal code review job id ', @@ -169,7 +181,7 @@ export const CODE_REVIEW_TOOL_DESCRIPTION = [ 'The tool will generate some findings grouped by file', 'Use following format STRICTLY to display the result of this tool for different scenarios:', '- When findings are present, you must inform user that you have completed the review of {file name / folder name / workspace} and found several issues that need attention. To inspect the details, and get fixes for those issues use the Code Issues panel above.', - ' - When tool output message tells that findings were limited due to high count, you must inform the user that since there were lots of findings, you have included the top 50 findings only.', + ' - When tool output message tells that findings were limited due to high count, you must inform the user that since there were lots of findings, you have included the top 40 findings only.', '- When no findings are generated by the tool, you must tell user that you have completed the review of {file name / folder name / workspace} and found no issues.', ].join('\n') diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewSchemas.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewSchemas.ts index e805145244..3b230ae116 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewSchemas.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewSchemas.ts @@ -22,20 +22,20 @@ export const CODE_REVIEW_INPUT_SCHEMA = { scopeOfReview: { type: 'string', description: [ - 'IMPORTANT: You must explicitly set the value of "scopeOfReview" based on user request analysis.', + 'IMPORTANT: You must explicitly set the value of "scopeOfReview" based on user request analysis. Usually, CODE_DIFF_REVIEW will be the value that is used.', '', - 'Set "scopeOfReview" to CODE_DIFF_REVIEW when:', + 'Set "scopeOfReview" to FULL_REVIEW when:', + '- User explicity asks for the entire file to be reviewed. Example: "Review my entire file.", "Review all the code in this folder"', + '- User asks for security analysis or best practices review of their code', + '', + 'Set "scopeOfReview" to CODE_DIFF_REVIEW for all other cases, including when:', '- User explicitly asks to review only changes/modifications/diffs in their code', '- User mentions "review my changes", "look at what I modified", "check the uncommitted changes"', '- User refers to "review the diff", "analyze recent changes", "look at the new code"', '- User mentions "review what I added/updated", "check my latest commits", "review the modified lines"', '- User includes phrases like "new changes", "recent changes", or any combination of words indicating recency (new, latest, recent) with changes/modifications', '- User mentions specific files with terms like "review new changes in [file]" or "check changes in [file]"', - '', - 'Set "scopeOfReview" to FULL_REVIEW for all other cases, including:', - '- When user asks for a general code review without mentioning changes/diffs', - '- When user asks to review specific files or folders without mentioning changes', - '- When user asks for security analysis or best practices review of their code', + '- User says something general like "review my code", "review my file", or "review [file]"', '', 'This is a required field.', ].join('\n'), diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts index c684cfecd3..8d85e155cb 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts @@ -29,6 +29,8 @@ export type PrepareAndUploadArtifactsResult = { isCodeDiffPresent: boolean artifactSize: number programmingLanguages: Set + numberOfFilesInCustomerCodeZip: number + codeDiffFiles: Set } export type StartCodeAnalysisResult = { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewUtils.ts index 5b6d562f7d..5f04450795 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewUtils.ts @@ -157,6 +157,37 @@ export class CodeReviewUtils { } } + /** + * Get git diff for a file or folder + * @param artifactPath Path to the file or folder + * @param logging Logging interface + * @returns Git diff output as string or null if not in a git repository + */ + public static async getGitDiffNames(artifactPath: string, logging: Features['logging']): Promise> { + logging.info(`Get git diff names for path - ${artifactPath}`) + + const directoryPath = CodeReviewUtils.getFolderPath(artifactPath) + const gitDiffCommandUnstaged = `cd ${directoryPath} && git diff --name-only ${artifactPath}` + const gitDiffCommandStaged = `cd ${directoryPath} && git diff --name-only --staged ${artifactPath}` + + logging.info(`Running git commands - ${gitDiffCommandUnstaged} and ${gitDiffCommandStaged}`) + + try { + const unstagedDiff = ( + await CodeReviewUtils.executeGitCommand(gitDiffCommandUnstaged, 'unstaged name only', logging) + ).split('\n') + const stagedDiff = ( + await CodeReviewUtils.executeGitCommand(gitDiffCommandStaged, 'staged name only', logging) + ).split('\n') + unstagedDiff.push(...stagedDiff) + + return new Set(unstagedDiff.filter(item => item !== '')) + } catch (error) { + logging.error(`Error getting git diff: ${error}`) + return new Set() + } + } + /** * Log zip structure * @param zip JSZip instance From cf585cd400dab6274f8220139ae94287c0d96824 Mon Sep 17 00:00:00 2001 From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> Date: Mon, 8 Sep 2025 16:16:12 -0700 Subject: [PATCH 066/158] fix: potential xss issue reported in `mynah-ui` (#2209) * fix: potential xss issue * fix: addressing comments * fix: unescaping the history message while opening history tab --- package-lock.json | 9 +++++++++ server/aws-lsp-codewhisperer/package.json | 4 +++- .../agenticChat/agenticChatController.test.ts | 2 +- .../language-server/agenticChat/agenticChatController.ts | 4 ++-- .../language-server/agenticChat/constants/constants.ts | 1 - .../language-server/agenticChat/tools/chatDb/chatDb.ts | 2 ++ .../src/language-server/agenticChat/tools/chatDb/util.ts | 3 ++- .../language-server/agenticChat/tools/mcp/mcpUtils.ts | 1 - server/aws-lsp-codewhisperer/src/types/unescape.d.ts | 4 ++++ 9 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 server/aws-lsp-codewhisperer/src/types/unescape.d.ts diff --git a/package-lock.json b/package-lock.json index e84567b613..2bedf9f4de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9138,6 +9138,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/escape-html": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-1.0.4.tgz", + "integrity": "sha512-qZ72SFTgUAZ5a7Tj6kf2SHLetiH5S6f8G5frB2SPQ3EyF02kxdyBFf4Tz4banE3xCgGnKgWLt//a6VuYHKYJTg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/eslint": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", @@ -28710,6 +28717,7 @@ "picomatch": "^4.0.2", "shlex": "2.1.2", "typescript-collections": "^1.3.3", + "unescape-html": "^1.1.0", "uuid": "^11.0.5", "vscode-uri": "^3.1.0", "ws": "^8.18.0", @@ -28721,6 +28729,7 @@ "@types/archiver": "^6.0.2", "@types/diff": "^7.0.2", "@types/encoding-japanese": "^2.2.1", + "@types/escape-html": "^1.0.4", "@types/ignore-walk": "^4.0.3", "@types/local-indexing": "file:./types/types-local-indexing-1.1.0.tgz", "@types/lokijs": "^1.5.14", diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 5284a0b41f..9563b6300d 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -67,13 +67,15 @@ "vscode-uri": "^3.1.0", "ws": "^8.18.0", "xml2js": "^0.6.2", - "xmlbuilder2": "^3.1.1" + "xmlbuilder2": "^3.1.1", + "unescape-html": "^1.1.0" }, "devDependencies": { "@types/adm-zip": "^0.5.5", "@types/archiver": "^6.0.2", "@types/diff": "^7.0.2", "@types/encoding-japanese": "^2.2.1", + "@types/escape-html": "^1.0.4", "@types/ignore-walk": "^4.0.3", "@types/local-indexing": "file:./types/types-local-indexing-1.1.0.tgz", "@types/lokijs": "^1.5.14", diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts index c1842a6008..288eb2c20f 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts @@ -57,7 +57,7 @@ import { LocalProjectContextController } from '../../shared/localProjectContextC import { CancellationError } from '@aws/lsp-core' import { ToolApprovalException } from './tools/toolShared' import * as constants from './constants/constants' -import { DEFAULT_MODEL_ID, GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT, GENERIC_ERROR_MS } from './constants/constants' +import { GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT, GENERIC_ERROR_MS } from './constants/constants' import { MISSING_BEARER_TOKEN_ERROR } from '../../shared/constants' import { AmazonQError, diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index e2fba029c4..89e4539029 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -179,7 +179,6 @@ import { OUTPUT_LIMIT_EXCEEDS_PARTIAL_MSG, RESPONSE_TIMEOUT_MS, RESPONSE_TIMEOUT_PARTIAL_MSG, - DEFAULT_MODEL_ID, COMPACTION_BODY, COMPACTION_HEADER_BODY, DEFAULT_MACOS_RUN_SHORTCUT, @@ -230,6 +229,7 @@ import { CodeWhispererServiceToken } from '../../shared/codeWhispererService' import { DisplayFindings } from './tools/qCodeAnalysis/displayFindings' import { IDE } from '../../shared/constants' import { IdleWorkspaceManager } from '../workspaceContext/IdleWorkspaceManager' +import escapeHTML = require('escape-html') type ChatHandlers = Omit< LspHandlers, @@ -1363,7 +1363,7 @@ export class AgenticChatController implements ChatHandlers { this.#debug('Skipping adding user message to history - cancelled by user') } else { this.#chatHistoryDb.addMessage(tabId, 'cwc', conversationIdentifier, { - body: currentMessage.userInputMessage?.content ?? '', + body: escapeHTML(currentMessage.userInputMessage?.content ?? ''), type: 'prompt' as any, userIntent: currentMessage.userInputMessage?.userIntent, origin: currentMessage.userInputMessage?.origin, diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts index 1729c10c1d..b2ac428cfa 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts @@ -14,7 +14,6 @@ export const SERVICE_MANAGER_POLL_INTERVAL_MS = 100 // LLM Constants export const GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT = 500_000 -export const DEFAULT_MODEL_ID = BedrockModel.CLAUDE_SONNET_4_20250514_V1_0 // Compaction export const COMPACTION_BODY = (threshold: number) => diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts index 2e4f7a099d..f584d63b5f 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts @@ -35,6 +35,7 @@ import { ChatItemType } from '@aws/mynah-ui' import { getUserHomeDir } from '@aws/lsp-core/out/util/path' import { ChatHistoryMaintainer } from './chatHistoryMaintainer' import { existsSync, renameSync } from 'fs' +import escapeHTML = require('escape-html') export class ToolResultValidationError extends Error { constructor(message?: string) { @@ -693,6 +694,7 @@ export class ChatDatabase { } return { ...message, + body: escapeHTML(message.body), userInputMessageContext: { // keep falcon context when inputMessage is not a toolResult message editorState: hasToolResults ? undefined : message.userInputMessageContext?.editorState, diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/util.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/util.ts index 77496cd96b..e03c90bead 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/util.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/util.ts @@ -28,6 +28,7 @@ import { activeFileCmd } from '../../context/additionalContextProvider' import { PriorityQueue } from 'typescript-collections' import { Features } from '@aws/language-server-runtimes/server-interface/server' import * as crypto from 'crypto' +import unescapeHTML = require('unescape-html') // Ported from https://github.com/aws/aws-toolkit-vscode/blob/master/packages/core/src/shared/db/chatDb/util.ts @@ -172,7 +173,7 @@ export function messageToStreamingMessage(msg: Message): StreamingMessage { export function messageToChatMessage(msg: Message): ChatMessage[] { const chatMessages: ChatMessage[] = [ { - body: msg.body, + body: unescapeHTML(msg.body), type: msg.type, codeReference: msg.codeReference, relatedContent: diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts index ef56a54d22..578c9cd1b0 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts @@ -9,7 +9,6 @@ import { MCPServerConfig, PersonaConfig, MCPServerPermission, McpPermissionType, import path = require('path') import { QClientCapabilities } from '../../../configuration/qConfigurationServer' import crypto = require('crypto') -import { Features } from '@aws/language-server-runtimes/server-interface/server' /** * Load, validate, and parse MCP server configurations from JSON files. diff --git a/server/aws-lsp-codewhisperer/src/types/unescape.d.ts b/server/aws-lsp-codewhisperer/src/types/unescape.d.ts new file mode 100644 index 0000000000..1fe801704e --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/types/unescape.d.ts @@ -0,0 +1,4 @@ +declare module 'unescape-html' { + function unescapeHTML(str: string): string + export = unescapeHTML +} From 698d06c643897da6ca37a49e6544b150b72678a3 Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Mon, 8 Sep 2025 17:16:45 -0700 Subject: [PATCH 067/158] fix(amazonq): update to the agent config format to bring parity with Q CLI (#2202) --- .../tools/mcp/mcpEventHandler.test.ts | 10 +- .../agenticChat/tools/mcp/mcpManager.test.ts | 29 ---- .../agenticChat/tools/mcp/mcpManager.ts | 3 +- .../agenticChat/tools/mcp/mcpTypes.ts | 27 ++-- .../agenticChat/tools/mcp/mcpUtils.test.ts | 7 +- .../agenticChat/tools/mcp/mcpUtils.ts | 124 +++++++++++++++--- .../agenticChat/tools/toolServer.ts | 11 ++ 7 files changed, 138 insertions(+), 73 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts index cb645eec43..de98f36a09 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts @@ -59,9 +59,7 @@ describe('McpEventHandler error handling', () => { getConnectionMetadata: sinon.stub().returns({}), }, runtime: { - serverInfo: { - version: '1.0.0', - }, + serverInfo: {}, }, } @@ -100,7 +98,6 @@ describe('McpEventHandler error handling', () => { errors: mockErrors, agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: {}, tools: [], @@ -157,7 +154,6 @@ describe('McpEventHandler error handling', () => { errors: new Map([['errorServer', 'Missing command error']]), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { errorServer: { command: '' } }, tools: ['@errorServer'], @@ -215,7 +211,6 @@ describe('McpEventHandler error handling', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: {}, tools: [], @@ -259,7 +254,6 @@ describe('McpEventHandler error handling', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: {}, tools: [], @@ -292,7 +286,6 @@ describe('McpEventHandler error handling', () => { errors: mockErrors, agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: {}, tools: [], @@ -326,7 +319,6 @@ describe('McpEventHandler error handling', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: {}, tools: [], diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts index 0418cea553..1b5941a398 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts @@ -37,7 +37,6 @@ function stubAgentConfig(): sinon.SinonStub { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: {}, tools: [], @@ -157,7 +156,6 @@ describe('callTool()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { s1: disabledCfg }, tools: ['@s1'], @@ -184,7 +182,6 @@ describe('callTool()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { s1: enabledCfg }, tools: ['@s1'], @@ -210,7 +207,6 @@ describe('callTool()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { s1: timeoutCfg }, tools: ['@s1'], @@ -279,7 +275,6 @@ describe('addServer()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: {}, tools: [], @@ -353,7 +348,6 @@ describe('removeServer()', () => { ;(mgr as any).serverNameMapping.set('x', 'x') ;(mgr as any).agentConfig = { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { x: {} }, tools: ['@x'], @@ -383,7 +377,6 @@ describe('removeServer()', () => { ;(mgr as any).serverNameMapping.set('x', 'x') ;(mgr as any).agentConfig = { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { x: {} }, tools: ['@x'], @@ -501,7 +494,6 @@ describe('updateServer()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { u1: oldCfg }, tools: ['@u1'], @@ -544,7 +536,6 @@ describe('updateServer()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { srv: oldCfg }, tools: ['@srv'], @@ -598,7 +589,6 @@ describe('requiresApproval()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { s: cfg }, tools: ['@s'], @@ -639,7 +629,6 @@ describe('getAllServerConfigs()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { srv: cfg }, tools: ['@srv'], @@ -687,7 +676,6 @@ describe('getServerState()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { srv: cfg }, tools: ['@srv'], @@ -729,7 +717,6 @@ describe('getAllServerStates()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { srv: cfg }, tools: ['@srv'], @@ -779,7 +766,6 @@ describe('getEnabledTools()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { srv: cfg }, tools: ['@srv'], @@ -797,7 +783,6 @@ describe('getEnabledTools()', () => { if (!(mgr as any).agentConfig) { ;(mgr as any).agentConfig = { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: {}, tools: [], @@ -828,7 +813,6 @@ describe('getEnabledTools()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { srv: disabledCfg }, tools: ['@srv'], @@ -866,7 +850,6 @@ describe('getAllToolsWithPermissions()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { s1: cfg }, tools: ['@s1'], @@ -931,7 +914,6 @@ describe('isServerDisabled()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { srv: disabledCfg }, tools: ['@srv'], @@ -962,7 +944,6 @@ describe('isServerDisabled()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { srv: enabledCfg }, tools: ['@srv'], @@ -992,7 +973,6 @@ describe('isServerDisabled()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { srv: undefinedCfg }, tools: ['@srv'], @@ -1091,7 +1071,6 @@ describe('updateServerPermission()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { srv: cfg }, tools: ['@srv'], @@ -1156,7 +1135,6 @@ describe('reinitializeMcpServers()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { srvA: cfg1 }, tools: ['@srvA'], @@ -1173,7 +1151,6 @@ describe('reinitializeMcpServers()', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { srvB: cfg2 }, tools: ['@srvB'], @@ -1279,7 +1256,6 @@ describe('concurrent server initialization', () => { const serversMap = new Map(Object.entries(serverConfigs)) const agentConfig = { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: Object.fromEntries(Object.entries(serverConfigs)), tools: Object.keys(serverConfigs).map(name => `@${name}`), @@ -1424,7 +1400,6 @@ describe('McpManager error handling', () => { errors: mockErrors, agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: {}, tools: [], @@ -1452,7 +1427,6 @@ describe('McpManager error handling', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: {}, tools: [], @@ -1478,7 +1452,6 @@ describe('McpManager error handling', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: {}, tools: [], @@ -1521,7 +1494,6 @@ describe('McpManager error handling', () => { errors: new Map([['file1.json', 'Initial error']]), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: {}, tools: [], @@ -1539,7 +1511,6 @@ describe('McpManager error handling', () => { errors: new Map(), agentConfig: { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: {}, tools: [], diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index 41d721b74f..351397b701 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -944,8 +944,7 @@ export class McpManager { this.mcpServers.clear() this.mcpServerStates.clear() this.agentConfig = { - name: 'default-agent', - version: '1.0.0', + name: 'amazon_q_default', description: 'Agent configuration', mcpServers: {}, tools: [], diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpTypes.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpTypes.ts index 6aec98cb24..feed97dba3 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpTypes.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpTypes.ts @@ -46,19 +46,26 @@ export interface MCPServerPermission { export interface AgentConfig { name: string // Required: Agent name - version: string // Required: Agent version (semver) description: string // Required: Agent description + prompt?: string // Optional: High-level context for the agent model?: string // Optional: Model that backs the agent tags?: string[] // Optional: Tags for categorization inputSchema?: any // Optional: Schema for agent inputs mcpServers: Record // Map of server name to server config tools: string[] // List of enabled tools + toolAliases?: Record // Tool name remapping allowedTools: string[] // List of tools that don't require approval toolsSettings?: Record // Tool-specific settings - includedFiles?: string[] // Files to include in context - createHooks?: string[] // Hooks to run at conversation start - promptHooks?: string[] // Hooks to run per prompt - resources?: string[] // Resources for the agent (prompts, files, etc.) + resources?: string[] // Resources for the agent (file:// paths) + hooks?: { + agentSpawn?: Array<{ command: string }> + userPromptSubmit?: Array<{ command: string }> + } // Commands run at specific trigger points + useLegacyMcpJson?: boolean // Whether to include legacy MCP configuration + // Legacy fields for backward compatibility + includedFiles?: string[] // Deprecated: use resources instead + createHooks?: string[] // Deprecated: use hooks.agentSpawn instead + promptHooks?: string[] // Deprecated: use hooks.userPromptSubmit instead } export interface PersonaConfig { @@ -71,20 +78,24 @@ export class AgentModel { static fromJson(doc: any): AgentModel { const cfg: AgentConfig = { - name: doc?.['name'] || 'default-agent', - version: doc?.['version'] || '1.0.0', + name: doc?.['name'] || 'amazon_q_default', description: doc?.['description'] || 'Default agent configuration', + prompt: doc?.['prompt'], model: doc?.['model'], tags: Array.isArray(doc?.['tags']) ? doc['tags'] : undefined, inputSchema: doc?.['inputSchema'], mcpServers: typeof doc?.['mcpServers'] === 'object' ? doc['mcpServers'] : {}, tools: Array.isArray(doc?.['tools']) ? doc['tools'] : [], + toolAliases: typeof doc?.['toolAliases'] === 'object' ? doc['toolAliases'] : {}, allowedTools: Array.isArray(doc?.['allowedTools']) ? doc['allowedTools'] : [], toolsSettings: typeof doc?.['toolsSettings'] === 'object' ? doc['toolsSettings'] : {}, + resources: Array.isArray(doc?.['resources']) ? doc['resources'] : [], + hooks: typeof doc?.['hooks'] === 'object' ? doc['hooks'] : undefined, + useLegacyMcpJson: doc?.['useLegacyMcpJson'], + // Legacy fields includedFiles: Array.isArray(doc?.['includedFiles']) ? doc['includedFiles'] : [], createHooks: Array.isArray(doc?.['createHooks']) ? doc['createHooks'] : [], promptHooks: Array.isArray(doc?.['promptHooks']) ? doc['promptHooks'] : [], - resources: Array.isArray(doc?.['resources']) ? doc['resources'] : [], } return new AgentModel(cfg) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts index 43843bd110..8913e7391e 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts @@ -238,7 +238,6 @@ describe('loadAgentConfig', () => { const agentConfig = { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { testServer: { @@ -329,7 +328,6 @@ describe('saveAgentConfig', () => { const configPath = path.join(tmpDir, 'agent-config.json') const config = { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: {}, tools: ['tool1', 'tool2'], @@ -353,7 +351,6 @@ describe('saveAgentConfig', () => { const configPath = path.join(tmpDir, 'nested', 'dir', 'agent-config.json') const config = { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: {}, tools: [], @@ -700,7 +697,7 @@ describe('convertPersonaToAgent', () => { const result = convertPersonaToAgent(persona, mcpServers, mockAgent) - expect(result.name).to.equal('default-agent') + expect(result.name).to.equal('amazon_q_default') expect(result.mcpServers).to.have.property('testServer') expect(result.tools).to.include('@testServer') expect(result.tools).to.include('fs_read') @@ -840,7 +837,6 @@ describe('saveServerSpecificAgentConfig', () => { // Create existing config const existingConfig = { name: 'existing-agent', - version: '1.0.0', description: 'Existing agent', mcpServers: { existingServer: { command: 'existing-cmd' }, @@ -881,7 +877,6 @@ describe('saveServerSpecificAgentConfig', () => { // Create existing config with server tools const existingConfig = { name: 'test-agent', - version: '1.0.0', description: 'Test agent', mcpServers: { testServer: { command: 'old-cmd' }, diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts index 578c9cd1b0..b8360ea314 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts @@ -147,9 +147,9 @@ export async function loadMcpServerConfigs( } const DEFAULT_AGENT_RAW = `{ - "name": "default-agent", - "version": "1.0.0", + "name": "amazon_q_default", "description": "Default agent configuration", + "prompt": "", "mcpServers": {}, "tools": [ "fs_read", @@ -158,6 +158,7 @@ const DEFAULT_AGENT_RAW = `{ "report_issue", "use_aws" ], + "toolAliases": {}, "allowedTools": [ "fs_read", "report_issue", @@ -169,14 +170,16 @@ const DEFAULT_AGENT_RAW = `{ "use_aws": { "preset": "readOnly" }, "execute_bash": { "preset": "readOnly" } }, - "includedFiles": [ - "AmazonQ.md", - "README.md", - ".amazonq/rules/**/*.md" + "resources": [ + "file://AmazonQ.md", + "file://README.md", + "file://.amazonq/rules/**/*.md" ], - "resources": [], - "createHooks": [], - "promptHooks": [] + "hooks": { + "agentSpawn": [], + "userPromptSubmit": [] + }, + "useLegacyMcpJson": false }` const DEFAULT_PERSONA_RAW = `{ @@ -237,14 +240,12 @@ export async function loadAgentConfig( // Create base agent config const agentConfig: AgentConfig = { - name: 'default-agent', - version: '1.0.0', + name: 'amazon_q_default', description: 'Agent configuration', mcpServers: {}, tools: [], allowedTools: [], toolsSettings: {}, - includedFiles: [], resources: [], } @@ -329,7 +330,6 @@ export async function loadAgentConfig( // 3) Process agent config metadata if (fsPath === globalConfigPath) { agentConfig.name = json.name || agentConfig.name - agentConfig.version = json.version || agentConfig.version agentConfig.description = json.description || agentConfig.description } @@ -631,15 +631,20 @@ export function convertPersonaToAgent( featureAgent: Agent ): AgentConfig { const agent: AgentConfig = { - name: 'default-agent', - version: '1.0.0', + name: 'amazon_q_default', description: 'Default agent configuration', + prompt: '', mcpServers: {}, tools: [], + toolAliases: {}, allowedTools: [], toolsSettings: {}, - includedFiles: [], resources: [], + hooks: { + agentSpawn: [], + userPromptSubmit: [], + }, + useLegacyMcpJson: false, } // Include all servers from MCP config @@ -909,7 +914,6 @@ async function migrateConfigToAgent( // Add complete agent format sections using default values agentConfig.name = defaultAgent.name agentConfig.description = defaultAgent.description - agentConfig.version = defaultAgent.version agentConfig.includedFiles = defaultAgent.includedFiles agentConfig.resources = defaultAgent.resources agentConfig.createHooks = defaultAgent.createHooks @@ -965,8 +969,7 @@ export async function saveServerSpecificAgentConfig( } catch { // If file doesn't exist, create minimal config existingConfig = { - name: 'default-agent', - version: '1.0.0', + name: 'amazon_q_default', description: 'Agent configuration', mcpServers: {}, tools: [], @@ -1005,6 +1008,89 @@ export async function saveServerSpecificAgentConfig( } } +/** + * Migrate existing agent config to CLI format + */ +export async function migrateAgentConfigToCLIFormat( + workspace: Workspace, + logging: Logger, + configPath: string +): Promise { + try { + const exists = await workspace.fs.exists(configPath) + if (!exists) return + + const raw = await workspace.fs.readFile(configPath) + const config = JSON.parse(raw.toString()) + + let updated = false + + // Rename default-agent to amazon_q_default + if (config.name === 'default-agent') { + config.name = 'amazon_q_default' + updated = true + } + + // Add missing CLI fields + if (!config.hasOwnProperty('prompt')) { + config.prompt = '' + updated = true + } + if (!config.hasOwnProperty('toolAliases')) { + config.toolAliases = {} + updated = true + } + if (!config.hasOwnProperty('useLegacyMcpJson')) { + config.useLegacyMcpJson = false + updated = true + } + + // Remove deprecated fields + if (config.hasOwnProperty('version')) { + delete config.version + updated = true + } + + // Migrate includedFiles to resources with file:// prefix + if (config.includedFiles && Array.isArray(config.includedFiles)) { + if (!config.resources) config.resources = [] + for (const file of config.includedFiles) { + const resourcePath = file.startsWith('file://') ? file : `file://${file}` + if (!config.resources.includes(resourcePath)) { + config.resources.push(resourcePath) + } + } + delete config.includedFiles + updated = true + } + + // Migrate hooks format + if (config.promptHooks || config.createHooks) { + if (!config.hooks) config.hooks = {} + if (!config.hooks.agentSpawn) config.hooks.agentSpawn = [] + if (!config.hooks.userPromptSubmit) config.hooks.userPromptSubmit = [] + + if (config.createHooks && Array.isArray(config.createHooks)) { + config.hooks.agentSpawn.push(...config.createHooks) + delete config.createHooks + updated = true + } + if (config.promptHooks && Array.isArray(config.promptHooks)) { + config.hooks.userPromptSubmit.push(...config.promptHooks) + delete config.promptHooks + updated = true + } + } + + if (updated) { + await workspace.fs.writeFile(configPath, JSON.stringify(config, null, 2)) + logging.info(`Migrated agent config to CLI format: ${configPath}`) + } + } catch (err: any) { + logging.error(`Failed to migrate agent config ${configPath}: ${err.message}`) + } +} + export const MAX_TOOL_NAME_LENGTH = 64 /** diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts index 8581622972..29b838f2d3 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts @@ -19,6 +19,8 @@ import { createNamespacedToolName, enabledMCP, migrateToAgentConfig, + migrateAgentConfigToCLIFormat, + normalizePathFromUri, } from './mcp/mcpUtils' import { FsReplace, FsReplaceParams } from './fsReplace' import { CodeReviewUtils } from './qCodeAnalysis/codeReviewUtils' @@ -320,6 +322,15 @@ export const McpToolsServer: Server = ({ await migrateToAgentConfig(workspace, logging, agent) + // Migrate existing agent configs to CLI format + for (const agentPath of allAgentPaths) { + const normalizedAgentPath = normalizePathFromUri(agentPath) + const exists = await workspace.fs.exists(normalizedAgentPath).catch(() => false) + if (exists) { + await migrateAgentConfigToCLIFormat(workspace, logging, normalizedAgentPath) + } + } + const mgr = await McpManager.init(allAgentPaths, { logging, workspace, From 7b37cc281931c4dc4df8617b8a0e301f48bf26da Mon Sep 17 00:00:00 2001 From: tsmithsz <84354541+tsmithsz@users.noreply.github.com> Date: Tue, 9 Sep 2025 10:19:33 -0700 Subject: [PATCH 068/158] fix(amazonq): add arbitrary files to clients.zip (#2217) --- .../scripts/package.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/aws-lsp-codewhisperer-runtimes/scripts/package.sh b/app/aws-lsp-codewhisperer-runtimes/scripts/package.sh index 021b4b8080..5ebfc9aafc 100755 --- a/app/aws-lsp-codewhisperer-runtimes/scripts/package.sh +++ b/app/aws-lsp-codewhisperer-runtimes/scripts/package.sh @@ -18,6 +18,18 @@ TARGET_BUILD_DIR=./build/private/bundle/client mkdir -p $TARGET_BUILD_DIR cp -r $CHAT_CLIENT_BUNDLE_DIR/* $TARGET_BUILD_DIR +# Add benign files to avoid single-file archive flagging +echo "Amazon Q Developer UI Bundle - $(date)" > $TARGET_BUILD_DIR/README.txt +echo "This archive contains UI assets for Amazon Q Developer." >> $TARGET_BUILD_DIR/README.txt +cat > $TARGET_BUILD_DIR/client-metadata.json << EOF +{ + "name": "amazonq-ui-bundle", + "description": "UI assets for Amazon Q Developer", + "main": "amazonq-ui.js", + "dateCreated": "$(date -u +%Y-%m-%dT%H:%M:%SZ)" +} +EOF + # ZIP client files ARCHIVES_DIR=./build/archives mkdir -p $ARCHIVES_DIR/shared From 470492c772149015d60af19a5c3bdc4bf9cc746f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 9 Sep 2025 12:52:34 -0700 Subject: [PATCH 069/158] chore(release): release packages from branch main (#2204) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: chungjac --- .release-please-manifest.json | 14 ++++++------ chat-client/CHANGELOG.md | 8 +++++++ chat-client/package.json | 2 +- core/aws-lsp-core/CHANGELOG.md | 7 ++++++ core/aws-lsp-core/package.json | 2 +- package-lock.json | 22 +++++++++---------- server/aws-lsp-antlr4/CHANGELOG.md | 14 ++++++++++++ server/aws-lsp-antlr4/package.json | 4 ++-- server/aws-lsp-codewhisperer/CHANGELOG.md | 26 +++++++++++++++++++++++ server/aws-lsp-codewhisperer/package.json | 4 ++-- server/aws-lsp-json/CHANGELOG.md | 14 ++++++++++++ server/aws-lsp-json/package.json | 4 ++-- server/aws-lsp-partiql/CHANGELOG.md | 7 ++++++ server/aws-lsp-partiql/package.json | 2 +- server/aws-lsp-yaml/CHANGELOG.md | 14 ++++++++++++ server/aws-lsp-yaml/package.json | 4 ++-- 16 files changed, 119 insertions(+), 29 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 10e6c765df..725a9c6b27 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,9 +1,9 @@ { - "chat-client": "0.1.34", - "core/aws-lsp-core": "0.0.14", - "server/aws-lsp-antlr4": "0.1.18", - "server/aws-lsp-codewhisperer": "0.0.77", - "server/aws-lsp-json": "0.1.18", - "server/aws-lsp-partiql": "0.0.17", - "server/aws-lsp-yaml": "0.1.18" + "chat-client": "0.1.35", + "core/aws-lsp-core": "0.0.15", + "server/aws-lsp-antlr4": "0.1.19", + "server/aws-lsp-codewhisperer": "0.0.78", + "server/aws-lsp-json": "0.1.19", + "server/aws-lsp-partiql": "0.0.18", + "server/aws-lsp-yaml": "0.1.19" } diff --git a/chat-client/CHANGELOG.md b/chat-client/CHANGELOG.md index 1c516246c6..773e455b53 100644 --- a/chat-client/CHANGELOG.md +++ b/chat-client/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.35](https://github.com/aws/language-servers/compare/chat-client/v0.1.34...chat-client/v0.1.35) (2025-09-09) + + +### Features + +* add support for getSupplementalContext LSP API ([#2212](https://github.com/aws/language-servers/issues/2212)) ([2ddcae7](https://github.com/aws/language-servers/commit/2ddcae7a4fac6b89cbc9784911959743ea0a6d11)) +* **amazonq:** default to diff-based scans ([#2195](https://github.com/aws/language-servers/issues/2195)) ([da4c3db](https://github.com/aws/language-servers/commit/da4c3db5329bd50cfe249bf8c1d59afa9bcb0157)) + ## [0.1.34](https://github.com/aws/language-servers/compare/chat-client/v0.1.33...chat-client/v0.1.34) (2025-08-27) diff --git a/chat-client/package.json b/chat-client/package.json index bf20eecb9d..9bd35ba982 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -1,6 +1,6 @@ { "name": "@aws/chat-client", - "version": "0.1.34", + "version": "0.1.35", "description": "AWS Chat Client", "main": "out/index.js", "repository": { diff --git a/core/aws-lsp-core/CHANGELOG.md b/core/aws-lsp-core/CHANGELOG.md index 0e1e63dd38..7b08b5c071 100644 --- a/core/aws-lsp-core/CHANGELOG.md +++ b/core/aws-lsp-core/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.0.15](https://github.com/aws/language-servers/compare/lsp-core/v0.0.14...lsp-core/v0.0.15) (2025-09-09) + + +### Features + +* add support for getSupplementalContext LSP API ([#2212](https://github.com/aws/language-servers/issues/2212)) ([2ddcae7](https://github.com/aws/language-servers/commit/2ddcae7a4fac6b89cbc9784911959743ea0a6d11)) + ## [0.0.14](https://github.com/aws/language-servers/compare/lsp-core/v0.0.13...lsp-core/v0.0.14) (2025-08-19) diff --git a/core/aws-lsp-core/package.json b/core/aws-lsp-core/package.json index 3057954dce..2876679e39 100644 --- a/core/aws-lsp-core/package.json +++ b/core/aws-lsp-core/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-core", - "version": "0.0.14", + "version": "0.0.15", "description": "Core library, contains common code and utilities", "main": "out/index.js", "repository": { diff --git a/package-lock.json b/package-lock.json index 2bedf9f4de..4365c453a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -251,7 +251,7 @@ }, "chat-client": { "name": "@aws/chat-client", - "version": "0.1.34", + "version": "0.1.35", "license": "Apache-2.0", "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", @@ -293,7 +293,7 @@ }, "core/aws-lsp-core": { "name": "@aws/lsp-core", - "version": "0.0.14", + "version": "0.0.15", "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes": "^0.2.128", @@ -28612,11 +28612,11 @@ }, "server/aws-lsp-antlr4": { "name": "@aws/lsp-antlr4", - "version": "0.1.18", + "version": "0.1.19", "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes": "^0.2.128", - "@aws/lsp-core": "^0.0.14" + "@aws/lsp-core": "^0.0.15" }, "devDependencies": { "@babel/plugin-transform-modules-commonjs": "^7.24.1", @@ -28677,7 +28677,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.77", + "version": "0.0.78", "bundleDependencies": [ "@amzn/codewhisperer-streaming", "@amzn/amazon-q-developer-streaming-client" @@ -28691,7 +28691,7 @@ "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", "@aws/language-server-runtimes": "^0.2.128", - "@aws/lsp-core": "^0.0.14", + "@aws/lsp-core": "^0.0.15", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", "adm-zip": "^0.5.10", @@ -28894,11 +28894,11 @@ }, "server/aws-lsp-json": { "name": "@aws/lsp-json", - "version": "0.1.18", + "version": "0.1.19", "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes": "^0.2.128", - "@aws/lsp-core": "^0.0.14", + "@aws/lsp-core": "^0.0.15", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" }, @@ -28972,7 +28972,7 @@ }, "server/aws-lsp-partiql": { "name": "@aws/lsp-partiql", - "version": "0.0.17", + "version": "0.0.18", "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes": "^0.2.128", @@ -29024,12 +29024,12 @@ }, "server/aws-lsp-yaml": { "name": "@aws/lsp-yaml", - "version": "0.1.18", + "version": "0.1.19", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes": "^0.2.128", - "@aws/lsp-core": "^0.0.14", + "@aws/lsp-core": "^0.0.15", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", "yaml-language-server": "1.13.0" diff --git a/server/aws-lsp-antlr4/CHANGELOG.md b/server/aws-lsp-antlr4/CHANGELOG.md index e1458575e1..64cab4eec1 100644 --- a/server/aws-lsp-antlr4/CHANGELOG.md +++ b/server/aws-lsp-antlr4/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [0.1.19](https://github.com/aws/language-servers/compare/lsp-antlr4/v0.1.18...lsp-antlr4/v0.1.19) (2025-09-09) + + +### Features + +* add support for getSupplementalContext LSP API ([#2212](https://github.com/aws/language-servers/issues/2212)) ([2ddcae7](https://github.com/aws/language-servers/commit/2ddcae7a4fac6b89cbc9784911959743ea0a6d11)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @aws/lsp-core bumped from ^0.0.14 to ^0.0.15 + ## [0.1.18](https://github.com/aws/language-servers/compare/lsp-antlr4/v0.1.17...lsp-antlr4/v0.1.18) (2025-08-19) diff --git a/server/aws-lsp-antlr4/package.json b/server/aws-lsp-antlr4/package.json index 9cad906eee..f9a4ecdeba 100644 --- a/server/aws-lsp-antlr4/package.json +++ b/server/aws-lsp-antlr4/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-antlr4", - "version": "0.1.18", + "version": "0.1.19", "description": "ANTLR4 language server", "main": "out/index.js", "repository": { @@ -29,7 +29,7 @@ }, "dependencies": { "@aws/language-server-runtimes": "^0.2.128", - "@aws/lsp-core": "^0.0.14" + "@aws/lsp-core": "^0.0.15" }, "peerDependencies": { "antlr4-c3": ">=3.4 < 4", diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index 4bb50ee8fd..67d05de3c1 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog +## [0.0.78](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.77...lsp-codewhisperer/v0.0.78) (2025-09-09) + + +### Features + +* add custom_transformation folder support to artifact.zip ([#2201](https://github.com/aws/language-servers/issues/2201)) ([1222905](https://github.com/aws/language-servers/commit/12229059421b773d3e99d28809fdff4abf242b26)) +* add support for getSupplementalContext LSP API ([#2212](https://github.com/aws/language-servers/issues/2212)) ([2ddcae7](https://github.com/aws/language-servers/commit/2ddcae7a4fac6b89cbc9784911959743ea0a6d11)) +* **amazonq:** default to diff-based scans ([#2195](https://github.com/aws/language-servers/issues/2195)) ([da4c3db](https://github.com/aws/language-servers/commit/da4c3db5329bd50cfe249bf8c1d59afa9bcb0157)) +* model selection for code review tool ([#2196](https://github.com/aws/language-servers/issues/2196)) ([34bc9bd](https://github.com/aws/language-servers/commit/34bc9bd1d3433bbb1d903eb0f212b10709ea8412)) + + +### Bug Fixes + +* **amazonq:** add IntelliSense autotriggerType ([#2199](https://github.com/aws/language-servers/issues/2199)) ([013aa59](https://github.com/aws/language-servers/commit/013aa5913c242451a91ed36b0dcf961a3f8ec697)) +* **amazonq:** fix to correct the client for getProfile request ([#2211](https://github.com/aws/language-servers/issues/2211)) ([8bde8c9](https://github.com/aws/language-servers/commit/8bde8c97e1e3bcd67d9816a3385c50c7765c3b2f)) +* **amazonq:** fix to update MCP servers list when last server is removed from agent config ([#2206](https://github.com/aws/language-servers/issues/2206)) ([512502a](https://github.com/aws/language-servers/commit/512502af947dcfed9288be2f67fc58affd4445fe)) +* **amazonq:** update to the agent config format to bring parity with Q CLI ([#2202](https://github.com/aws/language-servers/issues/2202)) ([698d06c](https://github.com/aws/language-servers/commit/698d06c643897da6ca37a49e6544b150b72678a3)) +* potential xss issue reported in `mynah-ui` ([#2209](https://github.com/aws/language-servers/issues/2209)) ([cf585cd](https://github.com/aws/language-servers/commit/cf585cd400dab6274f8220139ae94287c0d96824)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @aws/lsp-core bumped from ^0.0.14 to ^0.0.15 + ## [0.0.77](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.76...lsp-codewhisperer/v0.0.77) (2025-09-02) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 9563b6300d..3fb2f48e69 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.77", + "version": "0.0.78", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { @@ -37,7 +37,7 @@ "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", "@aws/language-server-runtimes": "^0.2.128", - "@aws/lsp-core": "^0.0.14", + "@aws/lsp-core": "^0.0.15", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", "adm-zip": "^0.5.10", diff --git a/server/aws-lsp-json/CHANGELOG.md b/server/aws-lsp-json/CHANGELOG.md index ecac136295..de134b8f6e 100644 --- a/server/aws-lsp-json/CHANGELOG.md +++ b/server/aws-lsp-json/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [0.1.19](https://github.com/aws/language-servers/compare/lsp-json/v0.1.18...lsp-json/v0.1.19) (2025-09-09) + + +### Features + +* add support for getSupplementalContext LSP API ([#2212](https://github.com/aws/language-servers/issues/2212)) ([2ddcae7](https://github.com/aws/language-servers/commit/2ddcae7a4fac6b89cbc9784911959743ea0a6d11)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @aws/lsp-core bumped from ^0.0.14 to ^0.0.15 + ## [0.1.18](https://github.com/aws/language-servers/compare/lsp-json/v0.1.17...lsp-json/v0.1.18) (2025-08-19) diff --git a/server/aws-lsp-json/package.json b/server/aws-lsp-json/package.json index 6b2c95bc49..b1ce196af0 100644 --- a/server/aws-lsp-json/package.json +++ b/server/aws-lsp-json/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-json", - "version": "0.1.18", + "version": "0.1.19", "description": "JSON Language Server", "main": "out/index.js", "repository": { @@ -27,7 +27,7 @@ }, "dependencies": { "@aws/language-server-runtimes": "^0.2.128", - "@aws/lsp-core": "^0.0.14", + "@aws/lsp-core": "^0.0.15", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" }, diff --git a/server/aws-lsp-partiql/CHANGELOG.md b/server/aws-lsp-partiql/CHANGELOG.md index dc68bdb063..37efbed366 100644 --- a/server/aws-lsp-partiql/CHANGELOG.md +++ b/server/aws-lsp-partiql/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.0.18](https://github.com/aws/language-servers/compare/lsp-partiql/v0.0.17...lsp-partiql/v0.0.18) (2025-09-09) + + +### Features + +* add support for getSupplementalContext LSP API ([#2212](https://github.com/aws/language-servers/issues/2212)) ([2ddcae7](https://github.com/aws/language-servers/commit/2ddcae7a4fac6b89cbc9784911959743ea0a6d11)) + ## [0.0.17](https://github.com/aws/language-servers/compare/lsp-partiql/v0.0.16...lsp-partiql/v0.0.17) (2025-08-19) diff --git a/server/aws-lsp-partiql/package.json b/server/aws-lsp-partiql/package.json index e5f59a4411..2dc6c0e968 100644 --- a/server/aws-lsp-partiql/package.json +++ b/server/aws-lsp-partiql/package.json @@ -3,7 +3,7 @@ "author": "Amazon Web Services", "license": "Apache-2.0", "description": "PartiQL language server", - "version": "0.0.17", + "version": "0.0.18", "repository": { "type": "git", "url": "https://github.com/aws/language-servers" diff --git a/server/aws-lsp-yaml/CHANGELOG.md b/server/aws-lsp-yaml/CHANGELOG.md index 5858e6eb66..c43fc8f8f3 100644 --- a/server/aws-lsp-yaml/CHANGELOG.md +++ b/server/aws-lsp-yaml/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [0.1.19](https://github.com/aws/language-servers/compare/lsp-yaml/v0.1.18...lsp-yaml/v0.1.19) (2025-09-09) + + +### Features + +* add support for getSupplementalContext LSP API ([#2212](https://github.com/aws/language-servers/issues/2212)) ([2ddcae7](https://github.com/aws/language-servers/commit/2ddcae7a4fac6b89cbc9784911959743ea0a6d11)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @aws/lsp-core bumped from ^0.0.14 to ^0.0.15 + ## [0.1.18](https://github.com/aws/language-servers/compare/lsp-yaml/v0.1.17...lsp-yaml/v0.1.18) (2025-08-19) diff --git a/server/aws-lsp-yaml/package.json b/server/aws-lsp-yaml/package.json index 213221d721..555b12c69a 100644 --- a/server/aws-lsp-yaml/package.json +++ b/server/aws-lsp-yaml/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-yaml", - "version": "0.1.18", + "version": "0.1.19", "description": "YAML Language Server", "main": "out/index.js", "repository": { @@ -27,7 +27,7 @@ }, "dependencies": { "@aws/language-server-runtimes": "^0.2.128", - "@aws/lsp-core": "^0.0.14", + "@aws/lsp-core": "^0.0.15", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", "yaml-language-server": "1.13.0" From 8e19f19a71e63a1196f4cb67ded8360c8da8129e Mon Sep 17 00:00:00 2001 From: Jayakrishna P Date: Tue, 9 Sep 2025 16:03:39 -0700 Subject: [PATCH 070/158] feat: feature to add iam inline suggestion support in codeWhispererservice (#2223) * Sync feature smus inline suggestions branch from main commits (#2109) * fix(amazonq): leverage lcs to find the chars added and removed (#2092) * fix: update client name to support Sagemaker AI origin for agentic chat (#2093) Co-authored-by: chungjac * chore(release): release packages from branch main (#2073) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * chore: format version.json after incrementing (#2068) * chore: merge agentic version 1.27.0 (#2107) * Bump agentic version: 1.27.0 * Revert "feat(amazonq): read tool ui revamp" This reverts commit c65428bab2cf5e47badf1e3a9453babcf881e60c. * fix: the style in version json (#2106) --------- Co-authored-by: aws-toolkit-automation <> Co-authored-by: Tai Lai Co-authored-by: Christopher Christou <39839589+awschristou@users.noreply.github.com> * fix(amazonq): persist mcp configs in agent json on start-up (#2112) --------- Co-authored-by: andrewyuq <89420755+andrewyuq@users.noreply.github.com> Co-authored-by: chungjac Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Christopher Christou <39839589+awschristou@users.noreply.github.com> Co-authored-by: Sherry Lu <75588211+XiaoxuanLu@users.noreply.github.com> Co-authored-by: Tai Lai Co-authored-by: Dung Dong * feat(amazonq): Integrate IAM Auth support for InlineSuggestions in Flare (#2134) * Chore: Sync test smus branch with main branch commits (#2097) * fix(amazonq): skips continuous monitoring when WCS sees workspace as idle (#2066) * fix(amazonq): skips continuous monitoring when WCS sees workspace as idle * fix(amazonq): skips creating remote workspace at the start --------- Co-authored-by: Jiatong Li * fix: sessionManager misused because there are 2 types of manager now (#2090) * chore: mapping adt plugin to abap to let inline suggestion work (#2085) * chore: support inline suggestion in adt plugin for eclipse * fix: add import URI * chore: add detailed error description for uri is empty for language id * feat(amazonq): read tool ui revamp * feat(amazonq): read tool message revamp (#2049) * feat(amazonq): read tool message revamp * fix tests * feat: file search ui (#2078) * feat: file search ui * fix tests * fix integration tests * remove unnecessary type check * fix: use quotes instead of backticks * fix: creating a new sesion for Edits trigger with next token (#2094) * chore: bump @aws/mynah-ui to 4.36.4 (#2096) --------- Co-authored-by: Jiatong Li Co-authored-by: Jiatong Li Co-authored-by: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Co-authored-by: Sherry Lu <75588211+XiaoxuanLu@users.noreply.github.com> Co-authored-by: Tai Lai Co-authored-by: atontb <104926752+atonaamz@users.noreply.github.com> * feat(amazonq): add inline suggestion support for iam auth client * fix(amazonq): skips continuous monitoring when WCS sees workspace as idle (#2066) * fix(amazonq): skips continuous monitoring when WCS sees workspace as idle * fix(amazonq): skips creating remote workspace at the start --------- Co-authored-by: Jiatong Li * fix: sessionManager misused because there are 2 types of manager now (#2090) * chore: mapping adt plugin to abap to let inline suggestion work (#2085) * fix(amazonq): leverage lcs to find the chars added and removed (#2092) * fix: update client name to support Sagemaker AI origin for agentic chat (#2093) Co-authored-by: chungjac * chore(release): release packages from branch main (#2073) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * chore: fix test failures in merge due to missing init of IdleWorkspaceManager --------- Co-authored-by: Jiatong Li Co-authored-by: Jiatong Li Co-authored-by: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Co-authored-by: Sherry Lu <75588211+XiaoxuanLu@users.noreply.github.com> Co-authored-by: Tai Lai Co-authored-by: atontb <104926752+atonaamz@users.noreply.github.com> Co-authored-by: andrewyuq <89420755+andrewyuq@users.noreply.github.com> Co-authored-by: chungjac Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: invictus <149003065+ashishrp-aws@users.noreply.github.com> * fix: add unit tests for IAM flow, remove redundant logs added for testing * fix: file formatting * fix: rebase from main, clean up redundant logs * fix: remove old code refs and debug logs * feat: use cw proxy server based on iam auth logic check * fix: todo comment and unused imports * fix: update codewhisperer server to use proper manager based on iam auth logic check * feat: create new codewhisperer server instance with dynamic service manager logic and add unit tests * fix: address pr comments, fix unit tests as per updated service manager logic --------- Co-authored-by: andrewyuq <89420755+andrewyuq@users.noreply.github.com> Co-authored-by: chungjac Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Christopher Christou <39839589+awschristou@users.noreply.github.com> Co-authored-by: Sherry Lu <75588211+XiaoxuanLu@users.noreply.github.com> Co-authored-by: Tai Lai Co-authored-by: Dung Dong Co-authored-by: Jiatong Li Co-authored-by: Jiatong Li Co-authored-by: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Co-authored-by: Tai Lai Co-authored-by: atontb <104926752+atonaamz@users.noreply.github.com> Co-authored-by: invictus <149003065+ashishrp-aws@users.noreply.github.com> Co-authored-by: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> --- .../src/agent-standalone.ts | 4 +- .../agenticChat/tools/toolServer.ts | 30 +++-- .../auto-trigger/autoTrigger.ts | 1 - .../codeWhispererServer.test.ts | 117 +++++++++++++++++- .../inline-completion/codeWhispererServer.ts | 49 ++++++-- .../src/shared/codeWhispererService.test.ts | 34 +++++ .../src/shared/codeWhispererService.ts | 105 ++++++++++++---- .../src/shared/utils.test.ts | 77 ++++++++++++ .../aws-lsp-codewhisperer/src/shared/utils.ts | 23 +++- 9 files changed, 392 insertions(+), 48 deletions(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/src/agent-standalone.ts b/app/aws-lsp-codewhisperer-runtimes/src/agent-standalone.ts index 7996472ada..49600a91b8 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/agent-standalone.ts +++ b/app/aws-lsp-codewhisperer-runtimes/src/agent-standalone.ts @@ -3,7 +3,7 @@ import { AmazonQServiceServerIAM, AmazonQServiceServerToken, CodeWhispererSecurityScanServerTokenProxy, - CodeWhispererServerTokenProxy, + CodeWhispererServer, QAgenticChatServerProxy, QConfigurationServerTokenProxy, QLocalProjectContextServerProxy, @@ -25,7 +25,7 @@ const version = versionJson.agenticChat const props = { version: version, servers: [ - CodeWhispererServerTokenProxy, + CodeWhispererServer, CodeWhispererSecurityScanServerTokenProxy, QConfigurationServerTokenProxy, QNetTransformServerTokenProxy, diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts index 29b838f2d3..d2257a45e4 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts @@ -11,7 +11,7 @@ import { McpTool } from './mcp/mcpTool' import { FileSearch, FileSearchParams } from './fileSearch' import { GrepSearch } from './grepSearch' import { CodeReview } from './qCodeAnalysis/codeReview' -import { CodeWhispererServiceToken } from '../../../shared/codeWhispererService' +import { CodeWhispererServiceIAM, CodeWhispererServiceToken } from '../../../shared/codeWhispererService' import { McpToolDefinition } from './mcp/mcpTypes' import { getGlobalAgentConfigPath, @@ -29,6 +29,7 @@ import { DisplayFindings } from './qCodeAnalysis/displayFindings' import { ProfileStatusMonitor } from './mcp/profileStatusMonitor' import { AmazonQTokenServiceManager } from '../../../shared/amazonQServiceManager/AmazonQTokenServiceManager' import { SERVICE_MANAGER_TIMEOUT_MS, SERVICE_MANAGER_POLL_INTERVAL_MS } from '../constants/constants' +import { isUsingIAMAuth } from '../../../shared/utils' export const FsToolsServer: Server = ({ workspace, logging, agent, lsp }) => { const fsReadTool = new FsRead({ workspace, lsp, logging }) @@ -127,15 +128,24 @@ export const QCodeAnalysisServer: Server = ({ return } - // Create the CodeWhisperer client - const codeWhispererClient = new CodeWhispererServiceToken( - credentialsProvider, - workspace, - logging, - process.env.CODEWHISPERER_REGION || DEFAULT_AWS_Q_REGION, - process.env.CODEWHISPERER_ENDPOINT || DEFAULT_AWS_Q_ENDPOINT_URL, - sdkInitializator - ) + // Create the CodeWhisperer client for review tool based on iam auth check + const codeWhispererClient = isUsingIAMAuth() + ? new CodeWhispererServiceIAM( + credentialsProvider, + workspace, + logging, + process.env.CODEWHISPERER_REGION || DEFAULT_AWS_Q_REGION, + process.env.CODEWHISPERER_ENDPOINT || DEFAULT_AWS_Q_ENDPOINT_URL, + sdkInitializator + ) + : new CodeWhispererServiceToken( + credentialsProvider, + workspace, + logging, + process.env.CODEWHISPERER_REGION || DEFAULT_AWS_Q_REGION, + process.env.CODEWHISPERER_ENDPOINT || DEFAULT_AWS_Q_ENDPOINT_URL, + sdkInitializator + ) agent.addTool( { diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts index b6657b229c..4255be11cc 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts @@ -217,7 +217,6 @@ export const autoTrigger = ( rightContextAtCurrentLine.trim() !== ')' && ['VSCODE', 'JETBRAINS'].includes(ide) ) { - logging.debug(`Skip auto trigger: immediate right context`) return { shouldTrigger: false, classifierResult: 0, diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts index e15400434c..61fb867a02 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts @@ -12,7 +12,7 @@ import { TestFeatures } from '@aws/language-server-runtimes/testing' import * as assert from 'assert' import { AWSError } from 'aws-sdk' import sinon, { StubbedInstance } from 'ts-sinon' -import { CodewhispererServerFactory, getLanguageIdFromUri } from './codeWhispererServer' +import { CodeWhispererServer, CodewhispererServerFactory, getLanguageIdFromUri } from './codeWhispererServer' import { CodeWhispererServiceBase, CodeWhispererServiceToken, @@ -55,6 +55,7 @@ import { import { CodeDiffTracker } from './codeDiffTracker' import { TelemetryService } from '../../shared/telemetry/telemetryService' import { initBaseTestServiceManager, TestAmazonQServiceManager } from '../../shared/amazonQServiceManager/testUtils' +import * as utils from '../../shared/utils' import { LocalProjectContextController } from '../../shared/localProjectContextController' import { URI } from 'vscode-uri' import { INVALID_TOKEN } from '../../shared/constants' @@ -107,6 +108,33 @@ describe('CodeWhisperer Server', () => { .callsFake(StubSessionIdGenerator) sessionManager = SessionManager.getInstance() sessionManagerSpy = sandbox.spy(sessionManager) + + // Stub the global service manager functions to ensure they return test service managers + sandbox + .stub( + require('../../shared/amazonQServiceManager/AmazonQTokenServiceManager'), + 'getOrThrowBaseTokenServiceManager' + ) + .callsFake(() => { + // Create a new test service manager + return TestAmazonQServiceManager.getInstance() + }) + + // Also stub the IAM service manager + sandbox + .stub( + require('../../shared/amazonQServiceManager/AmazonQIAMServiceManager'), + 'getOrThrowBaseIAMServiceManager' + ) + .callsFake(() => { + // Return the same test service manager + return TestAmazonQServiceManager.getInstance() + }) + + // Reset AmazonQTokenServiceManager singleton to prevent cross-test interference + const AmazonQTokenServiceManager = + require('../../shared/amazonQServiceManager/AmazonQTokenServiceManager').AmazonQTokenServiceManager + AmazonQTokenServiceManager.resetInstance() }) afterEach(() => { @@ -115,6 +143,14 @@ describe('CodeWhisperer Server', () => { sandbox.restore() sinon.restore() SESSION_IDS_LOG = [] + + // Reset all service manager singletons to prevent cross-test interference + const AmazonQTokenServiceManager = + require('../../shared/amazonQServiceManager/AmazonQTokenServiceManager').AmazonQTokenServiceManager + const AmazonQIAMServiceManager = + require('../../shared/amazonQServiceManager/AmazonQIAMServiceManager').AmazonQIAMServiceManager + AmazonQTokenServiceManager.resetInstance() + AmazonQIAMServiceManager.resetInstance() }) describe('Recommendations', () => { @@ -648,7 +684,8 @@ describe('CodeWhisperer Server', () => { it('handles partialResultToken in request', async () => { const manager = SessionManager.getInstance() - manager.createSession(SAMPLE_SESSION_DATA) + const session = manager.createSession(SAMPLE_SESSION_DATA) + manager.activateSession(session) await features.doInlineCompletionWithReferences( { textDocument: { uri: SOME_FILE.uri }, @@ -2394,6 +2431,38 @@ describe('CodeWhisperer Server', () => { TestAmazonQServiceManager.resetInstance() }) }) + + describe('IAM Error Handling', () => { + it('should handle IAM access denied errors', async () => { + const service = sinon.createStubInstance( + CodeWhispererServiceToken + ) as StubbedInstance + service.generateSuggestions.rejects(new Error('not authorized')) + + const features = new TestFeatures() + //@ts-ignore + features.logging = console + + TestAmazonQServiceManager.resetInstance() + const server = CodewhispererServerFactory(() => initBaseTestServiceManager(features, service)) + features.lsp.workspace.getConfiguration.returns(Promise.resolve({})) + await startServer(features, server) + features.openDocument(SOME_FILE) + + const result = await features.doInlineCompletionWithReferences( + { + textDocument: { uri: SOME_FILE.uri }, + position: { line: 0, character: 0 }, + context: { triggerKind: InlineCompletionTriggerKind.Invoked }, + }, + CancellationToken.None + ) + + assert.deepEqual(result, EMPTY_RESULT) + TestAmazonQServiceManager.resetInstance() + }) + }) + describe('getLanguageIdFromUri', () => { it('should return python for notebook cell URIs', () => { const uri = 'vscode-notebook-cell:/some/path/notebook.ipynb#cell1' @@ -2441,4 +2510,48 @@ describe('CodeWhisperer Server', () => { assert.strictEqual(getLanguageIdFromUri(uri), '') }) }) + + describe('Dynamic Service Manager Selection', () => { + it('should use Token service manager when not using IAM auth', async () => { + // Create isolated stubs for this test only + const isUsingIAMAuthStub = sinon.stub(utils, 'isUsingIAMAuth').returns(false) + const mockTokenService = TestAmazonQServiceManager.initInstance(new TestFeatures()) + mockTokenService.withCodeWhispererService(stubCodeWhispererService()) + + const features = new TestFeatures() + const server = CodeWhispererServer + + try { + await startServer(features, server) + + // Verify the correct service manager function was called + sinon.assert.calledWith(isUsingIAMAuthStub, features.credentialsProvider) + } finally { + isUsingIAMAuthStub.restore() + features.dispose() + TestAmazonQServiceManager.resetInstance() + } + }) + + it('should use IAM service manager when using IAM auth', async () => { + // Create isolated stubs for this test only + const isUsingIAMAuthStub = sinon.stub(utils, 'isUsingIAMAuth').returns(true) + const mockIAMService = TestAmazonQServiceManager.initInstance(new TestFeatures()) + mockIAMService.withCodeWhispererService(stubCodeWhispererService()) + + const features = new TestFeatures() + const server = CodeWhispererServer + + try { + await startServer(features, server) + + // Verify the correct service manager function was called + sinon.assert.calledWith(isUsingIAMAuthStub, features.credentialsProvider) + } finally { + isUsingIAMAuthStub.restore() + features.dispose() + TestAmazonQServiceManager.resetInstance() + } + }) + }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts index c869a534fd..4f28b46ea9 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts @@ -6,7 +6,6 @@ import { InlineCompletionTriggerKind, InlineCompletionWithReferencesParams, LogInlineCompletionSessionResultsParams, - Position, Range, Server, TextDocument, @@ -16,6 +15,10 @@ import { import { autoTrigger, getAutoTriggerType, getNormalizeOsName, triggerType } from './auto-trigger/autoTrigger' import { FileContext, + BaseGenerateSuggestionsRequest, + CodeWhispererServiceToken, + GenerateIAMSuggestionsRequest, + GenerateTokenSuggestionsRequest, GenerateSuggestionsRequest, GenerateSuggestionsResponse, getFileContext, @@ -23,7 +26,7 @@ import { SuggestionType, } from '../../shared/codeWhispererService' import { CodewhispererLanguage, getSupportedLanguageId } from '../../shared/languageDetection' -import { mergeEditSuggestionsWithFileContext, truncateOverlapWithRightContext } from './mergeRightUtils' +import { truncateOverlapWithRightContext } from './mergeRightUtils' import { CodeWhispererSession, SessionManager } from './session/sessionManager' import { CodePercentageTracker } from './codePercentage' import { getCompletionType, getEndPositionForAcceptedSuggestion, getErrorMessage, safeGet } from '../../shared/utils' @@ -59,6 +62,7 @@ import { EditCompletionHandler } from './editCompletionHandler' import { EMPTY_RESULT, ABAP_EXTENSIONS } from './constants' import { IdleWorkspaceManager } from '../workspaceContext/IdleWorkspaceManager' import { URI } from 'vscode-uri' +import { isUsingIAMAuth } from '../../shared/utils' const mergeSuggestionsWithRightContext = ( rightFileContext: string, @@ -102,7 +106,7 @@ const mergeSuggestionsWithRightContext = ( } export const CodewhispererServerFactory = - (serviceManager: () => AmazonQBaseServiceManager): Server => + (serviceManager: (credentialsProvider?: any) => AmazonQBaseServiceManager): Server => ({ credentialsProvider, lsp, workspace, telemetry, logging, runtime, sdkInitializator }) => { let lastUserModificationTime: number let timeSinceLastUserModification: number = 0 @@ -151,6 +155,13 @@ export const CodewhispererServerFactory = logging.log(`Skip concurrent inline completion`) return EMPTY_RESULT } + + // Add this check to ensure service manager is initialized + if (!amazonQServiceManager) { + logging.log('Amazon Q Service Manager not initialized yet') + return EMPTY_RESULT + } + isOnInlineCompletionHandlerInProgress = true try { @@ -167,6 +178,10 @@ export const CodewhispererServerFactory = const textDocument = await getTextDocument(params.textDocument.uri, workspace, logging) const codeWhispererService = amazonQServiceManager.getCodewhispererService() + const authType = codeWhispererService instanceof CodeWhispererServiceToken ? 'token' : 'iam' + logging.debug( + `[INLINE_COMPLETION] Service ready - auth: ${authType}, partial token: ${!!params.partialResultToken}` + ) if (params.partialResultToken && currentSession) { // subsequent paginated requests for current session try { @@ -362,11 +377,25 @@ export const CodewhispererServerFactory = extraContext + '\n' + requestContext.fileContext.leftFileContent } - const generateCompletionReq = { - ...requestContext, - ...(workspaceId ? { workspaceId: workspaceId } : {}), + // Create the appropriate request based on service type + let generateCompletionReq: BaseGenerateSuggestionsRequest + + if (codeWhispererService instanceof CodeWhispererServiceToken) { + const tokenRequest = requestContext as GenerateTokenSuggestionsRequest + generateCompletionReq = { + ...tokenRequest, + ...(workspaceId ? { workspaceId } : {}), + } + } else { + const iamRequest = requestContext as GenerateIAMSuggestionsRequest + generateCompletionReq = { + ...iamRequest, + } } + try { + const authType = codeWhispererService instanceof CodeWhispererServiceToken ? 'token' : 'iam' + logging.debug(`[INLINE_COMPLETION] API call - generateSuggestions (new session, ${authType})`) const suggestionResponse = await codeWhispererService.generateSuggestions(generateCompletionReq) return await processSuggestionResponse(suggestionResponse, newSession, true, selectionRange) } catch (error) { @@ -524,6 +553,7 @@ export const CodewhispererServerFactory = session: CodeWhispererSession ): InlineCompletionListWithReferences => { logging.log('Recommendation failure: ' + error) + emitServiceInvocationFailure(telemetry, session, error) // UTDE telemetry is not needed here because in error cases we don't care about UTDE for errored out sessions @@ -706,7 +736,7 @@ export const CodewhispererServerFactory = } const onInitializedHandler = async () => { - amazonQServiceManager = serviceManager() + amazonQServiceManager = serviceManager(credentialsProvider) const clientParams = safeGet( lsp.getClientInitializeParams(), @@ -875,6 +905,11 @@ export const CodewhispererServerFactory = } } +// Dynamic service manager factory that detects auth type at runtime +export const CodeWhispererServer = CodewhispererServerFactory((credentialsProvider?: any) => { + return isUsingIAMAuth(credentialsProvider) ? getOrThrowBaseIAMServiceManager() : getOrThrowBaseTokenServiceManager() +}) + export const CodeWhispererServerIAM = CodewhispererServerFactory(getOrThrowBaseIAMServiceManager) export const CodeWhispererServerToken = CodewhispererServerFactory(getOrThrowBaseTokenServiceManager) diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.test.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.test.ts index 187bc41f35..75c691a5e3 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.test.ts @@ -23,6 +23,8 @@ import { CodeWhispererServiceIAM, GenerateSuggestionsRequest, GenerateSuggestionsResponse, + isIAMRequest, + isTokenRequest, } from './codeWhispererService' import { RecentEditTracker } from '../language-server/inline-completion/tracker/codeEditTracker' import { CodeWhispererSupplementalContext } from './models/model' @@ -303,6 +305,38 @@ describe('CodeWhispererService', function () { const clientCall = (service.client.generateRecommendations as sinon.SinonStub).getCall(0) assert.strictEqual(clientCall.args[0].customizationArn, 'test-arn') }) + + it('should include serviceType in response', async function () { + const mockRequest: GenerateSuggestionsRequest = { + fileContext: { + filename: 'test.js', + programmingLanguage: { languageName: 'javascript' }, + leftFileContent: 'const x = ', + rightFileContent: '', + }, + maxResults: 5, + } + + const result = await service.generateSuggestions(mockRequest) + assert.strictEqual(result.responseContext.authType, 'iam') + }) + }) + + describe('Request Type Guards', function () { + it('should identify IAM vs Token requests', function () { + const iamRequest = { + fileContext: { + filename: 'test.js', + programmingLanguage: { languageName: 'javascript' }, + leftFileContent: '', + rightFileContent: '', + }, + } + const tokenRequest = { ...iamRequest, editorState: {} } + + assert.strictEqual(isIAMRequest(iamRequest), true) + assert.strictEqual(isTokenRequest(tokenRequest), true) + }) }) }) diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index 984bb6da76..1225e86435 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -42,22 +42,51 @@ import { FILENAME_CHARS_LIMIT, } from '../language-server/inline-completion/constants' +// Type guards for request classification +export function isTokenRequest(request: BaseGenerateSuggestionsRequest): request is GenerateTokenSuggestionsRequest { + return 'editorState' in request || 'predictionTypes' in request || 'supplementalContexts' in request +} + +export function isIAMRequest(request: BaseGenerateSuggestionsRequest): request is GenerateIAMSuggestionsRequest { + return !isTokenRequest(request) +} + export interface Suggestion extends CodeWhispererTokenClient.Completion, CodeWhispererSigv4Client.Recommendation { itemId: string } -export interface GenerateSuggestionsRequest extends CodeWhispererTokenClient.GenerateCompletionsRequest { - // TODO : This is broken due to Interface 'GenerateSuggestionsRequest' cannot simultaneously extend types 'GenerateCompletionsRequest' and 'GenerateRecommendationsRequest'. - //CodeWhispererSigv4Client.GenerateRecommendationsRequest { - maxResults: number +// Base request interface with common fields - using union type for FileContext compatibility +export interface BaseGenerateSuggestionsRequest { + fileContext: FileContext + maxResults?: number + nextToken?: string } -export type FileContext = GenerateSuggestionsRequest['fileContext'] +// IAM-specific request interface that directly extends the SigV4 client request +export interface GenerateIAMSuggestionsRequest extends CodeWhispererSigv4Client.GenerateRecommendationsRequest {} + +// Token-specific request interface that directly extends the Token client request +export interface GenerateTokenSuggestionsRequest extends CodeWhispererTokenClient.GenerateCompletionsRequest {} + +// Union type for backward compatibility +export type GenerateSuggestionsRequest = GenerateIAMSuggestionsRequest | GenerateTokenSuggestionsRequest + +// FileContext type that's compatible with both clients +export type FileContext = { + fileUri?: string // Optional in both clients + filename: string + programmingLanguage: { + languageName: string + } + leftFileContent: string + rightFileContent: string +} export interface ResponseContext { requestId: string codewhispererSessionId: string nextToken?: string + authType?: 'iam' | 'token' } export enum SuggestionType { @@ -142,7 +171,7 @@ export abstract class CodeWhispererServiceBase { abstract getCredentialsType(): CredentialsType - abstract generateSuggestions(request: GenerateSuggestionsRequest): Promise + abstract generateSuggestions(request: BaseGenerateSuggestionsRequest): Promise abstract constructSupplementalContext( document: TextDocument, @@ -242,23 +271,40 @@ export class CodeWhispererServiceIAM extends CodeWhispererServiceBase { return undefined } - async generateSuggestions(request: GenerateSuggestionsRequest): Promise { - // add cancellation check - // add error check - if (this.customizationArn) request = { ...request, customizationArn: this.customizationArn } - const response = await this.client.generateRecommendations(request).promise() - const responseContext = { + async generateSuggestions(request: BaseGenerateSuggestionsRequest): Promise { + // Cast is now safe because GenerateIAMSuggestionsRequest extends GenerateRecommendationsRequest + const iamRequest = request as GenerateIAMSuggestionsRequest + + // Add customization ARN if configured + if (this.customizationArn) { + ;(iamRequest as any).customizationArn = this.customizationArn + } + + // Warn about unsupported features for IAM auth + if ('editorState' in request || 'predictionTypes' in request || 'supplementalContexts' in request) { + console.warn('Advanced features not supported - using basic completion') + } + + const response = await this.client.generateRecommendations(iamRequest).promise() + + return this.mapCodeWhispererApiResponseToSuggestion(response, { requestId: response?.$response?.requestId, codewhispererSessionId: response?.$response?.httpResponse?.headers['x-amzn-sessionid'], nextToken: response.nextToken, - } + authType: 'iam' as const, + }) + } - for (const recommendation of response?.recommendations ?? []) { + private mapCodeWhispererApiResponseToSuggestion( + apiResponse: CodeWhispererSigv4Client.GenerateRecommendationsResponse, + responseContext: ResponseContext + ): GenerateSuggestionsResponse { + for (const recommendation of apiResponse?.recommendations ?? []) { Object.assign(recommendation, { itemId: this.generateItemId() }) } return { - suggestions: response.recommendations as Suggestion[], + suggestions: apiResponse.recommendations as Suggestion[], suggestionType: SuggestionType.COMPLETION, responseContext, } @@ -419,15 +465,22 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { return { ...request, profileArn: this.profileArn } } - async generateSuggestions(request: GenerateSuggestionsRequest): Promise { + async generateSuggestions(request: BaseGenerateSuggestionsRequest): Promise { + // Cast is now safe because GenerateTokenSuggestionsRequest extends GenerateCompletionsRequest // add cancellation check // add error check let logstr = `GenerateCompletion activity:\n` try { - if (this.customizationArn) request.customizationArn = this.customizationArn + const tokenRequest = request as GenerateTokenSuggestionsRequest + + // Add customizationArn if available + if (this.customizationArn) { + tokenRequest.customizationArn = this.customizationArn + } + const beforeApiCall = performance.now() let recentEditsLogStr = '' - const recentEdits = request.supplementalContexts?.filter(it => it.type === 'PreviousEditorState') + const recentEdits = tokenRequest.supplementalContexts?.filter(it => it.type === 'PreviousEditorState') if (recentEdits) { if (recentEdits.length === 0) { recentEditsLogStr += `No recent edits` @@ -440,23 +493,26 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { } } } + logstr += `@@request metadata@@ "endpoint": ${this.codeWhispererEndpoint}, - "predictionType": ${request.predictionTypes?.toString() ?? 'Not specified (COMPLETIONS)'}, - "filename": ${request.fileContext.filename}, + "predictionType": ${tokenRequest.predictionTypes?.toString() ?? 'Not specified (COMPLETIONS)'}, + "filename": ${tokenRequest.fileContext.filename}, "leftContextLength": ${request.fileContext.leftFileContent.length}, rightContextLength: ${request.fileContext.rightFileContent.length}, - "language": ${request.fileContext.programmingLanguage.languageName}, - "supplementalContextCount": ${request.supplementalContexts?.length ?? 0}, - "request.nextToken": ${request.nextToken}, + "language": ${tokenRequest.fileContext.programmingLanguage.languageName}, + "supplementalContextCount": ${tokenRequest.supplementalContexts?.length ?? 0}, + "request.nextToken": ${tokenRequest.nextToken}, "recentEdits": ${recentEditsLogStr}\n` - const response = await this.client.generateCompletions(this.withProfileArn(request)).promise() + const response = await this.client.generateCompletions(this.withProfileArn(tokenRequest)).promise() const responseContext = { requestId: response?.$response?.requestId, codewhispererSessionId: response?.$response?.httpResponse?.headers['x-amzn-sessionid'], nextToken: response.nextToken, + // CRITICAL: Add service type for proper error handling + authType: 'token' as const, } const r = this.mapCodeWhispererApiResponseToSuggestion(response, responseContext) @@ -467,6 +523,7 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { "sessionId": ${responseContext.codewhispererSessionId}, "response.completions.length": ${response.completions?.length ?? 0}, "response.predictions.length": ${response.predictions?.length ?? 0}, + "predictionType": ${tokenRequest.predictionTypes?.toString() ?? ''}, "latency": ${performance.now() - beforeApiCall}, "response.nextToken": ${response.nextToken}, "firstSuggestion": ${firstSuggestionLogstr}` diff --git a/server/aws-lsp-codewhisperer/src/shared/utils.test.ts b/server/aws-lsp-codewhisperer/src/shared/utils.test.ts index 85cd8817a7..7ffe837938 100644 --- a/server/aws-lsp-codewhisperer/src/shared/utils.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/utils.test.ts @@ -27,6 +27,7 @@ import { getClientName, sanitizeInput, sanitizeRequestInput, + isUsingIAMAuth, } from './utils' import { promises as fsPromises } from 'fs' @@ -185,6 +186,82 @@ describe('getOriginFromClientInfo', () => { }) }) +describe('isUsingIAMAuth', () => { + let originalEnv: string | undefined + + beforeEach(() => { + originalEnv = process.env.USE_IAM_AUTH + delete process.env.USE_IAM_AUTH + }) + + afterEach(() => { + if (originalEnv !== undefined) { + process.env.USE_IAM_AUTH = originalEnv + } else { + delete process.env.USE_IAM_AUTH + } + }) + + it('should return true when USE_IAM_AUTH environment variable is "true"', () => { + process.env.USE_IAM_AUTH = 'true' + assert.strictEqual(isUsingIAMAuth(), true) + }) + + it('should return false when USE_IAM_AUTH environment variable is not set', () => { + assert.strictEqual(isUsingIAMAuth(), false) + }) + + it('should return true when only IAM credentials are available', () => { + const mockProvider: CredentialsProvider = { + hasCredentials: sinon.stub().returns(true), + getCredentials: sinon + .stub() + .withArgs('iam') + .returns({ accessKeyId: 'AKIA...', secretAccessKey: 'secret' }) + .withArgs('bearer') + .returns(null), + getConnectionMetadata: sinon.stub(), + getConnectionType: sinon.stub(), + onCredentialsDeleted: sinon.stub(), + } + + assert.strictEqual(isUsingIAMAuth(mockProvider), true) + }) + + it('should return false when bearer credentials are available', () => { + const mockProvider: CredentialsProvider = { + hasCredentials: sinon.stub().returns(true), + getCredentials: sinon + .stub() + .withArgs('iam') + .returns({ accessKeyId: 'AKIA...', secretAccessKey: 'secret' }) + .withArgs('bearer') + .returns({ token: 'bearer-token' }), + getConnectionMetadata: sinon.stub(), + getConnectionType: sinon.stub(), + onCredentialsDeleted: sinon.stub(), + } + + assert.strictEqual(isUsingIAMAuth(mockProvider), false) + }) + + it('should return false when credential access fails', () => { + const mockProvider: CredentialsProvider = { + hasCredentials: sinon.stub().returns(true), + getCredentials: sinon.stub().throws(new Error('Access failed')), + getConnectionMetadata: sinon.stub(), + getConnectionType: sinon.stub(), + onCredentialsDeleted: sinon.stub(), + } + + assert.strictEqual(isUsingIAMAuth(mockProvider), false) + }) + + it('should return false when credentialsProvider is undefined', () => { + assert.strictEqual(isUsingIAMAuth(undefined), false) + }) +}) + describe('getSsoConnectionType', () => { const mockToken = 'mockToken' const mockCredsProvider: CredentialsProvider = { diff --git a/server/aws-lsp-codewhisperer/src/shared/utils.ts b/server/aws-lsp-codewhisperer/src/shared/utils.ts index a7a95d8801..af5cd14c28 100644 --- a/server/aws-lsp-codewhisperer/src/shared/utils.ts +++ b/server/aws-lsp-codewhisperer/src/shared/utils.ts @@ -392,8 +392,27 @@ export function getOriginFromClientInfo(clientName: string | undefined): Origin return 'IDE' } -export function isUsingIAMAuth(): boolean { - return process.env.USE_IAM_AUTH === 'true' +export function isUsingIAMAuth(credentialsProvider?: CredentialsProvider): boolean { + if (process.env.USE_IAM_AUTH === 'true') { + return true + } + + // CRITICAL: Add credential-based detection as fallback + if (credentialsProvider) { + try { + const iamCreds = credentialsProvider.getCredentials('iam') + const bearerCreds = credentialsProvider.getCredentials('bearer') + + // If only IAM creds available, use IAM + if (iamCreds && !(bearerCreds as any)?.token) { + return true + } + } catch (error) { + // If credential access fails, default to bearer + return false + } + } + return false } export const flattenMetric = (obj: any, prefix = '') => { From 62d48e50fa985b8cbcfd967283bfed3f8b1074a3 Mon Sep 17 00:00:00 2001 From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> Date: Tue, 9 Sep 2025 22:05:45 -0700 Subject: [PATCH 071/158] feat: upgrading node version from 18 to 24 (#2226) * feat: upgrade node version to 24 * fix: adding node 24 to overrides.json and using curl instead wget --- .../scripts/download-node.sh | 10 +++++----- attribution/overrides.json | 7 +++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/scripts/download-node.sh b/app/aws-lsp-codewhisperer-runtimes/scripts/download-node.sh index f0635fd8ff..44c3c1c462 100755 --- a/app/aws-lsp-codewhisperer-runtimes/scripts/download-node.sh +++ b/app/aws-lsp-codewhisperer-runtimes/scripts/download-node.sh @@ -5,13 +5,13 @@ # by src/scripts/copy-node-assets.ts, to produce the final bundle. set -e -NODE_VERSION="18" +NODE_VERSION="24" BASE_URL="https://nodejs.org/download/release/latest-v${NODE_VERSION}.x" SHASUMS_FILE="SHASUMS256.txt" ASSETS_DIR="build/node-assets" # Download SHASUMS256.txt -wget -q "$BASE_URL/$SHASUMS_FILE" -O "$SHASUMS_FILE" +curl -s "$BASE_URL/$SHASUMS_FILE" -o "$SHASUMS_FILE" # Extract exact Node.js version from any entry in SHASUMS256.txt NODE_SEMVER=$(grep -o 'node-v[0-9]*\.[0-9]*\.[0-9]*' SHASUMS256.txt | head -1 | cut -d'v' -f2) @@ -47,7 +47,7 @@ for actual_file in "${EXPECTED_FILES[@]}"; do echo "Updating $actual_file" mkdir -p "$(dirname "$filepath")" - wget -q "$BASE_URL/$actual_file" -O $filepath + curl -s "$BASE_URL/$actual_file" -o "$filepath" else echo "Warning: $actual_file not found in SHASUMS256.txt" fi @@ -58,7 +58,7 @@ LICENSE_URL="https://raw.githubusercontent.com/nodejs/node/v${NODE_SEMVER}/LICEN LICENSE_FILE="$ASSETS_DIR/LICENSE" echo "Fetching Node.js license from $LICENSE_URL" -wget -q "$LICENSE_URL" -O "$LICENSE_FILE" +curl -s "$LICENSE_URL" -o "$LICENSE_FILE" # Verify the license file was downloaded successfully if [ ! -s "$LICENSE_FILE" ]; then @@ -94,4 +94,4 @@ jq --indent 4 \ echo "Successfully updated Node.js version and license in $ATTRIBUTION_FILE" # Cleanup -rm -f "$SHASUMS_FILE" \ No newline at end of file +rm -f "$SHASUMS_FILE" diff --git a/attribution/overrides.json b/attribution/overrides.json index ed989c78d2..5f4222b4ad 100644 --- a/attribution/overrides.json +++ b/attribution/overrides.json @@ -11,5 +11,12 @@ }, "caniuse-lite": { "ignore": true + }, + "node": { + "name": "Node.js", + "version": "24.7.0", + "url": "https://github.com/nodejs/node", + "license": "MIT", + "licenseText": "Node.js is licensed for use as follows:\n\n\"\"\"\nCopyright Node.js contributors. All rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to\ndeal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or\nsell copies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n\"\"\"\n\nThis license applies to parts of Node.js originating from the\nhttps://github.com/joyent/node repository:\n\n\"\"\"\nCopyright Joyent, Inc. and other Node contributors. All rights reserved.\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to\ndeal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or\nsell copies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n\"\"\"\n\nThe Node.js license applies to all parts of Node.js that are not externally\nmaintained libraries.\n\nThe externally maintained libraries used by Node.js are:\n\n- Acorn, located at deps/acorn, is licensed as follows:\n \"\"\"\n MIT License\n\n Copyright (C) 2012-2022 by various contributors (see AUTHORS)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in\n all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n THE SOFTWARE.\n \"\"\"\n\n- c-ares, located at deps/cares, is licensed as follows:\n \"\"\"\n MIT License\n\n Copyright (c) 1998 Massachusetts Institute of Technology\n Copyright (c) 2007 - 2023 Daniel Stenberg with many contributors, see AUTHORS\n file.\n\n Permission is hereby granted, free of charge, to any person obtaining a copy of\n this software and associated documentation files (the \"Software\"), to deal in\n the Software without restriction, including without limitation the rights to\n use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\n the Software, and to permit persons to whom the Software is furnished to do so,\n subject to the following conditions:\n\n The above copyright notice and this permission notice (including the next\n paragraph) shall be included in all copies or substantial portions of the\n Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n \"\"\"\n\n- cjs-module-lexer, located at deps/cjs-module-lexer, is licensed as follows:\n \"\"\"\n MIT License\n -----------\n\n Copyright (C) 2018-2020 Guy Bedford\n\n Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- ittapi, located at deps/v8/third_party/ittapi, is licensed as follows:\n \"\"\"\n Copyright (c) 2019 Intel Corporation. All rights reserved.\n\n Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- amaro, located at deps/amaro, is licensed as follows:\n \"\"\"\n MIT License\n\n Copyright (c) Marco Ippolito and Amaro contributors\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n \"\"\"\n\n- swc, located at deps/amaro/dist, is licensed as follows:\n \"\"\"\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2024 SWC contributors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n \thttp://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n \"\"\"\n\n- ICU, located at deps/icu-small, is licensed as follows:\n \"\"\"\n UNICODE LICENSE V3\n\n COPYRIGHT AND PERMISSION NOTICE\n\n Copyright © 2016-2025 Unicode, Inc.\n\n NOTICE TO USER: Carefully read the following legal agreement. BY\n DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR\n SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE\n TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT\n DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.\n\n Permission is hereby granted, free of charge, to any person obtaining a\n copy of data files and any associated documentation (the \"Data Files\") or\n software and any associated documentation (the \"Software\") to deal in the\n Data Files or Software without restriction, including without limitation\n the rights to use, copy, modify, merge, publish, distribute, and/or sell\n copies of the Data Files or Software, and to permit persons to whom the\n Data Files or Software are furnished to do so, provided that either (a)\n this copyright and permission notice appear with all copies of the Data\n Files or Software, or (b) this copyright and permission notice appear in\n associated Documentation.\n\n THE DATA FILES AND SOFTWARE ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY\n KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF\n THIRD PARTY RIGHTS.\n\n IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE\n BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,\n OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\n WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\n ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA\n FILES OR SOFTWARE.\n\n Except as contained in this notice, the name of a copyright holder shall\n not be used in advertising or otherwise to promote the sale, use or other\n dealings in these Data Files or Software without prior written\n authorization of the copyright holder.\n\n SPDX-License-Identifier: Unicode-3.0\n\n ----------------------------------------------------------------------\n\n Third-Party Software Licenses\n\n This section contains third-party software notices and/or additional\n terms for licensed third-party software components included within ICU\n libraries.\n\n ----------------------------------------------------------------------\n\n ICU License - ICU 1.8.1 to ICU 57.1\n\n COPYRIGHT AND PERMISSION NOTICE\n\n Copyright (c) 1995-2016 International Business Machines Corporation and others\n All rights reserved.\n\n Permission is hereby granted, free of charge, to any person obtaining\n a copy of this software and associated documentation files (the\n \"Software\"), to deal in the Software without restriction, including\n without limitation the rights to use, copy, modify, merge, publish,\n distribute, and/or sell copies of the Software, and to permit persons\n to whom the Software is furnished to do so, provided that the above\n copyright notice(s) and this permission notice appear in all copies of\n the Software and that both the above copyright notice(s) and this\n permission notice appear in supporting documentation.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\n OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY\n SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER\n RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF\n CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN\n CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n Except as contained in this notice, the name of a copyright holder\n shall not be used in advertising or otherwise to promote the sale, use\n or other dealings in this Software without prior written authorization\n of the copyright holder.\n\n All trademarks and registered trademarks mentioned herein are the\n property of their respective owners.\n\n ----------------------------------------------------------------------\n\n Chinese/Japanese Word Break Dictionary Data (cjdict.txt)\n\n # The Google Chrome software developed by Google is licensed under\n # the BSD license. Other software included in this distribution is\n # provided under other licenses, as set forth below.\n #\n # The BSD License\n # http://opensource.org/licenses/bsd-license.php\n # Copyright (C) 2006-2008, Google Inc.\n #\n # All rights reserved.\n #\n # Redistribution and use in source and binary forms, with or without\n # modification, are permitted provided that the following conditions are met:\n #\n # Redistributions of source code must retain the above copyright notice,\n # this list of conditions and the following disclaimer.\n # Redistributions in binary form must reproduce the above\n # copyright notice, this list of conditions and the following\n # disclaimer in the documentation and/or other materials provided with\n # the distribution.\n # Neither the name of Google Inc. nor the names of its\n # contributors may be used to endorse or promote products derived from\n # this software without specific prior written permission.\n #\n #\n # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n # CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\n # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n #\n #\n # The word list in cjdict.txt are generated by combining three word lists\n # listed below with further processing for compound word breaking. The\n # frequency is generated with an iterative training against Google web\n # corpora.\n #\n # * Libtabe (Chinese)\n # - https://sourceforge.net/project/?group_id=1519\n # - Its license terms and conditions are shown below.\n #\n # * IPADIC (Japanese)\n # - http://chasen.aist-nara.ac.jp/chasen/distribution.html\n # - Its license terms and conditions are shown below.\n #\n # ---------COPYING.libtabe ---- BEGIN--------------------\n #\n # /*\n # * Copyright (c) 1999 TaBE Project.\n # * Copyright (c) 1999 Pai-Hsiang Hsiao.\n # * All rights reserved.\n # *\n # * Redistribution and use in source and binary forms, with or without\n # * modification, are permitted provided that the following conditions\n # * are met:\n # *\n # * . Redistributions of source code must retain the above copyright\n # * notice, this list of conditions and the following disclaimer.\n # * . Redistributions in binary form must reproduce the above copyright\n # * notice, this list of conditions and the following disclaimer in\n # * the documentation and/or other materials provided with the\n # * distribution.\n # * . Neither the name of the TaBE Project nor the names of its\n # * contributors may be used to endorse or promote products derived\n # * from this software without specific prior written permission.\n # *\n # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n # * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n # * OF THE POSSIBILITY OF SUCH DAMAGE.\n # */\n #\n # /*\n # * Copyright (c) 1999 Computer Systems and Communication Lab,\n # * Institute of Information Science, Academia\n # * Sinica. All rights reserved.\n # *\n # * Redistribution and use in source and binary forms, with or without\n # * modification, are permitted provided that the following conditions\n # * are met:\n # *\n # * . Redistributions of source code must retain the above copyright\n # * notice, this list of conditions and the following disclaimer.\n # * . Redistributions in binary form must reproduce the above copyright\n # * notice, this list of conditions and the following disclaimer in\n # * the documentation and/or other materials provided with the\n # * distribution.\n # * . Neither the name of the Computer Systems and Communication Lab\n # * nor the names of its contributors may be used to endorse or\n # * promote products derived from this software without specific\n # * prior written permission.\n # *\n # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n # * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n # * OF THE POSSIBILITY OF SUCH DAMAGE.\n # */\n #\n # Copyright 1996 Chih-Hao Tsai @ Beckman Institute,\n # University of Illinois\n # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4\n #\n # ---------------COPYING.libtabe-----END--------------------------------\n #\n #\n # ---------------COPYING.ipadic-----BEGIN-------------------------------\n #\n # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science\n # and Technology. All Rights Reserved.\n #\n # Use, reproduction, and distribution of this software is permitted.\n # Any copy of this software, whether in its original form or modified,\n # must include both the above copyright notice and the following\n # paragraphs.\n #\n # Nara Institute of Science and Technology (NAIST),\n # the copyright holders, disclaims all warranties with regard to this\n # software, including all implied warranties of merchantability and\n # fitness, in no event shall NAIST be liable for\n # any special, indirect or consequential damages or any damages\n # whatsoever resulting from loss of use, data or profits, whether in an\n # action of contract, negligence or other tortuous action, arising out\n # of or in connection with the use or performance of this software.\n #\n # A large portion of the dictionary entries\n # originate from ICOT Free Software. The following conditions for ICOT\n # Free Software applies to the current dictionary as well.\n #\n # Each User may also freely distribute the Program, whether in its\n # original form or modified, to any third party or parties, PROVIDED\n # that the provisions of Section 3 (\"NO WARRANTY\") will ALWAYS appear\n # on, or be attached to, the Program, which is distributed substantially\n # in the same form as set out herein and that such intended\n # distribution, if actually made, will neither violate or otherwise\n # contravene any of the laws and regulations of the countries having\n # jurisdiction over the User or the intended distribution itself.\n #\n # NO WARRANTY\n #\n # The program was produced on an experimental basis in the course of the\n # research and development conducted during the project and is provided\n # to users as so produced on an experimental basis. Accordingly, the\n # program is provided without any warranty whatsoever, whether express,\n # implied, statutory or otherwise. The term \"warranty\" used herein\n # includes, but is not limited to, any warranty of the quality,\n # performance, merchantability and fitness for a particular purpose of\n # the program and the nonexistence of any infringement or violation of\n # any right of any third party.\n #\n # Each user of the program will agree and understand, and be deemed to\n # have agreed and understood, that there is no warranty whatsoever for\n # the program and, accordingly, the entire risk arising from or\n # otherwise connected with the program is assumed by the user.\n #\n # Therefore, neither ICOT, the copyright holder, or any other\n # organization that participated in or was otherwise related to the\n # development of the program and their respective officials, directors,\n # officers and other employees shall be held liable for any and all\n # damages, including, without limitation, general, special, incidental\n # and consequential damages, arising out of or otherwise in connection\n # with the use or inability to use the program or any product, material\n # or result produced or otherwise obtained by using the program,\n # regardless of whether they have been advised of, or otherwise had\n # knowledge of, the possibility of such damages at any time during the\n # project or thereafter. Each user will be deemed to have agreed to the\n # foregoing by his or her commencement of use of the program. The term\n # \"use\" as used herein includes, but is not limited to, the use,\n # modification, copying and distribution of the program and the\n # production of secondary products from the program.\n #\n # In the case where the program, whether in its original form or\n # modified, was distributed or delivered to or received by a user from\n # any person, organization or entity other than ICOT, unless it makes or\n # grants independently of ICOT any specific warranty to the user in\n # writing, such person, organization or entity, will also be exempted\n # from and not be held liable to the user for any such damages as noted\n # above as far as the program is concerned.\n #\n # ---------------COPYING.ipadic-----END----------------------------------\n\n ----------------------------------------------------------------------\n\n Lao Word Break Dictionary Data (laodict.txt)\n\n # Copyright (C) 2016 and later: Unicode, Inc. and others.\n # License & terms of use: http://www.unicode.org/copyright.html\n # Copyright (c) 2015 International Business Machines Corporation\n # and others. All Rights Reserved.\n #\n # Project: https://github.com/rober42539/lao-dictionary\n # Dictionary: https://github.com/rober42539/lao-dictionary/laodict.txt\n # License: https://github.com/rober42539/lao-dictionary/LICENSE.txt\n # (copied below)\n #\n # This file is derived from the above dictionary version of Nov 22, 2020\n # ----------------------------------------------------------------------\n # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell.\n # All rights reserved.\n #\n # Redistribution and use in source and binary forms, with or without\n # modification, are permitted provided that the following conditions are met:\n #\n # Redistributions of source code must retain the above copyright notice, this\n # list of conditions and the following disclaimer. Redistributions in binary\n # form must reproduce the above copyright notice, this list of conditions and\n # the following disclaimer in the documentation and/or other materials\n # provided with the distribution.\n #\n # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n # \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n # OF THE POSSIBILITY OF SUCH DAMAGE.\n # --------------------------------------------------------------------------\n\n ----------------------------------------------------------------------\n\n Burmese Word Break Dictionary Data (burmesedict.txt)\n\n # Copyright (c) 2014 International Business Machines Corporation\n # and others. All Rights Reserved.\n #\n # This list is part of a project hosted at:\n # github.com/kanyawtech/myanmar-karen-word-lists\n #\n # --------------------------------------------------------------------------\n # Copyright (c) 2013, LeRoy Benjamin Sharon\n # All rights reserved.\n #\n # Redistribution and use in source and binary forms, with or without\n # modification, are permitted provided that the following conditions\n # are met: Redistributions of source code must retain the above\n # copyright notice, this list of conditions and the following\n # disclaimer. Redistributions in binary form must reproduce the\n # above copyright notice, this list of conditions and the following\n # disclaimer in the documentation and/or other materials provided\n # with the distribution.\n #\n # Neither the name Myanmar Karen Word Lists, nor the names of its\n # contributors may be used to endorse or promote products derived\n # from this software without specific prior written permission.\n #\n # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n # CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS\n # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\n # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR\n # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF\n # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n # SUCH DAMAGE.\n # --------------------------------------------------------------------------\n\n ----------------------------------------------------------------------\n\n Time Zone Database\n\n ICU uses the public domain data and code derived from Time Zone\n Database for its time zone support. The ownership of the TZ database\n is explained in BCP 175: Procedure for Maintaining the Time Zone\n Database section 7.\n\n # 7. Database Ownership\n #\n # The TZ database itself is not an IETF Contribution or an IETF\n # document. Rather it is a pre-existing and regularly updated work\n # that is in the public domain, and is intended to remain in the\n # public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do\n # not apply to the TZ Database or contributions that individuals make\n # to it. Should any claims be made and substantiated against the TZ\n # Database, the organization that is providing the IANA\n # Considerations defined in this RFC, under the memorandum of\n # understanding with the IETF, currently ICANN, may act in accordance\n # with all competent court orders. No ownership claims will be made\n # by ICANN or the IETF Trust on the database or the code. Any person\n # making a contribution to the database or code waives all rights to\n # future claims in that contribution or in the TZ Database.\n\n ----------------------------------------------------------------------\n\n Google double-conversion\n\n Copyright 2006-2011, the V8 project authors. All rights reserved.\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following\n disclaimer in the documentation and/or other materials provided\n with the distribution.\n * Neither the name of Google Inc. nor the names of its\n contributors may be used to endorse or promote products derived\n from this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n ----------------------------------------------------------------------\n\n JSON parsing library (nlohmann/json)\n\n File: vendor/json/upstream/single_include/nlohmann/json.hpp (only for ICU4C)\n\n MIT License\n\n Copyright (c) 2013-2022 Niels Lohmann\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n\n ----------------------------------------------------------------------\n\n File: aclocal.m4 (only for ICU4C)\n Section: pkg.m4 - Macros to locate and utilise pkg-config.\n\n Copyright © 2004 Scott James Remnant .\n Copyright © 2012-2015 Dan Nicholson\n\n This program is free software; you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation; either version 2 of the License, or\n (at your option) any later version.\n\n This program is distributed in the hope that it will be useful, but\n WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n General Public License for more details.\n\n You should have received a copy of the GNU General Public License\n along with this program; if not, write to the Free Software\n Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\n 02111-1307, USA.\n\n As a special exception to the GNU General Public License, if you\n distribute this file as part of a program that contains a\n configuration script generated by Autoconf, you may include it under\n the same distribution terms that you use for the rest of that\n program.\n\n (The condition for the exception is fulfilled because\n ICU4C includes a configuration script generated by Autoconf,\n namely the `configure` script.)\n\n ----------------------------------------------------------------------\n\n File: config.guess (only for ICU4C)\n\n This file is free software; you can redistribute it and/or modify it\n under the terms of the GNU General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n This program is distributed in the hope that it will be useful, but\n WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n General Public License for more details.\n\n You should have received a copy of the GNU General Public License\n along with this program; if not, see .\n\n As a special exception to the GNU General Public License, if you\n distribute this file as part of a program that contains a\n configuration script generated by Autoconf, you may include it under\n the same distribution terms that you use for the rest of that\n program. This Exception is an additional permission under section 7\n of the GNU General Public License, version 3 (\"GPLv3\").\n\n (The condition for the exception is fulfilled because\n ICU4C includes a configuration script generated by Autoconf,\n namely the `configure` script.)\n\n ----------------------------------------------------------------------\n\n File: install-sh (only for ICU4C)\n\n Copyright 1991 by the Massachusetts Institute of Technology\n\n Permission to use, copy, modify, distribute, and sell this software and its\n documentation for any purpose is hereby granted without fee, provided that\n the above copyright notice appear in all copies and that both that\n copyright notice and this permission notice appear in supporting\n documentation, and that the name of M.I.T. not be used in advertising or\n publicity pertaining to distribution of the software without specific,\n written prior permission. M.I.T. makes no representations about the\n suitability of this software for any purpose. It is provided \"as is\"\n without express or implied warranty.\n \"\"\"\n\n- libuv, located at deps/uv, is licensed as follows:\n \"\"\"\n Copyright (c) 2015-present libuv project contributors.\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to\n deal in the Software without restriction, including without limitation the\n rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n sell copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in\n all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n IN THE SOFTWARE.\n This license applies to parts of libuv originating from the\n https://github.com/joyent/libuv repository:\n\n ====\n\n Copyright Joyent, Inc. and other Node contributors. All rights reserved.\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to\n deal in the Software without restriction, including without limitation the\n rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n sell copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in\n all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n IN THE SOFTWARE.\n\n ====\n\n This license applies to all parts of libuv that are not externally\n maintained libraries.\n\n The externally maintained libraries used by libuv are:\n\n - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license.\n\n - inet_pton and inet_ntop implementations, contained in src/inet.c, are\n copyright the Internet Systems Consortium, Inc., and licensed under the ISC\n license.\n \"\"\"\n\n- llhttp, located at deps/llhttp, is licensed as follows:\n \"\"\"\n This software is licensed under the MIT License.\n\n Copyright Fedor Indutny, 2018.\n\n Permission is hereby granted, free of charge, to any person obtaining a\n copy of this software and associated documentation files (the\n \"Software\"), to deal in the Software without restriction, including\n without limitation the rights to use, copy, modify, merge, publish,\n distribute, sublicense, and/or sell copies of the Software, and to permit\n persons to whom the Software is furnished to do so, subject to the\n following conditions:\n\n The above copyright notice and this permission notice shall be included\n in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- corepack, located at deps/corepack, is licensed as follows:\n \"\"\"\n **Copyright © Corepack contributors**\n\n Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- undici, located at deps/undici, is licensed as follows:\n \"\"\"\n MIT License\n\n Copyright (c) Matteo Collina and Undici contributors\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n \"\"\"\n\n- postject, located at test/fixtures/postject-copy, is licensed as follows:\n \"\"\"\n Postject is licensed for use as follows:\n\n \"\"\"\n MIT License\n\n Copyright (c) 2022 Postman, Inc\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n \"\"\"\n\n The Postject license applies to all parts of Postject that are not externally\n maintained libraries.\n\n The externally maintained libraries used by Postject are:\n\n - LIEF, located at vendor/LIEF, is licensed as follows:\n \"\"\"\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2017 - 2022 R. Thomas\n Copyright 2017 - 2022 Quarkslab\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n \"\"\"\n \"\"\"\n\n- OpenSSL, located at deps/openssl, is licensed as follows:\n \"\"\"\n Apache License\n Version 2.0, January 2004\n https://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n \"\"\"\n\n- Punycode.js, located at lib/punycode.js, is licensed as follows:\n \"\"\"\n Copyright Mathias Bynens \n\n Permission is hereby granted, free of charge, to any person obtaining\n a copy of this software and associated documentation files (the\n \"Software\"), to deal in the Software without restriction, including\n without limitation the rights to use, copy, modify, merge, publish,\n distribute, sublicense, and/or sell copies of the Software, and to\n permit persons to whom the Software is furnished to do so, subject to\n the following conditions:\n\n The above copyright notice and this permission notice shall be\n included in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- V8, located at deps/v8, is licensed as follows:\n \"\"\"\n This license applies to all parts of V8 that are not externally\n maintained libraries. The externally maintained libraries used by V8\n are:\n\n - PCRE test suite, located in\n test/mjsunit/third_party/regexp-pcre/regexp-pcre.js. This is based on the\n test suite from PCRE-7.3, which is copyrighted by the University\n of Cambridge and Google, Inc. The copyright notice and license\n are embedded in regexp-pcre.js.\n\n - Layout tests, located in test/mjsunit/third_party/object-keys. These are\n based on layout tests from webkit.org which are copyrighted by\n Apple Computer, Inc. and released under a 3-clause BSD license.\n\n - Strongtalk assembler, the basis of the files assembler-arm-inl.h,\n assembler-arm.cc, assembler-arm.h, assembler-ia32-inl.h,\n assembler-ia32.cc, assembler-ia32.h, assembler-x64-inl.h,\n assembler-x64.cc, assembler-x64.h, assembler.cc and assembler.h.\n This code is copyrighted by Sun Microsystems Inc. and released\n under a 3-clause BSD license.\n\n - Valgrind client API header, located at third_party/valgrind/valgrind.h\n This is released under the BSD license.\n\n - The Wasm C/C++ API headers, located at third_party/wasm-api/wasm.{h,hh}\n This is released under the Apache license. The API's upstream prototype\n implementation also formed the basis of V8's implementation in\n src/wasm/c-api.cc.\n\n These libraries have their own licenses; we recommend you read them,\n as their terms may differ from the terms below.\n\n Further license information can be found in LICENSE files located in\n sub-directories.\n\n Copyright 2014, the V8 project authors. All rights reserved.\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following\n disclaimer in the documentation and/or other materials provided\n with the distribution.\n * Neither the name of Google Inc. nor the names of its\n contributors may be used to endorse or promote products derived\n from this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- SipHash, located at deps/v8/src/third_party/siphash, is licensed as follows:\n \"\"\"\n SipHash reference C implementation\n\n Copyright (c) 2016 Jean-Philippe Aumasson \n\n To the extent possible under law, the author(s) have dedicated all\n copyright and related and neighboring rights to this software to the public\n domain worldwide. This software is distributed without any warranty.\n \"\"\"\n\n- zlib, located at deps/zlib, is licensed as follows:\n \"\"\"\n zlib.h -- interface of the 'zlib' general purpose compression library\n version 1.3.1, January 22nd, 2024\n\n Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler\n\n This software is provided 'as-is', without any express or implied\n warranty. In no event will the authors be held liable for any damages\n arising from the use of this software.\n\n Permission is granted to anyone to use this software for any purpose,\n including commercial applications, and to alter it and redistribute it\n freely, subject to the following restrictions:\n\n 1. The origin of this software must not be misrepresented; you must not\n claim that you wrote the original software. If you use this software\n in a product, an acknowledgment in the product documentation would be\n appreciated but is not required.\n 2. Altered source versions must be plainly marked as such, and must not be\n misrepresented as being the original software.\n 3. This notice may not be removed or altered from any source distribution.\n\n Jean-loup Gailly Mark Adler\n jloup@gzip.org madler@alumni.caltech.edu\n \"\"\"\n\n- simdjson, located at deps/simdjson, is licensed as follows:\n \"\"\"\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2018-2025 The simdjson authors\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n \"\"\"\n\n- simdutf, located at deps/v8/third_party/simdutf, is licensed as follows:\n \"\"\"\n Copyright 2021 The simdutf authors\n\n Permission is hereby granted, free of charge, to any person obtaining a copy of\n this software and associated documentation files (the \"Software\"), to deal in\n the Software without restriction, including without limitation the rights to\n use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\n the Software, and to permit persons to whom the Software is furnished to do so,\n subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- ada, located at deps/ada, is licensed as follows:\n \"\"\"\n Copyright 2023 Yagiz Nizipli and Daniel Lemire\n\n Permission is hereby granted, free of charge, to any person obtaining a copy of\n this software and associated documentation files (the \"Software\"), to deal in\n the Software without restriction, including without limitation the rights to\n use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\n the Software, and to permit persons to whom the Software is furnished to do so,\n subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- minimatch, located at deps/minimatch, is licensed as follows:\n \"\"\"\n The ISC License\n\n Copyright (c) 2011-2023 Isaac Z. Schlueter and Contributors\n\n Permission to use, copy, modify, and/or distribute this software for any\n purpose with or without fee is hereby granted, provided that the above\n copyright notice and this permission notice appear in all copies.\n\n THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR\n IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n \"\"\"\n\n- npm, located at deps/npm, is licensed as follows:\n \"\"\"\n The npm application\n Copyright (c) npm, Inc. and Contributors\n Licensed on the terms of The Artistic License 2.0\n\n Node package dependencies of the npm application\n Copyright (c) their respective copyright owners\n Licensed on their respective license terms\n\n The npm public registry at https://registry.npmjs.org\n and the npm website at https://www.npmjs.com\n Operated by npm, Inc.\n Use governed by terms published on https://www.npmjs.com\n\n \"Node.js\"\n Trademark Joyent, Inc., https://joyent.com\n Neither npm nor npm, Inc. are affiliated with Joyent, Inc.\n\n The Node.js application\n Project of Node Foundation, https://nodejs.org\n\n The npm Logo\n Copyright (c) Mathias Pettersson and Brian Hammond\n\n \"Gubblebum Blocky\" typeface\n Copyright (c) Tjarda Koster, https://jelloween.deviantart.com\n Used with permission\n\n --------\n\n The Artistic License 2.0\n\n Copyright (c) 2000-2006, The Perl Foundation.\n\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n Preamble\n\n This license establishes the terms under which a given free software\n Package may be copied, modified, distributed, and/or redistributed.\n The intent is that the Copyright Holder maintains some artistic\n control over the development of that Package while still keeping the\n Package available as open source and free software.\n\n You are always permitted to make arrangements wholly outside of this\n license directly with the Copyright Holder of a given Package. If the\n terms of this license do not permit the full use that you propose to\n make of the Package, you should contact the Copyright Holder and seek\n a different licensing arrangement.\n\n Definitions\n\n \"Copyright Holder\" means the individual(s) or organization(s)\n named in the copyright notice for the entire Package.\n\n \"Contributor\" means any party that has contributed code or other\n material to the Package, in accordance with the Copyright Holder's\n procedures.\n\n \"You\" and \"your\" means any person who would like to copy,\n distribute, or modify the Package.\n\n \"Package\" means the collection of files distributed by the\n Copyright Holder, and derivatives of that collection and/or of\n those files. A given Package may consist of either the Standard\n Version, or a Modified Version.\n\n \"Distribute\" means providing a copy of the Package or making it\n accessible to anyone else, or in the case of a company or\n organization, to others outside of your company or organization.\n\n \"Distributor Fee\" means any fee that you charge for Distributing\n this Package or providing support for this Package to another\n party. It does not mean licensing fees.\n\n \"Standard Version\" refers to the Package if it has not been\n modified, or has been modified only in ways explicitly requested\n by the Copyright Holder.\n\n \"Modified Version\" means the Package, if it has been changed, and\n such changes were not explicitly requested by the Copyright\n Holder.\n\n \"Original License\" means this Artistic License as Distributed with\n the Standard Version of the Package, in its current version or as\n it may be modified by The Perl Foundation in the future.\n\n \"Source\" form means the source code, documentation source, and\n configuration files for the Package.\n\n \"Compiled\" form means the compiled bytecode, object code, binary,\n or any other form resulting from mechanical transformation or\n translation of the Source form.\n\n Permission for Use and Modification Without Distribution\n\n (1) You are permitted to use the Standard Version and create and use\n Modified Versions for any purpose without restriction, provided that\n you do not Distribute the Modified Version.\n\n Permissions for Redistribution of the Standard Version\n\n (2) You may Distribute verbatim copies of the Source form of the\n Standard Version of this Package in any medium without restriction,\n either gratis or for a Distributor Fee, provided that you duplicate\n all of the original copyright notices and associated disclaimers. At\n your discretion, such verbatim copies may or may not include a\n Compiled form of the Package.\n\n (3) You may apply any bug fixes, portability changes, and other\n modifications made available from the Copyright Holder. The resulting\n Package will still be considered the Standard Version, and as such\n will be subject to the Original License.\n\n Distribution of Modified Versions of the Package as Source\n\n (4) You may Distribute your Modified Version as Source (either gratis\n or for a Distributor Fee, and with or without a Compiled form of the\n Modified Version) provided that you clearly document how it differs\n from the Standard Version, including, but not limited to, documenting\n any non-standard features, executables, or modules, and provided that\n you do at least ONE of the following:\n\n (a) make the Modified Version available to the Copyright Holder\n of the Standard Version, under the Original License, so that the\n Copyright Holder may include your modifications in the Standard\n Version.\n\n (b) ensure that installation of your Modified Version does not\n prevent the user installing or running the Standard Version. In\n addition, the Modified Version must bear a name that is different\n from the name of the Standard Version.\n\n (c) allow anyone who receives a copy of the Modified Version to\n make the Source form of the Modified Version available to others\n under\n\n (i) the Original License or\n\n (ii) a license that permits the licensee to freely copy,\n modify and redistribute the Modified Version using the same\n licensing terms that apply to the copy that the licensee\n received, and requires that the Source form of the Modified\n Version, and of any works derived from it, be made freely\n available in that license fees are prohibited but Distributor\n Fees are allowed.\n\n Distribution of Compiled Forms of the Standard Version\n or Modified Versions without the Source\n\n (5) You may Distribute Compiled forms of the Standard Version without\n the Source, provided that you include complete instructions on how to\n get the Source of the Standard Version. Such instructions must be\n valid at the time of your distribution. If these instructions, at any\n time while you are carrying out such distribution, become invalid, you\n must provide new instructions on demand or cease further distribution.\n If you provide valid instructions or cease distribution within thirty\n days after you become aware that the instructions are invalid, then\n you do not forfeit any of your rights under this license.\n\n (6) You may Distribute a Modified Version in Compiled form without\n the Source, provided that you comply with Section 4 with respect to\n the Source of the Modified Version.\n\n Aggregating or Linking the Package\n\n (7) You may aggregate the Package (either the Standard Version or\n Modified Version) with other packages and Distribute the resulting\n aggregation provided that you do not charge a licensing fee for the\n Package. Distributor Fees are permitted, and licensing fees for other\n components in the aggregation are permitted. The terms of this license\n apply to the use and Distribution of the Standard or Modified Versions\n as included in the aggregation.\n\n (8) You are permitted to link Modified and Standard Versions with\n other works, to embed the Package in a larger work of your own, or to\n build stand-alone binary or bytecode versions of applications that\n include the Package, and Distribute the result without restriction,\n provided the result does not expose a direct interface to the Package.\n\n Items That are Not Considered Part of a Modified Version\n\n (9) Works (including, but not limited to, modules and scripts) that\n merely extend or make use of the Package, do not, by themselves, cause\n the Package to be a Modified Version. In addition, such works are not\n considered parts of the Package itself, and are not subject to the\n terms of this license.\n\n General Provisions\n\n (10) Any use, modification, and distribution of the Standard or\n Modified Versions is governed by this Artistic License. By using,\n modifying or distributing the Package, you accept this license. Do not\n use, modify, or distribute the Package, if you do not accept this\n license.\n\n (11) If your Modified Version has been derived from a Modified\n Version made by someone other than you, you are nevertheless required\n to ensure that your Modified Version complies with the requirements of\n this license.\n\n (12) This license does not grant you the right to use any trademark,\n service mark, tradename, or logo of the Copyright Holder.\n\n (13) This license includes the non-exclusive, worldwide,\n free-of-charge patent license to make, have made, use, offer to sell,\n sell, import and otherwise transfer the Package with respect to any\n patent claims licensable by the Copyright Holder that are necessarily\n infringed by the Package. If you institute patent litigation\n (including a cross-claim or counterclaim) against any party alleging\n that the Package constitutes direct or contributory patent\n infringement, then this Artistic License to you shall terminate on the\n date that such litigation is filed.\n\n (14) Disclaimer of Warranty:\n THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS \"AS\n IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED\n WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR\n NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL\n LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL\n BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\n DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF\n ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n --------\n \"\"\"\n\n- GYP, located at tools/gyp, is licensed as follows:\n \"\"\"\n Copyright (c) 2020 Node.js contributors. All rights reserved.\n Copyright (c) 2009 Google Inc. All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following disclaimer\n in the documentation and/or other materials provided with the\n distribution.\n * Neither the name of Google Inc. nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- inspector_protocol, located at deps/inspector_protocol, is licensed as follows:\n \"\"\"\n // Copyright 2016 The Chromium Authors.\n //\n // Redistribution and use in source and binary forms, with or without\n // modification, are permitted provided that the following conditions are\n // met:\n //\n // * Redistributions of source code must retain the above copyright\n // notice, this list of conditions and the following disclaimer.\n // * Redistributions in binary form must reproduce the above\n // copyright notice, this list of conditions and the following disclaimer\n // in the documentation and/or other materials provided with the\n // distribution.\n // * Neither the name of Google Inc. nor the names of its\n // contributors may be used to endorse or promote products derived from\n // this software without specific prior written permission.\n //\n // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n // \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- jinja2, located at tools/inspector_protocol/jinja2, is licensed as follows:\n \"\"\"\n Copyright (c) 2009 by the Jinja Team, see AUTHORS for more details.\n\n Some rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following\n disclaimer in the documentation and/or other materials provided\n with the distribution.\n\n * The names of the contributors may not be used to endorse or\n promote products derived from this software without specific\n prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- markupsafe, located at tools/inspector_protocol/markupsafe, is licensed as follows:\n \"\"\"\n Copyright (c) 2010 by Armin Ronacher and contributors. See AUTHORS\n for more details.\n\n Some rights reserved.\n\n Redistribution and use in source and binary forms of the software as well\n as documentation, with or without modification, are permitted provided\n that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following\n disclaimer in the documentation and/or other materials provided\n with the distribution.\n\n * The names of the contributors may not be used to endorse or\n promote products derived from this software without specific\n prior written permission.\n\n THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT\n NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER\n OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n DAMAGE.\n \"\"\"\n\n- cpplint.py, located at tools/cpplint.py, is licensed as follows:\n \"\"\"\n Copyright (c) 2009 Google Inc. All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following disclaimer\n in the documentation and/or other materials provided with the\n distribution.\n * Neither the name of Google Inc. nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- gypi_to_gn.py, located at tools/gypi_to_gn.py, is licensed as follows:\n \"\"\"\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following disclaimer\n in the documentation and/or other materials provided with the\n distribution.\n * Neither the name of Google LLC nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- gtest, located at deps/googletest, is licensed as follows:\n \"\"\"\n Copyright 2008, Google Inc.\n All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following disclaimer\n in the documentation and/or other materials provided with the\n distribution.\n * Neither the name of Google Inc. nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- nghttp2, located at deps/nghttp2, is licensed as follows:\n \"\"\"\n The MIT License\n\n Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa\n Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors\n\n Permission is hereby granted, free of charge, to any person obtaining\n a copy of this software and associated documentation files (the\n \"Software\"), to deal in the Software without restriction, including\n without limitation the rights to use, copy, modify, merge, publish,\n distribute, sublicense, and/or sell copies of the Software, and to\n permit persons to whom the Software is furnished to do so, subject to\n the following conditions:\n\n The above copyright notice and this permission notice shall be\n included in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- large_pages, located at src/large_pages, is licensed as follows:\n \"\"\"\n Copyright (C) 2018 Intel Corporation\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"),\n to deal in the Software without restriction, including without limitation\n the rights to use, copy, modify, merge, publish, distribute, sublicense,\n and/or sell copies of the Software, and to permit persons to whom\n the Software is furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included\n in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES\n OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE\n OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- caja, located at lib/internal/freeze_intrinsics.js, is licensed as follows:\n \"\"\"\n Adapted from SES/Caja - Copyright (C) 2011 Google Inc.\n Copyright (C) 2018 Agoric\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n \"\"\"\n\n- brotli, located at deps/brotli, is licensed as follows:\n \"\"\"\n Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in\n all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n THE SOFTWARE.\n \"\"\"\n\n- zstd, located at deps/zstd, is licensed as follows:\n \"\"\"\n BSD License\n\n For Zstandard software\n\n Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved.\n\n Redistribution and use in source and binary forms, with or without modification,\n are permitted provided that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n * Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n * Neither the name Facebook, nor Meta, nor the names of its contributors may\n be used to endorse or promote products derived from this software without\n specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\n ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\n ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- HdrHistogram, located at deps/histogram, is licensed as follows:\n \"\"\"\n The code in this repository code was Written by Gil Tene, Michael Barker,\n and Matt Warren, and released to the public domain, as explained at\n http://creativecommons.org/publicdomain/zero/1.0/\n\n For users of this code who wish to consume it under the \"BSD\" license\n rather than under the public domain or CC0 contribution text mentioned\n above, the code found under this directory is *also* provided under the\n following license (commonly referred to as the BSD 2-Clause License). This\n license does not detract from the above stated release of the code into\n the public domain, and simply represents an additional license granted by\n the Author.\n\n -----------------------------------------------------------------------------\n ** Beginning of \"BSD 2-Clause License\" text. **\n\n Copyright (c) 2012, 2013, 2014 Gil Tene\n Copyright (c) 2014 Michael Barker\n Copyright (c) 2014 Matt Warren\n All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice,\n this list of conditions and the following disclaimer.\n\n 2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- node-heapdump, located at src/heap_utils.cc, is licensed as follows:\n \"\"\"\n ISC License\n\n Copyright (c) 2012, Ben Noordhuis \n\n Permission to use, copy, modify, and/or distribute this software for any\n purpose with or without fee is hereby granted, provided that the above\n copyright notice and this permission notice appear in all copies.\n\n THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n === src/compat.h src/compat-inl.h ===\n\n ISC License\n\n Copyright (c) 2014, StrongLoop Inc.\n\n Permission to use, copy, modify, and/or distribute this software for any\n purpose with or without fee is hereby granted, provided that the above\n copyright notice and this permission notice appear in all copies.\n\n THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n \"\"\"\n\n- rimraf, located at lib/internal/fs/rimraf.js, is licensed as follows:\n \"\"\"\n The ISC License\n\n Copyright (c) Isaac Z. Schlueter and Contributors\n\n Permission to use, copy, modify, and/or distribute this software for any\n purpose with or without fee is hereby granted, provided that the above\n copyright notice and this permission notice appear in all copies.\n\n THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR\n IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n \"\"\"\n\n- uvwasi, located at deps/uvwasi, is licensed as follows:\n \"\"\"\n MIT License\n\n Copyright (c) 2019 Colin Ihrig and Contributors\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n \"\"\"\n\n- ngtcp2, located at deps/ngtcp2/ngtcp2/, is licensed as follows:\n \"\"\"\n The MIT License\n\n Copyright (c) 2016 ngtcp2 contributors\n\n Permission is hereby granted, free of charge, to any person obtaining\n a copy of this software and associated documentation files (the\n \"Software\"), to deal in the Software without restriction, including\n without limitation the rights to use, copy, modify, merge, publish,\n distribute, sublicense, and/or sell copies of the Software, and to\n permit persons to whom the Software is furnished to do so, subject to\n the following conditions:\n\n The above copyright notice and this permission notice shall be\n included in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- nghttp3, located at deps/ngtcp2/nghttp3/, is licensed as follows:\n \"\"\"\n The MIT License\n\n Copyright (c) 2019 nghttp3 contributors\n\n Permission is hereby granted, free of charge, to any person obtaining\n a copy of this software and associated documentation files (the\n \"Software\"), to deal in the Software without restriction, including\n without limitation the rights to use, copy, modify, merge, publish,\n distribute, sublicense, and/or sell copies of the Software, and to\n permit persons to whom the Software is furnished to do so, subject to\n the following conditions:\n\n The above copyright notice and this permission notice shall be\n included in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- node-fs-extra, located at lib/internal/fs/cp, is licensed as follows:\n \"\"\"\n (The MIT License)\n\n Copyright (c) 2011-2017 JP Richardson\n\n Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files\n (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,\n merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\n OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- on-exit-leak-free, located at lib/internal/process/finalization, is licensed as follows:\n \"\"\"\n MIT License\n\n Copyright (c) 2021 Matteo Collina\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n \"\"\"\n\n- sonic-boom, located at lib/internal/streams/fast-utf8-stream.js, is licensed as follows:\n \"\"\"\n MIT License\n\n Copyright (c) 2017 Matteo Collina\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n \"\"\"" } } From 49a4c756bddc9766155f9ebfac03355df974a8f6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 10 Sep 2025 10:32:37 -0700 Subject: [PATCH 072/158] chore(release): release packages from branch main (#2225) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- package-lock.json | 2 +- server/aws-lsp-codewhisperer/CHANGELOG.md | 7 +++++++ server/aws-lsp-codewhisperer/package.json | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 725a9c6b27..2cc2cea923 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -2,7 +2,7 @@ "chat-client": "0.1.35", "core/aws-lsp-core": "0.0.15", "server/aws-lsp-antlr4": "0.1.19", - "server/aws-lsp-codewhisperer": "0.0.78", + "server/aws-lsp-codewhisperer": "0.0.79", "server/aws-lsp-json": "0.1.19", "server/aws-lsp-partiql": "0.0.18", "server/aws-lsp-yaml": "0.1.19" diff --git a/package-lock.json b/package-lock.json index 4365c453a2..838f0c5fc1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28677,7 +28677,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.78", + "version": "0.0.79", "bundleDependencies": [ "@amzn/codewhisperer-streaming", "@amzn/amazon-q-developer-streaming-client" diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index 67d05de3c1..57a411ce81 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.0.79](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.78...lsp-codewhisperer/v0.0.79) (2025-09-10) + + +### Features + +* feature to add iam inline suggestion support in codeWhispererservice ([#2223](https://github.com/aws/language-servers/issues/2223)) ([8e19f19](https://github.com/aws/language-servers/commit/8e19f19a71e63a1196f4cb67ded8360c8da8129e)) + ## [0.0.78](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.77...lsp-codewhisperer/v0.0.78) (2025-09-09) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 3fb2f48e69..0b03332380 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.78", + "version": "0.0.79", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { From 2c50e6b85a5cb0f90d8e4ab4630424c09e1fb6b0 Mon Sep 17 00:00:00 2001 From: Richard Li <742829+rli@users.noreply.github.com> Date: Wed, 10 Sep 2025 17:21:15 -0700 Subject: [PATCH 073/158] build: remove node attribution from attribution/overrides.json (#2236) This is updated automatically by the build scripts --- attribution/overrides.json | 7 ------- 1 file changed, 7 deletions(-) diff --git a/attribution/overrides.json b/attribution/overrides.json index 5f4222b4ad..ed989c78d2 100644 --- a/attribution/overrides.json +++ b/attribution/overrides.json @@ -11,12 +11,5 @@ }, "caniuse-lite": { "ignore": true - }, - "node": { - "name": "Node.js", - "version": "24.7.0", - "url": "https://github.com/nodejs/node", - "license": "MIT", - "licenseText": "Node.js is licensed for use as follows:\n\n\"\"\"\nCopyright Node.js contributors. All rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to\ndeal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or\nsell copies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n\"\"\"\n\nThis license applies to parts of Node.js originating from the\nhttps://github.com/joyent/node repository:\n\n\"\"\"\nCopyright Joyent, Inc. and other Node contributors. All rights reserved.\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to\ndeal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or\nsell copies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE.\n\"\"\"\n\nThe Node.js license applies to all parts of Node.js that are not externally\nmaintained libraries.\n\nThe externally maintained libraries used by Node.js are:\n\n- Acorn, located at deps/acorn, is licensed as follows:\n \"\"\"\n MIT License\n\n Copyright (C) 2012-2022 by various contributors (see AUTHORS)\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in\n all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n THE SOFTWARE.\n \"\"\"\n\n- c-ares, located at deps/cares, is licensed as follows:\n \"\"\"\n MIT License\n\n Copyright (c) 1998 Massachusetts Institute of Technology\n Copyright (c) 2007 - 2023 Daniel Stenberg with many contributors, see AUTHORS\n file.\n\n Permission is hereby granted, free of charge, to any person obtaining a copy of\n this software and associated documentation files (the \"Software\"), to deal in\n the Software without restriction, including without limitation the rights to\n use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\n the Software, and to permit persons to whom the Software is furnished to do so,\n subject to the following conditions:\n\n The above copyright notice and this permission notice (including the next\n paragraph) shall be included in all copies or substantial portions of the\n Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n \"\"\"\n\n- cjs-module-lexer, located at deps/cjs-module-lexer, is licensed as follows:\n \"\"\"\n MIT License\n -----------\n\n Copyright (C) 2018-2020 Guy Bedford\n\n Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- ittapi, located at deps/v8/third_party/ittapi, is licensed as follows:\n \"\"\"\n Copyright (c) 2019 Intel Corporation. All rights reserved.\n\n Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- amaro, located at deps/amaro, is licensed as follows:\n \"\"\"\n MIT License\n\n Copyright (c) Marco Ippolito and Amaro contributors\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n \"\"\"\n\n- swc, located at deps/amaro/dist, is licensed as follows:\n \"\"\"\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2024 SWC contributors.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n \thttp://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n \"\"\"\n\n- ICU, located at deps/icu-small, is licensed as follows:\n \"\"\"\n UNICODE LICENSE V3\n\n COPYRIGHT AND PERMISSION NOTICE\n\n Copyright © 2016-2025 Unicode, Inc.\n\n NOTICE TO USER: Carefully read the following legal agreement. BY\n DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR\n SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE\n TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT\n DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.\n\n Permission is hereby granted, free of charge, to any person obtaining a\n copy of data files and any associated documentation (the \"Data Files\") or\n software and any associated documentation (the \"Software\") to deal in the\n Data Files or Software without restriction, including without limitation\n the rights to use, copy, modify, merge, publish, distribute, and/or sell\n copies of the Data Files or Software, and to permit persons to whom the\n Data Files or Software are furnished to do so, provided that either (a)\n this copyright and permission notice appear with all copies of the Data\n Files or Software, or (b) this copyright and permission notice appear in\n associated Documentation.\n\n THE DATA FILES AND SOFTWARE ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY\n KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF\n THIRD PARTY RIGHTS.\n\n IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE\n BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES,\n OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\n WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\n ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA\n FILES OR SOFTWARE.\n\n Except as contained in this notice, the name of a copyright holder shall\n not be used in advertising or otherwise to promote the sale, use or other\n dealings in these Data Files or Software without prior written\n authorization of the copyright holder.\n\n SPDX-License-Identifier: Unicode-3.0\n\n ----------------------------------------------------------------------\n\n Third-Party Software Licenses\n\n This section contains third-party software notices and/or additional\n terms for licensed third-party software components included within ICU\n libraries.\n\n ----------------------------------------------------------------------\n\n ICU License - ICU 1.8.1 to ICU 57.1\n\n COPYRIGHT AND PERMISSION NOTICE\n\n Copyright (c) 1995-2016 International Business Machines Corporation and others\n All rights reserved.\n\n Permission is hereby granted, free of charge, to any person obtaining\n a copy of this software and associated documentation files (the\n \"Software\"), to deal in the Software without restriction, including\n without limitation the rights to use, copy, modify, merge, publish,\n distribute, and/or sell copies of the Software, and to permit persons\n to whom the Software is furnished to do so, provided that the above\n copyright notice(s) and this permission notice appear in all copies of\n the Software and that both the above copyright notice(s) and this\n permission notice appear in supporting documentation.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\n OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY\n SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER\n RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF\n CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN\n CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n Except as contained in this notice, the name of a copyright holder\n shall not be used in advertising or otherwise to promote the sale, use\n or other dealings in this Software without prior written authorization\n of the copyright holder.\n\n All trademarks and registered trademarks mentioned herein are the\n property of their respective owners.\n\n ----------------------------------------------------------------------\n\n Chinese/Japanese Word Break Dictionary Data (cjdict.txt)\n\n # The Google Chrome software developed by Google is licensed under\n # the BSD license. Other software included in this distribution is\n # provided under other licenses, as set forth below.\n #\n # The BSD License\n # http://opensource.org/licenses/bsd-license.php\n # Copyright (C) 2006-2008, Google Inc.\n #\n # All rights reserved.\n #\n # Redistribution and use in source and binary forms, with or without\n # modification, are permitted provided that the following conditions are met:\n #\n # Redistributions of source code must retain the above copyright notice,\n # this list of conditions and the following disclaimer.\n # Redistributions in binary form must reproduce the above\n # copyright notice, this list of conditions and the following\n # disclaimer in the documentation and/or other materials provided with\n # the distribution.\n # Neither the name of Google Inc. nor the names of its\n # contributors may be used to endorse or promote products derived from\n # this software without specific prior written permission.\n #\n #\n # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n # CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\n # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n #\n #\n # The word list in cjdict.txt are generated by combining three word lists\n # listed below with further processing for compound word breaking. The\n # frequency is generated with an iterative training against Google web\n # corpora.\n #\n # * Libtabe (Chinese)\n # - https://sourceforge.net/project/?group_id=1519\n # - Its license terms and conditions are shown below.\n #\n # * IPADIC (Japanese)\n # - http://chasen.aist-nara.ac.jp/chasen/distribution.html\n # - Its license terms and conditions are shown below.\n #\n # ---------COPYING.libtabe ---- BEGIN--------------------\n #\n # /*\n # * Copyright (c) 1999 TaBE Project.\n # * Copyright (c) 1999 Pai-Hsiang Hsiao.\n # * All rights reserved.\n # *\n # * Redistribution and use in source and binary forms, with or without\n # * modification, are permitted provided that the following conditions\n # * are met:\n # *\n # * . Redistributions of source code must retain the above copyright\n # * notice, this list of conditions and the following disclaimer.\n # * . Redistributions in binary form must reproduce the above copyright\n # * notice, this list of conditions and the following disclaimer in\n # * the documentation and/or other materials provided with the\n # * distribution.\n # * . Neither the name of the TaBE Project nor the names of its\n # * contributors may be used to endorse or promote products derived\n # * from this software without specific prior written permission.\n # *\n # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n # * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n # * OF THE POSSIBILITY OF SUCH DAMAGE.\n # */\n #\n # /*\n # * Copyright (c) 1999 Computer Systems and Communication Lab,\n # * Institute of Information Science, Academia\n # * Sinica. All rights reserved.\n # *\n # * Redistribution and use in source and binary forms, with or without\n # * modification, are permitted provided that the following conditions\n # * are met:\n # *\n # * . Redistributions of source code must retain the above copyright\n # * notice, this list of conditions and the following disclaimer.\n # * . Redistributions in binary form must reproduce the above copyright\n # * notice, this list of conditions and the following disclaimer in\n # * the documentation and/or other materials provided with the\n # * distribution.\n # * . Neither the name of the Computer Systems and Communication Lab\n # * nor the names of its contributors may be used to endorse or\n # * promote products derived from this software without specific\n # * prior written permission.\n # *\n # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n # * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n # * OF THE POSSIBILITY OF SUCH DAMAGE.\n # */\n #\n # Copyright 1996 Chih-Hao Tsai @ Beckman Institute,\n # University of Illinois\n # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4\n #\n # ---------------COPYING.libtabe-----END--------------------------------\n #\n #\n # ---------------COPYING.ipadic-----BEGIN-------------------------------\n #\n # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science\n # and Technology. All Rights Reserved.\n #\n # Use, reproduction, and distribution of this software is permitted.\n # Any copy of this software, whether in its original form or modified,\n # must include both the above copyright notice and the following\n # paragraphs.\n #\n # Nara Institute of Science and Technology (NAIST),\n # the copyright holders, disclaims all warranties with regard to this\n # software, including all implied warranties of merchantability and\n # fitness, in no event shall NAIST be liable for\n # any special, indirect or consequential damages or any damages\n # whatsoever resulting from loss of use, data or profits, whether in an\n # action of contract, negligence or other tortuous action, arising out\n # of or in connection with the use or performance of this software.\n #\n # A large portion of the dictionary entries\n # originate from ICOT Free Software. The following conditions for ICOT\n # Free Software applies to the current dictionary as well.\n #\n # Each User may also freely distribute the Program, whether in its\n # original form or modified, to any third party or parties, PROVIDED\n # that the provisions of Section 3 (\"NO WARRANTY\") will ALWAYS appear\n # on, or be attached to, the Program, which is distributed substantially\n # in the same form as set out herein and that such intended\n # distribution, if actually made, will neither violate or otherwise\n # contravene any of the laws and regulations of the countries having\n # jurisdiction over the User or the intended distribution itself.\n #\n # NO WARRANTY\n #\n # The program was produced on an experimental basis in the course of the\n # research and development conducted during the project and is provided\n # to users as so produced on an experimental basis. Accordingly, the\n # program is provided without any warranty whatsoever, whether express,\n # implied, statutory or otherwise. The term \"warranty\" used herein\n # includes, but is not limited to, any warranty of the quality,\n # performance, merchantability and fitness for a particular purpose of\n # the program and the nonexistence of any infringement or violation of\n # any right of any third party.\n #\n # Each user of the program will agree and understand, and be deemed to\n # have agreed and understood, that there is no warranty whatsoever for\n # the program and, accordingly, the entire risk arising from or\n # otherwise connected with the program is assumed by the user.\n #\n # Therefore, neither ICOT, the copyright holder, or any other\n # organization that participated in or was otherwise related to the\n # development of the program and their respective officials, directors,\n # officers and other employees shall be held liable for any and all\n # damages, including, without limitation, general, special, incidental\n # and consequential damages, arising out of or otherwise in connection\n # with the use or inability to use the program or any product, material\n # or result produced or otherwise obtained by using the program,\n # regardless of whether they have been advised of, or otherwise had\n # knowledge of, the possibility of such damages at any time during the\n # project or thereafter. Each user will be deemed to have agreed to the\n # foregoing by his or her commencement of use of the program. The term\n # \"use\" as used herein includes, but is not limited to, the use,\n # modification, copying and distribution of the program and the\n # production of secondary products from the program.\n #\n # In the case where the program, whether in its original form or\n # modified, was distributed or delivered to or received by a user from\n # any person, organization or entity other than ICOT, unless it makes or\n # grants independently of ICOT any specific warranty to the user in\n # writing, such person, organization or entity, will also be exempted\n # from and not be held liable to the user for any such damages as noted\n # above as far as the program is concerned.\n #\n # ---------------COPYING.ipadic-----END----------------------------------\n\n ----------------------------------------------------------------------\n\n Lao Word Break Dictionary Data (laodict.txt)\n\n # Copyright (C) 2016 and later: Unicode, Inc. and others.\n # License & terms of use: http://www.unicode.org/copyright.html\n # Copyright (c) 2015 International Business Machines Corporation\n # and others. All Rights Reserved.\n #\n # Project: https://github.com/rober42539/lao-dictionary\n # Dictionary: https://github.com/rober42539/lao-dictionary/laodict.txt\n # License: https://github.com/rober42539/lao-dictionary/LICENSE.txt\n # (copied below)\n #\n # This file is derived from the above dictionary version of Nov 22, 2020\n # ----------------------------------------------------------------------\n # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell.\n # All rights reserved.\n #\n # Redistribution and use in source and binary forms, with or without\n # modification, are permitted provided that the following conditions are met:\n #\n # Redistributions of source code must retain the above copyright notice, this\n # list of conditions and the following disclaimer. Redistributions in binary\n # form must reproduce the above copyright notice, this list of conditions and\n # the following disclaimer in the documentation and/or other materials\n # provided with the distribution.\n #\n # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n # \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n # OF THE POSSIBILITY OF SUCH DAMAGE.\n # --------------------------------------------------------------------------\n\n ----------------------------------------------------------------------\n\n Burmese Word Break Dictionary Data (burmesedict.txt)\n\n # Copyright (c) 2014 International Business Machines Corporation\n # and others. All Rights Reserved.\n #\n # This list is part of a project hosted at:\n # github.com/kanyawtech/myanmar-karen-word-lists\n #\n # --------------------------------------------------------------------------\n # Copyright (c) 2013, LeRoy Benjamin Sharon\n # All rights reserved.\n #\n # Redistribution and use in source and binary forms, with or without\n # modification, are permitted provided that the following conditions\n # are met: Redistributions of source code must retain the above\n # copyright notice, this list of conditions and the following\n # disclaimer. Redistributions in binary form must reproduce the\n # above copyright notice, this list of conditions and the following\n # disclaimer in the documentation and/or other materials provided\n # with the distribution.\n #\n # Neither the name Myanmar Karen Word Lists, nor the names of its\n # contributors may be used to endorse or promote products derived\n # from this software without specific prior written permission.\n #\n # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n # CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS\n # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\n # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR\n # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF\n # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n # SUCH DAMAGE.\n # --------------------------------------------------------------------------\n\n ----------------------------------------------------------------------\n\n Time Zone Database\n\n ICU uses the public domain data and code derived from Time Zone\n Database for its time zone support. The ownership of the TZ database\n is explained in BCP 175: Procedure for Maintaining the Time Zone\n Database section 7.\n\n # 7. Database Ownership\n #\n # The TZ database itself is not an IETF Contribution or an IETF\n # document. Rather it is a pre-existing and regularly updated work\n # that is in the public domain, and is intended to remain in the\n # public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do\n # not apply to the TZ Database or contributions that individuals make\n # to it. Should any claims be made and substantiated against the TZ\n # Database, the organization that is providing the IANA\n # Considerations defined in this RFC, under the memorandum of\n # understanding with the IETF, currently ICANN, may act in accordance\n # with all competent court orders. No ownership claims will be made\n # by ICANN or the IETF Trust on the database or the code. Any person\n # making a contribution to the database or code waives all rights to\n # future claims in that contribution or in the TZ Database.\n\n ----------------------------------------------------------------------\n\n Google double-conversion\n\n Copyright 2006-2011, the V8 project authors. All rights reserved.\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following\n disclaimer in the documentation and/or other materials provided\n with the distribution.\n * Neither the name of Google Inc. nor the names of its\n contributors may be used to endorse or promote products derived\n from this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n ----------------------------------------------------------------------\n\n JSON parsing library (nlohmann/json)\n\n File: vendor/json/upstream/single_include/nlohmann/json.hpp (only for ICU4C)\n\n MIT License\n\n Copyright (c) 2013-2022 Niels Lohmann\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n\n ----------------------------------------------------------------------\n\n File: aclocal.m4 (only for ICU4C)\n Section: pkg.m4 - Macros to locate and utilise pkg-config.\n\n Copyright © 2004 Scott James Remnant .\n Copyright © 2012-2015 Dan Nicholson\n\n This program is free software; you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation; either version 2 of the License, or\n (at your option) any later version.\n\n This program is distributed in the hope that it will be useful, but\n WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n General Public License for more details.\n\n You should have received a copy of the GNU General Public License\n along with this program; if not, write to the Free Software\n Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\n 02111-1307, USA.\n\n As a special exception to the GNU General Public License, if you\n distribute this file as part of a program that contains a\n configuration script generated by Autoconf, you may include it under\n the same distribution terms that you use for the rest of that\n program.\n\n (The condition for the exception is fulfilled because\n ICU4C includes a configuration script generated by Autoconf,\n namely the `configure` script.)\n\n ----------------------------------------------------------------------\n\n File: config.guess (only for ICU4C)\n\n This file is free software; you can redistribute it and/or modify it\n under the terms of the GNU General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n This program is distributed in the hope that it will be useful, but\n WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n General Public License for more details.\n\n You should have received a copy of the GNU General Public License\n along with this program; if not, see .\n\n As a special exception to the GNU General Public License, if you\n distribute this file as part of a program that contains a\n configuration script generated by Autoconf, you may include it under\n the same distribution terms that you use for the rest of that\n program. This Exception is an additional permission under section 7\n of the GNU General Public License, version 3 (\"GPLv3\").\n\n (The condition for the exception is fulfilled because\n ICU4C includes a configuration script generated by Autoconf,\n namely the `configure` script.)\n\n ----------------------------------------------------------------------\n\n File: install-sh (only for ICU4C)\n\n Copyright 1991 by the Massachusetts Institute of Technology\n\n Permission to use, copy, modify, distribute, and sell this software and its\n documentation for any purpose is hereby granted without fee, provided that\n the above copyright notice appear in all copies and that both that\n copyright notice and this permission notice appear in supporting\n documentation, and that the name of M.I.T. not be used in advertising or\n publicity pertaining to distribution of the software without specific,\n written prior permission. M.I.T. makes no representations about the\n suitability of this software for any purpose. It is provided \"as is\"\n without express or implied warranty.\n \"\"\"\n\n- libuv, located at deps/uv, is licensed as follows:\n \"\"\"\n Copyright (c) 2015-present libuv project contributors.\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to\n deal in the Software without restriction, including without limitation the\n rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n sell copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in\n all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n IN THE SOFTWARE.\n This license applies to parts of libuv originating from the\n https://github.com/joyent/libuv repository:\n\n ====\n\n Copyright Joyent, Inc. and other Node contributors. All rights reserved.\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to\n deal in the Software without restriction, including without limitation the\n rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n sell copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in\n all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n IN THE SOFTWARE.\n\n ====\n\n This license applies to all parts of libuv that are not externally\n maintained libraries.\n\n The externally maintained libraries used by libuv are:\n\n - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license.\n\n - inet_pton and inet_ntop implementations, contained in src/inet.c, are\n copyright the Internet Systems Consortium, Inc., and licensed under the ISC\n license.\n \"\"\"\n\n- llhttp, located at deps/llhttp, is licensed as follows:\n \"\"\"\n This software is licensed under the MIT License.\n\n Copyright Fedor Indutny, 2018.\n\n Permission is hereby granted, free of charge, to any person obtaining a\n copy of this software and associated documentation files (the\n \"Software\"), to deal in the Software without restriction, including\n without limitation the rights to use, copy, modify, merge, publish,\n distribute, sublicense, and/or sell copies of the Software, and to permit\n persons to whom the Software is furnished to do so, subject to the\n following conditions:\n\n The above copyright notice and this permission notice shall be included\n in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- corepack, located at deps/corepack, is licensed as follows:\n \"\"\"\n **Copyright © Corepack contributors**\n\n Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- undici, located at deps/undici, is licensed as follows:\n \"\"\"\n MIT License\n\n Copyright (c) Matteo Collina and Undici contributors\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n \"\"\"\n\n- postject, located at test/fixtures/postject-copy, is licensed as follows:\n \"\"\"\n Postject is licensed for use as follows:\n\n \"\"\"\n MIT License\n\n Copyright (c) 2022 Postman, Inc\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n \"\"\"\n\n The Postject license applies to all parts of Postject that are not externally\n maintained libraries.\n\n The externally maintained libraries used by Postject are:\n\n - LIEF, located at vendor/LIEF, is licensed as follows:\n \"\"\"\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2017 - 2022 R. Thomas\n Copyright 2017 - 2022 Quarkslab\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n \"\"\"\n \"\"\"\n\n- OpenSSL, located at deps/openssl, is licensed as follows:\n \"\"\"\n Apache License\n Version 2.0, January 2004\n https://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n \"\"\"\n\n- Punycode.js, located at lib/punycode.js, is licensed as follows:\n \"\"\"\n Copyright Mathias Bynens \n\n Permission is hereby granted, free of charge, to any person obtaining\n a copy of this software and associated documentation files (the\n \"Software\"), to deal in the Software without restriction, including\n without limitation the rights to use, copy, modify, merge, publish,\n distribute, sublicense, and/or sell copies of the Software, and to\n permit persons to whom the Software is furnished to do so, subject to\n the following conditions:\n\n The above copyright notice and this permission notice shall be\n included in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- V8, located at deps/v8, is licensed as follows:\n \"\"\"\n This license applies to all parts of V8 that are not externally\n maintained libraries. The externally maintained libraries used by V8\n are:\n\n - PCRE test suite, located in\n test/mjsunit/third_party/regexp-pcre/regexp-pcre.js. This is based on the\n test suite from PCRE-7.3, which is copyrighted by the University\n of Cambridge and Google, Inc. The copyright notice and license\n are embedded in regexp-pcre.js.\n\n - Layout tests, located in test/mjsunit/third_party/object-keys. These are\n based on layout tests from webkit.org which are copyrighted by\n Apple Computer, Inc. and released under a 3-clause BSD license.\n\n - Strongtalk assembler, the basis of the files assembler-arm-inl.h,\n assembler-arm.cc, assembler-arm.h, assembler-ia32-inl.h,\n assembler-ia32.cc, assembler-ia32.h, assembler-x64-inl.h,\n assembler-x64.cc, assembler-x64.h, assembler.cc and assembler.h.\n This code is copyrighted by Sun Microsystems Inc. and released\n under a 3-clause BSD license.\n\n - Valgrind client API header, located at third_party/valgrind/valgrind.h\n This is released under the BSD license.\n\n - The Wasm C/C++ API headers, located at third_party/wasm-api/wasm.{h,hh}\n This is released under the Apache license. The API's upstream prototype\n implementation also formed the basis of V8's implementation in\n src/wasm/c-api.cc.\n\n These libraries have their own licenses; we recommend you read them,\n as their terms may differ from the terms below.\n\n Further license information can be found in LICENSE files located in\n sub-directories.\n\n Copyright 2014, the V8 project authors. All rights reserved.\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following\n disclaimer in the documentation and/or other materials provided\n with the distribution.\n * Neither the name of Google Inc. nor the names of its\n contributors may be used to endorse or promote products derived\n from this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- SipHash, located at deps/v8/src/third_party/siphash, is licensed as follows:\n \"\"\"\n SipHash reference C implementation\n\n Copyright (c) 2016 Jean-Philippe Aumasson \n\n To the extent possible under law, the author(s) have dedicated all\n copyright and related and neighboring rights to this software to the public\n domain worldwide. This software is distributed without any warranty.\n \"\"\"\n\n- zlib, located at deps/zlib, is licensed as follows:\n \"\"\"\n zlib.h -- interface of the 'zlib' general purpose compression library\n version 1.3.1, January 22nd, 2024\n\n Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler\n\n This software is provided 'as-is', without any express or implied\n warranty. In no event will the authors be held liable for any damages\n arising from the use of this software.\n\n Permission is granted to anyone to use this software for any purpose,\n including commercial applications, and to alter it and redistribute it\n freely, subject to the following restrictions:\n\n 1. The origin of this software must not be misrepresented; you must not\n claim that you wrote the original software. If you use this software\n in a product, an acknowledgment in the product documentation would be\n appreciated but is not required.\n 2. Altered source versions must be plainly marked as such, and must not be\n misrepresented as being the original software.\n 3. This notice may not be removed or altered from any source distribution.\n\n Jean-loup Gailly Mark Adler\n jloup@gzip.org madler@alumni.caltech.edu\n \"\"\"\n\n- simdjson, located at deps/simdjson, is licensed as follows:\n \"\"\"\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2018-2025 The simdjson authors\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n \"\"\"\n\n- simdutf, located at deps/v8/third_party/simdutf, is licensed as follows:\n \"\"\"\n Copyright 2021 The simdutf authors\n\n Permission is hereby granted, free of charge, to any person obtaining a copy of\n this software and associated documentation files (the \"Software\"), to deal in\n the Software without restriction, including without limitation the rights to\n use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\n the Software, and to permit persons to whom the Software is furnished to do so,\n subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- ada, located at deps/ada, is licensed as follows:\n \"\"\"\n Copyright 2023 Yagiz Nizipli and Daniel Lemire\n\n Permission is hereby granted, free of charge, to any person obtaining a copy of\n this software and associated documentation files (the \"Software\"), to deal in\n the Software without restriction, including without limitation the rights to\n use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\n the Software, and to permit persons to whom the Software is furnished to do so,\n subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- minimatch, located at deps/minimatch, is licensed as follows:\n \"\"\"\n The ISC License\n\n Copyright (c) 2011-2023 Isaac Z. Schlueter and Contributors\n\n Permission to use, copy, modify, and/or distribute this software for any\n purpose with or without fee is hereby granted, provided that the above\n copyright notice and this permission notice appear in all copies.\n\n THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR\n IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n \"\"\"\n\n- npm, located at deps/npm, is licensed as follows:\n \"\"\"\n The npm application\n Copyright (c) npm, Inc. and Contributors\n Licensed on the terms of The Artistic License 2.0\n\n Node package dependencies of the npm application\n Copyright (c) their respective copyright owners\n Licensed on their respective license terms\n\n The npm public registry at https://registry.npmjs.org\n and the npm website at https://www.npmjs.com\n Operated by npm, Inc.\n Use governed by terms published on https://www.npmjs.com\n\n \"Node.js\"\n Trademark Joyent, Inc., https://joyent.com\n Neither npm nor npm, Inc. are affiliated with Joyent, Inc.\n\n The Node.js application\n Project of Node Foundation, https://nodejs.org\n\n The npm Logo\n Copyright (c) Mathias Pettersson and Brian Hammond\n\n \"Gubblebum Blocky\" typeface\n Copyright (c) Tjarda Koster, https://jelloween.deviantart.com\n Used with permission\n\n --------\n\n The Artistic License 2.0\n\n Copyright (c) 2000-2006, The Perl Foundation.\n\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n Preamble\n\n This license establishes the terms under which a given free software\n Package may be copied, modified, distributed, and/or redistributed.\n The intent is that the Copyright Holder maintains some artistic\n control over the development of that Package while still keeping the\n Package available as open source and free software.\n\n You are always permitted to make arrangements wholly outside of this\n license directly with the Copyright Holder of a given Package. If the\n terms of this license do not permit the full use that you propose to\n make of the Package, you should contact the Copyright Holder and seek\n a different licensing arrangement.\n\n Definitions\n\n \"Copyright Holder\" means the individual(s) or organization(s)\n named in the copyright notice for the entire Package.\n\n \"Contributor\" means any party that has contributed code or other\n material to the Package, in accordance with the Copyright Holder's\n procedures.\n\n \"You\" and \"your\" means any person who would like to copy,\n distribute, or modify the Package.\n\n \"Package\" means the collection of files distributed by the\n Copyright Holder, and derivatives of that collection and/or of\n those files. A given Package may consist of either the Standard\n Version, or a Modified Version.\n\n \"Distribute\" means providing a copy of the Package or making it\n accessible to anyone else, or in the case of a company or\n organization, to others outside of your company or organization.\n\n \"Distributor Fee\" means any fee that you charge for Distributing\n this Package or providing support for this Package to another\n party. It does not mean licensing fees.\n\n \"Standard Version\" refers to the Package if it has not been\n modified, or has been modified only in ways explicitly requested\n by the Copyright Holder.\n\n \"Modified Version\" means the Package, if it has been changed, and\n such changes were not explicitly requested by the Copyright\n Holder.\n\n \"Original License\" means this Artistic License as Distributed with\n the Standard Version of the Package, in its current version or as\n it may be modified by The Perl Foundation in the future.\n\n \"Source\" form means the source code, documentation source, and\n configuration files for the Package.\n\n \"Compiled\" form means the compiled bytecode, object code, binary,\n or any other form resulting from mechanical transformation or\n translation of the Source form.\n\n Permission for Use and Modification Without Distribution\n\n (1) You are permitted to use the Standard Version and create and use\n Modified Versions for any purpose without restriction, provided that\n you do not Distribute the Modified Version.\n\n Permissions for Redistribution of the Standard Version\n\n (2) You may Distribute verbatim copies of the Source form of the\n Standard Version of this Package in any medium without restriction,\n either gratis or for a Distributor Fee, provided that you duplicate\n all of the original copyright notices and associated disclaimers. At\n your discretion, such verbatim copies may or may not include a\n Compiled form of the Package.\n\n (3) You may apply any bug fixes, portability changes, and other\n modifications made available from the Copyright Holder. The resulting\n Package will still be considered the Standard Version, and as such\n will be subject to the Original License.\n\n Distribution of Modified Versions of the Package as Source\n\n (4) You may Distribute your Modified Version as Source (either gratis\n or for a Distributor Fee, and with or without a Compiled form of the\n Modified Version) provided that you clearly document how it differs\n from the Standard Version, including, but not limited to, documenting\n any non-standard features, executables, or modules, and provided that\n you do at least ONE of the following:\n\n (a) make the Modified Version available to the Copyright Holder\n of the Standard Version, under the Original License, so that the\n Copyright Holder may include your modifications in the Standard\n Version.\n\n (b) ensure that installation of your Modified Version does not\n prevent the user installing or running the Standard Version. In\n addition, the Modified Version must bear a name that is different\n from the name of the Standard Version.\n\n (c) allow anyone who receives a copy of the Modified Version to\n make the Source form of the Modified Version available to others\n under\n\n (i) the Original License or\n\n (ii) a license that permits the licensee to freely copy,\n modify and redistribute the Modified Version using the same\n licensing terms that apply to the copy that the licensee\n received, and requires that the Source form of the Modified\n Version, and of any works derived from it, be made freely\n available in that license fees are prohibited but Distributor\n Fees are allowed.\n\n Distribution of Compiled Forms of the Standard Version\n or Modified Versions without the Source\n\n (5) You may Distribute Compiled forms of the Standard Version without\n the Source, provided that you include complete instructions on how to\n get the Source of the Standard Version. Such instructions must be\n valid at the time of your distribution. If these instructions, at any\n time while you are carrying out such distribution, become invalid, you\n must provide new instructions on demand or cease further distribution.\n If you provide valid instructions or cease distribution within thirty\n days after you become aware that the instructions are invalid, then\n you do not forfeit any of your rights under this license.\n\n (6) You may Distribute a Modified Version in Compiled form without\n the Source, provided that you comply with Section 4 with respect to\n the Source of the Modified Version.\n\n Aggregating or Linking the Package\n\n (7) You may aggregate the Package (either the Standard Version or\n Modified Version) with other packages and Distribute the resulting\n aggregation provided that you do not charge a licensing fee for the\n Package. Distributor Fees are permitted, and licensing fees for other\n components in the aggregation are permitted. The terms of this license\n apply to the use and Distribution of the Standard or Modified Versions\n as included in the aggregation.\n\n (8) You are permitted to link Modified and Standard Versions with\n other works, to embed the Package in a larger work of your own, or to\n build stand-alone binary or bytecode versions of applications that\n include the Package, and Distribute the result without restriction,\n provided the result does not expose a direct interface to the Package.\n\n Items That are Not Considered Part of a Modified Version\n\n (9) Works (including, but not limited to, modules and scripts) that\n merely extend or make use of the Package, do not, by themselves, cause\n the Package to be a Modified Version. In addition, such works are not\n considered parts of the Package itself, and are not subject to the\n terms of this license.\n\n General Provisions\n\n (10) Any use, modification, and distribution of the Standard or\n Modified Versions is governed by this Artistic License. By using,\n modifying or distributing the Package, you accept this license. Do not\n use, modify, or distribute the Package, if you do not accept this\n license.\n\n (11) If your Modified Version has been derived from a Modified\n Version made by someone other than you, you are nevertheless required\n to ensure that your Modified Version complies with the requirements of\n this license.\n\n (12) This license does not grant you the right to use any trademark,\n service mark, tradename, or logo of the Copyright Holder.\n\n (13) This license includes the non-exclusive, worldwide,\n free-of-charge patent license to make, have made, use, offer to sell,\n sell, import and otherwise transfer the Package with respect to any\n patent claims licensable by the Copyright Holder that are necessarily\n infringed by the Package. If you institute patent litigation\n (including a cross-claim or counterclaim) against any party alleging\n that the Package constitutes direct or contributory patent\n infringement, then this Artistic License to you shall terminate on the\n date that such litigation is filed.\n\n (14) Disclaimer of Warranty:\n THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS \"AS\n IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED\n WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR\n NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL\n LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL\n BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\n DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF\n ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n --------\n \"\"\"\n\n- GYP, located at tools/gyp, is licensed as follows:\n \"\"\"\n Copyright (c) 2020 Node.js contributors. All rights reserved.\n Copyright (c) 2009 Google Inc. All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following disclaimer\n in the documentation and/or other materials provided with the\n distribution.\n * Neither the name of Google Inc. nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- inspector_protocol, located at deps/inspector_protocol, is licensed as follows:\n \"\"\"\n // Copyright 2016 The Chromium Authors.\n //\n // Redistribution and use in source and binary forms, with or without\n // modification, are permitted provided that the following conditions are\n // met:\n //\n // * Redistributions of source code must retain the above copyright\n // notice, this list of conditions and the following disclaimer.\n // * Redistributions in binary form must reproduce the above\n // copyright notice, this list of conditions and the following disclaimer\n // in the documentation and/or other materials provided with the\n // distribution.\n // * Neither the name of Google Inc. nor the names of its\n // contributors may be used to endorse or promote products derived from\n // this software without specific prior written permission.\n //\n // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n // \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- jinja2, located at tools/inspector_protocol/jinja2, is licensed as follows:\n \"\"\"\n Copyright (c) 2009 by the Jinja Team, see AUTHORS for more details.\n\n Some rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following\n disclaimer in the documentation and/or other materials provided\n with the distribution.\n\n * The names of the contributors may not be used to endorse or\n promote products derived from this software without specific\n prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- markupsafe, located at tools/inspector_protocol/markupsafe, is licensed as follows:\n \"\"\"\n Copyright (c) 2010 by Armin Ronacher and contributors. See AUTHORS\n for more details.\n\n Some rights reserved.\n\n Redistribution and use in source and binary forms of the software as well\n as documentation, with or without modification, are permitted provided\n that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following\n disclaimer in the documentation and/or other materials provided\n with the distribution.\n\n * The names of the contributors may not be used to endorse or\n promote products derived from this software without specific\n prior written permission.\n\n THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT\n NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER\n OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n DAMAGE.\n \"\"\"\n\n- cpplint.py, located at tools/cpplint.py, is licensed as follows:\n \"\"\"\n Copyright (c) 2009 Google Inc. All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following disclaimer\n in the documentation and/or other materials provided with the\n distribution.\n * Neither the name of Google Inc. nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- gypi_to_gn.py, located at tools/gypi_to_gn.py, is licensed as follows:\n \"\"\"\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following disclaimer\n in the documentation and/or other materials provided with the\n distribution.\n * Neither the name of Google LLC nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- gtest, located at deps/googletest, is licensed as follows:\n \"\"\"\n Copyright 2008, Google Inc.\n All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following disclaimer\n in the documentation and/or other materials provided with the\n distribution.\n * Neither the name of Google Inc. nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- nghttp2, located at deps/nghttp2, is licensed as follows:\n \"\"\"\n The MIT License\n\n Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa\n Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors\n\n Permission is hereby granted, free of charge, to any person obtaining\n a copy of this software and associated documentation files (the\n \"Software\"), to deal in the Software without restriction, including\n without limitation the rights to use, copy, modify, merge, publish,\n distribute, sublicense, and/or sell copies of the Software, and to\n permit persons to whom the Software is furnished to do so, subject to\n the following conditions:\n\n The above copyright notice and this permission notice shall be\n included in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- large_pages, located at src/large_pages, is licensed as follows:\n \"\"\"\n Copyright (C) 2018 Intel Corporation\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"),\n to deal in the Software without restriction, including without limitation\n the rights to use, copy, modify, merge, publish, distribute, sublicense,\n and/or sell copies of the Software, and to permit persons to whom\n the Software is furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included\n in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES\n OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE\n OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- caja, located at lib/internal/freeze_intrinsics.js, is licensed as follows:\n \"\"\"\n Adapted from SES/Caja - Copyright (C) 2011 Google Inc.\n Copyright (C) 2018 Agoric\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n \"\"\"\n\n- brotli, located at deps/brotli, is licensed as follows:\n \"\"\"\n Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in\n all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n THE SOFTWARE.\n \"\"\"\n\n- zstd, located at deps/zstd, is licensed as follows:\n \"\"\"\n BSD License\n\n For Zstandard software\n\n Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved.\n\n Redistribution and use in source and binary forms, with or without modification,\n are permitted provided that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n * Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n * Neither the name Facebook, nor Meta, nor the names of its contributors may\n be used to endorse or promote products derived from this software without\n specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\n ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\n ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- HdrHistogram, located at deps/histogram, is licensed as follows:\n \"\"\"\n The code in this repository code was Written by Gil Tene, Michael Barker,\n and Matt Warren, and released to the public domain, as explained at\n http://creativecommons.org/publicdomain/zero/1.0/\n\n For users of this code who wish to consume it under the \"BSD\" license\n rather than under the public domain or CC0 contribution text mentioned\n above, the code found under this directory is *also* provided under the\n following license (commonly referred to as the BSD 2-Clause License). This\n license does not detract from the above stated release of the code into\n the public domain, and simply represents an additional license granted by\n the Author.\n\n -----------------------------------------------------------------------------\n ** Beginning of \"BSD 2-Clause License\" text. **\n\n Copyright (c) 2012, 2013, 2014 Gil Tene\n Copyright (c) 2014 Michael Barker\n Copyright (c) 2014 Matt Warren\n All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice,\n this list of conditions and the following disclaimer.\n\n 2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n THE POSSIBILITY OF SUCH DAMAGE.\n \"\"\"\n\n- node-heapdump, located at src/heap_utils.cc, is licensed as follows:\n \"\"\"\n ISC License\n\n Copyright (c) 2012, Ben Noordhuis \n\n Permission to use, copy, modify, and/or distribute this software for any\n purpose with or without fee is hereby granted, provided that the above\n copyright notice and this permission notice appear in all copies.\n\n THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n === src/compat.h src/compat-inl.h ===\n\n ISC License\n\n Copyright (c) 2014, StrongLoop Inc.\n\n Permission to use, copy, modify, and/or distribute this software for any\n purpose with or without fee is hereby granted, provided that the above\n copyright notice and this permission notice appear in all copies.\n\n THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n \"\"\"\n\n- rimraf, located at lib/internal/fs/rimraf.js, is licensed as follows:\n \"\"\"\n The ISC License\n\n Copyright (c) Isaac Z. Schlueter and Contributors\n\n Permission to use, copy, modify, and/or distribute this software for any\n purpose with or without fee is hereby granted, provided that the above\n copyright notice and this permission notice appear in all copies.\n\n THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR\n IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n \"\"\"\n\n- uvwasi, located at deps/uvwasi, is licensed as follows:\n \"\"\"\n MIT License\n\n Copyright (c) 2019 Colin Ihrig and Contributors\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n \"\"\"\n\n- ngtcp2, located at deps/ngtcp2/ngtcp2/, is licensed as follows:\n \"\"\"\n The MIT License\n\n Copyright (c) 2016 ngtcp2 contributors\n\n Permission is hereby granted, free of charge, to any person obtaining\n a copy of this software and associated documentation files (the\n \"Software\"), to deal in the Software without restriction, including\n without limitation the rights to use, copy, modify, merge, publish,\n distribute, sublicense, and/or sell copies of the Software, and to\n permit persons to whom the Software is furnished to do so, subject to\n the following conditions:\n\n The above copyright notice and this permission notice shall be\n included in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- nghttp3, located at deps/ngtcp2/nghttp3/, is licensed as follows:\n \"\"\"\n The MIT License\n\n Copyright (c) 2019 nghttp3 contributors\n\n Permission is hereby granted, free of charge, to any person obtaining\n a copy of this software and associated documentation files (the\n \"Software\"), to deal in the Software without restriction, including\n without limitation the rights to use, copy, modify, merge, publish,\n distribute, sublicense, and/or sell copies of the Software, and to\n permit persons to whom the Software is furnished to do so, subject to\n the following conditions:\n\n The above copyright notice and this permission notice shall be\n included in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- node-fs-extra, located at lib/internal/fs/cp, is licensed as follows:\n \"\"\"\n (The MIT License)\n\n Copyright (c) 2011-2017 JP Richardson\n\n Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files\n (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,\n merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\n OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n \"\"\"\n\n- on-exit-leak-free, located at lib/internal/process/finalization, is licensed as follows:\n \"\"\"\n MIT License\n\n Copyright (c) 2021 Matteo Collina\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n \"\"\"\n\n- sonic-boom, located at lib/internal/streams/fast-utf8-stream.js, is licensed as follows:\n \"\"\"\n MIT License\n\n Copyright (c) 2017 Matteo Collina\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n \"\"\"" } } From 5ce51896e68ba1fb366d2888574c3f2034b1c9f9 Mon Sep 17 00:00:00 2001 From: Richard Li <742829+rli@users.noreply.github.com> Date: Thu, 11 Sep 2025 00:03:53 -0700 Subject: [PATCH 074/158] build: fix download-node.sh (#2237) `download-node.sh` incorrectly reports success if `jq` fails --- .../scripts/download-node.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/scripts/download-node.sh b/app/aws-lsp-codewhisperer-runtimes/scripts/download-node.sh index 44c3c1c462..db99f68d06 100755 --- a/app/aws-lsp-codewhisperer-runtimes/scripts/download-node.sh +++ b/app/aws-lsp-codewhisperer-runtimes/scripts/download-node.sh @@ -4,7 +4,7 @@ # build/node-assets, which is picked up # by src/scripts/copy-node-assets.ts, to produce the final bundle. -set -e +set -eo pipefail NODE_VERSION="24" BASE_URL="https://nodejs.org/download/release/latest-v${NODE_VERSION}.x" SHASUMS_FILE="SHASUMS256.txt" @@ -69,9 +69,6 @@ fi echo "License file has been updated in $LICENSE_FILE" -# Read the escaped license text -LICENSE_TEXT=$(cat "$LICENSE_FILE") - # Update the attribution overrides file ATTRIBUTION_FILE="../../attribution/overrides.json" @@ -86,11 +83,13 @@ fi jq --indent 4 \ --arg name "Node.js" \ --arg version "$NODE_SEMVER" \ - --arg licenseText "$LICENSE_TEXT" \ + --rawfile licenseText "$LICENSE_FILE" \ --arg url "https://github.com/nodejs/node" \ --arg license "MIT" \ '.node.name = $name | .node.version = $version | .node.url = $url | .node.license = $license | .node.licenseText = $licenseText' \ - "$ATTRIBUTION_FILE" > "$ATTRIBUTION_FILE.tmp" && mv "$ATTRIBUTION_FILE.tmp" "$ATTRIBUTION_FILE" + "$ATTRIBUTION_FILE" > "$ATTRIBUTION_FILE.tmp" + +mv "$ATTRIBUTION_FILE.tmp" "$ATTRIBUTION_FILE" echo "Successfully updated Node.js version and license in $ATTRIBUTION_FILE" # Cleanup From e0941d1fa5cc9eaad8e8d798d0d12afbbbb25aa5 Mon Sep 17 00:00:00 2001 From: chungjac Date: Thu, 11 Sep 2025 12:50:48 -0700 Subject: [PATCH 075/158] chore: bump agentic version: 1.32.0 (#2246) Co-authored-by: aws-toolkit-automation <> --- app/aws-lsp-codewhisperer-runtimes/src/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/src/version.json b/app/aws-lsp-codewhisperer-runtimes/src/version.json index 6d9528a4e7..aec8038513 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/version.json +++ b/app/aws-lsp-codewhisperer-runtimes/src/version.json @@ -1,3 +1,3 @@ { - "agenticChat": "1.31.0" + "agenticChat": "1.32.0" } From b140060d804b6a639a1a5523d0a6f93ea9ae4783 Mon Sep 17 00:00:00 2001 From: Tai Lai Date: Mon, 15 Sep 2025 12:18:03 -0600 Subject: [PATCH 076/158] chore: bump @aws/mynah-ui to 4.36.6 (#2252) --- chat-client/package.json | 2 +- package-lock.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/chat-client/package.json b/chat-client/package.json index 9bd35ba982..3c10213f91 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -27,7 +27,7 @@ "@aws/chat-client-ui-types": "^0.1.56", "@aws/language-server-runtimes": "^0.2.128", "@aws/language-server-runtimes-types": "^0.1.50", - "@aws/mynah-ui": "^4.36.5" + "@aws/mynah-ui": "^4.36.6" }, "devDependencies": { "@types/jsdom": "^21.1.6", diff --git a/package-lock.json b/package-lock.json index 838f0c5fc1..affc82b825 100644 --- a/package-lock.json +++ b/package-lock.json @@ -257,7 +257,7 @@ "@aws/chat-client-ui-types": "^0.1.56", "@aws/language-server-runtimes": "^0.2.128", "@aws/language-server-runtimes-types": "^0.1.50", - "@aws/mynah-ui": "^4.36.5" + "@aws/mynah-ui": "^4.36.6" }, "devDependencies": { "@types/jsdom": "^21.1.6", @@ -4204,9 +4204,9 @@ "link": true }, "node_modules/@aws/mynah-ui": { - "version": "4.36.5", - "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.36.5.tgz", - "integrity": "sha512-HMXqvSpZT84mpY67ChzRDrd73Y9AFZVZ8RcOJ/rNWIXR44uryfNFg2nrvoP4GSn2P+kU8WIPGChHGmyX9N0UgA==", + "version": "4.36.6", + "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.36.6.tgz", + "integrity": "sha512-RIFKIasIgO00dYmRM+JS7dij1hzrNZchhf0+CyUNDUpw2Hcc86/8lP90F1F5rJIOtqtnguiPQ7XwmXxf+Tw5jQ==", "hasInstallScript": true, "license": "Apache License 2.0", "dependencies": { From debeb414fd0d4d873af2f36cde0ebbeab16d16a4 Mon Sep 17 00:00:00 2001 From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> Date: Mon, 15 Sep 2025 11:49:34 -0700 Subject: [PATCH 077/158] fix: migration from /agents ux (#2248) --- chat-client/src/client/mynahUi.ts | 15 +--- chat-client/src/client/tabs/tabFactory.ts | 58 -------------- .../src/client/texts/pairProgramming.test.ts | 69 +---------------- .../src/client/texts/pairProgramming.ts | 75 +------------------ 4 files changed, 3 insertions(+), 214 deletions(-) diff --git a/chat-client/src/client/mynahUi.ts b/chat-client/src/client/mynahUi.ts index 090e5bbf4d..e2ce161f6f 100644 --- a/chat-client/src/client/mynahUi.ts +++ b/chat-client/src/client/mynahUi.ts @@ -69,12 +69,7 @@ import { toMynahIcon, } from './utils' import { ChatHistory, ChatHistoryList } from './features/history' -import { - pairProgrammingModeOff, - pairProgrammingModeOn, - programmerModeCard, - createRerouteCard, -} from './texts/pairProgramming' +import { pairProgrammingModeOff, pairProgrammingModeOn, programmerModeCard } from './texts/pairProgramming' import { ContextRule, RulesList } from './features/rules' import { getModelSelectionChatItem, modelUnavailableBanner, modelThrottledBanner } from './texts/modelSelection' import { @@ -285,11 +280,6 @@ export const handleChatPrompt = ( // For /doc command, don't show any prompt in UI const displayPrompt = isReroutedCommand && prompt.command === '/doc' ? '' : userPrompt initializeChatResponse(mynahUi, tabId, displayPrompt, agenticMode) - - // If this is a rerouted command AND reroute feature is enabled, show the reroute card after the prompt - if (isReroutedCommand && tabFactory?.isRerouteEnabled() && prompt.command) { - mynahUi.addChatItem(tabId, createRerouteCard(prompt.command)) - } } const initializeChatResponse = (mynahUi: MynahUI, tabId: string, userPrompt?: string, agenticMode?: boolean) => { @@ -404,9 +394,6 @@ export const createMynahUi = ( const defaultTabBarData = tabFactory.getDefaultTabData() const defaultTabConfig: Partial = { quickActionCommands: defaultTabBarData.quickActionCommands, - ...(tabFactory.isRerouteEnabled() - ? { quickActionCommandsHeader: defaultTabBarData.quickActionCommandsHeader } - : {}), tabBarButtons: defaultTabBarData.tabBarButtons, contextCommands: [ ...(contextCommandGroups || []), diff --git a/chat-client/src/client/tabs/tabFactory.ts b/chat-client/src/client/tabs/tabFactory.ts index 6df349896c..bfb3091911 100644 --- a/chat-client/src/client/tabs/tabFactory.ts +++ b/chat-client/src/client/tabs/tabFactory.ts @@ -4,7 +4,6 @@ import { MynahIcons, MynahUIDataModel, QuickActionCommandGroup, - QuickActionCommandsHeader, TabBarMainAction, } from '@aws/mynah-ui' import { disclaimerCard } from '../texts/disclaimer' @@ -143,17 +142,6 @@ Select code & ask me to explain, debug or optimize it, or type \`/\` for quick a quickActionCommands: this.quickActionCommands, } : {}), - ...(this.reroute - ? { - quickActionCommandsHeader: { - status: 'warning', - icon: MynahIcons.INFO, - title: 'Q Developer agentic capabilities', - description: - "You can now ask Q directly in the chat to generate code, documentation, and unit tests. You don't need to explicitly use /dev, /test, /review or /doc", - } as QuickActionCommandsHeader, - } - : {}), } tabData.tabBarButtons = this.getTabBarButtons() @@ -229,50 +217,4 @@ Select code & ask me to explain, debug or optimize it, or type \`/\` for quick a return tabBarButtons.length ? tabBarButtons : undefined } - - // Enhanced welcome messages block for non-agentic mode - private getEnhancedWelcomeBlock() { - return { - text: '', - options: [ - { - pillText: 'Getting Started', - prompt: 'What can Amazon Q help me with?', - type: 'help', - }, - ], - } - } - - // Agentic welcome messages block - private getAgenticWelcomeBlock() { - return { - text: '', - options: [ - { - pillText: 'Getting Started', - prompt: 'What can Amazon Q help me with?', - type: 'help', - }, - ], - } - } - - // Legacy welcome messages block - private getWelcomeBlock() { - return { - text: 'Try Examples:', - options: [ - { - pillText: 'Explain selected code', - prompt: 'Explain selected code', - type: 'init-prompt', - }, - { - pillText: 'How can Amazon Q help me?', - type: 'help', - }, - ], - } - } } diff --git a/chat-client/src/client/texts/pairProgramming.test.ts b/chat-client/src/client/texts/pairProgramming.test.ts index 3ffec1bcaf..8181f50c8b 100644 --- a/chat-client/src/client/texts/pairProgramming.test.ts +++ b/chat-client/src/client/texts/pairProgramming.test.ts @@ -1,14 +1,10 @@ import * as assert from 'assert' -import { ChatItemType, MynahIcons } from '@aws/mynah-ui' +import { ChatItemType } from '@aws/mynah-ui' import { programmerModeCard, pairProgrammingPromptInput, pairProgrammingModeOn, pairProgrammingModeOff, - testRerouteCard, - docRerouteCard, - devRerouteCard, - createRerouteCard, } from './pairProgramming' describe('pairProgramming', () => { @@ -56,67 +52,4 @@ describe('pairProgramming', () => { assert.equal(pairProgrammingModeOff.body, 'Agentic coding - OFF') }) }) - - describe('testRerouteCard', () => { - it('has correct properties', () => { - assert.equal(testRerouteCard.type, ChatItemType.ANSWER) - assert.equal(testRerouteCard.border, true) - assert.equal(testRerouteCard.header?.padding, true) - assert.equal(testRerouteCard.header?.iconForegroundStatus, 'warning') - assert.equal(testRerouteCard.header?.icon, MynahIcons.INFO) - assert.ok(testRerouteCard.header?.body?.includes('generate unit tests')) - assert.ok(testRerouteCard.body?.includes("You don't need to explicitly use /test")) - }) - }) - - describe('docRerouteCard', () => { - it('has correct properties', () => { - assert.equal(docRerouteCard.type, ChatItemType.ANSWER) - assert.equal(docRerouteCard.border, true) - assert.equal(docRerouteCard.header?.padding, true) - assert.equal(docRerouteCard.header?.iconForegroundStatus, 'warning') - assert.equal(docRerouteCard.header?.icon, MynahIcons.INFO) - assert.ok(docRerouteCard.header?.body?.includes('generate documentation')) - assert.ok(docRerouteCard.body?.includes("You don't need to explicitly use /doc")) - }) - }) - - describe('devRerouteCard', () => { - it('has correct properties', () => { - assert.equal(devRerouteCard.type, ChatItemType.ANSWER) - assert.equal(devRerouteCard.border, true) - assert.equal(devRerouteCard.header?.padding, true) - assert.equal(devRerouteCard.header?.iconForegroundStatus, 'warning') - assert.equal(devRerouteCard.header?.icon, MynahIcons.INFO) - assert.ok(devRerouteCard.header?.body?.includes('generate code')) - assert.ok(devRerouteCard.body?.includes("You don't need to explicitly use /dev")) - }) - }) - - describe('createRerouteCard', () => { - it('returns testRerouteCard for /test command', () => { - const result = createRerouteCard('/test') - assert.deepEqual(result, testRerouteCard) - }) - - it('returns docRerouteCard for /doc command', () => { - const result = createRerouteCard('/doc') - assert.deepEqual(result, docRerouteCard) - }) - - it('returns devRerouteCard for /dev command', () => { - const result = createRerouteCard('/dev') - assert.deepEqual(result, devRerouteCard) - }) - - it('returns devRerouteCard for unknown command', () => { - const result = createRerouteCard('/unknown') - assert.deepEqual(result, devRerouteCard) - }) - - it('returns devRerouteCard for empty string', () => { - const result = createRerouteCard('') - assert.deepEqual(result, devRerouteCard) - }) - }) }) diff --git a/chat-client/src/client/texts/pairProgramming.ts b/chat-client/src/client/texts/pairProgramming.ts index c93918317f..335a37069c 100644 --- a/chat-client/src/client/texts/pairProgramming.ts +++ b/chat-client/src/client/texts/pairProgramming.ts @@ -1,4 +1,4 @@ -import { ChatItem, ChatItemFormItem, ChatItemType, MynahIcons } from '@aws/mynah-ui' +import { ChatItem, ChatItemFormItem, ChatItemType } from '@aws/mynah-ui' export const programmerModeCard: ChatItem = { type: ChatItemType.ANSWER, @@ -36,76 +36,3 @@ export const pairProgrammingModeOff: ChatItem = { fullWidth: true, body: 'Agentic coding - OFF', } - -export const testRerouteCard: ChatItem = { - type: ChatItemType.ANSWER, - border: true, - header: { - padding: true, - iconForegroundStatus: 'warning', - icon: MynahIcons.INFO, - body: 'You can now ask to generate unit tests directly in the chat.', - }, - body: `You don't need to explicitly use /test. We've redirected your request to chat. -Ask me to do things like: -• Add unit tests for highlighted functions in my active file -• Generate tests for null and empty inputs in my project`, -} - -export const docRerouteCard: ChatItem = { - type: ChatItemType.ANSWER, - border: true, - header: { - padding: true, - iconForegroundStatus: 'warning', - icon: MynahIcons.INFO, - body: 'You can now ask to generate documentation directly in the chat.', - }, - body: `You don't need to explicitly use /doc. We've redirected your request to chat.`, -} - -export const devRerouteCard: ChatItem = { - type: ChatItemType.ANSWER, - border: true, - header: { - padding: true, - iconForegroundStatus: 'warning', - icon: MynahIcons.INFO, - body: 'You can now ask to generate code directly in the chat.', - }, - body: `You don't need to explicitly use /dev. We've redirected your request to chat. -Ask me to do things like: -1. Create a project -2. Add a feature -3. Modify your files`, -} - -export const reviewRerouteCard: ChatItem = { - type: ChatItemType.ANSWER, - border: true, - header: { - padding: true, - iconForegroundStatus: 'warning', - icon: MynahIcons.INFO, - body: 'You can now ask to run code reviews directly in the chat.', - }, - body: `You don't need to explicitly use /review. We've redirected your request to chat. -Ask me to do things like: -• Perform a code review of uncommitted changes in my active file -• Perform a code review of my active file`, -} - -export const createRerouteCard = (command: string): ChatItem => { - switch (command) { - case '/test': - return testRerouteCard - case '/doc': - return docRerouteCard - case '/dev': - return devRerouteCard - case '/review': - return reviewRerouteCard - default: - return devRerouteCard // Default fallback - } -} From 4d3b938b7e961def0db2a51fba57e8fe73ea0a01 Mon Sep 17 00:00:00 2001 From: Richard Li <742829+rli@users.noreply.github.com> Date: Mon, 15 Sep 2025 11:56:08 -0700 Subject: [PATCH 078/158] feat: support sending requests with the 'external_idp' type (#2247) --- package-lock.json | 6 +++--- .../AmazonQTokenServiceManager.ts | 15 ++++++++------- .../qDeveloperProfiles.test.ts | 2 +- .../amazonQServiceManager/qDeveloperProfiles.ts | 3 ++- .../src/shared/codeWhispererService.ts | 4 ++++ .../src/shared/streamingClientService.ts | 13 +++++++++++++ .../aws-lsp-codewhisperer/src/shared/testUtils.ts | 2 +- server/aws-lsp-codewhisperer/src/shared/utils.ts | 6 ++---- 8 files changed, 34 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index affc82b825..15b9c955b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4036,9 +4036,9 @@ "link": true }, "node_modules/@aws/language-server-runtimes": { - "version": "0.2.128", - "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.2.128.tgz", - "integrity": "sha512-C666VAvY2PQ8CQkDzjL/+N9rfcFzY6vuGe733drMwwRVHt8On0B0PQPjy31ZjxHUUcjVp78Nb9vmSUEVBfxGTQ==", + "version": "0.2.129", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.2.129.tgz", + "integrity": "sha512-ZTObivXrC04FIZHlRgL/E3Dx+hq4wFMOXCGTMHlVUiRs8FaXLXvENZbi0+5/I3Ex/CNwazQWgVaBHJ+dMw42nw==", "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes-types": "^0.1.56", diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts index df144e72d6..903a57c0fa 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts @@ -236,10 +236,11 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< this.features.lsp.getClientInitializeParams()?.initializationOptions?.aws?.awsClientCapabilities ?.textDocument?.inlineCompletionWithReferences?.endpointOverride - // Connection type changed to 'builderId' - - if (newConnectionType === 'builderId') { - this.log('Detected New connection type: builderId') + // Connection type changed to 'builderId' | 'external_idp' + // for now pretend External IdP is just a special case of Builder ID where the subscription has already been established + // and user does not need a profile + if (newConnectionType === 'builderId' || newConnectionType === 'external_idp') { + this.log(`Detected New connection type: ${newConnectionType}`) this.resetCodewhispererService() // For the builderId connection type regional endpoint discovery chain is: @@ -247,12 +248,12 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< const clientParams = this.features.lsp.getClientInitializeParams() this.createCodewhispererServiceInstances( - 'builderId', + newConnectionType, clientParams?.initializationOptions?.aws?.region, endpointOverride ) this.state = 'INITIALIZED' - this.log('Initialized Amazon Q service with builderId connection') + this.log(`Initialized Amazon Q service with ${newConnectionType} connection`) // Emit auth success event ProfileStatusMonitor.emitAuthSuccess() @@ -506,7 +507,7 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< } private createCodewhispererServiceInstances( - connectionType: 'builderId' | 'identityCenter', + connectionType: Exclude, clientOrProfileRegion: string | undefined, endpointOverride: string | undefined ) { diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.test.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.test.ts index 022b3dedfa..8bf938bfa4 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.test.ts @@ -1,11 +1,11 @@ import * as assert from 'assert' import sinon, { StubbedInstance, stubInterface } from 'ts-sinon' import { CodeWhispererServiceToken } from '../codeWhispererService' -import { SsoConnectionType } from '../utils' import { AWSInitializationOptions, CancellationTokenSource, Logging, + SsoConnectionType, } from '@aws/language-server-runtimes/server-interface' import { AmazonQDeveloperProfile, diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.ts index 47f5ec7c37..20354d4fdb 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.ts @@ -4,8 +4,9 @@ import { Logging, LSPErrorCodes, ResponseError, + SsoConnectionType, } from '@aws/language-server-runtimes/server-interface' -import { isBool, isObject, SsoConnectionType } from '../utils' +import { isBool, isObject } from '../utils' import { AWS_Q_ENDPOINTS } from '../../shared/constants' import { CodeWhispererServiceToken } from '../codeWhispererService' import { AmazonQServiceProfileThrottlingError } from './errors' diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index 1225e86435..ba02c9c4e9 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -344,6 +344,10 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { if (!creds?.token) { throw new Error('Authorization failed, bearer token is not set') } + if (credentialsProvider.getConnectionType() === 'external_idp') { + httpRequest.headers['TokenType'] = 'EXTERNAL_IDP' + } + httpRequest.headers['Authorization'] = `Bearer ${creds.token}` httpRequest.headers['x-amzn-codewhisperer-optout'] = `${!this.shareCodeWhispererContentWithAWS}` diff --git a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts index cc0ec57070..167f360f4c 100644 --- a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts @@ -88,6 +88,19 @@ export class StreamingClientServiceToken extends StreamingClientServiceBase { }), customUserAgent: customUserAgent, }) + + this.client.middlewareStack.add( + (next, context) => args => { + if (credentialsProvider.getConnectionType() === 'external_idp') { + // @ts-ignore + args.request.headers['TokenType'] = 'EXTERNAL_IDP' + } + return next(args) + }, + { + step: 'build', + } + ) } public async sendMessage( diff --git a/server/aws-lsp-codewhisperer/src/shared/testUtils.ts b/server/aws-lsp-codewhisperer/src/shared/testUtils.ts index 38d6e960cb..795cb465d4 100644 --- a/server/aws-lsp-codewhisperer/src/shared/testUtils.ts +++ b/server/aws-lsp-codewhisperer/src/shared/testUtils.ts @@ -1,11 +1,11 @@ import { TextDocument } from 'vscode-languageserver-textdocument' import { CodeWhispererServiceBase, ResponseContext, Suggestion } from './codeWhispererService' import { TestFeatures } from '@aws/language-server-runtimes/testing' -import { SsoConnectionType } from './utils' import { stubInterface } from 'ts-sinon' import { StreamingClientServiceBase } from './streamingClientService' import { SessionData } from '../language-server/inline-completion/session/sessionManager' import { WorkspaceFolder } from '@aws/language-server-runtimes/protocol' +import { SsoConnectionType } from '@aws/language-server-runtimes/server-interface' export const HELLO_WORLD_IN_CSHARP = `class HelloWorld { diff --git a/server/aws-lsp-codewhisperer/src/shared/utils.ts b/server/aws-lsp-codewhisperer/src/shared/utils.ts index af5cd14c28..9169be165f 100644 --- a/server/aws-lsp-codewhisperer/src/shared/utils.ts +++ b/server/aws-lsp-codewhisperer/src/shared/utils.ts @@ -3,6 +3,7 @@ import { BearerCredentials, CredentialsProvider, Position, + SsoConnectionType, } from '@aws/language-server-runtimes/server-interface' import { AWSError, Credentials } from 'aws-sdk' import { distance } from 'fastest-levenshtein' @@ -31,7 +32,6 @@ import { getAuthFollowUpType } from '../language-server/chat/utils' import ignore = require('ignore') import { InitializeParams } from '@aws/language-server-runtimes/server-interface' import { QClientCapabilities } from '../language-server/configuration/qConfigurationServer' -export type SsoConnectionType = 'builderId' | 'identityCenter' | 'none' export function isAwsError(error: unknown): error is AWSError { if (error === undefined) { @@ -436,9 +436,7 @@ export const flattenMetric = (obj: any, prefix = '') => { } export function getSsoConnectionType(credentialsProvider: CredentialsProvider): SsoConnectionType { - const connectionMetadata = credentialsProvider.getConnectionMetadata() - const startUrl = connectionMetadata?.sso?.startUrl - return !startUrl ? 'none' : startUrl.includes(BUILDER_ID_START_URL) ? 'builderId' : 'identityCenter' + return credentialsProvider.getConnectionType() } // Port of implementation in AWS Toolkit for VSCode From 2f6e86b0a676674744b962b0e335543c6c39e9e1 Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Mon, 15 Sep 2025 12:45:53 -0700 Subject: [PATCH 079/158] feat(amazonq): support for wildcard permissions from agent config (#2249) --- .../tools/mcp/agentPermissionManager.test.ts | 213 ++++++++++++++++++ .../tools/mcp/agentPermissionManager.ts | 211 +++++++++++++++++ .../agenticChat/tools/mcp/mcpManager.ts | 150 +----------- 3 files changed, 433 insertions(+), 141 deletions(-) create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.ts diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.test.ts new file mode 100644 index 0000000000..2c50dfcdc0 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.test.ts @@ -0,0 +1,213 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. + * All Rights Reserved. SPDX-License-Identifier: Apache-2.0 + */ + +import { expect } from 'chai' +import { AgentPermissionManager } from './agentPermissionManager' +import { AgentConfig, McpPermissionType } from './mcpTypes' + +describe('AgentPermissionManager', () => { + let agentConfig: AgentConfig + let manager: AgentPermissionManager + + beforeEach(() => { + agentConfig = { + name: 'test-agent', + description: 'Test agent', + mcpServers: {}, + tools: [], + allowedTools: [], + } + manager = new AgentPermissionManager(agentConfig) + }) + + describe('matchesPattern', () => { + it('matches exact patterns', () => { + expect(manager['matchesPattern']('tool1', 'tool1')).to.be.true + expect(manager['matchesPattern']('tool1', 'tool2')).to.be.false + }) + + it('matches wildcard patterns', () => { + expect(manager['matchesPattern']('tool1', '*')).to.be.true + expect(manager['matchesPattern']('tool1', 'tool*')).to.be.true + expect(manager['matchesPattern']('tool1', '*1')).to.be.true + expect(manager['matchesPattern']('tool1', 'to*l1')).to.be.true + expect(manager['matchesPattern']('tool1', 'foo*')).to.be.false + }) + + it('matches question mark patterns', () => { + expect(manager['matchesPattern']('tool1', 'tool?')).to.be.true + expect(manager['matchesPattern']('tool1', '?ool1')).to.be.true + expect(manager['matchesPattern']('tool1', 'tool??')).to.be.false + }) + + it('escapes regex special characters', () => { + expect(manager['matchesPattern']('tool.1', 'tool.1')).to.be.true + expect(manager['matchesPattern']('tool+1', 'tool+1')).to.be.true + expect(manager['matchesPattern']('tool[1]', 'tool[1]')).to.be.true + }) + }) + + describe('isToolEnabled', () => { + it('returns true for exact tool matches', () => { + agentConfig.tools = ['tool1', '@server/tool2'] + expect(manager.isToolEnabled('', 'tool1')).to.be.true + expect(manager.isToolEnabled('server', 'tool2')).to.be.true + }) + + it('returns true for server prefix matches', () => { + agentConfig.tools = ['@server'] + expect(manager.isToolEnabled('server', 'tool1')).to.be.true + }) + + it('returns true for wildcard matches', () => { + agentConfig.tools = ['*'] + expect(manager.isToolEnabled('server', 'tool1')).to.be.true + + agentConfig.tools = ['tool*'] + expect(manager.isToolEnabled('', 'tool1')).to.be.true + expect(manager.isToolEnabled('', 'foo1')).to.be.false + }) + + it('returns false for non-matching tools', () => { + agentConfig.tools = ['tool1'] + expect(manager.isToolEnabled('', 'tool2')).to.be.false + expect(manager.isToolEnabled('server', 'tool1')).to.be.false + }) + }) + + describe('isToolAlwaysAllowed', () => { + it('returns true for exact tool matches', () => { + agentConfig.allowedTools = ['tool1', '@server/tool2'] + expect(manager.isToolAlwaysAllowed('', 'tool1')).to.be.true + expect(manager.isToolAlwaysAllowed('server', 'tool2')).to.be.true + }) + + it('returns true for server prefix matches', () => { + agentConfig.allowedTools = ['@server'] + expect(manager.isToolAlwaysAllowed('server', 'tool1')).to.be.true + }) + + it('returns true for wildcard matches', () => { + agentConfig.allowedTools = ['tool*'] + expect(manager.isToolAlwaysAllowed('', 'tool1')).to.be.true + expect(manager.isToolAlwaysAllowed('', 'foo1')).to.be.false + }) + + it('returns false for non-matching tools', () => { + agentConfig.allowedTools = ['tool1'] + expect(manager.isToolAlwaysAllowed('', 'tool2')).to.be.false + }) + }) + + describe('getToolPermission', () => { + it('returns alwaysAllow for always allowed tools', () => { + agentConfig.allowedTools = ['tool1'] + expect(manager.getToolPermission('', 'tool1')).to.equal(McpPermissionType.alwaysAllow) + }) + + it('returns ask for enabled but not always allowed tools', () => { + agentConfig.tools = ['tool1'] + expect(manager.getToolPermission('', 'tool1')).to.equal(McpPermissionType.ask) + }) + + it('returns deny for non-enabled tools', () => { + expect(manager.getToolPermission('', 'tool1')).to.equal(McpPermissionType.deny) + }) + + it('prioritizes alwaysAllow over enabled', () => { + agentConfig.tools = ['tool1'] + agentConfig.allowedTools = ['tool1'] + expect(manager.getToolPermission('', 'tool1')).to.equal(McpPermissionType.alwaysAllow) + }) + }) + + describe('setToolPermission', () => { + it('sets deny permission correctly', () => { + agentConfig.tools = ['tool1'] + agentConfig.allowedTools = ['tool1'] + + manager.setToolPermission('', 'tool1', McpPermissionType.deny) + + expect(agentConfig.tools).to.not.include('tool1') + expect(agentConfig.allowedTools).to.not.include('tool1') + }) + + it('sets ask permission correctly', () => { + manager.setToolPermission('', 'tool1', McpPermissionType.ask) + + expect(agentConfig.tools).to.include('tool1') + expect(agentConfig.allowedTools).to.not.include('tool1') + }) + + it('sets alwaysAllow permission correctly', () => { + manager.setToolPermission('', 'tool1', McpPermissionType.alwaysAllow) + + expect(agentConfig.tools).to.include('tool1') + expect(agentConfig.allowedTools).to.include('tool1') + }) + + it('removes conflicting wildcards', () => { + agentConfig.tools = ['tool*'] + agentConfig.allowedTools = ['tool*'] + + manager.setToolPermission('', 'tool1', McpPermissionType.deny) + + expect(agentConfig.tools).to.not.include('tool*') + expect(agentConfig.allowedTools).to.not.include('tool*') + }) + + it('handles server-scoped tools', () => { + manager.setToolPermission('server', 'tool1', McpPermissionType.ask) + + expect(agentConfig.tools).to.include('@server/tool1') + }) + }) + + describe('setServerPermission', () => { + it('sets deny permission for entire server', () => { + agentConfig.tools = ['@server', '@server/tool1'] + agentConfig.allowedTools = ['@server/tool2'] + + manager.setServerPermission('server', McpPermissionType.deny) + + expect(agentConfig.tools).to.not.include('@server') + expect(agentConfig.tools).to.not.include('@server/tool1') + expect(agentConfig.allowedTools).to.not.include('@server/tool2') + }) + + it('sets ask permission for entire server', () => { + manager.setServerPermission('server', McpPermissionType.ask) + + expect(agentConfig.tools).to.include('@server') + expect(agentConfig.allowedTools).to.not.include('@server') + }) + + it('sets alwaysAllow permission for entire server', () => { + manager.setServerPermission('server', McpPermissionType.alwaysAllow) + + expect(agentConfig.tools).to.include('@server') + expect(agentConfig.allowedTools).to.include('@server') + }) + + it('removes specific tools when setting server permission', () => { + agentConfig.tools = ['@server/tool1', '@server/tool2'] + agentConfig.allowedTools = ['@server/tool3'] + + manager.setServerPermission('server', McpPermissionType.ask) + + expect(agentConfig.tools).to.not.include('@server/tool1') + expect(agentConfig.tools).to.not.include('@server/tool2') + expect(agentConfig.allowedTools).to.not.include('@server/tool3') + expect(agentConfig.tools).to.include('@server') + }) + }) + + describe('getAgentConfig', () => { + it('returns the current agent config', () => { + const config = manager.getAgentConfig() + expect(config).to.equal(agentConfig) + }) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.ts new file mode 100644 index 0000000000..143ffd0475 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.ts @@ -0,0 +1,211 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. + * All Rights Reserved. SPDX-License-Identifier: Apache-2.0 + */ + +import { AgentConfig, McpPermissionType } from './mcpTypes' + +/** + * Manages agent tool permissions with wildcard support for reading and simple patterns for writing + */ +export class AgentPermissionManager { + constructor(private agentConfig: AgentConfig) {} + + /** + * Check if a tool matches a pattern using glob-style wildcards + */ + private matchesPattern(toolName: string, pattern: string): boolean { + // Handle exact matches first + if (pattern === toolName) return true + + // Convert glob pattern to regex + // Escape special regex characters except * and ? + const regexPattern = pattern + .replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape regex special chars + .replace(/\*/g, '.*') // * matches any sequence + .replace(/\?/g, '.') // ? matches single character + + const regex = new RegExp(`^${regexPattern}$`) + return regex.test(toolName) + } + + /** + * Check if a tool is enabled (in tools array) + */ + isToolEnabled(serverName: string, toolName: string): boolean { + const toolId = serverName ? `@${serverName}/${toolName}` : toolName + const serverPrefix = serverName ? `@${serverName}` : '' + + // Check exact matches first + if (this.agentConfig.tools.includes(toolId)) return true + if (serverPrefix && this.agentConfig.tools.includes(serverPrefix)) return true + + // Check wildcard patterns + for (const tool of this.agentConfig.tools) { + if (tool.includes('*') || tool.includes('?')) { + if (this.matchesPattern(toolId, tool)) return true + } + } + + // Check for global wildcard + return this.agentConfig.tools.includes('*') + } + + /** + * Check if a tool is always allowed (in allowedTools array) + */ + isToolAlwaysAllowed(serverName: string, toolName: string): boolean { + const toolId = serverName ? `@${serverName}/${toolName}` : toolName + const serverPrefix = serverName ? `@${serverName}` : '' + + // Check exact matches first + if (this.agentConfig.allowedTools.includes(toolId)) return true + if (serverPrefix && this.agentConfig.allowedTools.includes(serverPrefix)) return true + + // Check wildcard patterns + for (const allowedTool of this.agentConfig.allowedTools) { + if (allowedTool.includes('*') || allowedTool.includes('?')) { + if (this.matchesPattern(toolId, allowedTool)) return true + } + } + + return false + } + + /** + * Get permission type for a tool + */ + getToolPermission(serverName: string, toolName: string): McpPermissionType { + const isEnabled = this.isToolEnabled(serverName, toolName) + const isAlwaysAllowed = this.isToolAlwaysAllowed(serverName, toolName) + + // If tool is always allowed, it's implicitly enabled + if (isAlwaysAllowed) { + return McpPermissionType.alwaysAllow + } + + // If tool is enabled but not always allowed, ask for permission + if (isEnabled) { + return McpPermissionType.ask + } + + // Tool is not enabled and not always allowed + return McpPermissionType.deny + } + + /** + * Set permission for a tool (uses simple patterns for writing) + */ + setToolPermission(serverName: string, toolName: string, permission: McpPermissionType): void { + const toolId = serverName ? `@${serverName}/${toolName}` : toolName + const serverPrefix = serverName ? `@${serverName}` : '' + + // Remove conflicting wildcards that would affect this tool + this.removeConflictingWildcards(toolId) + + switch (permission) { + case McpPermissionType.deny: + this.removeTool(toolId, serverPrefix) + this.removeFromAllowedTools(toolId, serverPrefix) + break + + case McpPermissionType.ask: + this.addTool(toolId) + this.removeFromAllowedTools(toolId, serverPrefix) + break + + case McpPermissionType.alwaysAllow: + this.addTool(toolId) + this.addToAllowedTools(toolId) + break + } + } + + /** + * Remove wildcards that would conflict with specific tool permission + */ + private removeConflictingWildcards(toolId: string): void { + // Remove wildcards from tools array that would match this tool + this.agentConfig.tools = this.agentConfig.tools.filter(tool => { + if (!tool.includes('*') && !tool.includes('?')) return true + return !this.matchesPattern(toolId, tool) + }) + + // Remove wildcards from allowedTools array that would match this tool + this.agentConfig.allowedTools = this.agentConfig.allowedTools.filter(tool => { + if (!tool.includes('*') && !tool.includes('?')) return true + return !this.matchesPattern(toolId, tool) + }) + } + + /** + * Add tool to tools array + */ + private addTool(toolId: string): void { + if (!this.agentConfig.tools.includes(toolId)) { + this.agentConfig.tools.push(toolId) + } + } + + /** + * Remove tool from tools array + */ + private removeTool(toolId: string, serverPrefix?: string): void { + this.agentConfig.tools = this.agentConfig.tools.filter(tool => tool !== toolId && tool !== serverPrefix) + } + + /** + * Add tool to allowedTools array + */ + private addToAllowedTools(toolId: string): void { + if (!this.agentConfig.allowedTools.includes(toolId)) { + this.agentConfig.allowedTools.push(toolId) + } + } + + /** + * Remove tool from allowedTools array + */ + private removeFromAllowedTools(toolId: string, serverPrefix?: string): void { + this.agentConfig.allowedTools = this.agentConfig.allowedTools.filter( + tool => tool !== toolId && tool !== serverPrefix + ) + } + + /** + * Set server-wide permission (uses @serverName pattern) + */ + setServerPermission(serverName: string, permission: McpPermissionType): void { + const serverPrefix = `@${serverName}` + + // Remove all specific tools from this server + this.agentConfig.tools = this.agentConfig.tools.filter(tool => !tool.startsWith(`${serverPrefix}/`)) + this.agentConfig.allowedTools = this.agentConfig.allowedTools.filter( + tool => !tool.startsWith(`${serverPrefix}/`) + ) + + switch (permission) { + case McpPermissionType.deny: + this.removeTool(serverPrefix, serverPrefix) + this.removeFromAllowedTools(serverPrefix, serverPrefix) + break + + case McpPermissionType.ask: + this.addTool(serverPrefix) + this.removeFromAllowedTools(serverPrefix, serverPrefix) + break + + case McpPermissionType.alwaysAllow: + this.addTool(serverPrefix) + this.addToAllowedTools(serverPrefix) + break + } + } + + /** + * Get updated agent config + */ + getAgentConfig(): AgentConfig { + return this.agentConfig + } +} diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index 351397b701..a6dd3eda7b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -40,6 +40,7 @@ import { URI } from 'vscode-uri' import { sanitizeInput } from '../../../../shared/utils' import { ProfileStatusMonitor } from './profileStatusMonitor' import { OAuthClient } from './mcpOauthClient' +import { AgentPermissionManager } from './agentPermissionManager' export const MCP_SERVER_STATUS_CHANGED = 'mcpServerStatusChanged' export const AGENT_TOOLS_CHANGED = 'agentToolsChanged' @@ -65,6 +66,7 @@ export class McpManager { private toolNameMapping: Map private serverNameMapping: Map private agentConfig!: AgentConfig + private permissionManager!: AgentPermissionManager private constructor( private agentPaths: string[], @@ -177,6 +179,7 @@ export class McpManager { // Extract agent config and other data this.agentConfig = result.agentConfig + this.permissionManager = new AgentPermissionManager(this.agentConfig) this.mcpServers = result.servers this.serverNameMapping = result.serverNameMapping @@ -539,22 +542,7 @@ export class McpManager { // Get unsanitized server name for prefix const unsanitizedServerName = this.serverNameMapping.get(server) || server - - // Check if the server is enabled as a whole (@server) - const serverPrefix = `@${unsanitizedServerName}` - const isWholeServerEnabled = this.agentConfig.tools.includes(serverPrefix) - - // Check if the specific tool is enabled - const toolId = `${serverPrefix}/${tool}` - const isSpecificToolEnabled = this.agentConfig.tools.includes(toolId) - - // If server is enabled as a whole, all tools are enabled - if (isWholeServerEnabled) { - return false - } - - // Otherwise, check if this specific tool is enabled - return !isSpecificToolEnabled + return !this.permissionManager.isToolEnabled(server === 'builtIn' ? 'builtIn' : unsanitizedServerName, tool) } /** @@ -569,42 +557,8 @@ export class McpManager { * Returns tool permission type for a given tool. */ public getToolPerm(server: string, tool: string): McpPermissionType { - // For built-in tools, check directly without prefix - if (server === 'builtIn') { - return this.agentConfig.allowedTools.includes(tool) ? McpPermissionType.alwaysAllow : McpPermissionType.ask - } - - // Get unsanitized server name for prefix const unsanitizedServerName = this.serverNameMapping.get(server) || server - - // Check if the server is enabled as a whole (@server) - const serverPrefix = `@${unsanitizedServerName}` - const isWholeServerEnabled = this.agentConfig.tools.includes(serverPrefix) - - // Check if the specific tool is enabled - const toolId = `${serverPrefix}/${tool}` - const isSpecificToolEnabled = this.agentConfig.tools.includes(toolId) - - // If the tool is not enabled, return deny - if (!isWholeServerEnabled && !isSpecificToolEnabled) { - return McpPermissionType.deny - } - - // If server is enabled as a whole, check if the server itself is in allowedTools - if (isWholeServerEnabled) { - // If server is in allowedTools, all tools are alwaysAllow - if (this.agentConfig.allowedTools.includes(serverPrefix)) { - return McpPermissionType.alwaysAllow - } - - // Otherwise, check if specific tool is in allowedTools - return this.agentConfig.allowedTools.includes(toolId) - ? McpPermissionType.alwaysAllow - : McpPermissionType.ask - } - - // For specific tools, check if it's in allowedTools - return this.agentConfig.allowedTools.includes(toolId) ? McpPermissionType.alwaysAllow : McpPermissionType.ask + return this.permissionManager.getToolPermission(server === 'builtIn' ? 'builtIn' : unsanitizedServerName, tool) } /** @@ -1005,99 +959,13 @@ export class McpManager { const serverPrefix = `@${unsanitizedServerName}` - // Track tools that should be enabled - const toolsToEnable = new Set() - const toolsToAlwaysAllow = new Set() - - // Check if server is enabled as a whole - const isWholeServerEnabled = this.agentConfig.tools.includes(serverPrefix) - - // Process each tool permission + // Process each tool permission using the permission manager for (const [toolName, permission] of Object.entries(perm.toolPerms || {})) { - const toolId = `${serverPrefix}/${toolName}` - - if (permission === McpPermissionType.deny) { - // For deny: if server is enabled as a whole, we need to switch to individual tools - if (isWholeServerEnabled) { - // Get all tools for this server - const serverTools = this.mcpTools.filter(t => t.serverName === serverName) - - // Remove server prefix from tools - this.agentConfig.tools = this.agentConfig.tools.filter(t => t !== serverPrefix) - - // Add all tools except the denied one - for (const t of serverTools) { - if (t.toolName !== toolName) { - const tid = `${serverPrefix}/${t.toolName}` - if (!this.agentConfig.tools.includes(tid)) { - this.agentConfig.tools.push(tid) - } - toolsToEnable.add(tid) - } - } - } else { - // Just remove the specific tool - this.agentConfig.tools = this.agentConfig.tools.filter(t => t !== toolId) - } - - // Always remove from allowedTools - this.agentConfig.allowedTools = this.agentConfig.allowedTools.filter(t => t !== toolId) - } else { - // For ask or alwaysAllow: add to tools - toolsToEnable.add(toolId) - - // For alwaysAllow: also add to allowedTools - if (permission === McpPermissionType.alwaysAllow) { - toolsToAlwaysAllow.add(toolId) - } else { - // For ask: remove from allowedTools if present - this.agentConfig.allowedTools = this.agentConfig.allowedTools.filter(t => t !== toolId) - } - } - } - - // If all tools are enabled, use @serverName instead of individual tools - const allTools = this.mcpTools.filter(t => t.serverName === serverName).map(t => t.toolName) - - // Check if all tools are enabled, considering both: - // 1. The server might already be enabled as a whole (isWholeServerEnabled) - // 2. All tools might be individually enabled in toolsToEnable - const allToolsEnabled = - allTools.length > 0 && - // If server is already enabled as a whole and no tools are being denied - ((isWholeServerEnabled && !Object.values(perm.toolPerms || {}).includes(McpPermissionType.deny)) || - // Or if all tools are individually enabled - allTools.every( - toolName => - toolsToEnable.has(`${serverPrefix}/${toolName}`) || - !Object.keys(perm.toolPerms || {}).includes(toolName) - )) - - // Update tools list - if (allToolsEnabled) { - // Remove individual tool entries - this.agentConfig.tools = this.agentConfig.tools.filter(t => !t.startsWith(`${serverPrefix}/`)) - // Add server prefix if not already there - if (!this.agentConfig.tools.includes(serverPrefix)) { - this.agentConfig.tools.push(serverPrefix) - } - } else { - // Remove server prefix if present - this.agentConfig.tools = this.agentConfig.tools.filter(t => t !== serverPrefix) - // Add individual tools - for (const toolId of toolsToEnable) { - if (!this.agentConfig.tools.includes(toolId)) { - this.agentConfig.tools.push(toolId) - } - } + this.permissionManager.setToolPermission(unsanitizedServerName, toolName, permission) } - // Update allowedTools list - for (const toolId of toolsToAlwaysAllow) { - if (!this.agentConfig.allowedTools.includes(toolId)) { - this.agentConfig.allowedTools.push(toolId) - } - } + // Update the agent config from the permission manager + this.agentConfig = this.permissionManager.getAgentConfig() // Update mcpServerPermissions map immediately to reflect changes this.mcpServerPermissions.set(serverName, { From 8eb3c340534f3c66fd9082a83b31e84a4d9348bb Mon Sep 17 00:00:00 2001 From: liumofei-amazon <98127670+liumofei-amazon@users.noreply.github.com> Date: Mon, 15 Sep 2025 16:59:34 -0700 Subject: [PATCH 080/158] feat(amazonq): semantic search tool integration (#2283) --- .../agenticChat/agenticChatController.ts | 70 +++- .../workspaceContext/semanticSearch.test.ts | 345 ++++++++++++++++++ .../tools/workspaceContext/semanticSearch.ts | 130 +++++++ .../language-server/workspaceContext/util.ts | 7 + .../workspaceContextServer.ts | 57 +-- .../workspaceFolderManager.test.ts | 280 +++++++++++++- .../workspaceFolderManager.ts | 48 ++- 7 files changed, 902 insertions(+), 35 deletions(-) create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/workspaceContext/semanticSearch.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/workspaceContext/semanticSearch.ts diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 89e4539029..23c726f364 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -230,6 +230,7 @@ import { DisplayFindings } from './tools/qCodeAnalysis/displayFindings' import { IDE } from '../../shared/constants' import { IdleWorkspaceManager } from '../workspaceContext/IdleWorkspaceManager' import escapeHTML = require('escape-html') +import { SemanticSearch } from './tools/workspaceContext/semanticSearch' type ChatHandlers = Omit< LspHandlers, @@ -1906,7 +1907,9 @@ export class AgenticChatController implements ChatHandlers { } case CodeReview.toolName: case DisplayFindings.toolName: - // no need to write tool message for CodeReview or DisplayFindings + // no need to write tool message for CodeReview or DisplayFindings + case SemanticSearch.toolName: + // For internal A/B we don't need tool message break // — DEFAULT ⇒ Only MCP tools, but can also handle generic tool execution messages default: @@ -2123,6 +2126,9 @@ export class AgenticChatController implements ChatHandlers { }) } break + case SemanticSearch.toolName: + await this.#handleSemanticSearchToolResult(toolUse, result, session, chatResultStream) + break // — DEFAULT ⇒ MCP tools default: await this.#handleMcpToolResult(toolUse, result, session, chatResultStream) @@ -4648,6 +4654,64 @@ export class AgenticChatController implements ChatHandlers { }) } + async #handleSemanticSearchToolResult( + toolUse: ToolUse, + result: any, + session: ChatSessionService, + chatResultStream: AgenticChatResultStream + ): Promise { + // Early return if toolUseId is undefined + if (!toolUse.toolUseId) { + this.#log(`Cannot handle semantic search tool result: missing toolUseId`) + return + } + + // Format the tool result and input as JSON strings + const toolInput = JSON.stringify(toolUse.input, null, 2) + const toolResultContent = typeof result === 'string' ? result : JSON.stringify(result, null, 2) + + const toolResultCard: ChatMessage = { + type: 'tool', + messageId: toolUse.toolUseId, + summary: { + content: { + header: { + icon: 'tools', + body: `${SemanticSearch.toolName}`, + fileList: undefined, + }, + }, + collapsedContent: [ + { + header: { + body: 'Parameters', + }, + body: `\`\`\`json\n${toolInput}\n\`\`\``, + }, + { + header: { + body: 'Result', + }, + body: `\`\`\`json\n${toolResultContent}\n\`\`\``, + }, + ], + }, + } + + // Get the stored blockId for this tool use + const cachedToolUse = session.toolUseLookup.get(toolUse.toolUseId) + const cachedButtonBlockId = (cachedToolUse as any)?.cachedButtonBlockId + + if (cachedButtonBlockId !== undefined) { + // Update the existing card with the results + await chatResultStream.overwriteResultBlock(toolResultCard, cachedButtonBlockId) + } else { + // Fallback to creating a new card + this.#log(`Warning: No blockId found for tool use ${toolUse.toolUseId}, creating new card`) + await chatResultStream.writeResultBlock(toolResultCard) + } + } + scheduleABTestingFetching(userContext: UserContext | undefined) { if (!userContext) { return @@ -4671,8 +4735,8 @@ export class AgenticChatController implements ChatHandlers { codeWhispererServiceToken .listFeatureEvaluations({ userContext }) .then(result => { - const feature = result.featureEvaluations?.find( - feature => feature.feature === 'MaestroWorkspaceContext' + const feature = result.featureEvaluations?.find(feature => + ['MaestroWorkspaceContext', 'SematicSearchTool'].includes(feature.feature) ) if (feature) { this.#abTestingAllocation = { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/workspaceContext/semanticSearch.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/workspaceContext/semanticSearch.test.ts new file mode 100644 index 0000000000..b785f5f6d2 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/workspaceContext/semanticSearch.test.ts @@ -0,0 +1,345 @@ +import * as assert from 'assert' +import * as sinon from 'sinon' +import axios from 'axios' +import { SemanticSearch, SemanticSearchParams, CodeChunkResult } from './semanticSearch' +import { TestFeatures } from '@aws/language-server-runtimes/testing' +import { BearerCredentials } from '@aws/language-server-runtimes/server-interface' +import { WorkspaceFolderManager } from '../../../workspaceContext/workspaceFolderManager' + +describe('SemanticSearch Tool', () => { + let features: TestFeatures + let semanticSearch: SemanticSearch + let axiosPostStub: sinon.SinonStub + let workspaceFolderManagerStub: sinon.SinonStub + let mockCredentialsProvider: any + let mockWorkspaceState: any + + beforeEach(() => { + features = new TestFeatures() + + // Mock credentials provider + mockCredentialsProvider = { + getCredentials: sinon.stub().returns({ + token: 'mock-bearer-token', + } as BearerCredentials), + } + + // Mock workspace state + mockWorkspaceState = { + webSocketClient: { + isConnected: sinon.stub().returns(true), + }, + environmentId: 'test-env-123', + workspaceId: 'test-workspace-456', + } + + // Stub WorkspaceFolderManager.getInstance() + workspaceFolderManagerStub = sinon.stub(WorkspaceFolderManager, 'getInstance').returns({ + getWorkspaceState: () => mockWorkspaceState, + } as any) + + // Stub axios.post + axiosPostStub = sinon.stub(axios, 'post') + + semanticSearch = new SemanticSearch(features.logging, mockCredentialsProvider, 'us-east-1') + }) + + afterEach(() => { + sinon.restore() + }) + + describe('validation', () => { + it('should reject empty query', () => { + assert.throws( + () => semanticSearch.validate({ query: '' }), + /Semantic search query cannot be empty/i, + 'Expected an error for empty query' + ) + }) + + it('should reject whitespace-only query', () => { + assert.throws( + () => semanticSearch.validate({ query: ' \t\n ' }), + /Semantic search query cannot be empty/i, + 'Expected an error for whitespace-only query' + ) + }) + + it('should accept valid query', () => { + assert.doesNotThrow( + () => semanticSearch.validate({ query: 'valid search query' }), + 'Should accept valid query' + ) + }) + + it('should accept query with programming language', () => { + assert.doesNotThrow( + () => semanticSearch.validate({ query: 'test', programmingLanguage: 'typescript' }), + 'Should accept query with programming language' + ) + }) + }) + + describe('error handling', () => { + it('should throw error when bearer token is missing', async () => { + mockCredentialsProvider.getCredentials.returns({ token: null }) + + await assert.rejects( + semanticSearch.invoke({ query: 'test query' }), + /Authorization failed, bearer token is not set/i, + 'Expected error when bearer token is missing' + ) + }) + + it('should throw error when workspace is not connected', async () => { + mockWorkspaceState.webSocketClient.isConnected.returns(false) + + await assert.rejects( + semanticSearch.invoke({ query: 'test query' }), + /Remote workspace is not ready yet/i, + 'Expected error when workspace is not connected' + ) + }) + + it('should throw error when environmentId is missing', async () => { + mockWorkspaceState.environmentId = null + + await assert.rejects( + semanticSearch.invoke({ query: 'test query' }), + /Remote workspace is not ready yet/i, + 'Expected error when environmentId is missing' + ) + }) + + it('should throw error when WorkspaceFolderManager instance is null', async () => { + workspaceFolderManagerStub.returns(null) + + await assert.rejects( + semanticSearch.invoke({ query: 'test query' }), + /Remote workspace is not ready yet/i, + 'Expected error when WorkspaceFolderManager instance is null' + ) + }) + + it('should handle axios network errors', async () => { + axiosPostStub.rejects(new Error('Network error')) + + await assert.rejects( + semanticSearch.invoke({ query: 'test query' }), + /Network error/i, + 'Expected network error to be propagated' + ) + }) + }) + + describe('successful invocation', () => { + const mockSemanticResults: CodeChunkResult[] = [ + { + fileUri: '/workspace/src/main.ts', + content: 'function main() { console.log("Hello World"); }', + score: 0.95, + }, + { + fileUri: 'file:///workspace/src/utils.js', + content: 'export function helper() { return true; }', + score: 0.87, + }, + { + fileUri: 'workspace/src/config.json', + content: '{ "name": "test-project" }', + score: 0.72, + }, + ] + + beforeEach(() => { + axiosPostStub.resolves({ + data: { + contextResult: { + documentContext: { + queryOutputMap: { + SEMANTIC: mockSemanticResults, + }, + }, + }, + }, + }) + }) + + it('should perform semantic search with basic query', async () => { + const result = await semanticSearch.invoke({ query: 'test function' }) + + // Verify axios was called with correct parameters + assert.ok(axiosPostStub.calledOnce, 'axios.post should be called once') + + const [url, requestBody, config] = axiosPostStub.firstCall.args + assert.strictEqual(url, 'https://test-env-123--8080.wc.q.us-east-1.amazonaws.com/getWorkspaceContext') + assert.strictEqual(requestBody.workspaceId, 'test-workspace-456') + assert.strictEqual(requestBody.contextParams.documentContextParams.query, 'test function') + assert.strictEqual(config.headers.Authorization, 'Bearer mock-bearer-token') + + // Verify result structure + assert.strictEqual(result.output.kind, 'json') + const content = result.output.content as any[] + assert.strictEqual(content.length, 3) + }) + + it('should include programming language filter when specified', async () => { + await semanticSearch.invoke({ + query: 'test function', + programmingLanguage: 'typescript', + }) + + const [, requestBody] = axiosPostStub.firstCall.args + const queryConfig = requestBody.contextParams.documentContextParams.queryConfigurationMap.SEMANTIC + assert.strictEqual(queryConfig.programmingLanguage, 'typescript') + }) + + it('should not include programming language when not specified', async () => { + await semanticSearch.invoke({ query: 'test function' }) + + const [, requestBody] = axiosPostStub.firstCall.args + const queryConfig = requestBody.contextParams.documentContextParams.queryConfigurationMap.SEMANTIC + assert.ok(!('programmingLanguage' in queryConfig)) + }) + + it('should normalize file URIs correctly', async () => { + const result = await semanticSearch.invoke({ query: 'test' }) + const content = result.output.content as any[] + + // Check URI normalization + assert.strictEqual(content[0].fileUri, 'file:///workspace/src/main.ts') + assert.strictEqual(content[1].fileUri, 'file:///workspace/src/utils.js') // Already has file:// + assert.strictEqual(content[2].fileUri, 'file:///workspace/src/config.json') + }) + + it('should include similarity scores when available', async () => { + const result = await semanticSearch.invoke({ query: 'test' }) + const content = result.output.content as any[] + + assert.strictEqual(content[0].similarityScore, 0.95) + assert.strictEqual(content[1].similarityScore, 0.87) + assert.strictEqual(content[2].similarityScore, 0.72) + }) + + it('should handle results without scores', async () => { + const resultsWithoutScores: CodeChunkResult[] = [ + { + fileUri: '/workspace/test.js', + content: 'test content', + // No score property + }, + ] + + axiosPostStub.resolves({ + data: { + contextResult: { + documentContext: { + queryOutputMap: { + SEMANTIC: resultsWithoutScores, + }, + }, + }, + }, + }) + + const result = await semanticSearch.invoke({ query: 'test' }) + const content = result.output.content as any[] + + assert.strictEqual(content.length, 1) + assert.strictEqual(content[0].fileUri, 'file:///workspace/test.js') + assert.strictEqual(content[0].content, 'test content') + assert.ok(!('similarityScore' in content[0])) + }) + + it('should handle empty search results', async () => { + axiosPostStub.resolves({ + data: { + contextResult: { + documentContext: { + queryOutputMap: { + SEMANTIC: [], + }, + }, + }, + }, + }) + + const result = await semanticSearch.invoke({ query: 'nonexistent' }) + const content = result.output.content as any[] + + assert.strictEqual(content.length, 0) + }) + + it('should handle missing semantic results', async () => { + axiosPostStub.resolves({ + data: { + contextResult: { + documentContext: { + queryOutputMap: { + SEMANTIC: undefined, + }, + }, + }, + }, + }) + + const result = await semanticSearch.invoke({ query: 'test' }) + const content = result.output.content as any[] + + assert.strictEqual(content.length, 0) + }) + + it('should handle malformed response structure', async () => { + axiosPostStub.resolves({ + data: { + // Missing expected structure + }, + }) + + const result = await semanticSearch.invoke({ query: 'test' }) + const content = result.output.content as any[] + + assert.strictEqual(content.length, 0) + }) + }) + + describe('getSpec', () => { + it('should return correct tool specification', () => { + const spec = semanticSearch.getSpec() + + assert.strictEqual(spec.name, 'semanticSearch') + assert.ok(spec.description.includes('semantic search')) + assert.strictEqual(spec.inputSchema.type, 'object') + assert.ok('query' in spec.inputSchema.properties) + assert.ok('programmingLanguage' in spec.inputSchema.properties) + assert.deepStrictEqual(spec.inputSchema.required, ['query']) + }) + + it('should have correct programming language enum values', () => { + const spec = semanticSearch.getSpec() + const langProperty = spec.inputSchema.properties.programmingLanguage as any + + assert.deepStrictEqual(langProperty.enum, ['java', 'python', 'javascript', 'typescript']) + }) + }) + + describe('constructor', () => { + it('should construct with correct endpoint suffix', () => { + const search1 = new SemanticSearch(features.logging, mockCredentialsProvider, 'us-west-2') + const search2 = new SemanticSearch(features.logging, mockCredentialsProvider, 'eu-west-1') + + // We can't directly test the private property, but we can test the behavior + // by mocking a call and checking the URL + axiosPostStub.resolves({ + data: { contextResult: { documentContext: { queryOutputMap: { SEMANTIC: [] } } } }, + }) + + // Test us-west-2 + search1.invoke({ query: 'test' }).catch(() => {}) // Ignore validation errors + // Test eu-west-1 + search2.invoke({ query: 'test' }).catch(() => {}) // Ignore validation errors + + // The endpoint construction is tested indirectly through the invoke method tests above + }) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/workspaceContext/semanticSearch.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/workspaceContext/semanticSearch.ts new file mode 100644 index 0000000000..898a6ddf56 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/workspaceContext/semanticSearch.ts @@ -0,0 +1,130 @@ +import { InvokeOutput } from '../toolShared' +import { BearerCredentials, CredentialsProvider, Logging } from '@aws/language-server-runtimes/server-interface' +import { WorkspaceFolderManager } from '../../../workspaceContext/workspaceFolderManager' +import { normalizeFileUri } from '../../../workspaceContext/util' +import axios from 'axios' + +export interface SemanticSearchParams { + query: string + programmingLanguage?: 'java' | 'python' | 'javascript' | 'typescript' +} + +export interface CodeChunkResult { + fileUri: string + content: string + score?: number +} + +export class SemanticSearch { + static readonly toolName = 'semanticSearch' + + private readonly logging: Logging + private readonly credentialsProvider: CredentialsProvider + private readonly remoteEndpointSuffix: string + constructor(logging: Logging, credentialsProvider: CredentialsProvider, region: string) { + this.logging = logging + this.credentialsProvider = credentialsProvider + this.remoteEndpointSuffix = `--8080.wc.q.${region}.amazonaws.com` + } + + public validate(params: SemanticSearchParams) { + if (!params.query || params.query.trim().length === 0) { + throw new Error('Semantic search query cannot be empty.') + } + } + + public async invoke(params: SemanticSearchParams): Promise { + const creds = this.credentialsProvider.getCredentials('bearer') as BearerCredentials + if (!creds?.token) { + throw new Error('Authorization failed, bearer token is not set') + } + + const remoteWorkspaceState = WorkspaceFolderManager.getInstance()?.getWorkspaceState() + if (!remoteWorkspaceState?.webSocketClient?.isConnected() || !remoteWorkspaceState.environmentId) { + throw new Error('Remote workspace is not ready yet.') + } + + const environmentId = remoteWorkspaceState.environmentId + const endpoint = `https://${environmentId}${this.remoteEndpointSuffix}/getWorkspaceContext` + const response = await axios.post( + endpoint, + { + workspaceId: remoteWorkspaceState.workspaceId, + contextParams: { + documentContextParams: { + query: params.query, + queryConfigurationMap: { + SEMANTIC: { + maxResult: 15, + includeDependencies: false, + ...(params.programmingLanguage && { programmingLanguage: params.programmingLanguage }), + }, + }, + }, + }, + }, + { + headers: { + Authorization: `Bearer ${creds.token}`, + }, + } + ) + + return this.createOutput(response.data.contextResult?.documentContext?.queryOutputMap?.SEMANTIC) + } + + private createOutput(semanticSearchResult: CodeChunkResult[] | undefined): InvokeOutput { + const filteredResults = + semanticSearchResult?.map(result => { + return { + fileUri: normalizeFileUri(result.fileUri), + content: result.content, + ...(result.score !== undefined && { similarityScore: result.score }), + } + }) || [] + + return { + output: { + kind: 'json', + content: filteredResults, + }, + } + } + + public getSpec() { + return { + name: SemanticSearch.toolName, + description: + 'A tool for finding semantically relevant code snippets in a codebase.\n\n' + + '## Overview\n' + + 'This is a semantic search tool that understands the intent and context behind queries, helping you find code snippets most relevant to your search.\n\n' + + '## When to use\n' + + '- When you need to locate specific functionality in a codebase\n' + + '- When looking for implementation patterns related to certain concepts\n' + + '- When you want to understand how particular features are coded\n' + + '- When exploring unfamiliar codebases to find relevant sections\n\n' + + '## When not to use\n' + + '- When you already know the exact file location\n\n' + + '## Notes\n' + + '- Before searching, identify the essential concepts and atomic information units in the query\n' + + '- For complex questions, break down the query into core components or key facts to improve search relevance\n' + + "- Unless there is a clear reason to modify the search query, extract the key concepts using the user's original wording\n" + + "- The user's exact phrasing often contains critical contextual cues that enhance semantic matching\n", + inputSchema: { + type: 'object' as const, + properties: { + query: { + type: 'string' as const, + description: 'The search query to find relevant code snippets.', + }, + programmingLanguage: { + type: 'string' as const, + enum: ['java', 'python', 'javascript', 'typescript'], + description: 'Optional programming language to filter search results.', + }, + }, + required: ['query'] as const, + }, + } + } +} diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/util.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/util.ts index c4a3e5446e..21d6d41397 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/util.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/util.ts @@ -29,6 +29,13 @@ export const findWorkspaceRootFolder = ( return matchingFolder } +/** + * Helper function to normalize relative path e.g : src/java/test.java to file:///src/java/test/java for workspace context + */ +export const normalizeFileUri = (fileUri: string): string => { + return fileUri.startsWith('file://') ? fileUri : `file://${fileUri.startsWith('/') ? fileUri : '/' + fileUri}` +} + export const cleanUrl = (s3Url: string): string => { return new URL(s3Url).origin + new URL(s3Url).pathname } diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts index 92dc0823e3..62119088da 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceContextServer.ts @@ -35,7 +35,7 @@ function shouldIgnoreFile(workspaceFolder: WorkspaceFolder, fileUri: string): bo } export const WorkspaceContextServer = (): Server => features => { - const { credentialsProvider, workspace, logging, lsp, runtime, sdkInitializator } = features + const { agent, credentialsProvider, workspace, logging, lsp, runtime, sdkInitializator } = features let workspaceIdentifier: string = '' let workspaceFolders: WorkspaceFolder[] = [] @@ -50,6 +50,7 @@ export const WorkspaceContextServer = (): Server => features => { let isOptedIn: boolean = false let abTestingEvaluated = false let abTestingEnabled = false + let semanticSearchAbTestingEnabled = false let amazonQServiceManager: AmazonQTokenServiceManager let allowedExtension: string[] = ['AmazonQ-For-VSCode', 'Amazon Q For JetBrains'] let isSupportedExtension = false @@ -182,36 +183,38 @@ export const WorkspaceContextServer = (): Server => features => { } try { + const clientParams = safeGet(lsp.getClientInitializeParams()) + const userContext = makeUserContextObject( + clientParams, + runtime.platform, + 'CodeWhisperer', + amazonQServiceManager.serverInfo + ) ?? { + ideCategory: 'VSCODE', + operatingSystem: 'MAC', + product: 'CodeWhisperer', + } + const result = await amazonQServiceManager.getCodewhispererService().listFeatureEvaluations({ userContext }) + result.featureEvaluations?.forEach(feature => { + logging.log(`A/B Cohort Assignment feature: ${feature.feature} - variation: ${feature.variation}`) + }) + abTestingEnabled = + result.featureEvaluations?.some( + feature => + feature.feature === 'BuilderIdServiceSideProjectContext' && feature.variation === 'TREATMENT' + ) ?? false + semanticSearchAbTestingEnabled = + result.featureEvaluations?.some( + feature => feature.feature === 'SematicSearchTool' && feature.variation === 'TREATMENT' + ) ?? false const startUrl = credentialsProvider.getConnectionMetadata()?.sso?.startUrl if (startUrl && startUrl.includes(INTERNAL_USER_START_URL)) { // Overriding abTestingEnabled to true for all internal users abTestingEnabled = true - } else { - const clientParams = safeGet(lsp.getClientInitializeParams()) - const userContext = makeUserContextObject( - clientParams, - runtime.platform, - 'CodeWhisperer', - amazonQServiceManager.serverInfo - ) ?? { - ideCategory: 'VSCODE', - operatingSystem: 'MAC', - product: 'CodeWhisperer', - } - - const result = await amazonQServiceManager - .getCodewhispererService() - .listFeatureEvaluations({ userContext }) - logging.log(`${JSON.stringify(result)}`) - abTestingEnabled = - result.featureEvaluations?.some( - feature => - feature.feature === 'BuilderIdServiceSideProjectContext' && - feature.variation === 'TREATMENT' - ) ?? false } - - logging.info(`A/B testing enabled: ${abTestingEnabled}`) + logging.info( + `A/B testing enabled: ${abTestingEnabled} semantic search enabled ${semanticSearchAbTestingEnabled}` + ) abTestingEvaluated = true } catch (error: any) { logging.error(`Error while checking A/B status: ${error.code}`) @@ -241,6 +244,7 @@ export const WorkspaceContextServer = (): Server => features => { artifactManager = new ArtifactManager(workspace, logging, workspaceFolders) dependencyDiscoverer = new DependencyDiscoverer(workspace, logging, workspaceFolders, artifactManager) workspaceFolderManager = WorkspaceFolderManager.createInstance( + agent, amazonQServiceManager, logging, artifactManager, @@ -307,6 +311,7 @@ export const WorkspaceContextServer = (): Server => features => { await evaluateABTesting() isWorkflowInitialized = true + workspaceFolderManager.setSemanticSearchToolStatus(semanticSearchAbTestingEnabled) workspaceFolderManager.resetAdminOptOutAndFeatureDisabledStatus() if (!isUserEligibleForWorkspaceContext()) { diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts index cbdb71db1d..e9f252d7a6 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts @@ -1,7 +1,7 @@ import { WorkspaceFolderManager } from './workspaceFolderManager' import sinon, { stubInterface, StubbedInstance } from 'ts-sinon' import { AmazonQTokenServiceManager } from '../../shared/amazonQServiceManager/AmazonQTokenServiceManager' -import { CredentialsProvider, Logging } from '@aws/language-server-runtimes/server-interface' +import { Agent, CredentialsProvider, Logging, ToolClassification } from '@aws/language-server-runtimes/server-interface' import { DependencyDiscoverer } from './dependency/dependencyDiscoverer' import { WorkspaceFolder } from 'vscode-languageserver-protocol' import { ArtifactManager } from './artifactManager' @@ -9,8 +9,10 @@ import { CodeWhispererServiceToken } from '../../shared/codeWhispererService' import { ListWorkspaceMetadataResponse } from '../../client/token/codewhispererbearertokenclient' import { IdleWorkspaceManager } from './IdleWorkspaceManager' import { AWSError } from 'aws-sdk' +import { SemanticSearch } from '../agenticChat/tools/workspaceContext/semanticSearch' describe('WorkspaceFolderManager', () => { + let mockAgent: StubbedInstance let mockServiceManager: StubbedInstance let mockLogging: StubbedInstance let mockCredentialsProvider: StubbedInstance @@ -20,6 +22,7 @@ describe('WorkspaceFolderManager', () => { let workspaceFolderManager: WorkspaceFolderManager beforeEach(() => { + mockAgent = stubInterface() mockServiceManager = stubInterface() mockLogging = stubInterface() mockCredentialsProvider = stubInterface() @@ -61,6 +64,7 @@ describe('WorkspaceFolderManager', () => { // Create the WorkspaceFolderManager instance using the static createInstance method workspaceFolderManager = WorkspaceFolderManager.createInstance( + mockAgent, mockServiceManager, mockLogging, mockArtifactManager, @@ -113,6 +117,7 @@ describe('WorkspaceFolderManager', () => { // Create the WorkspaceFolderManager instance using the static createInstance method workspaceFolderManager = WorkspaceFolderManager.createInstance( + mockAgent, mockServiceManager, mockLogging, mockArtifactManager, @@ -130,10 +135,6 @@ describe('WorkspaceFolderManager', () => { // Verify that resetWebSocketClient was called once sinon.assert.calledOnce(resetWebSocketClientSpy) - sinon.assert.calledWith( - mockLogging.log, - sinon.match(/Session is idle, skipping remote workspace status check/) - ) }) }) @@ -161,6 +162,7 @@ describe('WorkspaceFolderManager', () => { // Create the WorkspaceFolderManager instance workspaceFolderManager = WorkspaceFolderManager.createInstance( + mockAgent, mockServiceManager, mockLogging, mockArtifactManager, @@ -209,6 +211,7 @@ describe('WorkspaceFolderManager', () => { // Create the WorkspaceFolderManager instance workspaceFolderManager = WorkspaceFolderManager.createInstance( + mockAgent, mockServiceManager, mockLogging, mockArtifactManager, @@ -225,4 +228,271 @@ describe('WorkspaceFolderManager', () => { expect(workspaceFolderManager.isFeatureDisabled()).toBe(false) }) }) + + describe('semantic search tool management', () => { + beforeEach(() => { + const workspaceFolders: WorkspaceFolder[] = [ + { + uri: 'file:///test/workspace', + name: 'test-workspace', + }, + ] + + workspaceFolderManager = WorkspaceFolderManager.createInstance( + mockAgent, + mockServiceManager, + mockLogging, + mockArtifactManager, + mockDependencyDiscoverer, + workspaceFolders, + mockCredentialsProvider, + 'test-workspace-identifier' + ) + + // Mock service manager methods + mockServiceManager.getRegion.returns('us-east-1') + }) + + describe('setSemanticSearchToolStatus', () => { + it('should set semantic search tool status to enabled', () => { + // Act + workspaceFolderManager.setSemanticSearchToolStatus(true) + + // Assert - we can't directly access the private property, but we can test the behavior + // through other methods that depend on this status + expect(workspaceFolderManager).toBeDefined() + }) + + it('should set semantic search tool status to disabled', () => { + // Act + workspaceFolderManager.setSemanticSearchToolStatus(false) + + // Assert + expect(workspaceFolderManager).toBeDefined() + }) + }) + + describe('registerSemanticSearchTool', () => { + it('should register semantic search tool when not already present', () => { + // Setup + mockAgent.getTools.returns([]) // No existing tools + workspaceFolderManager.setSemanticSearchToolStatus(true) + + // Act - call the private method through establishConnection + const mockMetadata = { + environmentId: 'test-env-123', + environmentAddress: 'wss://test.amazonaws.com', + workspaceStatus: 'READY' as const, + } + + // Spy on the private method + const registerSemanticSearchToolSpy = sinon.spy( + workspaceFolderManager as any, + 'registerSemanticSearchTool' + ) + + // Trigger establishConnection which calls registerSemanticSearchTool + ;(workspaceFolderManager as any).establishConnection(mockMetadata) + + // Assert + sinon.assert.calledOnce(registerSemanticSearchToolSpy) + sinon.assert.calledOnce(mockAgent.addTool) + + // Verify the tool was added with correct parameters + const addToolCall = mockAgent.addTool.getCall(0) + expect(addToolCall.args[0].name).toBe(SemanticSearch.toolName) + expect(addToolCall.args[2]).toBe(ToolClassification.BuiltIn) + }) + + it('should not register semantic search tool when already present', () => { + // Setup - mock existing tool + const existingTool = { + name: SemanticSearch.toolName, + description: 'Mock semantic search tool', + inputSchema: { type: 'object' as const, properties: {}, required: [] }, + } + mockAgent.getTools.returns([existingTool]) + workspaceFolderManager.setSemanticSearchToolStatus(true) + + // Act + const mockMetadata = { + environmentId: 'test-env-123', + environmentAddress: 'wss://test.amazonaws.com', + workspaceStatus: 'READY' as const, + } + + ;(workspaceFolderManager as any).establishConnection(mockMetadata) + + // Assert - addTool should not be called since tool already exists + sinon.assert.notCalled(mockAgent.addTool) + }) + + it('should not register semantic search tool when status is disabled', () => { + // Setup + mockAgent.getTools.returns([]) + workspaceFolderManager.setSemanticSearchToolStatus(false) // Disabled + + // Act + const mockMetadata = { + environmentId: 'test-env-123', + environmentAddress: 'wss://test.amazonaws.com', + workspaceStatus: 'READY' as const, + } + + ;(workspaceFolderManager as any).establishConnection(mockMetadata) + + // Assert - addTool should not be called since semantic search is disabled + sinon.assert.notCalled(mockAgent.addTool) + }) + }) + + describe('removeSemanticSearchTool', () => { + it('should remove semantic search tool when present', () => { + // Setup - mock existing tool + const existingTool = { + name: SemanticSearch.toolName, + description: 'Mock semantic search tool', + inputSchema: { type: 'object' as const, properties: {}, required: [] }, + } + mockAgent.getTools.returns([existingTool]) + workspaceFolderManager.setSemanticSearchToolStatus(true) + + // Act - call removeSemanticSearchTool through clearAllWorkspaceResources + workspaceFolderManager.clearAllWorkspaceResources() + + // Assert + sinon.assert.calledOnce(mockAgent.removeTool) + sinon.assert.calledWith(mockAgent.removeTool, SemanticSearch.toolName) + }) + + it('should not remove semantic search tool when not present', () => { + // Setup - no existing tools + mockAgent.getTools.returns([]) + workspaceFolderManager.setSemanticSearchToolStatus(true) + + // Act + workspaceFolderManager.clearAllWorkspaceResources() + + // Assert - removeTool should not be called since tool doesn't exist + sinon.assert.notCalled(mockAgent.removeTool) + }) + + it('should remove semantic search tool when session becomes idle', async () => { + // Setup + const existingTool = { + name: SemanticSearch.toolName, + description: 'Mock semantic search tool', + inputSchema: { type: 'object' as const, properties: {}, required: [] }, + } + mockAgent.getTools.returns([existingTool]) + workspaceFolderManager.setSemanticSearchToolStatus(true) + + // Mock IdleSessionManager to return true (idle) + sinon.stub(IdleWorkspaceManager, 'isSessionIdle').returns(true) + + const workspaceFolders: WorkspaceFolder[] = [ + { + uri: 'file:///test/workspace', + name: 'test-workspace', + }, + ] + + // Update workspace folders to trigger the idle check + workspaceFolderManager.updateWorkspaceFolders(workspaceFolders) + + // Act - trigger checkRemoteWorkspaceStatusAndReact which handles idle state + await workspaceFolderManager.checkRemoteWorkspaceStatusAndReact() + + // Assert + sinon.assert.calledOnce(mockAgent.removeTool) + sinon.assert.calledWith(mockAgent.removeTool, SemanticSearch.toolName) + }) + }) + }) + + describe('resetAdminOptOutAndFeatureDisabledStatus', () => { + it('should reset both opt-out and feature disabled status', () => { + // Setup + const workspaceFolders: WorkspaceFolder[] = [ + { + uri: 'file:///test/workspace', + name: 'test-workspace', + }, + ] + + workspaceFolderManager = WorkspaceFolderManager.createInstance( + mockAgent, + mockServiceManager, + mockLogging, + mockArtifactManager, + mockDependencyDiscoverer, + workspaceFolders, + mockCredentialsProvider, + 'test-workspace-identifier' + ) + + // Simulate both statuses being set to true + // We can't directly set these private properties, but we can test the behavior + // by triggering conditions that would set them and then resetting + + // Act + workspaceFolderManager.resetAdminOptOutAndFeatureDisabledStatus() + + // Assert - verify the statuses are reset + expect(workspaceFolderManager.getOptOutStatus()).toBe(false) + expect(workspaceFolderManager.isFeatureDisabled()).toBe(false) + }) + }) + + describe('feature disabled handling in checkRemoteWorkspaceStatusAndReact', () => { + it('should handle feature disabled state and clear resources', async () => { + // Setup + const workspaceFolders: WorkspaceFolder[] = [ + { + uri: 'file:///test/workspace', + name: 'test-workspace', + }, + ] + + // Mock IdleSessionManager to return false (not idle) + sinon.stub(IdleWorkspaceManager, 'isSessionIdle').returns(false) + + // Mock listWorkspaceMetadata to throw AccessDeniedException with feature not supported + const mockError: AWSError = { + name: 'AccessDeniedException', + message: 'Feature is not supported', + code: 'AccessDeniedException', + time: new Date(), + retryable: false, + statusCode: 403, + } + + mockCodeWhispererService.listWorkspaceMetadata.rejects(mockError) + + workspaceFolderManager = WorkspaceFolderManager.createInstance( + mockAgent, + mockServiceManager, + mockLogging, + mockArtifactManager, + mockDependencyDiscoverer, + workspaceFolders, + mockCredentialsProvider, + 'test-workspace-identifier' + ) + + // Spy on clearAllWorkspaceResources + const clearAllWorkspaceResourcesSpy = sinon.stub( + workspaceFolderManager as any, + 'clearAllWorkspaceResources' + ) + + // Act + await workspaceFolderManager.checkRemoteWorkspaceStatusAndReact() + + // Assert + expect(workspaceFolderManager.isFeatureDisabled()).toBe(true) + sinon.assert.calledOnce(clearAllWorkspaceResourcesSpy) + sinon.assert.calledWith(mockLogging.log, sinon.match(/Feature disabled, clearing all resources/)) + }) + }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts index 1644851258..89511d34e4 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts @@ -6,7 +6,7 @@ import { WorkspaceMetadata, WorkspaceStatus, } from '../../client/token/codewhispererbearertokenclient' -import { CredentialsProvider, Logging } from '@aws/language-server-runtimes/server-interface' +import { Agent, CredentialsProvider, Logging, ToolClassification } from '@aws/language-server-runtimes/server-interface' import { ArtifactManager, FileMetadata } from './artifactManager' import { cleanUrl, @@ -21,17 +21,20 @@ import { URI } from 'vscode-uri' import path = require('path') import { isAwsError } from '../../shared/utils' import { IdleWorkspaceManager } from './IdleWorkspaceManager' +import { SemanticSearch, SemanticSearchParams } from '../agenticChat/tools/workspaceContext/semanticSearch' interface WorkspaceState { remoteWorkspaceState: WorkspaceStatus messageQueue: any[] webSocketClient?: WebSocketClient workspaceId?: string + environmentId?: string } type WorkspaceRoot = string export class WorkspaceFolderManager { + private agent: Agent private serviceManager: AmazonQTokenServiceManager private logging: Logging private artifactManager: ArtifactManager @@ -56,10 +59,12 @@ export class WorkspaceFolderManager { private messageQueueConsumerInterval: NodeJS.Timeout | undefined private isOptedOut: boolean = false private featureDisabled: boolean = false // Serve as a server-side control. If true, stop WCS features + private semanticSearchToolEnabled: boolean = false private isCheckingRemoteWorkspaceStatus: boolean = false private isArtifactUploadedToRemoteWorkspace: boolean = false static createInstance( + agent: Agent, serviceManager: AmazonQTokenServiceManager, logging: Logging, artifactManager: ArtifactManager, @@ -70,6 +75,7 @@ export class WorkspaceFolderManager { ): WorkspaceFolderManager { if (!this.instance) { this.instance = new WorkspaceFolderManager( + agent, serviceManager, logging, artifactManager, @@ -87,6 +93,7 @@ export class WorkspaceFolderManager { } private constructor( + agent: Agent, serviceManager: AmazonQTokenServiceManager, logging: Logging, artifactManager: ArtifactManager, @@ -95,6 +102,7 @@ export class WorkspaceFolderManager { credentialsProvider: CredentialsProvider, workspaceIdentifier: string ) { + this.agent = agent this.serviceManager = serviceManager this.logging = logging this.artifactManager = artifactManager @@ -149,6 +157,10 @@ export class WorkspaceFolderManager { return this.featureDisabled } + setSemanticSearchToolStatus(semanticSearchToolEnabled: boolean): void { + this.semanticSearchToolEnabled = semanticSearchToolEnabled + } + getWorkspaceState(): WorkspaceState { return this.workspaceState } @@ -231,6 +243,7 @@ export class WorkspaceFolderManager { this.workspaceState.webSocketClient?.destroyClient() this.dependencyDiscoverer.dispose() this.artifactManager.dispose() + this.removeSemanticSearchTool() } /** @@ -324,6 +337,10 @@ export class WorkspaceFolderManager { const webSocketClient = new WebSocketClient(websocketUrl, this.logging, this.credentialsProvider) this.workspaceState.remoteWorkspaceState = 'CONNECTED' this.workspaceState.webSocketClient = webSocketClient + this.workspaceState.environmentId = existingMetadata.environmentId + if (this.semanticSearchToolEnabled) { + this.registerSemanticSearchTool() + } } initializeWorkspaceStatusMonitor() { @@ -443,6 +460,9 @@ export class WorkspaceFolderManager { try { if (IdleWorkspaceManager.isSessionIdle()) { this.resetWebSocketClient() + if (this.semanticSearchToolEnabled) { + this.removeSemanticSearchTool() + } this.logging.log('Session is idle, skipping remote workspace status check') return } @@ -668,6 +688,32 @@ export class WorkspaceFolderManager { } } + private registerSemanticSearchTool() { + const existingTool = this.agent.getTools().find(tool => tool.name === SemanticSearch.toolName) + if (!existingTool) { + const semanticSearchTool = new SemanticSearch( + this.logging, + this.credentialsProvider, + this.serviceManager.getRegion() || 'us-east-1' + ) + this.agent.addTool( + semanticSearchTool.getSpec(), + async (input: SemanticSearchParams) => { + semanticSearchTool.validate(input) + return await semanticSearchTool.invoke(input) + }, + ToolClassification.BuiltIn + ) + } + } + + private removeSemanticSearchTool() { + const existingTool = this.agent.getTools().find(tool => tool.name === SemanticSearch.toolName) + if (existingTool) { + this.agent.removeTool(SemanticSearch.toolName) + } + } + private async createNewWorkspace() { const createWorkspaceResult = await this.createWorkspace(this.workspaceIdentifier) const workspaceDetails = createWorkspaceResult.response From a3e66f2d414060adde90cc7312f07c6359ae3246 Mon Sep 17 00:00:00 2001 From: finncas Date: Tue, 16 Sep 2025 11:15:12 -0700 Subject: [PATCH 081/158] fix: filetype filtering and consolidation of other filtering logic during artifact generation (#2233) * fix: filetype filtering during artifact generation * fix: filetype filtering during artifact generation * fix: filetype filtering during artifact generation * fix: updated unit test * fix: add regex filtering to artifact manager --- .../netTransform/artifactManager.ts | 83 ++++- ...nager.createRequirementJsonContent.test.ts | 337 ++++++++++++++++++ .../tests/artifactManager.general.test.ts | 284 +++++++++++++++ 3 files changed, 691 insertions(+), 13 deletions(-) create mode 100644 server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.createRequirementJsonContent.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.general.test.ts diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts index 4b1e9818cd..40461dda7e 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts @@ -23,6 +23,13 @@ const sourceCodeFolderName = 'sourceCode' const packagesFolderName = 'packages' const thirdPartyPackageFolderName = 'thirdpartypackages' const customTransformationFolderName = 'customTransformation' +const filteredExtensions = ['.suo', '.meta', '.user', '.obj', '.tmp', '.log', '.dbmdl', '.jfm', '.pdb'] +const filteredDirectories = ['.git', 'bin', 'obj', '.idea', '.vs', 'artifactworkspace', 'node_modules', 'nuget.config'] +const failedCopies: string[] = [] +const filteredPathRegex: RegExp[] = [ + /\\users\\[^\\]+\\appdata/i, // IgnoreCase flag with 'i' + /.+\.(vspscc|vssscc)$/, +] export class ArtifactManager { private workspace: Workspace @@ -160,16 +167,25 @@ export class ArtifactManager { async createRequirementJsonContent(request: StartTransformRequest): Promise { const projects: Project[] = [] - for (const project of request.ProjectMetadata) { const sourceCodeFilePaths = project.SourceCodeFilePaths.filter(filePath => filePath) const codeFiles: CodeFile[] = [] const references: References[] = [] - for (const filePath of sourceCodeFilePaths) { try { + if (this.shouldFilterFile(filePath)) { + continue + } await this.copySourceFile(request.SolutionRootPath, filePath) const contentHash = await this.calculateMD5Async(filePath) + if (contentHash.length == 0) { + //if can't generate hash then file copy failed previously + continue + } + if (contentHash.length == 0) { + //if can't generate hash then file copy failed previously + continue + } const relativePath = this.normalizeSourceFileRelativePath(request.SolutionRootPath, filePath) codeFiles.push({ contentMd5Hash: contentHash, @@ -181,6 +197,9 @@ export class ArtifactManager { } for (const reference of project.ExternalReferences) { + if (this.shouldFilterFile(reference.AssemblyFullPath)) { + continue + } try { const relativePath = this.normalizeReferenceFileRelativePath( reference.RelativePath, @@ -215,6 +234,8 @@ export class ArtifactManager { for (const pkg of request.PackageReferences) { if (!pkg.NetCompatiblePackageFilePath) { continue + } else if (this.shouldFilterFile(pkg.NetCompatiblePackageFilePath)) { + continue } try { const packageRelativePath = this.normalizePackageFileRelativePath(pkg.NetCompatiblePackageFilePath) @@ -301,7 +322,24 @@ export class ArtifactManager { `Custom transformation folder not accessible (not found or no permissions): ${customTransformationPath}` ) } - + this.logging.log( + `Files with extensions ${filteredExtensions.join(', ')} are not zipped, as they are not necessary for transformation` + ) + this.logging.log( + `Files in directories ${filteredDirectories.join(', ')} are not zipped, as they are not necessary for transformation` + ) + if (failedCopies.length > 0) { + this.logging.log(`Files - ${failedCopies.join(',')} - could not be copied.`) + } + this.logging.log( + `Files with extensions ${filteredExtensions.join(', ')} are not zipped, as they are not necessary for transformation` + ) + this.logging.log( + `Files in directories ${filteredDirectories.join(', ')} are not zipped, as they are not necessary for transformation` + ) + if (failedCopies.length > 0) { + this.logging.log(`Files - ${failedCopies.join(',')} - could not be copied.`) + } const zipPath = path.join(this.workspacePath, zipFileName) this.logging.log('Zipping files to ' + zipPath) await this.zipDirectory(folderPath, zipPath) @@ -394,17 +432,23 @@ export class ArtifactManager { //Packages folder has been deleted to avoid duplicates in artifacts.zip return } - - return new Promise((resolve, reject) => { - fs.copyFile(sourceFilePath, destFilePath, err => { - if (err) { - this.logging.log(`Failed to copy from ${sourceFilePath} and error is ${err}`) - reject(err) - } else { - resolve() - } + if (this.shouldFilterFile(sourceFilePath)) { + return + } else { + return new Promise((resolve, reject) => { + fs.copyFile(sourceFilePath, destFilePath, err => { + if (err) { + this.logging.log(`Failed to copy from ${sourceFilePath} and error is ${err}`) + failedCopies.push(sourceFilePath) + resolve() + failedCopies.push(sourceFilePath) + resolve() + } else { + resolve() + } + }) }) - }) + } } async calculateMD5Async(filePath: string): Promise { @@ -420,4 +464,17 @@ export class ArtifactManager { return '' } } + shouldFilterFile(filePath: string): boolean { + if (filteredExtensions.includes(path.extname(filePath).toLowerCase())) { + return true + } + const dirPath = path.dirname(filePath).toLowerCase() + const pathSegments = dirPath.split(path.sep) + + if (pathSegments.some(segment => filteredDirectories.includes(segment))) { + return true + } + + return filteredPathRegex.some(regex => regex.test(filePath)) + } } diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.createRequirementJsonContent.test.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.createRequirementJsonContent.test.ts new file mode 100644 index 0000000000..4bf5a31f29 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.createRequirementJsonContent.test.ts @@ -0,0 +1,337 @@ +import { expect } from 'chai' +import { Workspace, Logging } from '@aws/language-server-runtimes/server-interface' +import { StartTransformRequest, RequirementJson } from '../models' +import { ArtifactManager } from '../artifactManager' +import { StubbedInstance, stubInterface } from 'ts-sinon' +import { EXAMPLE_REQUEST } from './mockData' +import sinon = require('sinon') +import * as fs from 'fs' +import * as path from 'path' + +describe('ArtifactManager - createRequirementJsonContent', () => { + let workspace: StubbedInstance + let artifactManager: ArtifactManager + let mockedLogging: StubbedInstance + let baseRequest: StartTransformRequest + let fsStubs: { [key: string]: sinon.SinonStub } + + const setupRequest = (overrides: Partial = {}): StartTransformRequest => ({ + ...EXAMPLE_REQUEST, + SolutionRootPath: path.join('C:', 'solution'), + SolutionFilePath: path.join('C:', 'solution', 'test.sln'), + SelectedProjectPath: path.join('C:', 'solution', 'project.csproj'), + TransformNetStandardProjects: true, + ProjectMetadata: [ + { + Name: 'TestProject', + ProjectPath: path.join('C:', 'solution', 'project.csproj'), + ProjectTargetFramework: 'net48', + ProjectLanguage: 'C#', + ProjectType: 'Console', + SourceCodeFilePaths: [path.join('C:', 'solution', 'file1.cs'), path.join('C:', 'solution', 'file2.vb')], + ExternalReferences: [ + { + ProjectPath: path.join('C:', 'solution', 'project.csproj'), + RelativePath: path.join('lib', 'assembly1.dll'), + AssemblyFullPath: path.join('C:', 'solution', 'lib', 'assembly1.dll'), + IncludedInArtifact: true, + }, + ], + }, + ], + PackageReferences: [ + { + Id: 'TestPackage', + Versions: ['1.0.0'], + IsPrivatePackage: false, + NetCompatiblePackageFilePath: path.join('C:', 'packages', 'test.nupkg'), + }, + ], + ...overrides, + }) + + const mockFileSystem = () => { + fsStubs = { + existsSync: sinon.stub(fs, 'existsSync').returns(true), + mkdirSync: sinon.stub(fs, 'mkdirSync'), + copyFile: sinon.stub(fs, 'copyFile').callsArg(2), + createReadStream: sinon.stub(fs, 'createReadStream').returns({ + [Symbol.asyncIterator]: async function* () { + yield Buffer.from('test content') + }, + } as any), + } + } + + beforeEach(() => { + workspace = stubInterface() + mockedLogging = stubInterface() + artifactManager = new ArtifactManager(workspace, mockedLogging, 'test-workspace', 'test-solution') + baseRequest = setupRequest() + mockFileSystem() + }) + + afterEach(() => { + sinon.restore() + }) + + describe('Basic functionality', () => { + it('should generate requirement json with correct structure', async () => { + const result = await artifactManager.createRequirementJsonContent(baseRequest) + + expect(result).to.have.property('EntryPath') + expect(result).to.have.property('SolutionPath') + expect(result).to.have.property('Projects') + expect(result).to.have.property('TransformNetStandardProjects', true) + expect(result).to.have.property('Packages') + expect(result.Projects).to.have.length(1) + }) + + it('should process source code files correctly', async () => { + const result = await artifactManager.createRequirementJsonContent(baseRequest) + + expect(result.Projects[0].codeFiles).to.have.length(2) + expect(result.Projects[0].codeFiles[0]).to.have.property('contentMd5Hash') + expect(result.Projects[0].codeFiles[0]).to.have.property('relativePath') + }) + + it('should process project metadata correctly', async () => { + const result = await artifactManager.createRequirementJsonContent(baseRequest) + const project = result.Projects[0] + + expect(project).to.have.property('projectFilePath') + expect(project).to.have.property('projectTarget', 'net48') + expect(project).to.have.property('codeFiles') + expect(project).to.have.property('references') + }) + }) + + describe('Filtering functionality', () => { + it('should filter source code files with filtered extensions', async () => { + const request = setupRequest({ + ProjectMetadata: [ + { + ...baseRequest.ProjectMetadata[0], + SourceCodeFilePaths: [ + path.join('C:', 'solution', 'file1.cs'), + path.join('C:', 'solution', 'file2.suo'), // Should be filtered + path.join('C:', 'solution', 'file3.pdb'), // Should be filtered + path.join('C:', 'solution', 'file4.vb'), + ], + ExternalReferences: [], + }, + ], + }) + + const result = await artifactManager.createRequirementJsonContent(request) + + // Should only include .cs and .vb files, not .suo or .pdb + expect(result.Projects[0].codeFiles).to.have.length(2) + }) + + it('should filter external references with filtered extensions', async () => { + const request = setupRequest({ + ProjectMetadata: [ + { + ...baseRequest.ProjectMetadata[0], + SourceCodeFilePaths: [path.join('C:', 'solution', 'file1.cs')], + ExternalReferences: [ + { + ProjectPath: path.join('C:', 'solution', 'project.csproj'), + RelativePath: path.join('lib', 'assembly1.dll'), + AssemblyFullPath: path.join('C:', 'solution', 'lib', 'assembly1.dll'), + IncludedInArtifact: true, + }, + { + ProjectPath: path.join('C:', 'solution', 'project.csproj'), + RelativePath: path.join('lib', 'debug.pdb'), + AssemblyFullPath: path.join('C:', 'solution', 'lib', 'debug.pdb'), // Should be filtered + IncludedInArtifact: true, + }, + ], + }, + ], + }) + + const result = await artifactManager.createRequirementJsonContent(request) + + // Should only include .dll reference, not .pdb + expect(result.Projects[0].references).to.have.length(1) + }) + + it('should filter package references with filtered extensions', async () => { + const request = setupRequest({ + PackageReferences: [ + { + Id: 'ValidPackage', + Versions: ['1.0.0'], + IsPrivatePackage: false, + NetCompatiblePackageFilePath: path.join('C:', 'packages', 'valid.nupkg'), + }, + { + Id: 'FilteredPackage', + Versions: ['1.0.0'], + IsPrivatePackage: false, + NetCompatiblePackageFilePath: path.join('C:', 'packages', 'filtered.pdb'), // Should be filtered + }, + ], + }) + + const result = await artifactManager.createRequirementJsonContent(request) + + // Should only include valid package, not filtered one + expect((result as any).Packages).to.have.length(1) + }) + }) + + describe('Error handling', () => { + it('should handle file processing errors gracefully', async () => { + fsStubs.copyFile.callsArgWith(2, new Error('Copy failed')) + fsStubs.createReadStream.throws(new Error('Read failed')) + + const result = await artifactManager.createRequirementJsonContent(baseRequest) + + expect(result).to.have.property('Projects') + expect(result.Projects[0].codeFiles).to.have.length(0) + }) + + it('should handle reference processing errors gracefully', async () => { + fsStubs.copyFile.callsArgWith(2, new Error('Reference copy failed')) + + const result = await artifactManager.createRequirementJsonContent(baseRequest) + + // Reference is still added even if copy fails, but error is logged + expect(result.Projects[0].references).to.have.length(1) + expect(mockedLogging.log.called).to.be.true + }) + }) + + describe('Package processing', () => { + it('should handle null PackageReferences', async () => { + const request = setupRequest({ PackageReferences: undefined }) + + const result = await artifactManager.createRequirementJsonContent(request) + expect((result as any).Packages).to.have.length(0) + }) + + it('should skip packages without NetCompatiblePackageFilePath', async () => { + const request = setupRequest({ + PackageReferences: [ + { + Id: 'EmptyPathPackage', + Versions: ['1.0.0'], + IsPrivatePackage: false, + NetCompatiblePackageFilePath: undefined, + }, + { + Id: 'ValidPackage', + Versions: ['1.0.0'], + IsPrivatePackage: false, + NetCompatiblePackageFilePath: path.join('C:', 'packages', 'valid.nupkg'), + }, + ], + }) + + const result = await artifactManager.createRequirementJsonContent(request) + expect((result as any).Packages).to.have.length(1) + }) + }) + + describe('Optional properties', () => { + it('should include EnableRazorViewTransform when defined', async () => { + const request = setupRequest({ EnableRazorViewTransform: true }) + + const result = await artifactManager.createRequirementJsonContent(request) + expect(result).to.have.property('EnableRazorViewTransform', true) + }) + + it('should include EnableWebFormsTransform when defined', async () => { + const request = setupRequest({ EnableWebFormsTransform: false }) + + const result = await artifactManager.createRequirementJsonContent(request) + expect(result).to.have.property('EnableWebFormsTransform', false) + }) + + it('should exclude optional properties when undefined', async () => { + const request = setupRequest({ + EnableRazorViewTransform: undefined, + EnableWebFormsTransform: undefined, + }) + + const result = await artifactManager.createRequirementJsonContent(request) + expect(result).to.not.have.property('EnableRazorViewTransform') + expect(result).to.not.have.property('EnableWebFormsTransform') + }) + }) + + describe('Edge cases', () => { + it('should handle empty project metadata', async () => { + const request = setupRequest({ ProjectMetadata: [] }) + + const result = await artifactManager.createRequirementJsonContent(request) + expect(result.Projects).to.have.length(0) + }) + + it('should handle empty source code file paths', async () => { + const request = setupRequest({ + ProjectMetadata: [ + { + ...baseRequest.ProjectMetadata[0], + SourceCodeFilePaths: [], + ExternalReferences: [], + }, + ], + }) + + const result = await artifactManager.createRequirementJsonContent(request) + expect(result.Projects[0].codeFiles).to.have.length(0) + expect(result.Projects[0].references).to.have.length(0) + }) + + it('should filter out empty file paths', async () => { + const request = setupRequest({ + ProjectMetadata: [ + { + ...baseRequest.ProjectMetadata[0], + SourceCodeFilePaths: [ + path.join('C:', 'solution', 'file1.cs'), + '', // Empty path should be filtered + null as any, // Null path should be filtered + path.join('C:', 'solution', 'file2.vb'), + ], + }, + ], + }) + + const result = await artifactManager.createRequirementJsonContent(request) + expect(result.Projects[0].codeFiles).to.have.length(2) + }) + }) + + describe('Multiple projects', () => { + it('should process multiple projects correctly', async () => { + const request = setupRequest({ + ProjectMetadata: [ + baseRequest.ProjectMetadata[0], + { + Name: 'SecondProject', + ProjectPath: path.join('C:', 'solution', 'project2.csproj'), + ProjectTargetFramework: 'net6.0', + ProjectLanguage: 'C#', + ProjectType: 'Library', + SourceCodeFilePaths: [path.join('C:', 'solution', 'file3.cs')], + ExternalReferences: [], + }, + ], + }) + + const result = await artifactManager.createRequirementJsonContent(request) + + expect(result.Projects).to.have.length(2) + expect(result.Projects[0].projectTarget).to.equal('net48') + expect(result.Projects[1].projectTarget).to.equal('net6.0') + expect(result.Projects[0].codeFiles).to.have.length(2) + expect(result.Projects[1].codeFiles).to.have.length(1) + }) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.general.test.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.general.test.ts new file mode 100644 index 0000000000..7a5299a620 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.general.test.ts @@ -0,0 +1,284 @@ +import { expect } from 'chai' +import { Workspace, Logging } from '@aws/language-server-runtimes/server-interface' +import { StartTransformRequest } from '../models' +import { ArtifactManager } from '../artifactManager' +import { StubbedInstance, stubInterface } from 'ts-sinon' +import { EXAMPLE_REQUEST } from './mockData' +import sinon = require('sinon') +import * as fs from 'fs' +import * as path from 'path' +import * as os from 'os' + +describe('ArtifactManager - Complete Coverage', () => { + let workspace: StubbedInstance + let artifactManager: ArtifactManager + let mockedLogging: StubbedInstance + let baseRequest: StartTransformRequest + let tempDir: string + + const createTestRequest = (overrides: Partial = {}): StartTransformRequest => ({ + ...EXAMPLE_REQUEST, + SolutionRootPath: path.join(tempDir, 'solution'), + SolutionFilePath: path.join(tempDir, 'solution', 'test.sln'), + SolutionConfigPaths: [path.join(tempDir, 'config.xml')], + DatabaseSettings: { Tools: [{ Name: 'Test', Properties: {} }] }, + DmsArn: 'arn:aws:dms:region:account:task/test', + ...overrides, + }) + + beforeEach(() => { + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'artifact-test-')) + workspace = stubInterface() + workspace.fs = { + exists: sinon.stub().resolves(true), + rm: sinon.stub().resolves(), + } as any + mockedLogging = stubInterface() + artifactManager = new ArtifactManager(workspace, mockedLogging, tempDir, path.join(tempDir, 'solution')) + baseRequest = createTestRequest() + }) + + afterEach(() => { + sinon.restore() + if (fs.existsSync(tempDir)) { + fs.rmSync(tempDir, { recursive: true, force: true }) + } + }) + + describe('createTransformationPreferencesContent', () => { + it('should create valid transformation preferences with database settings', async () => { + const result = await artifactManager.createTransformationPreferencesContent(baseRequest) + + expect(result).to.have.property('Transformations') + expect(result).to.have.property('Metadata') + expect(result.Transformations.DatabaseModernization).to.exist + expect(result.Transformations.DatabaseModernization?.Enabled).to.be.true + expect(result.Transformations.DatabaseModernization?.DatabaseSettings).to.deep.equal( + baseRequest.DatabaseSettings + ) + expect(result.Transformations.DatabaseModernization?.DmsArn).to.equal(baseRequest.DmsArn) + expect(result.Metadata.GeneratedAt).to.be.a('string') + }) + + it('should handle DmsArn only scenario', async () => { + const request = createTestRequest({ + DatabaseSettings: undefined, + DmsArn: 'arn:aws:dms:test', + }) + + const result = await artifactManager.createTransformationPreferencesContent(request) + + expect(result.Transformations.DatabaseModernization?.DmsArn).to.equal('arn:aws:dms:test') + expect(result.Transformations.DatabaseModernization?.DatabaseSettings?.Tools).to.have.length(1) + expect(result.Transformations.DatabaseModernization?.DatabaseSettings?.Tools?.[0].Name).to.equal('DMS') + }) + + it('should handle no database configuration', async () => { + const request = createTestRequest({ + DatabaseSettings: undefined, + DmsArn: undefined, + }) + + const result = await artifactManager.createTransformationPreferencesContent(request) + expect(result.Transformations.DatabaseModernization).to.be.undefined + }) + }) + + describe('removeDir method', () => { + it('should call workspace.fs.rm when directory exists', async () => { + await artifactManager.removeDir('test-dir') + + expect((workspace.fs.exists as sinon.SinonStub).calledWith('test-dir')).to.be.true + expect((workspace.fs.rm as sinon.SinonStub).calledWith('test-dir')).to.be.true + }) + + it('should not call rm when directory does not exist', async () => { + workspace.fs.exists = sinon.stub().resolves(false) + + await artifactManager.removeDir('test-dir') + expect((workspace.fs.rm as sinon.SinonStub).called).to.be.false + }) + }) + + describe('cleanup method', () => { + it('should handle cleanup gracefully when files exist', () => { + // Create test files + const artifactFolder = path.join(tempDir, 'artifact') + const zipFile = path.join(tempDir, 'artifact.zip') + fs.mkdirSync(artifactFolder, { recursive: true }) + fs.writeFileSync(zipFile, 'test') + + expect(() => artifactManager.cleanup()).to.not.throw() + expect(fs.existsSync(artifactFolder)).to.be.false + expect(fs.existsSync(zipFile)).to.be.false + }) + + it('should handle cleanup errors gracefully', () => { + // Test with non-existent directory + expect(() => artifactManager.cleanup()).to.not.throw() + }) + }) + + describe('file writing methods', () => { + it('should write requirement json with correct content', async () => { + const testDir = path.join(tempDir, 'test-dir') + fs.mkdirSync(testDir, { recursive: true }) + const testContent = '{"test": "content"}' + + await artifactManager.writeRequirementJsonAsync(testDir, testContent) + + const filePath = path.join(testDir, 'requirement.json') + expect(fs.existsSync(filePath)).to.be.true + expect(fs.readFileSync(filePath, 'utf8')).to.equal(testContent) + }) + + it('should write transformation preferences with correct content', async () => { + const testDir = path.join(tempDir, 'test-dir') + fs.mkdirSync(testDir, { recursive: true }) + const testContent = '{"preferences": "data"}' + + await artifactManager.writeTransformationPreferencesAsync(testDir, testContent) + + const filePath = path.join(testDir, 'transformation-preferences.json') + expect(fs.existsSync(filePath)).to.be.true + expect(fs.readFileSync(filePath, 'utf8')).to.equal(testContent) + }) + }) + + describe('path helper methods', () => { + it('should normalize source file paths correctly', () => { + const solutionRoot = path.join('C:', 'solution') + const filePath = path.join('C:', 'solution', 'src', 'file.cs') + + const result = artifactManager.normalizeSourceFileRelativePath(solutionRoot, filePath) + expect(result).to.include('sourceCode') + expect(result).to.include('src') + expect(result).to.include('file.cs') + }) + + it('should normalize reference file paths correctly', () => { + const relativePath = path.join('lib', 'test.dll') + + const result = artifactManager.normalizeReferenceFileRelativePath(relativePath, true) + expect(result).to.include('references') + expect(result).to.include('lib') + expect(result).to.include('test.dll') + }) + + it('should normalize package file paths correctly', () => { + const packagePath = path.join('C:', 'packages', 'test.nupkg') + + const result = artifactManager.normalizePackageFileRelativePath(packagePath) + expect(result).to.include('packages') + expect(result).to.include('test.nupkg') + }) + }) + + describe('getSha256Async static method', () => { + it('should calculate SHA256 hash for existing file', async () => { + const testFile = path.join(tempDir, 'test.txt') + const testContent = 'test content for hashing' + fs.writeFileSync(testFile, testContent) + + const result = await ArtifactManager.getSha256Async(testFile) + + expect(result).to.be.a('string') + expect(result).to.have.length.greaterThan(0) + // Verify it's a valid base64 string + expect(() => Buffer.from(result, 'base64')).to.not.throw() + }) + }) + + describe('zipArtifact method', () => { + it('should return empty string when artifact folder does not exist', async () => { + const result = await artifactManager.zipArtifact() + expect(result).to.equal('') + }) + + it('should create zip path when artifact folder exists', async () => { + const artifactFolder = path.join(tempDir, 'artifact') + fs.mkdirSync(artifactFolder, { recursive: true }) + fs.writeFileSync(path.join(artifactFolder, 'test.txt'), 'test') + + // Mock zipDirectory to avoid actual zip creation + sinon.stub(artifactManager, 'zipDirectory').resolves() + + const result = await artifactManager.zipArtifact() + expect(result).to.include('artifact.zip') + expect(path.isAbsolute(result)).to.be.true + }) + }) + + describe('copySolutionConfigFiles', () => { + it('should process config files when present', async () => { + const copyStub = sinon.stub(artifactManager, 'copySourceFile').resolves() + const request = createTestRequest({ + SolutionConfigPaths: ['config1.xml', 'config2.json'], + }) + + await artifactManager.copySolutionConfigFiles(request) + + expect(copyStub.callCount).to.equal(2) + expect(copyStub.firstCall.args[1]).to.equal('config1.xml') + expect(copyStub.secondCall.args[1]).to.equal('config2.json') + }) + + it('should handle empty config paths array', async () => { + const copyStub = sinon.stub(artifactManager, 'copySourceFile').resolves() + const request = createTestRequest({ SolutionConfigPaths: [] }) + + await artifactManager.copySolutionConfigFiles(request) + expect(copyStub.called).to.be.false + }) + }) + + describe('removeDuplicateNugetPackagesFolder', () => { + it('should remove packages folder when it exists', async () => { + const packagesFolder = path.join(tempDir, 'artifact', 'sourceCode', 'packages') + fs.mkdirSync(packagesFolder, { recursive: true }) + fs.writeFileSync(path.join(packagesFolder, 'test.nupkg'), 'test') + + await artifactManager.removeDuplicateNugetPackagesFolder(baseRequest) + expect(fs.existsSync(packagesFolder)).to.be.false + }) + + it('should handle non-existent packages folder gracefully', async () => { + await artifactManager.removeDuplicateNugetPackagesFolder(baseRequest) + // Should not throw + }) + }) + + describe('shouldFilterFile', () => { + it('should filter filetypes', async () => { + expect(artifactManager.shouldFilterFile('test.cs')).to.be.false + expect(artifactManager.shouldFilterFile('test.jfm.cs')).to.be.false + expect(artifactManager.shouldFilterFile('test.jfm')).to.be.true + }) + + it('should filter directories', async () => { + const unfilteredString = path.join('test', 'solution', 'test.cs') + const filteredString = path.join('test', 'artifactworkspace', 'test.cs') + const filteredStringWithCasing = path.join('test', 'ArtifactWorkspace', 'test.cs') + + expect(artifactManager.shouldFilterFile(unfilteredString)).to.be.false + expect(artifactManager.shouldFilterFile(filteredString)).to.be.true + expect(artifactManager.shouldFilterFile(filteredStringWithCasing)).to.be.true + }) + + it('should filter regex', async () => { + const unfilteredString = '\\users\\test\\dataApp\\test.cs' + const unfilteredStringWithExtraDir = '\\users\\extraDir\\test\\appData\\test.cs' + const filteredString = '\\users\\test\\appdata\\test.cs' + const filteredStringWithCasing = '\\USERS\\test\\APPdata\\test.cs' + const filteredExtension = '\\users\\test\\project.vspscc' + const filteredExtensionTwo = '\\users\\test\\project.vssscc' + + expect(artifactManager.shouldFilterFile(unfilteredString)).to.be.false + expect(artifactManager.shouldFilterFile(unfilteredStringWithExtraDir)).to.be.false + expect(artifactManager.shouldFilterFile(filteredString)).to.be.true + expect(artifactManager.shouldFilterFile(filteredStringWithCasing)).to.be.true + expect(artifactManager.shouldFilterFile(filteredExtension)).to.be.true + expect(artifactManager.shouldFilterFile(filteredExtensionTwo)).to.be.true + }) + }) +}) From 6488e654f2c50a18338db205650e70ae4223d7cf Mon Sep 17 00:00:00 2001 From: tsmithsz <84354541+tsmithsz@users.noreply.github.com> Date: Tue, 16 Sep 2025 11:29:40 -0700 Subject: [PATCH 082/158] chore: bump runtimes to 0.2.129 (#2286) --- app/aws-lsp-antlr4-runtimes/package.json | 2 +- app/aws-lsp-buildspec-runtimes/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- app/aws-lsp-identity-runtimes/package.json | 2 +- app/aws-lsp-json-runtimes/package.json | 2 +- .../package.json | 2 +- app/aws-lsp-s3-runtimes/package.json | 2 +- app/aws-lsp-yaml-json-webworker/package.json | 2 +- app/aws-lsp-yaml-runtimes/package.json | 2 +- chat-client/package.json | 2 +- client/vscode/package.json | 2 +- core/aws-lsp-core/package.json | 2 +- .../q-agentic-chat-server/package.json | 2 +- package-lock.json | 52 +++++++++---------- server/aws-lsp-antlr4/package.json | 2 +- server/aws-lsp-buildspec/package.json | 2 +- server/aws-lsp-cloudformation/package.json | 2 +- server/aws-lsp-codewhisperer/package.json | 2 +- server/aws-lsp-identity/package.json | 2 +- server/aws-lsp-json/package.json | 2 +- server/aws-lsp-notification/package.json | 2 +- server/aws-lsp-partiql/package.json | 2 +- server/aws-lsp-s3/package.json | 2 +- server/aws-lsp-yaml/package.json | 2 +- server/device-sso-auth-lsp/package.json | 2 +- server/hello-world-lsp/package.json | 2 +- 27 files changed, 52 insertions(+), 52 deletions(-) diff --git a/app/aws-lsp-antlr4-runtimes/package.json b/app/aws-lsp-antlr4-runtimes/package.json index 20409656e1..ae9fdd3531 100644 --- a/app/aws-lsp-antlr4-runtimes/package.json +++ b/app/aws-lsp-antlr4-runtimes/package.json @@ -12,7 +12,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-antlr4": "*", "antlr4-c3": "^3.4.1", "antlr4ng": "^3.0.4" diff --git a/app/aws-lsp-buildspec-runtimes/package.json b/app/aws-lsp-buildspec-runtimes/package.json index a080ed2edb..16920a2b0a 100644 --- a/app/aws-lsp-buildspec-runtimes/package.json +++ b/app/aws-lsp-buildspec-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-buildspec": "^0.0.1" } } diff --git a/app/aws-lsp-cloudformation-runtimes/package.json b/app/aws-lsp-cloudformation-runtimes/package.json index ad4c547839..48aa6e04f4 100644 --- a/app/aws-lsp-cloudformation-runtimes/package.json +++ b/app/aws-lsp-cloudformation-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-cloudformation": "^0.0.1" } } diff --git a/app/aws-lsp-codewhisperer-runtimes/package.json b/app/aws-lsp-codewhisperer-runtimes/package.json index 18de7dab8c..c06633a363 100644 --- a/app/aws-lsp-codewhisperer-runtimes/package.json +++ b/app/aws-lsp-codewhisperer-runtimes/package.json @@ -23,7 +23,7 @@ "local-build": "node scripts/local-build.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", diff --git a/app/aws-lsp-identity-runtimes/package.json b/app/aws-lsp-identity-runtimes/package.json index 4aa4f9d7f3..e94f0f6c54 100644 --- a/app/aws-lsp-identity-runtimes/package.json +++ b/app/aws-lsp-identity-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-identity": "^0.0.1" } } diff --git a/app/aws-lsp-json-runtimes/package.json b/app/aws-lsp-json-runtimes/package.json index 78815f73cc..2e4fdae3da 100644 --- a/app/aws-lsp-json-runtimes/package.json +++ b/app/aws-lsp-json-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-json": "*" }, "devDependencies": { diff --git a/app/aws-lsp-notification-runtimes/package.json b/app/aws-lsp-notification-runtimes/package.json index cb5e90a9e5..b0e5d02768 100644 --- a/app/aws-lsp-notification-runtimes/package.json +++ b/app/aws-lsp-notification-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-notification": "^0.0.1" } } diff --git a/app/aws-lsp-s3-runtimes/package.json b/app/aws-lsp-s3-runtimes/package.json index a5eac053e3..c1e2621e36 100644 --- a/app/aws-lsp-s3-runtimes/package.json +++ b/app/aws-lsp-s3-runtimes/package.json @@ -10,7 +10,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-s3": "^0.0.1" } } diff --git a/app/aws-lsp-yaml-json-webworker/package.json b/app/aws-lsp-yaml-json-webworker/package.json index 14f0c58491..7df12df32b 100644 --- a/app/aws-lsp-yaml-json-webworker/package.json +++ b/app/aws-lsp-yaml-json-webworker/package.json @@ -11,7 +11,7 @@ "serve:webpack": "NODE_ENV=development webpack serve" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, diff --git a/app/aws-lsp-yaml-runtimes/package.json b/app/aws-lsp-yaml-runtimes/package.json index e935c9ee0a..d1645de29b 100644 --- a/app/aws-lsp-yaml-runtimes/package.json +++ b/app/aws-lsp-yaml-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-yaml": "*" }, "devDependencies": { diff --git a/chat-client/package.json b/chat-client/package.json index 3c10213f91..46e3947d73 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/language-server-runtimes-types": "^0.1.50", "@aws/mynah-ui": "^4.36.6" }, diff --git a/client/vscode/package.json b/client/vscode/package.json index 6b936bfd3f..a943422cfa 100644 --- a/client/vscode/package.json +++ b/client/vscode/package.json @@ -352,7 +352,7 @@ "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", diff --git a/core/aws-lsp-core/package.json b/core/aws-lsp-core/package.json index 2876679e39..d005da5751 100644 --- a/core/aws-lsp-core/package.json +++ b/core/aws-lsp-core/package.json @@ -28,7 +28,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", diff --git a/integration-tests/q-agentic-chat-server/package.json b/integration-tests/q-agentic-chat-server/package.json index 7018052547..9bbb5ab9d4 100644 --- a/integration-tests/q-agentic-chat-server/package.json +++ b/integration-tests/q-agentic-chat-server/package.json @@ -9,7 +9,7 @@ "test-integ": "npm run compile && mocha --timeout 30000 \"./out/**/*.test.js\" --retries 2" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "*" }, "devDependencies": { diff --git a/package-lock.json b/package-lock.json index 15b9c955b4..2e44531586 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,7 +48,7 @@ "name": "@aws/lsp-antlr4-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-antlr4": "*", "antlr4-c3": "^3.4.1", "antlr4ng": "^3.0.4" @@ -71,7 +71,7 @@ "name": "@aws/lsp-buildspec-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-buildspec": "^0.0.1" } }, @@ -79,7 +79,7 @@ "name": "@aws/lsp-cloudformation-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-cloudformation": "^0.0.1" } }, @@ -87,7 +87,7 @@ "name": "@aws/lsp-codewhisperer-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", @@ -120,7 +120,7 @@ "name": "@aws/lsp-identity-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-identity": "^0.0.1" } }, @@ -128,7 +128,7 @@ "name": "@aws/lsp-json-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-json": "*" }, "devDependencies": { @@ -148,7 +148,7 @@ "name": "@aws/lsp-notification-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-notification": "^0.0.1" } }, @@ -181,7 +181,7 @@ "name": "@aws/lsp-s3-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-s3": "^0.0.1" }, "bin": { @@ -192,7 +192,7 @@ "name": "@aws/lsp-yaml-json-webworker", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, @@ -212,7 +212,7 @@ "name": "@aws/lsp-yaml-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-yaml": "*" }, "devDependencies": { @@ -255,7 +255,7 @@ "license": "Apache-2.0", "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/language-server-runtimes-types": "^0.1.50", "@aws/mynah-ui": "^4.36.6" }, @@ -280,7 +280,7 @@ "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", @@ -296,7 +296,7 @@ "version": "0.0.15", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", @@ -327,7 +327,7 @@ "name": "@aws/q-agentic-chat-server-integration-tests", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "*" }, "devDependencies": { @@ -28615,7 +28615,7 @@ "version": "0.1.19", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.15" }, "devDependencies": { @@ -28657,7 +28657,7 @@ "name": "@aws/lsp-buildspec", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", @@ -28668,7 +28668,7 @@ "name": "@aws/lsp-cloudformation", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", @@ -28690,7 +28690,7 @@ "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.15", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", @@ -28832,7 +28832,7 @@ "dependencies": { "@aws-sdk/client-sso-oidc": "^3.616.0", "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.12", "@smithy/node-http-handler": "^3.2.5", "@smithy/shared-ini-file-loader": "^4.0.1", @@ -28897,7 +28897,7 @@ "version": "0.1.19", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.15", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" @@ -28914,7 +28914,7 @@ "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1" }, @@ -28975,7 +28975,7 @@ "version": "0.0.18", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "antlr4-c3": "3.4.2", "antlr4ng": "3.0.14", "web-tree-sitter": "0.22.6" @@ -28997,7 +28997,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" @@ -29028,7 +29028,7 @@ "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.15", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", @@ -29042,7 +29042,7 @@ "name": "@amzn/device-sso-auth-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "vscode-languageserver": "^9.0.1" }, "devDependencies": { @@ -29053,7 +29053,7 @@ "name": "@aws/hello-world-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/server/aws-lsp-antlr4/package.json b/server/aws-lsp-antlr4/package.json index f9a4ecdeba..668c58742d 100644 --- a/server/aws-lsp-antlr4/package.json +++ b/server/aws-lsp-antlr4/package.json @@ -28,7 +28,7 @@ "clean": "rm -rf node_modules" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.15" }, "peerDependencies": { diff --git a/server/aws-lsp-buildspec/package.json b/server/aws-lsp-buildspec/package.json index f0184e0ff8..3d8bdc4671 100644 --- a/server/aws-lsp-buildspec/package.json +++ b/server/aws-lsp-buildspec/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-cloudformation/package.json b/server/aws-lsp-cloudformation/package.json index 89b56ede3f..14860f5ea9 100644 --- a/server/aws-lsp-cloudformation/package.json +++ b/server/aws-lsp-cloudformation/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 0b03332380..c4ab40a63a 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -36,7 +36,7 @@ "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.15", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", diff --git a/server/aws-lsp-identity/package.json b/server/aws-lsp-identity/package.json index 3d90af77e4..e5e2009798 100644 --- a/server/aws-lsp-identity/package.json +++ b/server/aws-lsp-identity/package.json @@ -26,7 +26,7 @@ "dependencies": { "@aws-sdk/client-sso-oidc": "^3.616.0", "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.12", "@smithy/node-http-handler": "^3.2.5", "@smithy/shared-ini-file-loader": "^4.0.1", diff --git a/server/aws-lsp-json/package.json b/server/aws-lsp-json/package.json index b1ce196af0..919fb24959 100644 --- a/server/aws-lsp-json/package.json +++ b/server/aws-lsp-json/package.json @@ -26,7 +26,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.15", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" diff --git a/server/aws-lsp-notification/package.json b/server/aws-lsp-notification/package.json index 740a109f48..de4646132f 100644 --- a/server/aws-lsp-notification/package.json +++ b/server/aws-lsp-notification/package.json @@ -22,7 +22,7 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1" }, diff --git a/server/aws-lsp-partiql/package.json b/server/aws-lsp-partiql/package.json index 2dc6c0e968..da7a3a8a53 100644 --- a/server/aws-lsp-partiql/package.json +++ b/server/aws-lsp-partiql/package.json @@ -24,7 +24,7 @@ "out" ], "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "antlr4-c3": "3.4.2", "antlr4ng": "3.0.14", "web-tree-sitter": "0.22.6" diff --git a/server/aws-lsp-s3/package.json b/server/aws-lsp-s3/package.json index 8829f1dd87..067230017d 100644 --- a/server/aws-lsp-s3/package.json +++ b/server/aws-lsp-s3/package.json @@ -9,7 +9,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.12", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" diff --git a/server/aws-lsp-yaml/package.json b/server/aws-lsp-yaml/package.json index 555b12c69a..c6f4b5267c 100644 --- a/server/aws-lsp-yaml/package.json +++ b/server/aws-lsp-yaml/package.json @@ -26,7 +26,7 @@ "postinstall": "node patchYamlPackage.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.15", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", diff --git a/server/device-sso-auth-lsp/package.json b/server/device-sso-auth-lsp/package.json index 9bca2bf0b7..2093f85a07 100644 --- a/server/device-sso-auth-lsp/package.json +++ b/server/device-sso-auth-lsp/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/server/hello-world-lsp/package.json b/server/hello-world-lsp/package.json index b5944a3223..b411c0b52f 100644 --- a/server/hello-world-lsp/package.json +++ b/server/hello-world-lsp/package.json @@ -13,7 +13,7 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", + "@aws/language-server-runtimes": "^0.2.129", "vscode-languageserver": "^9.0.1" }, "devDependencies": { From 264ff67923941ae34c6659910358aeb0d5c7a314 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 12:18:05 -0700 Subject: [PATCH 083/158] chore(release): release packages from branch main (#2282) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .release-please-manifest.json | 4 ++-- chat-client/CHANGELOG.md | 7 +++++++ chat-client/package.json | 2 +- package-lock.json | 4 ++-- server/aws-lsp-codewhisperer/CHANGELOG.md | 14 ++++++++++++++ server/aws-lsp-codewhisperer/package.json | 2 +- 6 files changed, 27 insertions(+), 6 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2cc2cea923..b1266e246d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,8 +1,8 @@ { - "chat-client": "0.1.35", + "chat-client": "0.1.36", "core/aws-lsp-core": "0.0.15", "server/aws-lsp-antlr4": "0.1.19", - "server/aws-lsp-codewhisperer": "0.0.79", + "server/aws-lsp-codewhisperer": "0.0.80", "server/aws-lsp-json": "0.1.19", "server/aws-lsp-partiql": "0.0.18", "server/aws-lsp-yaml": "0.1.19" diff --git a/chat-client/CHANGELOG.md b/chat-client/CHANGELOG.md index 773e455b53..fb94865004 100644 --- a/chat-client/CHANGELOG.md +++ b/chat-client/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.1.36](https://github.com/aws/language-servers/compare/chat-client/v0.1.35...chat-client/v0.1.36) (2025-09-16) + + +### Bug Fixes + +* migration from /agents ux ([#2248](https://github.com/aws/language-servers/issues/2248)) ([debeb41](https://github.com/aws/language-servers/commit/debeb414fd0d4d873af2f36cde0ebbeab16d16a4)) + ## [0.1.35](https://github.com/aws/language-servers/compare/chat-client/v0.1.34...chat-client/v0.1.35) (2025-09-09) diff --git a/chat-client/package.json b/chat-client/package.json index 46e3947d73..a20d2cc5a1 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -1,6 +1,6 @@ { "name": "@aws/chat-client", - "version": "0.1.35", + "version": "0.1.36", "description": "AWS Chat Client", "main": "out/index.js", "repository": { diff --git a/package-lock.json b/package-lock.json index 2e44531586..a2ad6312f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -251,7 +251,7 @@ }, "chat-client": { "name": "@aws/chat-client", - "version": "0.1.35", + "version": "0.1.36", "license": "Apache-2.0", "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", @@ -28677,7 +28677,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.79", + "version": "0.0.80", "bundleDependencies": [ "@amzn/codewhisperer-streaming", "@amzn/amazon-q-developer-streaming-client" diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index 57a411ce81..bb326a1b18 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [0.0.80](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.79...lsp-codewhisperer/v0.0.80) (2025-09-16) + + +### Features + +* **amazonq:** semantic search tool integration ([#2283](https://github.com/aws/language-servers/issues/2283)) ([8eb3c34](https://github.com/aws/language-servers/commit/8eb3c340534f3c66fd9082a83b31e84a4d9348bb)) +* **amazonq:** support for wildcard permissions from agent config ([#2249](https://github.com/aws/language-servers/issues/2249)) ([2f6e86b](https://github.com/aws/language-servers/commit/2f6e86b0a676674744b962b0e335543c6c39e9e1)) +* support sending requests with the 'external_idp' type ([#2247](https://github.com/aws/language-servers/issues/2247)) ([4d3b938](https://github.com/aws/language-servers/commit/4d3b938b7e961def0db2a51fba57e8fe73ea0a01)) + + +### Bug Fixes + +* filetype filtering and consolidation of other filtering logic during artifact generation ([#2233](https://github.com/aws/language-servers/issues/2233)) ([a3e66f2](https://github.com/aws/language-servers/commit/a3e66f2d414060adde90cc7312f07c6359ae3246)) + ## [0.0.79](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.78...lsp-codewhisperer/v0.0.79) (2025-09-10) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index c4ab40a63a..1a0b12eb74 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.79", + "version": "0.0.80", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { From 3b147b4845af89e8903b3b0ab1aa61014eab5599 Mon Sep 17 00:00:00 2001 From: tsmithsz <84354541+tsmithsz@users.noreply.github.com> Date: Tue, 16 Sep 2025 14:09:01 -0700 Subject: [PATCH 084/158] ci: remove condition preventing manual trigger of build actions (#2289) --- .github/workflows/create-agent-standalone.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/create-agent-standalone.yml b/.github/workflows/create-agent-standalone.yml index f50b5b43b0..afde98b14a 100644 --- a/.github/workflows/create-agent-standalone.yml +++ b/.github/workflows/create-agent-standalone.yml @@ -8,7 +8,6 @@ on: jobs: build: runs-on: ubuntu-latest - if: github.event_name == 'push' || github.actor_id == github.repository_owner_id steps: - name: Checkout repository From 905de69928331998501299dad9e66da681366fd6 Mon Sep 17 00:00:00 2001 From: tsmithsz <84354541+tsmithsz@users.noreply.github.com> Date: Wed, 17 Sep 2025 08:23:24 -0700 Subject: [PATCH 085/158] chore: bump agentic version: 1.33.0 (#2293) Co-authored-by: aws-toolkit-automation <> --- app/aws-lsp-codewhisperer-runtimes/src/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/src/version.json b/app/aws-lsp-codewhisperer-runtimes/src/version.json index aec8038513..b67df644b8 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/version.json +++ b/app/aws-lsp-codewhisperer-runtimes/src/version.json @@ -1,3 +1,3 @@ { - "agenticChat": "1.32.0" + "agenticChat": "1.33.0" } From 36f3eedd1cad3fca4fc48792ba40b6470f733bfa Mon Sep 17 00:00:00 2001 From: finncas Date: Wed, 17 Sep 2025 08:41:02 -0700 Subject: [PATCH 086/158] fix: quick fix for repeated logging from squashed commit (#2291) --- .../netTransform/artifactManager.ts | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts index 40461dda7e..2f3fe47373 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts @@ -182,10 +182,6 @@ export class ArtifactManager { //if can't generate hash then file copy failed previously continue } - if (contentHash.length == 0) { - //if can't generate hash then file copy failed previously - continue - } const relativePath = this.normalizeSourceFileRelativePath(request.SolutionRootPath, filePath) codeFiles.push({ contentMd5Hash: contentHash, @@ -331,15 +327,6 @@ export class ArtifactManager { if (failedCopies.length > 0) { this.logging.log(`Files - ${failedCopies.join(',')} - could not be copied.`) } - this.logging.log( - `Files with extensions ${filteredExtensions.join(', ')} are not zipped, as they are not necessary for transformation` - ) - this.logging.log( - `Files in directories ${filteredDirectories.join(', ')} are not zipped, as they are not necessary for transformation` - ) - if (failedCopies.length > 0) { - this.logging.log(`Files - ${failedCopies.join(',')} - could not be copied.`) - } const zipPath = path.join(this.workspacePath, zipFileName) this.logging.log('Zipping files to ' + zipPath) await this.zipDirectory(folderPath, zipPath) @@ -441,8 +428,6 @@ export class ArtifactManager { this.logging.log(`Failed to copy from ${sourceFilePath} and error is ${err}`) failedCopies.push(sourceFilePath) resolve() - failedCopies.push(sourceFilePath) - resolve() } else { resolve() } From 41c99af02b3f415e39898f11c3c21ac530f9c406 Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Wed, 17 Sep 2025 10:30:16 -0700 Subject: [PATCH 087/158] fix(amazonq): support mcp config files for backwards compatbility (#2292) --- .../agenticChat/tools/mcp/mcpManager.ts | 88 ++++++++++++++----- .../agenticChat/tools/mcp/mcpTypes.ts | 2 +- .../agenticChat/tools/mcp/mcpUtils.test.ts | 3 +- .../agenticChat/tools/mcp/mcpUtils.ts | 83 ++++++++++++++--- 4 files changed, 138 insertions(+), 38 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index a6dd3eda7b..6f395c507f 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -898,14 +898,14 @@ export class McpManager { this.mcpServers.clear() this.mcpServerStates.clear() this.agentConfig = { - name: 'amazon_q_default', + name: 'q_ide_default', description: 'Agent configuration', mcpServers: {}, tools: [], allowedTools: [], toolsSettings: {}, - includedFiles: [], resources: [], + useLegacyMcpJson: true, } if (!keepInstance) { McpManager.#instance = undefined @@ -959,7 +959,10 @@ export class McpManager { const serverPrefix = `@${unsanitizedServerName}` - // Process each tool permission using the permission manager + // Check if this is a legacy MCP server (from MCP config file) + const isLegacyMcpServer = serverConfig.__configPath__?.endsWith('mcp.json') + + // For agent config servers, use the permission manager for (const [toolName, permission] of Object.entries(perm.toolPerms || {})) { this.permissionManager.setToolPermission(unsanitizedServerName, toolName, permission) } @@ -967,26 +970,24 @@ export class McpManager { // Update the agent config from the permission manager this.agentConfig = this.permissionManager.getAgentConfig() - // Update mcpServerPermissions map immediately to reflect changes - this.mcpServerPermissions.set(serverName, { - enabled: perm.enabled, - toolPerms: perm.toolPerms || {}, - }) - - // Update server enabled/disabled state in agent config - if (this.agentConfig.mcpServers[unsanitizedServerName]) { - this.agentConfig.mcpServers[unsanitizedServerName].disabled = !perm.enabled - } + if (isLegacyMcpServer) { + // For legacy MCP servers, save permissions to agent config file and update MCP config for enable/disable + const mcpConfigPath = serverConfig.__configPath__! + const agentPath = mcpConfigPath.replace( + path.sep + 'mcp.json', + path.sep + 'agents' + path.sep + 'default.json' + ) - // Also update the mcpServers map - if (serverConfig) { - serverConfig.disabled = !perm.enabled - } + // Update MCP config for enable/disable + await this.mutateConfigFile(mcpConfigPath, (json: any) => { + if (!json.mcpServers[unsanitizedServerName]) { + json.mcpServers[unsanitizedServerName] = { ...serverConfig } + delete json.mcpServers[unsanitizedServerName].__configPath__ + } + json.mcpServers[unsanitizedServerName].disabled = !perm.enabled + }) - // Save only server-specific changes to agent config - const agentPath = perm.__configPath__ - if (agentPath) { - // Collect server-specific tools and allowedTools + // Use the same function but with corrected agent path const serverPrefix = `@${unsanitizedServerName}` const serverTools = this.agentConfig.tools.filter( tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) @@ -999,13 +1000,56 @@ export class McpManager { this.features.workspace, this.features.logging, unsanitizedServerName, - this.agentConfig.mcpServers[unsanitizedServerName], + null, // Don't save server config to agent file for legacy servers serverTools, serverAllowedTools, agentPath ) } + // Update mcpServerPermissions map immediately to reflect changes + this.mcpServerPermissions.set(serverName, { + enabled: perm.enabled, + toolPerms: perm.toolPerms || {}, + }) + + // Update server enabled/disabled state (only for non-legacy servers) + if (!isLegacyMcpServer) { + if (this.agentConfig.mcpServers[unsanitizedServerName]) { + this.agentConfig.mcpServers[unsanitizedServerName].disabled = !perm.enabled + } + } + + // Always update the mcpServers map + if (serverConfig) { + serverConfig.disabled = !perm.enabled + } + + // Save only server-specific changes to agent config (for non-legacy servers) + if (!isLegacyMcpServer) { + const agentPath = perm.__configPath__ + if (agentPath) { + // Collect server-specific tools and allowedTools + const serverPrefix = `@${unsanitizedServerName}` + const serverTools = this.agentConfig.tools.filter( + tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) + ) + const serverAllowedTools = this.agentConfig.allowedTools.filter( + tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) + ) + + await saveServerSpecificAgentConfig( + this.features.workspace, + this.features.logging, + unsanitizedServerName, + this.agentConfig.mcpServers[unsanitizedServerName], + serverTools, + serverAllowedTools, + agentPath + ) + } + } + // enable/disable server if (this.isServerDisabled(serverName)) { const client = this.clients.get(serverName) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpTypes.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpTypes.ts index feed97dba3..962ce8080a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpTypes.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpTypes.ts @@ -78,7 +78,7 @@ export class AgentModel { static fromJson(doc: any): AgentModel { const cfg: AgentConfig = { - name: doc?.['name'] || 'amazon_q_default', + name: doc?.['name'] || 'q_ide_default', description: doc?.['description'] || 'Default agent configuration', prompt: doc?.['prompt'], model: doc?.['model'], diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts index 8913e7391e..4d1f953d79 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts @@ -207,6 +207,7 @@ describe('loadAgentConfig', () => { mkdir: (d: string, opts: any) => Promise.resolve(fs.mkdirSync(d, { recursive: opts.recursive })), getUserHomeDir: () => tmpDir, }, + getAllWorkspaceFolders: () => [], } logger = { warn: () => {}, info: () => {}, error: () => {}, debug: () => {} } }) @@ -697,7 +698,7 @@ describe('convertPersonaToAgent', () => { const result = convertPersonaToAgent(persona, mcpServers, mockAgent) - expect(result.name).to.equal('amazon_q_default') + expect(result.name).to.equal('q_ide_default') expect(result.mcpServers).to.have.property('testServer') expect(result.tools).to.include('@testServer') expect(result.tools).to.include('fs_read') diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts index b8360ea314..522f7cdecf 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts @@ -147,7 +147,7 @@ export async function loadMcpServerConfigs( } const DEFAULT_AGENT_RAW = `{ - "name": "amazon_q_default", + "name": "q_ide_default", "description": "Default agent configuration", "prompt": "", "mcpServers": {}, @@ -179,7 +179,7 @@ const DEFAULT_AGENT_RAW = `{ "agentSpawn": [], "userPromptSubmit": [] }, - "useLegacyMcpJson": false + "useLegacyMcpJson": true }` const DEFAULT_PERSONA_RAW = `{ @@ -222,6 +222,7 @@ const DEFAULT_PERSONA_RAW = `{ * - Load global first (if exists), then workspace files—workspace overrides. * - Combines functionality of loadMcpServerConfigs and loadPersonaPermissions * - Handles server configurations and permissions from the same agent file + * - Supports backwards compatibility with MCP config files when useLegacyMcpJson is true */ export async function loadAgentConfig( workspace: Workspace, @@ -240,13 +241,14 @@ export async function loadAgentConfig( // Create base agent config const agentConfig: AgentConfig = { - name: 'amazon_q_default', + name: 'q_ide_default', description: 'Agent configuration', mcpServers: {}, tools: [], allowedTools: [], toolsSettings: {}, resources: [], + useLegacyMcpJson: true, // Default to true for backwards compatibility } // Normalize paths @@ -272,6 +274,9 @@ export async function loadAgentConfig( return 0 }) + // Track useLegacyMcpJson value - workspace takes precedence over global + let useLegacyMcpJsonValue: boolean | undefined + // Process each path like loadMcpServerConfigs for (const fsPath of sortedPaths) { // 1) Skip missing files or create default global @@ -333,6 +338,17 @@ export async function loadAgentConfig( agentConfig.description = json.description || agentConfig.description } + // Track useLegacyMcpJson - workspace files take precedence + if (json.useLegacyMcpJson !== undefined) { + if (fsPath !== globalConfigPath) { + // Workspace file - always takes precedence + useLegacyMcpJsonValue = json.useLegacyMcpJson + } else if (useLegacyMcpJsonValue === undefined) { + // Global file - only use if no workspace value set + useLegacyMcpJsonValue = json.useLegacyMcpJson + } + } + // 4) Process permissions (tools and allowedTools) if (Array.isArray(json.tools)) { for (const tool of json.tools) { @@ -460,8 +476,46 @@ export async function loadAgentConfig( } } + // Set final useLegacyMcpJson value - default to true if not specified anywhere + agentConfig.useLegacyMcpJson = useLegacyMcpJsonValue !== undefined ? useLegacyMcpJsonValue : true + + // Load MCP config files if useLegacyMcpJson is true + if (agentConfig.useLegacyMcpJson) { + const wsUris = workspace.getAllWorkspaceFolders()?.map(f => f.uri) ?? [] + const mcpPaths = [...getWorkspaceMcpConfigPaths(wsUris), getGlobalMcpConfigPath(workspace.fs.getUserHomeDir())] + + const mcpResult = await loadMcpServerConfigs(workspace, logging, mcpPaths) + + // MCP configs have precedence over agent configs + // Merge MCP servers into the result, overriding any from agent config + for (const [sanitizedName, mcpConfig] of mcpResult.servers) { + const originalName = mcpResult.serverNameMapping.get(sanitizedName) + if (originalName) { + servers.set(sanitizedName, mcpConfig) + serverNameMapping.set(sanitizedName, originalName) + + // Add MCP server tools to agent config for permission management + const serverPrefix = `@${originalName}` + if (!agentConfig.tools.includes(serverPrefix)) { + agentConfig.tools.push(serverPrefix) + } + + logging.info(`Loaded MCP server '${originalName}' from legacy MCP config`) + } + } + + // Merge MCP config errors + for (const [key, error] of mcpResult.errors) { + configErrors.set(`mcp_${key}`, error) + } + + logging.info(`Loaded ${mcpResult.servers.size} servers from legacy MCP configs`) + } + // Return the agent config, servers, server name mapping, and errors - logging.info(`Successfully processed ${uniquePaths.length} agent config files`) + logging.info( + `Successfully processed ${uniquePaths.length} agent config files and ${agentConfig.useLegacyMcpJson ? 'legacy MCP configs' : 'no legacy MCP configs'}` + ) return { servers, serverNameMapping, @@ -631,7 +685,7 @@ export function convertPersonaToAgent( featureAgent: Agent ): AgentConfig { const agent: AgentConfig = { - name: 'amazon_q_default', + name: 'q_ide_default', description: 'Default agent configuration', prompt: '', mcpServers: {}, @@ -644,7 +698,7 @@ export function convertPersonaToAgent( agentSpawn: [], userPromptSubmit: [], }, - useLegacyMcpJson: false, + useLegacyMcpJson: true, } // Include all servers from MCP config @@ -969,7 +1023,7 @@ export async function saveServerSpecificAgentConfig( } catch { // If file doesn't exist, create minimal config existingConfig = { - name: 'amazon_q_default', + name: 'q_ide_default', description: 'Agent configuration', mcpServers: {}, tools: [], @@ -995,11 +1049,12 @@ export async function saveServerSpecificAgentConfig( } else { // Update or add server existingConfig.mcpServers[serverName] = serverConfig - // Add new server tools - existingConfig.tools.push(...serverTools) - existingConfig.allowedTools.push(...serverAllowedTools) } + // Add new server tools + existingConfig.tools.push(...serverTools) + existingConfig.allowedTools.push(...serverAllowedTools) + await workspace.fs.writeFile(configPath, JSON.stringify(existingConfig, null, 2)) logging.info(`Saved server-specific agent config for ${serverName} to ${configPath}`) } catch (err: any) { @@ -1025,9 +1080,9 @@ export async function migrateAgentConfigToCLIFormat( let updated = false - // Rename default-agent to amazon_q_default - if (config.name === 'default-agent') { - config.name = 'amazon_q_default' + // Rename default-agent to q_ide_default + if (config.name !== 'q_ide_default') { + config.name = 'q_ide_default' updated = true } @@ -1041,7 +1096,7 @@ export async function migrateAgentConfigToCLIFormat( updated = true } if (!config.hasOwnProperty('useLegacyMcpJson')) { - config.useLegacyMcpJson = false + config.useLegacyMcpJson = true updated = true } From fcee77c1b06e69f9096d8e98a0cfcc42d7fddb01 Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Wed, 17 Sep 2025 11:58:10 -0700 Subject: [PATCH 088/158] fix(amazonq): fix to add filewatcher for mcp config files (#2295) --- .../agenticChat/tools/mcp/mcpEventHandler.ts | 15 ++++++++++++--- .../agenticChat/tools/mcp/mcpManager.ts | 3 ++- .../agenticChat/tools/mcp/mcpUtils.ts | 17 ++++++++++------- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts index d167299106..0e52bfa4ce 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts @@ -12,7 +12,14 @@ import { Status, } from '@aws/language-server-runtimes/protocol' -import { getGlobalAgentConfigPath, getWorkspaceAgentConfigPaths, sanitizeName, normalizePathFromUri } from './mcpUtils' +import { + getGlobalAgentConfigPath, + getWorkspaceAgentConfigPaths, + sanitizeName, + normalizePathFromUri, + getWorkspaceMcpConfigPaths, + getGlobalMcpConfigPath, +} from './mcpUtils' import { McpPermissionType, MCPServerConfig, @@ -1472,13 +1479,15 @@ export class McpEventHandler { this.#features.logging.warn(`Failed to get user home directory: ${e}`) } - // Only watch agent config files + // Watch both agent config files and MCP config files const agentPaths = [ ...getWorkspaceAgentConfigPaths(wsUris), ...(homeDir ? [getGlobalAgentConfigPath(homeDir)] : []), ] - const allPaths = [...agentPaths] + const mcpPaths = [...getWorkspaceMcpConfigPaths(wsUris), ...(homeDir ? [getGlobalMcpConfigPath(homeDir)] : [])] + + const allPaths = [...agentPaths, ...mcpPaths] this.#fileWatcher.watchPaths(allPaths, () => { // Store the current programmatic state when the event is triggered diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index 6f395c507f..e79b505f7c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -1003,7 +1003,8 @@ export class McpManager { null, // Don't save server config to agent file for legacy servers serverTools, serverAllowedTools, - agentPath + agentPath, + isLegacyMcpServer ) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts index 522f7cdecf..e6a7c605ab 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts @@ -1010,7 +1010,8 @@ export async function saveServerSpecificAgentConfig( serverConfig: any, serverTools: string[], serverAllowedTools: string[], - configPath: string + configPath: string, + isLegacyMcpServer: boolean = false ): Promise { try { await workspace.fs.mkdir(path.dirname(configPath), { recursive: true }) @@ -1043,12 +1044,14 @@ export async function saveServerSpecificAgentConfig( tool => tool !== serverPrefix && !tool.startsWith(`${serverPrefix}/`) ) - if (serverConfig === null) { - // Remove server entirely - delete existingConfig.mcpServers[serverName] - } else { - // Update or add server - existingConfig.mcpServers[serverName] = serverConfig + if (!isLegacyMcpServer) { + if (serverConfig === null) { + // Remove server entirely + delete existingConfig.mcpServers[serverName] + } else { + // Update or add server + existingConfig.mcpServers[serverName] = serverConfig + } } // Add new server tools From c7a9a8e1ba5c1a284d661e683dd46133860a1d3d Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Wed, 17 Sep 2025 13:46:41 -0700 Subject: [PATCH 089/158] fix(amazonq): fix for mcp permissions read/write inconsistencies (#2296) --- .../tools/mcp/agentPermissionManager.test.ts | 7 +- .../tools/mcp/agentPermissionManager.ts | 362 ++++++++++++++++-- .../tools/mcp/mcpEventHandler.test.ts | 11 + .../agenticChat/tools/mcp/mcpManager.test.ts | 20 +- .../agenticChat/tools/mcp/mcpManager.ts | 39 +- .../agenticChat/tools/mcp/mcpTool.test.ts | 13 +- .../agenticChat/tools/mcp/mcpUtils.ts | 28 +- .../agenticChat/tools/toolServer.ts | 1 + 8 files changed, 413 insertions(+), 68 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.test.ts index 2c50dfcdc0..b120a11fe4 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.test.ts @@ -19,7 +19,12 @@ describe('AgentPermissionManager', () => { tools: [], allowedTools: [], } - manager = new AgentPermissionManager(agentConfig) + manager = new AgentPermissionManager( + agentConfig, + undefined, // getAvailableTools + undefined, // getAllAvailableServers + undefined // getAllBuiltinTools + ) }) describe('matchesPattern', () => { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.ts index 143ffd0475..cb9e1c859e 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/agentPermissionManager.ts @@ -9,7 +9,12 @@ import { AgentConfig, McpPermissionType } from './mcpTypes' * Manages agent tool permissions with wildcard support for reading and simple patterns for writing */ export class AgentPermissionManager { - constructor(private agentConfig: AgentConfig) {} + constructor( + private agentConfig: AgentConfig, + private getAvailableTools?: (serverName: string) => string[], + private getAllAvailableServers?: () => string[], + private getAllBuiltinTools?: () => string[] + ) {} /** * Check if a tool matches a pattern using glob-style wildcards @@ -36,19 +41,29 @@ export class AgentPermissionManager { const toolId = serverName ? `@${serverName}/${toolName}` : toolName const serverPrefix = serverName ? `@${serverName}` : '' - // Check exact matches first + // Check exact matches first (exact matches take precedence) if (this.agentConfig.tools.includes(toolId)) return true if (serverPrefix && this.agentConfig.tools.includes(serverPrefix)) return true + // Check for global wildcard + if (this.agentConfig.tools.includes('*')) return true + + // Check for @builtin pattern (built-in tools only) + if (!serverName && this.agentConfig.tools.includes('@builtin')) return true + // Check wildcard patterns for (const tool of this.agentConfig.tools) { if (tool.includes('*') || tool.includes('?')) { + // For server patterns like @*-mcp, match against server prefix + if (serverName && tool.startsWith('@') && !tool.includes('/')) { + if (this.matchesPattern(serverPrefix, tool)) return true + } + // For full tool patterns if (this.matchesPattern(toolId, tool)) return true } } - // Check for global wildcard - return this.agentConfig.tools.includes('*') + return false } /** @@ -76,68 +91,79 @@ export class AgentPermissionManager { * Get permission type for a tool */ getToolPermission(serverName: string, toolName: string): McpPermissionType { + const toolId = serverName ? `@${serverName}/${toolName}` : toolName + const serverPrefix = serverName ? `@${serverName}` : '' + + // Check exact matches first (exact matches take precedence over patterns) + const exactInTools = this.agentConfig.tools.includes(toolId) + const exactInAllowed = this.agentConfig.allowedTools.includes(toolId) + const serverInTools = serverPrefix && this.agentConfig.tools.includes(serverPrefix) + const serverInAllowed = serverPrefix && this.agentConfig.allowedTools.includes(serverPrefix) + + // If exact match in allowedTools or server-wide in allowedTools + if (exactInAllowed || serverInAllowed) { + return McpPermissionType.alwaysAllow + } + + // If exact match in tools, check if also in allowedTools patterns + if (exactInTools) { + const isAlwaysAllowed = this.isToolAlwaysAllowed(serverName, toolName) + return isAlwaysAllowed ? McpPermissionType.alwaysAllow : McpPermissionType.ask + } + + // If server-wide in tools, check if also in allowedTools patterns + if (serverInTools) { + const isAlwaysAllowed = this.isToolAlwaysAllowed(serverName, toolName) + return isAlwaysAllowed ? McpPermissionType.alwaysAllow : McpPermissionType.ask + } + + // Fall back to pattern matching const isEnabled = this.isToolEnabled(serverName, toolName) const isAlwaysAllowed = this.isToolAlwaysAllowed(serverName, toolName) - // If tool is always allowed, it's implicitly enabled - if (isAlwaysAllowed) { + // Tool must be enabled first before it can be always allowed + if (isEnabled && isAlwaysAllowed) { return McpPermissionType.alwaysAllow } - // If tool is enabled but not always allowed, ask for permission if (isEnabled) { return McpPermissionType.ask } - // Tool is not enabled and not always allowed return McpPermissionType.deny } /** - * Set permission for a tool (uses simple patterns for writing) + * Set permission for a tool - removes conflicting wildcards and replaces with explicit tools */ setToolPermission(serverName: string, toolName: string, permission: McpPermissionType): void { const toolId = serverName ? `@${serverName}/${toolName}` : toolName const serverPrefix = serverName ? `@${serverName}` : '' - // Remove conflicting wildcards that would affect this tool - this.removeConflictingWildcards(toolId) - switch (permission) { case McpPermissionType.deny: - this.removeTool(toolId, serverPrefix) - this.removeFromAllowedTools(toolId, serverPrefix) + this.removeConflictingWildcardsForDeny(serverName, toolName) + this.removeConflictingAllowedWildcardsForDeny(serverName, toolName) break case McpPermissionType.ask: - this.addTool(toolId) - this.removeFromAllowedTools(toolId, serverPrefix) + this.removeConflictingAllowedWildcardsForAsk(serverName, toolName) + if (!this.isToolEnabled(serverName, toolName)) { + this.addTool(toolId) + } break case McpPermissionType.alwaysAllow: - this.addTool(toolId) - this.addToAllowedTools(toolId) + if (!this.isToolEnabled(serverName, toolName)) { + this.addTool(toolId) + } + if (!this.isToolAlwaysAllowed(serverName, toolName)) { + this.addToAllowedTools(toolId) + } break } } - /** - * Remove wildcards that would conflict with specific tool permission - */ - private removeConflictingWildcards(toolId: string): void { - // Remove wildcards from tools array that would match this tool - this.agentConfig.tools = this.agentConfig.tools.filter(tool => { - if (!tool.includes('*') && !tool.includes('?')) return true - return !this.matchesPattern(toolId, tool) - }) - - // Remove wildcards from allowedTools array that would match this tool - this.agentConfig.allowedTools = this.agentConfig.allowedTools.filter(tool => { - if (!tool.includes('*') && !tool.includes('?')) return true - return !this.matchesPattern(toolId, tool) - }) - } - /** * Add tool to tools array */ @@ -164,7 +190,7 @@ export class AgentPermissionManager { } /** - * Remove tool from allowedTools array + * Remove tool from allowedTools array (only exact matches) */ private removeFromAllowedTools(toolId: string, serverPrefix?: string): void { this.agentConfig.allowedTools = this.agentConfig.allowedTools.filter( @@ -202,6 +228,270 @@ export class AgentPermissionManager { } } + /** + * Convert server-wide permission to individual tools, excluding the denied tool + */ + private convertServerWideToIndividualTools(serverName: string, deniedToolName: string): void { + const serverPrefix = `@${serverName}` + + // Remove server-wide permission + this.agentConfig.tools = this.agentConfig.tools.filter(tool => tool !== serverPrefix) + + // If we have a callback to get available tools, add them individually + if (this.getAvailableTools) { + const availableTools = this.getAvailableTools(serverName) + for (const toolName of availableTools) { + if (toolName !== deniedToolName) { + const toolId = `@${serverName}/${toolName}` + this.addTool(toolId) + } + } + } + // If no callback, we just remove server-wide permission (limitation) + } + + /** + * Remove conflicting wildcards from tools when denying a tool + */ + private removeConflictingWildcardsForDeny(serverName: string, toolName: string): void { + const toolId = serverName ? `@${serverName}/${toolName}` : toolName + const serverPrefix = serverName ? `@${serverName}` : '' + + // Handle global wildcard (*) + if (this.agentConfig.tools.includes('*')) { + this.expandGlobalWildcard(serverName, toolName) + } + + // Handle server-wide wildcard (@server) + if (serverPrefix && this.agentConfig.tools.includes(serverPrefix)) { + this.convertServerWideToIndividualTools(serverName, toolName) + } + + // Handle @builtin wildcard + if (!serverName && this.agentConfig.tools.includes('@builtin')) { + this.expandBuiltinWildcard(toolName) + } + + // Handle pattern wildcards + this.removeMatchingPatternWildcards(serverName, toolName) + + // Remove explicit tool entry + this.removeTool(toolId, serverPrefix) + } + + /** + * Remove conflicting wildcards from allowedTools when denying a tool + */ + private removeConflictingAllowedWildcardsForDeny(serverName: string, toolName: string): void { + const toolId = serverName ? `@${serverName}/${toolName}` : toolName + const serverPrefix = serverName ? `@${serverName}` : '' + + // Remove exact matches + this.agentConfig.allowedTools = this.agentConfig.allowedTools.filter( + tool => tool !== toolId && tool !== serverPrefix + ) + + // Remove matching wildcards and expand them + const toRemove: string[] = [] + for (const allowedTool of this.agentConfig.allowedTools) { + if (allowedTool.includes('*') || allowedTool.includes('?')) { + if (this.matchesPattern(toolId, allowedTool)) { + toRemove.push(allowedTool) + } + } + } + + for (const pattern of toRemove) { + this.expandAllowedPatternWildcard(pattern, serverName, toolName) + } + } + + /** + * Remove conflicting wildcards from allowedTools when setting to ask + */ + private removeConflictingAllowedWildcardsForAsk(serverName: string, toolName: string): void { + const toolId = serverName ? `@${serverName}/${toolName}` : toolName + const serverPrefix = serverName ? `@${serverName}` : '' + + // Remove exact matches + this.agentConfig.allowedTools = this.agentConfig.allowedTools.filter( + tool => tool !== toolId && tool !== serverPrefix + ) + + // Remove matching wildcards and expand them (excluding the tool being set to ask) + const toRemove: string[] = [] + for (const allowedTool of this.agentConfig.allowedTools) { + if (allowedTool.includes('*') || allowedTool.includes('?')) { + if (this.matchesPattern(toolId, allowedTool)) { + toRemove.push(allowedTool) + } + } + } + + for (const pattern of toRemove) { + this.expandAllowedPatternWildcard(pattern, serverName, toolName) + } + } + + /** + * Expand global wildcard (*) to all available tools except the denied one + */ + private expandGlobalWildcard(deniedServerName: string, deniedToolName: string): void { + this.agentConfig.tools = this.agentConfig.tools.filter(tool => tool !== '*') + + if (this.getAvailableTools) { + // Get all available servers (this should be provided by the manager) + const allServers = this.getAvailableServers() + for (const serverName of allServers) { + const tools = this.getAvailableTools(serverName) + for (const toolName of tools) { + if (!(serverName === deniedServerName && toolName === deniedToolName)) { + this.addTool(`@${serverName}/${toolName}`) + } + } + } + + // Add builtin tools (except denied one) + const builtinTools = this.getBuiltinTools() + for (const toolName of builtinTools) { + if (!(deniedServerName === '' && toolName === deniedToolName)) { + this.addTool(toolName) + } + } + } + } + + /** + * Expand @builtin wildcard to all builtin tools except the denied one + */ + private expandBuiltinWildcard(deniedToolName: string): void { + this.agentConfig.tools = this.agentConfig.tools.filter(tool => tool !== '@builtin') + + const builtinTools = this.getBuiltinTools() + for (const toolName of builtinTools) { + if (toolName !== deniedToolName) { + this.addTool(toolName) + } + } + } + + /** + * Remove pattern wildcards that match the tool and expand them + */ + private removeMatchingPatternWildcards(serverName: string, toolName: string): void { + const toolId = serverName ? `@${serverName}/${toolName}` : toolName + const serverPrefix = serverName ? `@${serverName}` : '' + + const toRemove: string[] = [] + for (const tool of this.agentConfig.tools) { + if (tool.includes('*') || tool.includes('?')) { + if (serverName && tool.startsWith('@') && !tool.includes('/')) { + if (this.matchesPattern(serverPrefix, tool)) { + toRemove.push(tool) + } + } else if (this.matchesPattern(toolId, tool)) { + toRemove.push(tool) + } + } + } + + for (const pattern of toRemove) { + this.expandPatternWildcard(pattern, serverName, toolName) + } + } + + /** + * Expand a pattern wildcard to individual tools except the denied one + */ + private expandPatternWildcard(pattern: string, deniedServerName: string, deniedToolName: string): void { + this.agentConfig.tools = this.agentConfig.tools.filter(tool => tool !== pattern) + + if (!this.getAvailableTools) return + + if (pattern.startsWith('@') && !pattern.includes('/')) { + // Server pattern like @*-mcp + const allServers = this.getAvailableServers() + for (const serverName of allServers) { + const serverPrefix = `@${serverName}` + if (this.matchesPattern(serverPrefix, pattern)) { + const tools = this.getAvailableTools(serverName) + for (const toolName of tools) { + if (!(serverName === deniedServerName && toolName === deniedToolName)) { + this.addTool(`@${serverName}/${toolName}`) + } + } + } + } + } else { + // Tool pattern like @fs/read_* + const allServers = this.getAvailableServers() + for (const serverName of allServers) { + const tools = this.getAvailableTools(serverName) + for (const toolName of tools) { + const toolId = `@${serverName}/${toolName}` + if (this.matchesPattern(toolId, pattern)) { + if (!(serverName === deniedServerName && toolName === deniedToolName)) { + this.addTool(toolId) + } + } + } + } + } + } + + /** + * Expand allowedTools pattern wildcard except the denied tool + */ + private expandAllowedPatternWildcard(pattern: string, deniedServerName: string, deniedToolName: string): void { + this.agentConfig.allowedTools = this.agentConfig.allowedTools.filter(tool => tool !== pattern) + + if (!this.getAvailableTools) return + + if (pattern.startsWith('@') && !pattern.includes('/')) { + // Server pattern like @git + const allServers = this.getAvailableServers() + for (const serverName of allServers) { + const serverPrefix = `@${serverName}` + if (this.matchesPattern(serverPrefix, pattern)) { + const tools = this.getAvailableTools(serverName) + for (const toolName of tools) { + if (!(serverName === deniedServerName && toolName === deniedToolName)) { + this.addToAllowedTools(`@${serverName}/${toolName}`) + } + } + } + } + } else { + // Tool pattern like @fs/* + const allServers = this.getAvailableServers() + for (const serverName of allServers) { + const tools = this.getAvailableTools(serverName) + for (const toolName of tools) { + const toolId = `@${serverName}/${toolName}` + if (this.matchesPattern(toolId, pattern)) { + if (!(serverName === deniedServerName && toolName === deniedToolName)) { + this.addToAllowedTools(toolId) + } + } + } + } + } + } + + /** + * Get all available servers + */ + private getAvailableServers(): string[] { + return this.getAllAvailableServers?.() || [] + } + + /** + * Get all builtin tools + */ + private getBuiltinTools(): string[] { + return this.getAllBuiltinTools?.() || [] + } + /** * Get updated agent config */ diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts index de98f36a09..b55f24614a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.test.ts @@ -49,6 +49,17 @@ describe('McpEventHandler error handling', () => { }, agent: { getTools: sinon.stub().returns([]), + getBuiltInToolNames: sinon + .stub() + .returns([ + 'fsRead', + 'fsWrite', + 'executeBash', + 'listDirectory', + 'fileSearch', + 'codeReview', + 'displayFindings', + ]), }, lsp: {}, telemetry: { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts index 1b5941a398..a717fc6b93 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.test.ts @@ -28,7 +28,25 @@ const fakeWorkspace = { getUserHomeDir: () => '', getAllWorkspaceFolders: () => [{ uri: '/fake/workspace' }], } -const features = { logging: fakeLogging, workspace: fakeWorkspace, lsp: {} } as any +const features = { + logging: fakeLogging, + workspace: fakeWorkspace, + lsp: {}, + telemetry: { emitMetric: () => {} }, + credentialsProvider: { getConnectionMetadata: () => ({}) }, + runtime: { serverInfo: { version: '1.0.0' } }, + agent: { + getBuiltInToolNames: () => [ + 'fsRead', + 'fsWrite', + 'executeBash', + 'listDirectory', + 'fileSearch', + 'codeReview', + 'displayFindings', + ], + }, +} as any function stubAgentConfig(): sinon.SinonStub { return sinon.stub(mcpUtils, 'loadAgentConfig').resolves({ diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index e79b505f7c..027bf743c0 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -72,7 +72,7 @@ export class McpManager { private agentPaths: string[], private features: Pick< Features, - 'logging' | 'workspace' | 'lsp' | 'telemetry' | 'credentialsProvider' | 'runtime' + 'logging' | 'workspace' | 'lsp' | 'telemetry' | 'credentialsProvider' | 'runtime' | 'agent' > ) { this.mcpTools = [] @@ -89,7 +89,10 @@ export class McpManager { public static async init( agentPaths: string[], - features: Pick + features: Pick< + Features, + 'logging' | 'workspace' | 'lsp' | 'telemetry' | 'credentialsProvider' | 'runtime' | 'agent' + > ): Promise { if (!McpManager.#instance) { const mgr = new McpManager(agentPaths, features) @@ -179,7 +182,12 @@ export class McpManager { // Extract agent config and other data this.agentConfig = result.agentConfig - this.permissionManager = new AgentPermissionManager(this.agentConfig) + this.permissionManager = new AgentPermissionManager( + this.agentConfig, + (serverName: string) => this.getAvailableToolsForServer(serverName), + () => this.getAllAvailableServerNames(), + () => this.getAllBuiltinToolNames() + ) this.mcpServers = result.servers this.serverNameMapping = result.serverNameMapping @@ -1088,6 +1096,31 @@ export class McpManager { return !this.agentConfig.allowedTools.includes(toolId) } + /** + * Get available tools for a specific server + */ + private getAvailableToolsForServer(serverName: string): string[] { + return this.mcpTools.filter(tool => tool.serverName === serverName).map(tool => tool.toolName) + } + + /** + * Get all available server names + */ + private getAllAvailableServerNames(): string[] { + const serverNames = new Set() + for (const tool of this.mcpTools) { + serverNames.add(tool.serverName) + } + return Array.from(serverNames) + } + + /** + * Get all builtin tool names + */ + private getAllBuiltinToolNames(): string[] { + return this.features.agent?.getBuiltInToolNames() || [] + } + /** * get server's tool permission */ diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpTool.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpTool.test.ts index b0f936ac46..683c5ff8ac 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpTool.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpTool.test.ts @@ -25,9 +25,20 @@ describe('McpTool', () => { }, telemetry: { record: () => {}, emitMetric: () => {} }, runtime: { serverInfo: { version: '1.0.0' } }, + agent: { + getBuiltInToolNames: () => [ + 'fsRead', + 'fsWrite', + 'executeBash', + 'listDirectory', + 'fileSearch', + 'codeReview', + 'displayFindings', + ], + }, } as unknown as Pick< import('@aws/language-server-runtimes/server-interface/server').Features, - 'logging' | 'workspace' | 'lsp' | 'credentialsProvider' | 'telemetry' | 'runtime' + 'logging' | 'workspace' | 'lsp' | 'credentialsProvider' | 'telemetry' | 'runtime' | 'agent' > const definition: McpToolDefinition = { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts index e6a7c605ab..3a9df3e11e 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts @@ -684,22 +684,7 @@ export function convertPersonaToAgent( mcpServers: Record, featureAgent: Agent ): AgentConfig { - const agent: AgentConfig = { - name: 'q_ide_default', - description: 'Default agent configuration', - prompt: '', - mcpServers: {}, - tools: [], - toolAliases: {}, - allowedTools: [], - toolsSettings: {}, - resources: [], - hooks: { - agentSpawn: [], - userPromptSubmit: [], - }, - useLegacyMcpJson: true, - } + const agent: AgentConfig = JSON.parse(DEFAULT_AGENT_RAW) // Include all servers from MCP config Object.entries(mcpServers).forEach(([name, config]) => { @@ -1023,16 +1008,7 @@ export async function saveServerSpecificAgentConfig( existingConfig = JSON.parse(raw.toString()) } catch { // If file doesn't exist, create minimal config - existingConfig = { - name: 'q_ide_default', - description: 'Agent configuration', - mcpServers: {}, - tools: [], - allowedTools: [], - toolsSettings: {}, - includedFiles: [], - resources: [], - } + existingConfig = JSON.parse(DEFAULT_AGENT_RAW) } // Remove existing server tools from arrays diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts index d2257a45e4..23b279b1f5 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/toolServer.ts @@ -348,6 +348,7 @@ export const McpToolsServer: Server = ({ telemetry, credentialsProvider, runtime, + agent, }) McpManager.instance.clearToolNameMapping() From d207b6e9dfded650c6f65c675ee45c52f8222571 Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:01:08 -0700 Subject: [PATCH 090/158] fix: inline UTD telemetry empty cases dont differentiate Edit and Completion (#2288) --- .../src/shared/codeWhispererService.ts | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index ba02c9c4e9..c16b23110e 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -519,7 +519,11 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { authType: 'token' as const, } - const r = this.mapCodeWhispererApiResponseToSuggestion(response, responseContext) + const r = this.mapCodeWhispererApiResponseToSuggestion( + response, + tokenRequest.predictionTypes, + responseContext + ) const firstSuggestionLogstr = r.suggestions.length > 0 ? `\n${r.suggestions[0].content}` : 'No suggestion' logstr += `@@response metadata@@ @@ -543,20 +547,36 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { private mapCodeWhispererApiResponseToSuggestion( apiResponse: GenerateCompletionsResponse, + requestPredictionType: CodeWhispererTokenClient.PredictionTypes | undefined, responseContext: ResponseContext ): GenerateSuggestionsResponse { - if (apiResponse?.predictions && apiResponse.predictions.length > 0) { - const suggestionType = apiResponse.predictions[0].edit ? SuggestionType.EDIT : SuggestionType.COMPLETION - const predictionType = suggestionType === SuggestionType.COMPLETION ? 'completion' : 'edit' + // "Predictions" will be returned if clients speicifed predictionType in the generateCompletion request, otherwise "Completions" will be returned for the backward compatibility + if (apiResponse?.predictions) { + // Infer suggestion type from the actual suggestions if any, otherwise use client specified prediction tyoe + if (apiResponse.predictions.length > 0) { + const suggestionType = apiResponse.predictions[0].edit ? SuggestionType.EDIT : SuggestionType.COMPLETION + const predictionType = suggestionType === SuggestionType.COMPLETION ? 'completion' : 'edit' - return { - suggestions: apiResponse.predictions.map(prediction => ({ - content: prediction[predictionType]?.content ?? '', - references: prediction[predictionType]?.references ?? [], - itemId: this.generateItemId(), - })), - suggestionType, - responseContext, + return { + suggestions: apiResponse.predictions.map(prediction => ({ + content: prediction[predictionType]?.content ?? '', + references: prediction[predictionType]?.references ?? [], + itemId: this.generateItemId(), + })), + suggestionType, + responseContext, + } + } else if (apiResponse.predictions.length === 0) { + const suggestionType = + requestPredictionType && requestPredictionType.includes('EDITS') + ? SuggestionType.EDIT + : SuggestionType.COMPLETION + + return { + suggestions: [], + suggestionType: suggestionType, + responseContext, + } } } From eb081e6bc6bef4182ab89e295bff97c4e828096b Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:50:03 -0700 Subject: [PATCH 091/158] revert: inline UTD telemetry empty cases dont differentiate Edit and Completion (#2288) (#2297) This reverts commit d207b6e9dfded650c6f65c675ee45c52f8222571. --- .../src/shared/codeWhispererService.ts | 44 +++++-------------- 1 file changed, 12 insertions(+), 32 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index c16b23110e..ba02c9c4e9 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -519,11 +519,7 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { authType: 'token' as const, } - const r = this.mapCodeWhispererApiResponseToSuggestion( - response, - tokenRequest.predictionTypes, - responseContext - ) + const r = this.mapCodeWhispererApiResponseToSuggestion(response, responseContext) const firstSuggestionLogstr = r.suggestions.length > 0 ? `\n${r.suggestions[0].content}` : 'No suggestion' logstr += `@@response metadata@@ @@ -547,36 +543,20 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { private mapCodeWhispererApiResponseToSuggestion( apiResponse: GenerateCompletionsResponse, - requestPredictionType: CodeWhispererTokenClient.PredictionTypes | undefined, responseContext: ResponseContext ): GenerateSuggestionsResponse { - // "Predictions" will be returned if clients speicifed predictionType in the generateCompletion request, otherwise "Completions" will be returned for the backward compatibility - if (apiResponse?.predictions) { - // Infer suggestion type from the actual suggestions if any, otherwise use client specified prediction tyoe - if (apiResponse.predictions.length > 0) { - const suggestionType = apiResponse.predictions[0].edit ? SuggestionType.EDIT : SuggestionType.COMPLETION - const predictionType = suggestionType === SuggestionType.COMPLETION ? 'completion' : 'edit' - - return { - suggestions: apiResponse.predictions.map(prediction => ({ - content: prediction[predictionType]?.content ?? '', - references: prediction[predictionType]?.references ?? [], - itemId: this.generateItemId(), - })), - suggestionType, - responseContext, - } - } else if (apiResponse.predictions.length === 0) { - const suggestionType = - requestPredictionType && requestPredictionType.includes('EDITS') - ? SuggestionType.EDIT - : SuggestionType.COMPLETION + if (apiResponse?.predictions && apiResponse.predictions.length > 0) { + const suggestionType = apiResponse.predictions[0].edit ? SuggestionType.EDIT : SuggestionType.COMPLETION + const predictionType = suggestionType === SuggestionType.COMPLETION ? 'completion' : 'edit' - return { - suggestions: [], - suggestionType: suggestionType, - responseContext, - } + return { + suggestions: apiResponse.predictions.map(prediction => ({ + content: prediction[predictionType]?.content ?? '', + references: prediction[predictionType]?.references ?? [], + itemId: this.generateItemId(), + })), + suggestionType, + responseContext, } } From 8641860295c4e089d09154fa5411c305f2f4ecce Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Thu, 18 Sep 2025 09:27:02 -0700 Subject: [PATCH 092/158] fix(amazonq): fix for delete mcp for mcp config, disable and create corresponding agent file (#2298) --- .../agenticChat/tools/mcp/mcpManager.ts | 21 ++++++++++++++- .../agenticChat/tools/mcp/mcpUtils.ts | 27 +++++++++++-------- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index 027bf743c0..8275c2a971 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -744,6 +744,24 @@ export class McpManager { this.mcpTools = this.mcpTools.filter(t => t.serverName !== serverName) this.mcpServerStates.delete(serverName) + // Check if this is a legacy MCP server (from MCP config file) + const isLegacyMcpServer = cfg.__configPath__?.endsWith('mcp.json') + let agentPath: string | undefined + + if (isLegacyMcpServer && unsanitizedName) { + // Remove from MCP config file + await this.mutateConfigFile(cfg.__configPath__, (json: any) => { + if (json.mcpServers && json.mcpServers[unsanitizedName]) { + delete json.mcpServers[unsanitizedName] + } + }) + + agentPath = cfg.__configPath__.replace( + path.sep + 'mcp.json', + path.sep + 'agents' + path.sep + 'default.json' + ) + } + // Remove from agent config if (unsanitizedName && this.agentConfig) { // Remove server from mcpServers @@ -783,7 +801,8 @@ export class McpManager { null, // null indicates server should be removed [], [], - cfg.__configPath__ + isLegacyMcpServer ? agentPath! : cfg.__configPath__, + isLegacyMcpServer ) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts index 3a9df3e11e..ca174261cc 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts @@ -107,14 +107,20 @@ export async function loadMcpServerConfigs( configErrors.set(`${name}_timeout`, errorMsg) } const cfg: MCPServerConfig = { - url: entry.url, - headers: typeof entry.headers === 'object' && entry.headers !== null ? entry.headers : undefined, - command: entry.command, - args: Array.isArray(entry.args) ? entry.args.map(String) : [], - env: typeof entry.env === 'object' && entry.env !== null ? entry.env : {}, + command: (entry as any).command, + url: (entry as any).url, + args: Array.isArray((entry as any).args) ? (entry as any).args.map(String) : [], + env: typeof (entry as any).env === 'object' && (entry as any).env !== null ? (entry as any).env : {}, + headers: + typeof (entry as any).headers === 'object' && (entry as any).headers !== null + ? (entry as any).headers + : undefined, initializationTimeout: - typeof entry.initializationTimeout === 'number' ? entry.initializationTimeout : undefined, - timeout: typeof entry.timeout === 'number' ? entry.timeout : undefined, + typeof (entry as any).initializationTimeout === 'number' + ? (entry as any).initializationTimeout + : undefined, + timeout: typeof (entry as any).timeout === 'number' ? (entry as any).timeout : undefined, + disabled: typeof (entry as any).disabled === 'boolean' ? (entry as any).disabled : false, __configPath__: fsPath, } @@ -1074,10 +1080,6 @@ export async function migrateAgentConfigToCLIFormat( config.toolAliases = {} updated = true } - if (!config.hasOwnProperty('useLegacyMcpJson')) { - config.useLegacyMcpJson = true - updated = true - } // Remove deprecated fields if (config.hasOwnProperty('version')) { @@ -1116,6 +1118,9 @@ export async function migrateAgentConfigToCLIFormat( } } + config.useLegacyMcpJson = true + updated = true + if (updated) { await workspace.fs.writeFile(configPath, JSON.stringify(config, null, 2)) logging.info(`Migrated agent config to CLI format: ${configPath}`) From 50dafe1a5af536757c0c4d81c929ddae5652434f Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Thu, 18 Sep 2025 13:18:55 -0700 Subject: [PATCH 093/158] chore: profile change log is recording stale profile instead of new updated one (#2250) --- .../shared/amazonQServiceManager/AmazonQTokenServiceManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts index 903a57c0fa..d5cee6db7c 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts @@ -418,9 +418,9 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< const newRegion = newProfile.identityDetails.region if (oldRegion === newRegion) { this.log(`New profile is in the same region as old one, keeping exising service.`) - this.log(`New active profile is ${this.activeIdcProfile.arn}, region ${oldRegion}`) this.activeIdcProfile = newProfile this.state = 'INITIALIZED' + this.log(`New active profile is ${this.activeIdcProfile.arn}, region ${newRegion}`) if (this.cachedCodewhispererService) { this.cachedCodewhispererService.profileArn = newProfile.arn From c8aa7bd3e9d39ed327972bbc950ad72e8e401581 Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Thu, 18 Sep 2025 14:06:18 -0700 Subject: [PATCH 094/158] fix(amazonq): fix for legacy mcp permission consistentcy and config update (#2300) --- .../agenticChat/tools/mcp/mcpEventHandler.ts | 50 +++++- .../agenticChat/tools/mcp/mcpManager.ts | 166 ++++++++++++------ 2 files changed, 157 insertions(+), 59 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts index 0e52bfa4ce..efc22344cc 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpEventHandler.ts @@ -789,8 +789,11 @@ export class McpEventHandler { try { if (isEditMode && originalServerName) { const serverToRemove = this.#serverNameBeforeUpdate || originalServerName + const serverConfig = McpManager.instance.getAllServerConfigs().get(serverToRemove) + const isLegacyMcpServer = serverConfig?.__configPath__?.endsWith('mcp.json') ?? false + const configPath = isLegacyMcpServer ? await this.#getMcpConfigPath(isGlobal) : agentPath await McpManager.instance.removeServer(serverToRemove) - await McpManager.instance.addServer(serverName, config, agentPath) + await McpManager.instance.addServer(serverName, config, configPath, isLegacyMcpServer) } else { // Create new server await McpManager.instance.addServer(serverName, config, agentPath) @@ -1267,7 +1270,9 @@ export class McpEventHandler { numTools: McpManager.instance.getAllToolsWithPermissions(serverName).length, scope: serverConfig.__configPath__ === - getGlobalAgentConfigPath(this.#features.workspace.fs.getUserHomeDir()) + getGlobalAgentConfigPath(this.#features.workspace.fs.getUserHomeDir()) || + serverConfig.__configPath__ === + getGlobalMcpConfigPath(this.#features.workspace.fs.getUserHomeDir()) ? 'global' : 'workspace', transportType: transportType, @@ -1296,12 +1301,13 @@ export class McpEventHandler { ([name, _]) => !mcpManager.isServerDisabled(name) ) - // Get the global agent path + // Get the global paths const globalAgentPath = getGlobalAgentConfigPath(this.#features.workspace.fs.getUserHomeDir()) + const globalMcpPath = getGlobalMcpConfigPath(this.#features.workspace.fs.getUserHomeDir()) // Count global vs project servers const globalServers = Array.from(serverConfigs.entries()).filter( - ([_, config]) => config.__configPath__ === globalAgentPath + ([_, config]) => config.__configPath__ === globalAgentPath || config.__configPath__ === globalMcpPath ).length const projectServers = serverConfigs.size - globalServers @@ -1339,7 +1345,10 @@ export class McpEventHandler { url: transportType === TransportType.HTTP ? config.url : undefined, enabled: enabled, numTools: mcpManager.getAllToolsWithPermissions(serverName).length, - scope: config.__configPath__ === globalAgentPath ? 'global' : 'workspace', + scope: + config.__configPath__ === globalAgentPath || config.__configPath__ === globalMcpPath + ? 'global' + : 'workspace', transportType: transportType, languageServerVersion: this.#features.runtime.serverInfo.version, }) @@ -1410,6 +1419,37 @@ export class McpEventHandler { return globalAgentPath } + /** + * Gets the appropriate MCP config path, checking workspace path first if it exists + * @returns The MCP config path to use (workspace if exists, otherwise global) + */ + async #getMcpConfigPath(isGlobal: boolean = true): Promise { + const globalMcpPath = getGlobalMcpConfigPath(this.#features.workspace.fs.getUserHomeDir()) + if (isGlobal) { + return globalMcpPath + } + // Get workspace folders and check for workspace MCP path + const workspaceFolders = this.#features.workspace.getAllWorkspaceFolders() + if (workspaceFolders && workspaceFolders.length > 0) { + const workspacePaths = workspaceFolders.map(folder => folder.uri) + const workspaceMcpPaths = getWorkspaceMcpConfigPaths(workspacePaths) + + if (Array.isArray(workspaceMcpPaths) && workspaceMcpPaths.length > 0) { + try { + // Convert URI format to filesystem path if needed using the utility function + const mcpPath = normalizePathFromUri(workspaceMcpPaths[0], this.#features.logging) + + return mcpPath + } catch (e) { + this.#features.logging.warn(`Failed to check if workspace MCP path exists: ${e}`) + } + } + } + + // Return global path if workspace path doesn't exist or there was an error + return globalMcpPath + } + /** * Processes permission updates from the UI */ diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts index 8275c2a971..9b155b3d8c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpManager.ts @@ -645,7 +645,12 @@ export class McpManager { /** * Add a new server: persist config, register in memory, and initialize. */ - public async addServer(serverName: string, cfg: MCPServerConfig, agentPath: string): Promise { + public async addServer( + serverName: string, + cfg: MCPServerConfig, + configPath: string, + isLegacyMcpServer: boolean = false + ): Promise { try { const sanitizedName = sanitizeName(serverName) if ( @@ -655,64 +660,116 @@ export class McpManager { throw new Error(`MCP: server '${sanitizedName}' already exists`) } - // Add server to agent config - const serverConfig: MCPServerConfig = { - command: cfg.command, - url: cfg.url, - initializationTimeout: cfg.initializationTimeout, - disabled: cfg.disabled ?? false, - } - // Only add timeout to agent config if it's not 0 - if (cfg.timeout !== undefined) { - serverConfig.timeout = cfg.timeout - } - if (cfg.args && cfg.args.length > 0) { - serverConfig.args = cfg.args - } - if (cfg.env && !isEmptyEnv(cfg.env)) { - serverConfig.env = cfg.env - } - if (cfg.headers && !isEmptyEnv(cfg.headers)) { - serverConfig.headers = cfg.headers - } + if (isLegacyMcpServer) { + // Handle legacy MCP config file + await this.mutateConfigFile(configPath, (json: any) => { + if (!json.mcpServers) { + json.mcpServers = {} + } + json.mcpServers[serverName] = { + command: cfg.command, + url: cfg.url, + args: cfg.args, + env: cfg.env, + headers: cfg.headers, + timeout: cfg.timeout, + initializationTimeout: cfg.initializationTimeout, + disabled: cfg.disabled ?? false, + } + }) - // Add to agent config - this.agentConfig.mcpServers[serverName] = serverConfig + // Move tool permissions to corresponding agent path + const agentPath = configPath.replace( + path.sep + 'mcp.json', + path.sep + 'agents' + path.sep + 'default.json' + ) - // We don't need to store configPath anymore as we're using agent config - const newCfg: MCPServerConfig = { ...cfg, __configPath__: agentPath } - this.mcpServers.set(sanitizedName, newCfg) - this.serverNameMapping.set(sanitizedName, serverName) + const serverPrefix = `@${serverName}` + let serverTools = this.agentConfig.tools.filter( + tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) + ) + if (serverTools.length === 0) { + serverTools = [serverPrefix] + } + let serverAllowedTools = this.agentConfig.allowedTools.filter( + tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) + ) - // Check if the server already has permissions in the agent config - const serverPrefix = `@${serverName}` - const hasServerInTools = this.agentConfig.tools.some( - tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) - ) + // Push to agent config after setup + this.agentConfig.tools.push(...serverTools.filter(tool => !this.agentConfig.tools.includes(tool))) + this.agentConfig.allowedTools.push( + ...serverAllowedTools.filter(tool => !this.agentConfig.allowedTools.includes(tool)) + ) - // Only set permissions if the server doesn't already have them - if (!hasServerInTools) { - // Enable the server as a whole rather than individual tools - this.agentConfig.tools.push(serverPrefix) - } + await saveServerSpecificAgentConfig( + this.features.workspace, + this.features.logging, + serverName, + null, + serverTools, + serverAllowedTools, + agentPath, + true + ) + } else { + // Add server to agent config + const serverConfig: MCPServerConfig = { + command: cfg.command, + url: cfg.url, + initializationTimeout: cfg.initializationTimeout, + disabled: cfg.disabled ?? false, + } + // Only add timeout to agent config if it's not 0 + if (cfg.timeout !== undefined) { + serverConfig.timeout = cfg.timeout + } + if (cfg.args && cfg.args.length > 0) { + serverConfig.args = cfg.args + } + if (cfg.env && !isEmptyEnv(cfg.env)) { + serverConfig.env = cfg.env + } + if (cfg.headers && !isEmptyEnv(cfg.headers)) { + serverConfig.headers = cfg.headers + } - // Save server-specific changes to agent config - const serverTools = this.agentConfig.tools.filter( - tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) - ) - const serverAllowedTools = this.agentConfig.allowedTools.filter( - tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) - ) + // Add to agent config + this.agentConfig.mcpServers[serverName] = serverConfig - await saveServerSpecificAgentConfig( - this.features.workspace, - this.features.logging, - serverName, - serverConfig, - serverTools, - serverAllowedTools, - agentPath - ) + // Check if the server already has permissions in the agent config + const serverPrefix = `@${serverName}` + const hasServerInTools = this.agentConfig.tools.some( + tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) + ) + + // Only set permissions if the server doesn't already have them + if (!hasServerInTools) { + // Enable the server as a whole rather than individual tools + this.agentConfig.tools.push(serverPrefix) + } + + // Save server-specific changes to agent config + const serverTools = this.agentConfig.tools.filter( + tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) + ) + const serverAllowedTools = this.agentConfig.allowedTools.filter( + tool => tool === serverPrefix || tool.startsWith(`${serverPrefix}/`) + ) + + await saveServerSpecificAgentConfig( + this.features.workspace, + this.features.logging, + serverName, + serverConfig, + serverTools, + serverAllowedTools, + configPath + ) + } + + const newCfg: MCPServerConfig = { ...cfg, __configPath__: configPath } + this.mcpServers.set(sanitizedName, newCfg) + this.serverNameMapping.set(sanitizedName, serverName) // Add server tools to tools list after initialization await this.initOneServer(sanitizedName, newCfg, AuthIntent.Interactive) @@ -1286,7 +1343,8 @@ export class McpManager { if (!config) return false const globalAgentPath = getGlobalAgentConfigPath(this.features.workspace.fs.getUserHomeDir()) - return config.__configPath__ === globalAgentPath + const globalMcpPath = getGlobalMcpConfigPath(this.features.workspace.fs.getUserHomeDir()) + return config.__configPath__ === globalAgentPath || config.__configPath__ === globalMcpPath } public setToolNameMapping(mapping: Map): void { From 60bc68d1d4d2ce8a0373be6ce7551e961fc2cdb8 Mon Sep 17 00:00:00 2001 From: BlakeLazarine Date: Fri, 19 Sep 2025 10:09:34 -0700 Subject: [PATCH 095/158] fix(amazonq): improve messaging for code review (#2303) * fix(amazonq): improve messaging for code review * fix(amazonq): fix unit tests --------- Co-authored-by: Blake Lazarine --- .../tools/qCodeAnalysis/codeReview.test.ts | 6 ++++-- .../tools/qCodeAnalysis/codeReview.ts | 21 +++++++++++++++---- .../qCodeAnalysis/codeReviewConstants.ts | 2 +- .../tools/qCodeAnalysis/codeReviewTypes.ts | 1 + .../qCodeAnalysis/codeReviewUtils.test.ts | 6 ++++-- .../tools/qCodeAnalysis/codeReviewUtils.ts | 6 ++++-- 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts index 71586d3450..a6d346a469 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts @@ -436,7 +436,7 @@ describe('CodeReview', () => { const ruleArtifacts = [{ path: '/test/rule.json' }] // Mock countZipFiles to return only rule artifacts count - sandbox.stub(CodeReviewUtils, 'countZipFiles').returns(1) + sandbox.stub(CodeReviewUtils, 'countZipFiles').returns([1, new Set(['/test/rule.json'])]) try { await (codeReview as any).prepareFilesAndFoldersForUpload( @@ -462,7 +462,9 @@ describe('CodeReview', () => { } sandbox.stub(JSZip.prototype, 'file').callsFake(mockZip.file) sandbox.stub(JSZip.prototype, 'generateAsync').callsFake(mockZip.generateAsync) - sandbox.stub(CodeReviewUtils, 'countZipFiles').returns(3) + sandbox + .stub(CodeReviewUtils, 'countZipFiles') + .returns([3, new Set(['/test/file.js', '/test/path1/rule.json', '/test/path2/rule.json'])]) sandbox.stub(require('crypto'), 'randomUUID').returns('test-uuid-123') await (codeReview as any).prepareFilesAndFoldersForUpload( diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts index 74d6d817a1..61a24652f4 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts @@ -118,9 +118,18 @@ export class CodeReview { setup.isFullReviewRequest = true this.overrideDiffScan = true } - const reviewMessage = setup.isFullReviewRequest - ? `Reviewing the entire code in ${nonRuleFiles} file${nonRuleFiles > 1 ? 's' : ''}...` - : `Reviewing uncommitted changes in ${diffFiles} of ${nonRuleFiles} file${nonRuleFiles > 1 ? 's' : ''}...` + + let reviewMessage: string + if (nonRuleFiles == 1) { + reviewMessage = setup.isFullReviewRequest + ? `Reviewing the code in ${path.basename(uploadResult.filePathsInZip.values().next().value as string)}...` + : `Reviewing uncommitted changes in ${path.basename(uploadResult.filePathsInZip.values().next().value as string)}...` + } else { + reviewMessage = setup.isFullReviewRequest + ? `Reviewing the code in ${nonRuleFiles} files}...` + : `Reviewing uncommitted changes in ${diffFiles} of ${nonRuleFiles} files}...` + } + await chatStreamWriter?.write(reviewMessage) // 4. Wait for scan to complete @@ -223,6 +232,7 @@ export class CodeReview { programmingLanguages, numberOfFilesInCustomerCodeZip, codeDiffFiles, + filePathsInZip, } = await this.prepareFilesAndFoldersForUpload( setup.fileArtifacts, setup.folderArtifacts, @@ -275,6 +285,7 @@ export class CodeReview { programmingLanguages: programmingLanguages, numberOfFilesInCustomerCodeZip, codeDiffFiles, + filePathsInZip, } } @@ -588,6 +599,7 @@ export class CodeReview { programmingLanguages: Set numberOfFilesInCustomerCodeZip: number codeDiffFiles: Set + filePathsInZip: Set }> { try { this.logging.info( @@ -606,7 +618,7 @@ export class CodeReview { !isFullReviewRequest ) - let numberOfFilesInCustomerCodeZip = CodeReviewUtils.countZipFiles(customerCodeZip) + let [numberOfFilesInCustomerCodeZip, filePathsInZip] = CodeReviewUtils.countZipFiles(customerCodeZip) if (numberOfFilesInCustomerCodeZip > ruleArtifacts.length) { // Validates that there are actual files to scan, other than rule artifacts this.logging.info(`Total files in customerCodeZip - ${numberOfFilesInCustomerCodeZip}`) @@ -649,6 +661,7 @@ export class CodeReview { programmingLanguages, numberOfFilesInCustomerCodeZip, codeDiffFiles, + filePathsInZip, } } catch (error) { this.logging.error(`Error preparing files for upload: ${error}`) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts index 0a9356acdc..32e940d14c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts @@ -180,7 +180,7 @@ export const CODE_REVIEW_TOOL_DESCRIPTION = [ '**Format to display output**', 'The tool will generate some findings grouped by file', 'Use following format STRICTLY to display the result of this tool for different scenarios:', - '- When findings are present, you must inform user that you have completed the review of {file name / folder name / workspace} and found several issues that need attention. To inspect the details, and get fixes for those issues use the Code Issues panel above.', + '- When findings are present, you must inform user that you have completed the review of {file name / folder name / workspace} and found several issues that need attention. To inspect the details, and get fixes for those issues use the Code Issues panel.', ' - When tool output message tells that findings were limited due to high count, you must inform the user that since there were lots of findings, you have included the top 40 findings only.', '- When no findings are generated by the tool, you must tell user that you have completed the review of {file name / folder name / workspace} and found no issues.', ].join('\n') diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts index 8d85e155cb..ea7aa33bf6 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts @@ -31,6 +31,7 @@ export type PrepareAndUploadArtifactsResult = { programmingLanguages: Set numberOfFilesInCustomerCodeZip: number codeDiffFiles: Set + filePathsInZip: Set } export type StartCodeAnalysisResult = { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewUtils.test.ts index 81e2f3915d..e4d40f1a65 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewUtils.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewUtils.test.ts @@ -249,14 +249,16 @@ describe('CodeReviewUtils', () => { }, } as unknown as JSZip - const count = CodeReviewUtils.countZipFiles(mockZip) + const [count, files] = CodeReviewUtils.countZipFiles(mockZip) expect(count).to.equal(3) + expect(files).to.deep.equal(new Set(['file1.js', 'dir1/file2.ts', 'dir2/file3.py'])) }) it('should return 0 for empty zip', () => { const mockZip = { files: {} } as unknown as JSZip - const count = CodeReviewUtils.countZipFiles(mockZip) + const [count, files] = CodeReviewUtils.countZipFiles(mockZip) expect(count).to.equal(0) + expect(files).to.deep.equal(new Set()) }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewUtils.ts index 5f04450795..a7b545117c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewUtils.ts @@ -209,15 +209,17 @@ export class CodeReviewUtils { * @param zip JSZip instance * @returns number of files in zip */ - public static countZipFiles(zip: JSZip): number { + public static countZipFiles(zip: JSZip): [number, Set] { let count = 0 + let filePaths: Set = new Set() Object.keys(zip.files).forEach(filePath => { let item = zip.files[filePath] if (!item.dir) { count += 1 + filePaths.add(filePath) } }) - return count + return [count, filePaths] } /** From 84e2c8c12f5d828192a302fa11483063d33b059c Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Fri, 19 Sep 2025 14:10:37 -0700 Subject: [PATCH 096/158] fix: inline UTD empty cases dont differentiate Edit and Completion (#2287) --- .../inline-completion/codeWhispererServer.ts | 6 +++--- .../inline-completion/editCompletionHandler.ts | 3 ++- .../inline-completion/session/sessionManager.ts | 6 ++++-- .../src/language-server/inline-completion/telemetry.ts | 2 +- .../src/shared/telemetry/telemetryService.ts | 7 ++++--- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts index 4f28b46ea9..e70727b12c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts @@ -426,7 +426,7 @@ export const CodewhispererServerFactory = session.responseContext = suggestionResponse.responseContext session.codewhispererSessionId = suggestionResponse.responseContext.codewhispererSessionId session.timeToFirstRecommendation = new Date().getTime() - session.startTime - session.suggestionType = suggestionResponse.suggestionType + session.predictionType = SuggestionType.COMPLETION } else { session.suggestions = [...session.suggestions, ...suggestionResponse.suggestions] } @@ -454,7 +454,7 @@ export const CodewhispererServerFactory = // session was closed by user already made decisions consequent completion request before new paginated API response was received if ( - session.suggestionType !== SuggestionType.EDIT && // TODO: this is a shorterm fix to allow Edits tabtabtab experience, however the real solution is to manage such sessions correctly + session.predictionType !== SuggestionType.EDIT && // TODO: this is a shorterm fix to allow Edits tabtabtab experience, however the real solution is to manage such sessions correctly (session.state === 'CLOSED' || session.state === 'DISCARD') ) { return EMPTY_RESULT @@ -640,7 +640,7 @@ export const CodewhispererServerFactory = let deletedLengthForEdits = 0 if (acceptedSuggestion) { codePercentageTracker.countSuccess(session.language) - if (session.suggestionType === SuggestionType.EDIT && acceptedSuggestion.content) { + if (session.predictionType === SuggestionType.EDIT && acceptedSuggestion.content) { // [acceptedSuggestion.insertText] will be undefined for NEP suggestion. Use [acceptedSuggestion.content] instead. // Since [acceptedSuggestion.content] is in the form of a diff, transform the content into addedCharacters and deletedCharacters. const { addedLines, deletedLines } = getAddedAndDeletedLines(acceptedSuggestion.content) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts index 550de06708..a340365b9f 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts @@ -16,6 +16,7 @@ import { GenerateSuggestionsRequest, GenerateSuggestionsResponse, getFileContext, + SuggestionType, } from '../../shared/codeWhispererService' import { CodeWhispererSession, SessionManager } from './session/sessionManager' import { CursorTracker } from './tracker/cursorTracker' @@ -340,7 +341,7 @@ export class EditCompletionHandler { session.responseContext = suggestionResponse.responseContext session.codewhispererSessionId = suggestionResponse.responseContext.codewhispererSessionId session.timeToFirstRecommendation = new Date().getTime() - session.startTime - session.suggestionType = suggestionResponse.suggestionType + session.predictionType = SuggestionType.EDIT } else { session.suggestions = [...session.suggestions, ...suggestionResponse.suggestions] } diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts index 2a4af79ff6..3aeef8bc8d 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts @@ -91,7 +91,9 @@ export class CodeWhispererSession { customizationArn?: string includeImportsWithSuggestions?: boolean codewhispererSuggestionImportCount: number = 0 - suggestionType?: string + + // Suggestion type specified by the clients, could be either "EDIT" or "COMPLETION" + predictionType?: SuggestionType // Track the most recent itemId for paginated Edit suggestions constructor(data: SessionData) { @@ -175,7 +177,7 @@ export class CodeWhispererSession { if ( this.state === 'CLOSED' || this.state === 'DISCARD' || - (this.completionSessionResult && this.suggestionType === SuggestionType.COMPLETION) + (this.completionSessionResult && this.predictionType === SuggestionType.COMPLETION) ) { return } diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts index 73e3a526a4..4847072122 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts @@ -156,7 +156,7 @@ export const emitUserTriggerDecisionTelemetry = async ( // Edits show one suggestion sequentially (with pagination), so use latest itemId state; // Completions show multiple suggestions together, so aggregate all states const userTriggerDecision = - session.suggestionType === SuggestionType.EDIT + session.predictionType === SuggestionType.EDIT ? session.getUserTriggerDecision(itemId) : session.getAggregatedUserTriggerDecision() diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts index 78182c076f..59375e8adc 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts @@ -22,7 +22,6 @@ import { ChatAddMessageEvent, UserIntent, InlineChatEvent, - AgenticChatEventStatus, IdeDiagnostic, UserModificationEvent, } from '../../client/token/codewhispererbearertokenclient' @@ -201,6 +200,7 @@ export class TelemetryService { streakLength?: number ) { session.decisionMadeTimestamp = performance.now() + // Toolkit telemetry API if (this.enableTelemetryEventsToDestination) { const data: CodeWhispererUserTriggerDecisionEvent = { codewhispererSessionId: session.codewhispererSessionId || '', @@ -256,8 +256,9 @@ export class TelemetryService { acceptedSuggestion && acceptedSuggestion.content ? acceptedSuggestion.content.length : 0 const perceivedLatencyMilliseconds = session.triggerType === 'OnDemand' ? session.timeToFirstRecommendation : timeSinceLastUserModification - const isInlineEdit = session.suggestionType === SuggestionType.EDIT + const isInlineEdit = session.predictionType === SuggestionType.EDIT + // RTS STE API const event: UserTriggerDecisionEvent = { sessionId: session.codewhispererSessionId || '', requestId: session.responseContext?.requestId || '', @@ -283,7 +284,7 @@ export class TelemetryService { addedIdeDiagnostics: addedIdeDiagnostics, removedIdeDiagnostics: removedIdeDiagnostics, streakLength: streakLength ?? 0, - suggestionType: isInlineEdit ? 'EDITS' : 'COMPLETIONS', + suggestionType: session.predictionType, } this.logging.info(`Invoking SendTelemetryEvent:UserTriggerDecisionEvent with: "requestId": ${event.requestId} From fab073c855109b15005bfd880894471c35652ffc Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Fri, 19 Sep 2025 16:30:16 -0700 Subject: [PATCH 097/158] fix(amazonq): fix to normlize workspace paths in windows (#2306) --- .../agenticChat/tools/mcp/mcpUtils.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts index ca174261cc..8ca2aff48a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts @@ -634,7 +634,10 @@ export async function loadPersonaPermissions( /** Given an array of workspace diretory, return each workspace persona config location */ export function getWorkspacePersonaConfigPaths(wsUris: string[]): string[] { - return wsUris.map(uri => path.join(uri, '.amazonq', 'personas', 'default.json')) + return wsUris.map(uri => { + const fsPath = normalizePathFromUri(uri) + return path.join(fsPath, '.amazonq', 'personas', 'default.json') + }) } /** Given a user's home directory, return the global persona config location */ @@ -644,7 +647,10 @@ export function getGlobalPersonaConfigPath(home: string): string { /** Given an array of workspace diretory, return each workspace agent config location */ export function getWorkspaceAgentConfigPaths(wsUris: string[]): string[] { - return wsUris.map(uri => path.join(uri, '.amazonq', 'agents', 'default.json')) + return wsUris.map(uri => { + const fsPath = normalizePathFromUri(uri) + return path.join(fsPath, '.amazonq', 'agents', 'default.json') + }) } /** Given a user's home directory, return the global agent config location */ @@ -654,7 +660,10 @@ export function getGlobalAgentConfigPath(home: string): string { /** Given an array of workspace diretory, return each workspace mcp config location */ export function getWorkspaceMcpConfigPaths(wsUris: string[]): string[] { - return wsUris.map(uri => path.join(uri, '.amazonq', 'mcp.json')) + return wsUris.map(uri => { + const fsPath = normalizePathFromUri(uri) + return path.join(fsPath, '.amazonq', 'mcp.json') + }) } /** Given a user's home directory, return the global mcp config location */ From f53bbdca37cf865335c5ea4f05efe31c348d5695 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 11:50:35 -0700 Subject: [PATCH 098/158] chore(release): release packages from branch main (#2294) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- package-lock.json | 2 +- server/aws-lsp-codewhisperer/CHANGELOG.md | 21 +++++++++++++++++++++ server/aws-lsp-codewhisperer/package.json | 2 +- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b1266e246d..e1caa1ac4b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -2,7 +2,7 @@ "chat-client": "0.1.36", "core/aws-lsp-core": "0.0.15", "server/aws-lsp-antlr4": "0.1.19", - "server/aws-lsp-codewhisperer": "0.0.80", + "server/aws-lsp-codewhisperer": "0.0.81", "server/aws-lsp-json": "0.1.19", "server/aws-lsp-partiql": "0.0.18", "server/aws-lsp-yaml": "0.1.19" diff --git a/package-lock.json b/package-lock.json index a2ad6312f2..59509ce1a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28677,7 +28677,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.80", + "version": "0.0.81", "bundleDependencies": [ "@amzn/codewhisperer-streaming", "@amzn/amazon-q-developer-streaming-client" diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index bb326a1b18..a9a9eaa131 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## [0.0.81](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.80...lsp-codewhisperer/v0.0.81) (2025-09-19) + + +### Bug Fixes + +* **amazonq:** fix for delete mcp for mcp config, disable and create corresponding agent file ([#2298](https://github.com/aws/language-servers/issues/2298)) ([8641860](https://github.com/aws/language-servers/commit/8641860295c4e089d09154fa5411c305f2f4ecce)) +* **amazonq:** fix for legacy mcp permission consistentcy and config update ([#2300](https://github.com/aws/language-servers/issues/2300)) ([c8aa7bd](https://github.com/aws/language-servers/commit/c8aa7bd3e9d39ed327972bbc950ad72e8e401581)) +* **amazonq:** fix for mcp permissions read/write inconsistencies ([#2296](https://github.com/aws/language-servers/issues/2296)) ([c7a9a8e](https://github.com/aws/language-servers/commit/c7a9a8e1ba5c1a284d661e683dd46133860a1d3d)) +* **amazonq:** fix to add filewatcher for mcp config files ([#2295](https://github.com/aws/language-servers/issues/2295)) ([fcee77c](https://github.com/aws/language-servers/commit/fcee77c1b06e69f9096d8e98a0cfcc42d7fddb01)) +* **amazonq:** fix to normlize workspace paths in windows ([#2306](https://github.com/aws/language-servers/issues/2306)) ([fab073c](https://github.com/aws/language-servers/commit/fab073c855109b15005bfd880894471c35652ffc)) +* **amazonq:** improve messaging for code review ([#2303](https://github.com/aws/language-servers/issues/2303)) ([60bc68d](https://github.com/aws/language-servers/commit/60bc68d1d4d2ce8a0373be6ce7551e961fc2cdb8)) +* **amazonq:** support mcp config files for backwards compatbility ([#2292](https://github.com/aws/language-servers/issues/2292)) ([41c99af](https://github.com/aws/language-servers/commit/41c99af02b3f415e39898f11c3c21ac530f9c406)) +* inline UTD empty cases dont differentiate Edit and Completion ([#2287](https://github.com/aws/language-servers/issues/2287)) ([84e2c8c](https://github.com/aws/language-servers/commit/84e2c8c12f5d828192a302fa11483063d33b059c)) +* inline UTD telemetry empty cases dont differentiate Edit and Completion ([#2288](https://github.com/aws/language-servers/issues/2288)) ([d207b6e](https://github.com/aws/language-servers/commit/d207b6e9dfded650c6f65c675ee45c52f8222571)) +* quick fix for repeated logging from squashed commit ([#2291](https://github.com/aws/language-servers/issues/2291)) ([36f3eed](https://github.com/aws/language-servers/commit/36f3eedd1cad3fca4fc48792ba40b6470f733bfa)) + + +### Reverts + +* inline UTD telemetry empty cases dont differentiate Edit and Completion ([#2288](https://github.com/aws/language-servers/issues/2288)) ([#2297](https://github.com/aws/language-servers/issues/2297)) ([eb081e6](https://github.com/aws/language-servers/commit/eb081e6bc6bef4182ab89e295bff97c4e828096b)) + ## [0.0.80](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.79...lsp-codewhisperer/v0.0.80) (2025-09-16) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 1a0b12eb74..8d07e72a6d 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.80", + "version": "0.0.81", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { From fe128b67e6d792c1c3d30217de4c6765aff860db Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Mon, 22 Sep 2025 17:18:49 -0700 Subject: [PATCH 099/158] chore: bump agentic version: 1.34.0 (#2315) Co-authored-by: aws-toolkit-automation <> --- app/aws-lsp-codewhisperer-runtimes/src/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/src/version.json b/app/aws-lsp-codewhisperer-runtimes/src/version.json index b67df644b8..ea9cb1ee08 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/version.json +++ b/app/aws-lsp-codewhisperer-runtimes/src/version.json @@ -1,3 +1,3 @@ { - "agenticChat": "1.33.0" + "agenticChat": "1.34.0" } From 0e215fc0e475b4c40a8237492371716982d4d532 Mon Sep 17 00:00:00 2001 From: Boyu Date: Tue, 23 Sep 2025 09:13:55 -0700 Subject: [PATCH 100/158] feat: memory bank support (#2314) * feat: support memory bank (#2299) * feat: poc for adding memory bank as rules * feat: changed to use simlar prompt from kiro * feat: implement iteration based guidelines generation from science doc * fix: fixing issues from poc code * fix: refine UX messages * fix: improving memory bank pre-processing logic (#2301) * fix: limit file size for during memory bank analysis (#2304) * fix: ehance memory bank prompt for more determinastic file name and path (#2305) * fix: fix windows path issue for memory bank (#2307) * fix: small path fix for button text, remove unnecessary logs (#2310) --------- Co-authored-by: aws-toolkit-automation <43144436+aws-toolkit-automation@users.noreply.github.com> --- chat-client/src/client/features/rules.test.ts | 31 +- chat-client/src/client/features/rules.ts | 41 +- .../agenticChat/agenticChatController.ts | 93 +- .../context/additionalContextProvider.ts | 64 +- .../memorybank/memoryBankController.test.ts | 247 ++++++ .../memorybank/memoryBankController.ts | 793 ++++++++++++++++++ .../context/memorybank/memoryBankPrompts.ts | 153 ++++ 7 files changed, 1412 insertions(+), 10 deletions(-) create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankController.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankController.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankPrompts.ts diff --git a/chat-client/src/client/features/rules.test.ts b/chat-client/src/client/features/rules.test.ts index c8f93ed4eb..cc0817b443 100644 --- a/chat-client/src/client/features/rules.test.ts +++ b/chat-client/src/client/features/rules.test.ts @@ -22,6 +22,7 @@ describe('rules', () => { messager = { onRuleClick: sinon.stub(), + onChatPrompt: sinon.stub(), } as unknown as Messager rulesList = new RulesList(mynahUi, messager) @@ -142,6 +143,22 @@ describe('rules', () => { assert.equal(formArgs[2][1].id, ContextRule.SubmitButtonId) }) + it('calls messager when create memory bank is clicked', () => { + const createMemoryBankItem: DetailedListItem = { + id: ContextRule.CreateMemoryBankId, + description: 'Generate Memory Bank', + } + + onItemClick(createMemoryBankItem) + + // Should send a chat prompt + sinon.assert.calledOnce(messager.onChatPrompt as sinon.SinonStub) + + const chatPromptArgs = (messager.onChatPrompt as sinon.SinonStub).getCall(0).args[0] + assert.equal(chatPromptArgs.prompt.prompt, 'Generate a Memory Bank for this project') + assert.equal(chatPromptArgs.prompt.escapedPrompt, 'Generate a Memory Bank for this project') + }) + it('calls messager when regular rule is clicked', () => { const ruleItem: DetailedListItem = { id: 'test-rule-id', @@ -267,21 +284,27 @@ describe('rules', () => { const result = convertRulesListToDetailedListGroup(rulesFolder) - assert.equal(result.length, 3) // 2 folders + create rule group + assert.equal(result.length, 3) // 2 folders + actions group assert.equal(result[0].groupName, 'test-folder') assert.equal(result[0].children?.length, 2) assert.equal(result[0].children?.[0].id, 'rule-1') assert.equal(result[0].children?.[0].description, 'Test Rule 1') assert.equal(result[1].groupName, 'inactive-folder') assert.equal(result[1].children?.length, 0) - assert.equal(result[2].children?.[0].id, ContextRule.CreateRuleId) + assert.equal(result[2].groupName, 'Actions') + assert.equal(result[2].children?.length, 2) // Memory Bank + Create Rule + assert.equal(result[2].children?.[0].id, ContextRule.CreateMemoryBankId) + assert.equal(result[2].children?.[1].id, ContextRule.CreateRuleId) }) it('handles empty rules array', () => { const result = convertRulesListToDetailedListGroup([]) - assert.equal(result.length, 1) // Only create rule group - assert.equal(result[0].children?.[0].id, ContextRule.CreateRuleId) + assert.equal(result.length, 1) // Only actions group + assert.equal(result[0].groupName, 'Actions') + assert.equal(result[0].children?.length, 2) // Memory Bank + Create Rule + assert.equal(result[0].children?.[0].id, ContextRule.CreateMemoryBankId) + assert.equal(result[0].children?.[1].id, ContextRule.CreateRuleId) }) }) }) diff --git a/chat-client/src/client/features/rules.ts b/chat-client/src/client/features/rules.ts index f5ea2cca22..0b47cc1f93 100644 --- a/chat-client/src/client/features/rules.ts +++ b/chat-client/src/client/features/rules.ts @@ -6,6 +6,7 @@ import { MynahDetailedList } from './history' export const ContextRule = { CreateRuleId: 'create-rule', + CreateMemoryBankId: 'create-memory-bank', CancelButtonId: 'cancel-create-rule', SubmitButtonId: 'submit-create-rule', RuleNameFieldId: 'rule-name', @@ -68,12 +69,29 @@ export class RulesList { ], `Create a rule` ) + } else if (item.id === ContextRule.CreateMemoryBankId) { + this.rulesList?.close() + this.handleMemoryBankCreation() } else { this.messager.onRuleClick({ tabId: this.tabId, type: 'rule', id: item.id }) } } } + private handleMemoryBankCreation = () => { + // Close the rules list first + this.rulesList?.close() + + // Use the current tab, the tabId should be the same as the one used for the rules list + this.messager.onChatPrompt({ + prompt: { + prompt: 'Generate a Memory Bank for this project', + escapedPrompt: 'Generate a Memory Bank for this project', + }, + tabId: this.tabId, + }) + } + showLoading(tabId: string) { this.tabId = tabId const rulesList = this.mynahUi.openTopBarButtonOverlay({ @@ -156,6 +174,24 @@ const createRuleListItem: DetailedListItem = { id: ContextRule.CreateRuleId, } +function createMemoryBankListItem(rules: RulesFolder[]): DetailedListItem { + // Handles button text changes between "Generation" and "Regenerate" + const memoryBankFiles = ['product', 'structure', 'tech', 'guidelines'] + + const memoryBankFolder = rules.find(folder => folder.folderName === 'memory-bank') + + const hasMemoryBankFiles = + memoryBankFolder && memoryBankFolder.rules.some(rule => memoryBankFiles.includes(rule.name)) + + const buttonText = hasMemoryBankFiles ? 'Regenerate Memory Bank' : 'Generate Memory Bank' + + return { + description: buttonText, + icon: MynahIcons.FOLDER, + id: ContextRule.CreateMemoryBankId, + } +} + export function convertRulesListToDetailedListGroup(rules: RulesFolder[]): DetailedListItemGroup[] { return rules .map( @@ -179,7 +215,10 @@ export function convertRulesListToDetailedListGroup(rules: RulesFolder[]): Detai })), }) as DetailedListItemGroup ) - .concat({ children: [createRuleListItem] }) + .concat({ + groupName: 'Actions', + children: [createMemoryBankListItem(rules), createRuleListItem], + }) } function convertRuleStatusToIcon(status: boolean | 'indeterminate'): MynahIcons | undefined { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 23c726f364..ab73ca644f 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -231,6 +231,7 @@ import { IDE } from '../../shared/constants' import { IdleWorkspaceManager } from '../workspaceContext/IdleWorkspaceManager' import escapeHTML = require('escape-html') import { SemanticSearch } from './tools/workspaceContext/semanticSearch' +import { MemoryBankController } from './context/memorybank/memoryBankController' type ChatHandlers = Omit< LspHandlers, @@ -267,6 +268,7 @@ export class AgenticChatController implements ChatHandlers { #chatHistoryDb: ChatDatabase #additionalContextProvider: AdditionalContextProvider #contextCommandsProvider: ContextCommandsProvider + #memoryBankController: MemoryBankController #stoppedToolUses = new Set() #userWrittenCodeTracker: UserWrittenCodeTracker | undefined #toolUseStartTimes: Record = {} @@ -370,6 +372,7 @@ export class AgenticChatController implements ChatHandlers { this.#mcpEventHandler = new McpEventHandler(features, telemetryService) this.#origin = getOriginFromClientInfo(getClientName(this.#features.lsp.getClientInitializeParams())) this.#activeUserTracker = ActiveUserTracker.getInstance(this.#features) + this.#memoryBankController = MemoryBankController.getInstance(features) } async onExecuteCommand(params: ExecuteCommandParams, _token: CancellationToken): Promise { @@ -833,6 +836,93 @@ export class AgenticChatController implements ChatHandlers { IdleWorkspaceManager.recordActivityTimestamp() + // Memory Bank Creation Flow - Delegate to MemoryBankController + if (this.#memoryBankController.isMemoryBankCreationRequest(params.prompt.prompt)) { + this.#features.logging.info(`Memory Bank creation request detected for tabId: ${params.tabId}`) + + // Store original prompt to prevent data loss on failure + const originalPrompt = params.prompt.prompt + + try { + const workspaceFolders = workspaceUtils.getWorkspaceFolderPaths(this.#features.workspace) + const workspaceUri = workspaceFolders.length > 0 ? workspaceFolders[0] : '' + + if (!workspaceUri) { + throw new Error('No workspace folder found for Memory Bank creation') + } + + // Check if memory bank already exists to provide appropriate user feedback + const memoryBankExists = await this.#memoryBankController.memoryBankExists(workspaceUri) + const actionType = memoryBankExists ? 'Regenerating' : 'Generating' + this.#features.logging.info(`${actionType} Memory Bank for workspace: ${workspaceUri}`) + + const resultStream = this.#getChatResultStream(params.partialResultToken) + await resultStream.writeResultBlock({ + body: `Preparing to analyze your project...`, + type: 'answer', + messageId: crypto.randomUUID(), + }) + + const comprehensivePrompt = await this.#memoryBankController.prepareComprehensiveMemoryBankPrompt( + workspaceUri, + async (prompt: string) => { + // Direct LLM call for ranking - no agentic loop + try { + if (!this.#serviceManager) { + throw new Error('amazonQServiceManager is not initialized') + } + + const client = this.#serviceManager.getStreamingClient() + const requestInput: SendMessageCommandInput = { + conversationState: { + chatTriggerType: ChatTriggerType.MANUAL, + currentMessage: { + userInputMessage: { + content: prompt, + }, + }, + }, + } + + const response = await client.sendMessage(requestInput) + + let responseContent = '' + const maxResponseSize = 50000 // 50KB limit + + if (response.sendMessageResponse) { + for await (const chatEvent of response.sendMessageResponse) { + if (chatEvent.assistantResponseEvent?.content) { + responseContent += chatEvent.assistantResponseEvent.content + if (responseContent.length > maxResponseSize) { + this.#features.logging.warn('LLM response exceeded size limit, truncating') + break + } + } + } + } + + return responseContent.trim() + } catch (error) { + this.#features.logging.error(`Memory Bank LLM ranking failed: ${error}`) + return '' // Empty string triggers TF-IDF fallback + } + } + ) + + // Only update prompt if we got a valid comprehensive prompt + if (comprehensivePrompt && comprehensivePrompt.trim().length > 0) { + params.prompt.prompt = comprehensivePrompt + } else { + this.#features.logging.warn('Empty comprehensive prompt received, using original prompt') + params.prompt.prompt = originalPrompt + } + } catch (error) { + this.#features.logging.error(`Memory Bank preparation failed: ${error}`) + // Restore original prompt to ensure no data loss + params.prompt.prompt = originalPrompt + } + } + const maybeDefaultResponse = !params.prompt.command && getDefaultChatResponse(params.prompt.prompt) if (maybeDefaultResponse) { return maybeDefaultResponse @@ -909,7 +999,8 @@ export class AgenticChatController implements ChatHandlers { const additionalContext = await this.#additionalContextProvider.getAdditionalContext( triggerContext, params.tabId, - params.context + params.context, + params.prompt.prompt ) // Add active file to context list if it's not already there const activeFile = diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/additionalContextProvider.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/additionalContextProvider.ts index 733d1df28c..466f0feed9 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/additionalContextProvider.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/additionalContextProvider.ts @@ -33,7 +33,7 @@ import { ChatDatabase } from '../tools/chatDb/chatDb' import { ChatMessage, ImageBlock, ImageFormat } from '@amzn/codewhisperer-streaming' import { getRelativePathWithUri, getRelativePathWithWorkspaceFolder } from '../../workspaceContext/util' import { isSupportedImageExtension, MAX_IMAGE_CONTEXT_COUNT } from '../../../shared/imageVerification' -import { mergeFileLists } from './contextUtils' +import { MemoryBankController } from './memorybank/memoryBankController' export const ACTIVE_EDITOR_CONTEXT_ID = 'active-editor' @@ -151,6 +151,30 @@ export class AdditionalContextProvider { // Filter rules based on user's rules preferences for current tab let rulesState = this.chatDb.getRules(tabId) || { folders: {}, rules: {} } + + // Ensure memory bank files are active by default when first discovered + const memoryBankFiles = rulesFiles.filter(rule => rule.id?.includes('memory-bank')) + if (memoryBankFiles.length > 0) { + let needsUpdate = false + + const memoryBankFolderName = 'memory-bank' + if (rulesState.folders[memoryBankFolderName] === undefined) { + rulesState.folders[memoryBankFolderName] = true + needsUpdate = true + } + + memoryBankFiles.forEach(file => { + if (rulesState.rules[file.id] === undefined) { + rulesState.rules[file.id] = true + needsUpdate = true + } + }) + + if (needsUpdate) { + this.chatDb.setRules(tabId, rulesState) + } + } + return rulesFiles.filter(rule => { // If the rule has an explicit state in rulesState, use that value if (rulesState.rules[rule.id] !== undefined) { @@ -199,7 +223,8 @@ export class AdditionalContextProvider { async getAdditionalContext( triggerContext: TriggerContext, tabId: string, - context?: ContextCommand[] + context?: ContextCommand[], + prompt?: string ): Promise { triggerContext.contextInfo = getInitialContextInfo() @@ -220,7 +245,33 @@ export class AdditionalContextProvider { : workspaceUtils.getWorkspaceFolderPaths(this.features.workspace)[0] if (workspaceRules.length > 0) { - pinnedContextCommands.push(...workspaceRules) + // Check if this is a memory bank generation request + const isMemoryBankRequest = prompt + ? new MemoryBankController(this.features).isMemoryBankCreationRequest(prompt) + : false + + let rulesToInclude = workspaceRules + + if (isMemoryBankRequest) { + // Exclude memory bank files from context when regenerating memory bank + const memoryBankFiles = workspaceRules.filter(rule => rule.id?.includes('memory-bank')) + rulesToInclude = workspaceRules.filter(rule => !rule.id?.includes('memory-bank')) + + if (memoryBankFiles.length > 0) { + this.features.logging.info( + `Memory Bank: excluding ${memoryBankFiles.length} existing memory bank files from context` + ) + } + } else { + // Normal behavior: include all workspace rules (including memory bank files) + const memoryBankFiles = workspaceRules.filter(rule => rule.id?.includes('memory-bank')) + if (memoryBankFiles.length > 0) { + this.features.logging.info(`Including ${memoryBankFiles.length} memory bank files in chat context`) + } + } + + // Add the filtered rules to pinned context + pinnedContextCommands.push(...rulesToInclude) } // Merge pinned context with context added to prompt, avoiding duplicates @@ -675,7 +726,12 @@ export class AdditionalContextProvider { if (dirPath === '.') { folderName = undefined } else { - folderName = dirPath + // Special handling for memory bank files + if (dirPath === '.amazonq/rules/memory-bank') { + folderName = 'memory-bank' + } else { + folderName = dirPath + } } } else { // In multi-workspace: include workspace folder name for all files diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankController.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankController.test.ts new file mode 100644 index 0000000000..a20488c7b3 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankController.test.ts @@ -0,0 +1,247 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. + * All Rights Reserved. SPDX-License-Identifier: Apache-2.0 + */ + +import * as assert from 'assert' +import * as sinon from 'sinon' +import { MemoryBankController } from './memoryBankController' +import { MemoryBankPrompts } from './memoryBankPrompts' + +describe('MemoryBankController', () => { + let controller: MemoryBankController + let mockFeatures: any + let mockWorkspace: any + let mockFs: any + let mockLogging: any + + beforeEach(() => { + mockFs = { + exists: sinon.stub(), + mkdir: sinon.stub(), + readFile: sinon.stub(), + readdir: sinon.stub(), + } + + mockWorkspace = { + fs: mockFs, + } + + mockLogging = { + info: sinon.stub(), + error: sinon.stub(), + warn: sinon.stub(), + } + + mockFeatures = { + workspace: mockWorkspace, + logging: mockLogging, + } + + controller = new MemoryBankController(mockFeatures) + }) + + afterEach(() => { + sinon.restore() + // Reset singleton instance + ;(MemoryBankController as any).instance = undefined + }) + + describe('getInstance', () => { + it('should return singleton instance', () => { + const instance1 = MemoryBankController.getInstance(mockFeatures) + const instance2 = MemoryBankController.getInstance(mockFeatures) + + assert.strictEqual(instance1, instance2) + }) + + it('should create new instance if none exists', () => { + const instance = MemoryBankController.getInstance(mockFeatures) + + assert.ok(instance instanceof MemoryBankController) + }) + }) + + describe('isMemoryBankCreationRequest', () => { + it('should detect memory bank creation requests', () => { + const testCases = [ + 'create a memory bank', + 'Create a Memory Bank', + 'CREATE MEMORY BANK', + 'Create a Memory Bank for this project', + 'generate memory bank for this project', + 'generate memory bank', + 'build memory bank', + 'make memory bank', + 'setup memory bank', + ] + + testCases.forEach(prompt => { + const result = controller.isMemoryBankCreationRequest(prompt) + assert.strictEqual(result, true, `Failed to detect: "${prompt}"`) + }) + }) + + it('should not detect non-memory bank requests', () => { + const testCases = [ + 'create a file', + 'help me with code', + 'explain this function', + 'memory usage optimization', + 'bank account management', + ] + + testCases.forEach(prompt => { + const result = controller.isMemoryBankCreationRequest(prompt) + assert.strictEqual(result, false, `False positive for: "${prompt}"`) + }) + }) + }) + + describe('prompt delegation', () => { + it('should delegate prompt generation to MemoryBankPrompts class', () => { + // Test that controller properly delegates to MemoryBankPrompts + // This ensures clean separation of concerns + const filesString = 'test.ts has 100 lines and a mean lexical dissimilarity of 0.85' + const prompt = MemoryBankPrompts.getFileRankingPrompt(filesString, 15) + + assert.ok(typeof prompt === 'string') + assert.ok(prompt.length > 100) + assert.ok(prompt.includes('JSON list')) + assert.ok(prompt.includes('15')) + assert.ok(prompt.includes(filesString)) + }) + }) + + describe('Science Pipeline Methods', () => { + it('should delegate file ranking prompt to MemoryBankPrompts', () => { + const filesString = 'test.ts has 100 lines and a mean lexical dissimilarity of 0.85' + const prompt = MemoryBankPrompts.getFileRankingPrompt(filesString, 15) + + assert.ok(typeof prompt === 'string') + assert.ok(prompt.includes('JSON list')) + assert.ok(prompt.includes('15')) + assert.ok(prompt.includes(filesString)) + }) + + describe('TF-IDF Lexical Dissimilarity', () => { + it('should calculate TF-IDF dissimilarity for multiple files', async () => { + const files = [ + { path: 'file1.ts', size: 50 }, + { path: 'file2.ts', size: 75 }, + { path: 'file3.ts', size: 100 }, + ] + + // Mock file contents with different lexical patterns + mockFs.readFile.onFirstCall().resolves('function calculateSum(a, b) { return a + b; }') + mockFs.readFile.onSecondCall().resolves('class UserService { constructor() {} getUser() {} }') + mockFs.readFile.onThirdCall().resolves('const config = { apiUrl: "https://api.example.com" }') + + const result = await controller.calculateLexicalDissimilarity(files) + + assert.strictEqual(result.length, 3) + assert.ok(result.every(f => f.dissimilarity >= 0 && f.dissimilarity <= 1)) + assert.ok(result.every(f => typeof f.dissimilarity === 'number')) + + // Verify all original properties are preserved + result.forEach((file, index) => { + assert.strictEqual(file.path, files[index].path) + assert.strictEqual(file.size, files[index].size) + }) + }) + + it('should handle empty or unreadable files gracefully', async () => { + const files = [ + { path: 'readable.ts', size: 50 }, + { path: 'unreadable.ts', size: 25 }, + ] + + mockFs.readFile.onFirstCall().resolves('function test() { return true; }') + mockFs.readFile.onSecondCall().rejects(new Error('File not found')) + + const result = await controller.calculateLexicalDissimilarity(files) + + assert.strictEqual(result.length, 2) + assert.ok(result.every(f => f.dissimilarity >= 0 && f.dissimilarity <= 1)) + sinon.assert.calledOnce(mockLogging.warn) + }) + + it('should return fallback values on calculation error', async () => { + const files = [{ path: 'test.ts', size: 50 }] + + mockFs.readFile.rejects(new Error('Filesystem error')) + + const result = await controller.calculateLexicalDissimilarity(files) + + assert.strictEqual(result.length, 1) + assert.strictEqual(result[0].dissimilarity, 0.85) + sinon.assert.calledOnce(mockLogging.error) + }) + }) + + it('should provide TF-IDF analysis methods', () => { + assert.ok(typeof controller.discoverAllSourceFiles === 'function') + assert.ok(typeof controller.calculateFileLineCount === 'function') + assert.ok(typeof controller.calculateLexicalDissimilarity === 'function') + assert.ok(typeof controller.executeGuidelinesGenerationPipeline === 'function') + }) + + it('should format files for ranking correctly', () => { + const files = [ + { path: 'test1.ts', size: 100, dissimilarity: 0.85 }, + { path: 'test2.ts', size: 200, dissimilarity: 0.75 }, + ] + + const formatted = controller.formatFilesForRanking(files) + + assert.ok(typeof formatted === 'string') + assert.ok(formatted.includes('test1.ts has 100 lines')) + assert.ok(formatted.includes('test2.ts has 200 lines')) + assert.ok(formatted.includes('0.850000')) + assert.ok(formatted.includes('0.750000')) + }) + }) + + describe('memoryBankExists', () => { + const workspaceFolder = '/test/workspace' + + it('should return false if memory bank directory does not exist', async () => { + mockFs.exists.resolves(false) + + const result = await controller.memoryBankExists(workspaceFolder) + + assert.strictEqual(result, false) + sinon.assert.calledOnce(mockFs.exists) + }) + + it('should return false if directory exists but no files exist', async () => { + mockFs.exists.onFirstCall().resolves(true) // directory exists + mockFs.exists.onSecondCall().resolves(false) // product.md doesn't exist + mockFs.exists.onThirdCall().resolves(false) // structure.md doesn't exist + mockFs.exists.onCall(3).resolves(false) // tech.md doesn't exist + mockFs.exists.onCall(4).resolves(false) // guidelines.md doesn't exist + + const result = await controller.memoryBankExists(workspaceFolder) + + assert.strictEqual(result, false) + }) + + it('should return true if directory exists and at least one file exists', async () => { + mockFs.exists.onFirstCall().resolves(true) // directory exists + mockFs.exists.onSecondCall().resolves(true) // product.md exists + + const result = await controller.memoryBankExists(workspaceFolder) + + assert.strictEqual(result, true) + }) + + it('should handle filesystem errors gracefully', async () => { + mockFs.exists.rejects(new Error('File system error')) + + const result = await controller.memoryBankExists(workspaceFolder) + + assert.strictEqual(result, false) + sinon.assert.calledOnce(mockLogging.error) + }) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankController.ts new file mode 100644 index 0000000000..ebbcd27290 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankController.ts @@ -0,0 +1,793 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. + * All Rights Reserved. SPDX-License-Identifier: Apache-2.0 + */ + +import { Features } from '@aws/language-server-runtimes/server-interface/server' +import { MemoryBankPrompts } from './memoryBankPrompts' +import { normalizePathFromUri } from '../../tools/mcp/mcpUtils' + +const MEMORY_BANK_DIRECTORY = '.amazonq/rules/memory-bank' +const MEMORY_BANK_FILES = { + PRODUCT: 'product.md', + STRUCTURE: 'structure.md', + TECH: 'tech.md', + GUIDELINES: 'guidelines.md', +} as const + +/** + * Controller for Memory Bank functionality + * Handles memory bank creation detection and prompt generation + */ +export class MemoryBankController { + private static instance: MemoryBankController | undefined + + constructor(private features: Features) {} + + static getInstance(features: Features): MemoryBankController { + if (!MemoryBankController.instance) { + MemoryBankController.instance = new MemoryBankController(features) + } + return MemoryBankController.instance + } + + /** + * Check if a prompt is requesting memory bank creation + * Can be expanded based on feedbacks + */ + isMemoryBankCreationRequest(prompt: string): boolean { + const normalizedPrompt = prompt.toLowerCase().trim() + + const triggers = [ + 'create a memory bank', + 'create memory bank', + 'generate a memory bank', + 'generate memory bank', + 'regenerate memory bank', + 'build memory bank', + 'make memory bank', + 'setup memory bank', + ] + + return triggers.some(trigger => normalizedPrompt.includes(trigger)) + } + + /** + * Prepare comprehensive memory bank creation prompt with all necessary input + * This does all the programmatic work upfront and creates a single comprehensive prompt + */ + async prepareComprehensiveMemoryBankPrompt( + workspaceFolderUri: string, + llmCallFunction: (prompt: string) => Promise + ): Promise { + try { + this.features.logging.info(`Memory Bank: Starting pre-processing for workspace: "${workspaceFolderUri}"`) + + // Step 1: Clean directory + await this.cleanMemoryBankDirectory(workspaceFolderUri) + + // Step 2: Execute deterministic analysis (TF-IDF) + this.features.logging.info(`Memory Bank: running analysis for workspace`) + const analysisResults = await this.executeGuidelinesGenerationPipeline(workspaceFolderUri) + + // Step 3: Make LLM call for file ranking + const rankingPrompt = MemoryBankPrompts.getFileRankingPrompt(analysisResults.formattedFilesString, 10) + const rankedFilesResponse = await llmCallFunction(rankingPrompt) + + // Step 4: Parse ranked files + let rankedFilesList: string[] = [] + try { + // Clean the response - remove any markdown formatting or extra text + let cleanResponse = rankedFilesResponse.trim() + + // Extract JSON array if it's wrapped in markdown or other text + const jsonMatch = cleanResponse.match(/\[.*\]/s) + if (jsonMatch) { + cleanResponse = jsonMatch[0] + } else { + // Handle case where LLM returns comma-separated quoted strings without brackets + if (cleanResponse.includes('",') && cleanResponse.includes('"')) { + // Add brackets to make it a valid JSON array + cleanResponse = `[${cleanResponse}]` + } + } + + rankedFilesList = JSON.parse(cleanResponse) + if (!Array.isArray(rankedFilesList)) { + throw new Error('Invalid ranking response format - not an array') + } + + // Validate that all items are strings (file paths) + rankedFilesList = rankedFilesList.filter(item => typeof item === 'string' && item.length > 0) + + if (rankedFilesList.length === 0) { + throw new Error('No valid file paths in ranking response') + } + + this.features.logging.info( + `Memory Bank: parsed ${rankedFilesList.length} ranked files from LLM response` + ) + } catch (error) { + this.features.logging.warn( + `Memory Bank: failed to parse LLM ranking response, using TF-IDF fallback: ${error}` + ) + rankedFilesList = analysisResults.rankedFilesList.slice(0, 10) + } + + this.features.logging.info( + `Memory Bank: using ${rankedFilesList.length} files for documentation generation` + ) + + // Step 5: Create the comprehensive prompt with ranked files and workspace path + const normalizedWorkspacePath = normalizePathFromUri(workspaceFolderUri, this.features.logging) + + this.features.logging.info(`Memory Bank: Generating final prompt with path: "${normalizedWorkspacePath}"`) + const finalPrompt = MemoryBankPrompts.getCompleteMemoryBankPrompt(rankedFilesList, normalizedWorkspacePath) + return finalPrompt + } catch (error) { + this.features.logging.error(`Memory Bank preparation failed: ${error}`) + throw error + } + } + + /** + * Clean and recreate memory bank directory + */ + async cleanMemoryBankDirectory(workspaceFolderUri: string): Promise { + try { + const normalizedWorkspacePath = normalizePathFromUri(workspaceFolderUri, this.features.logging) + const memoryBankPath = `${normalizedWorkspacePath}/${MEMORY_BANK_DIRECTORY}` + + // Remove all existing memory bank files to ensure clean recreation + const filesToRemove = ['product.md', 'structure.md', 'tech.md', 'guidelines.md'] + let removedCount = 0 + for (const fileName of filesToRemove) { + const filePath = `${memoryBankPath}/${fileName}` + try { + const exists = await this.features.workspace.fs.exists(filePath) + if (exists) { + await this.features.workspace.fs.rm(filePath) + removedCount++ + } + } catch (error) { + // Ignore errors when removing files that don't exist + this.features.logging.error(`Could not remove ${fileName}: ${error}`) + } + } + + if (removedCount > 0) { + this.features.logging.info(`Memory Bank: cleaned ${removedCount} existing files`) + } + + // Create the directory structure using mkdir with recursive option + await this.features.workspace.fs.mkdir(memoryBankPath, { recursive: true }) + } catch (error) { + this.features.logging.error(`Memory Bank directory creation failed: ${error}`) + throw error + } + } + + /** + * files discovery + */ + async discoverAllSourceFiles( + workspaceFolderUri: string, + extensions: string[] + ): Promise> { + try { + // Recursively discover all source files + const allWorkspaceFolders = this.features.workspace.getAllWorkspaceFolders() + + const workspaceFolders = allWorkspaceFolders?.map(({ uri }) => { + return normalizePathFromUri(uri, this.features.logging) + }) ?? [normalizePathFromUri(workspaceFolderUri, this.features.logging)] + + // Collect files from all workspace folders + let allSourceFiles: string[] = [] + + for (const folder of workspaceFolders) { + const sourceFiles = await this.discoverSourceFiles(folder, extensions) + this.features.logging.info(`Found ${sourceFiles.length} files in "${folder}"`) + allSourceFiles.push(...sourceFiles) + } + + this.features.logging.info(`Total files discovered: ${allSourceFiles.length}`) + + // OPTIMIZATION: Parallel file size calculation with batching + const batchSize = 10 // Process 10 files at a time + const files: Array<{ path: string; size: number }> = [] + + for (let i = 0; i < allSourceFiles.length; i += batchSize) { + const batch = allSourceFiles.slice(i, i + batchSize) + const batchResults = await Promise.all( + batch.map(async filePath => ({ + path: filePath, + size: await this.calculateFileLineCount(filePath), + })) + ) + files.push(...batchResults) + } + + return files + } catch (error) { + this.features.logging.error(`Error in getAllFiles: ${error}`) + return [] + } + } + + /** + * line counting + */ + async calculateFileLineCount(filePath: string): Promise { + try { + const content = await this.features.workspace.fs.readFile(filePath) + return content.split('\n').length + } catch (error) { + this.features.logging.error(`Error reading file ${filePath}: ${error}`) + return 0 + } + } + + /** + * lexical dissimilarity calculation + */ + async calculateLexicalDissimilarity( + files: Array<{ path: string; size: number }> + ): Promise> { + try { + // OPTIMIZATION: Parallel file reading with batching + const batchSize = 20 // Process 20 files at a time to reduce I/O overhead + const fileContents: string[] = [] + let hasReadErrors = false + + for (let i = 0; i < files.length; i += batchSize) { + const batch = files.slice(i, i + batchSize) + const batchContents = await Promise.all( + batch.map(async file => { + try { + return await this.features.workspace.fs.readFile(file.path) + } catch (error) { + this.features.logging.warn(`Could not read file for TF-IDF analysis: ${file.path}`) + hasReadErrors = true + return '' // Empty content for unreadable files + } + }) + ) + fileContents.push(...batchContents) + } + + // Check if all files are empty (no content to analyze) + const hasContent = fileContents.some(content => content.trim().length > 0) + if (!hasContent) { + // If no files have content due to read errors, log as error + if (hasReadErrors) { + this.features.logging.error( + 'All files failed to read or are empty, using fallback dissimilarity values' + ) + } + // If no files have content, return fallback values + return files.map(f => ({ ...f, dissimilarity: 0.85 })) + } + + // Step 2: Get the TF-IDF vectors for each file (equivalent to sklearn's TfidfVectorizer) + const tfidfMatrix = this.createTfidfMatrix(fileContents) + + // Step 3: Get the cosine similarity of each file (equivalent to sklearn's cosine_similarity) + const cosineSimilarities = this.calculateCosineSimilarityMatrix(tfidfMatrix) + + // Step 4: Get the lexical dissimilarity of each file (1 - similarity) + const lexicalDissimilarities: Array<{ path: string; size: number; dissimilarity: number }> = [] + for (let i = 0; i < cosineSimilarities.length; i++) { + // Calculate mean similarity for this file with all files (including itself) + const meanSimilarity = + cosineSimilarities[i].reduce((sum, sim) => sum + sim, 0) / cosineSimilarities[i].length + + // Dissimilarity = 1 - mean_similarity (exactly like Python code) + const dissimilarity = 1 - meanSimilarity + + lexicalDissimilarities.push({ + path: files[i].path, + size: files[i].size, + dissimilarity: Math.max(0.0, Math.min(1.0, dissimilarity)), // Ensure bounds [0,1] + }) + } + + return lexicalDissimilarities + } catch (error) { + this.features.logging.error(`Error in calculateLexicalDissimilarity: ${error}`) + // Fallback to reasonable defaults if TF-IDF calculation fails + return files.map(f => ({ ...f, dissimilarity: 0.85 })) + } + } + + /** + * Create TF-IDF matrix, Returns array of TF-IDF vectors, where each vector is a Map + */ + private createTfidfMatrix(documents: string[]): Map[] { + // Step 1: Tokenize all documents and build vocabulary + const tokenizedDocs = documents.map(doc => this.tokenizeDocument(doc)) + const vocabulary = new Set() + tokenizedDocs.forEach(tokens => tokens.forEach(token => vocabulary.add(token))) + + const vocabArray = Array.from(vocabulary) + const numDocs = documents.length + + // Step 2: Calculate document frequencies (DF) + const documentFrequencies = new Map() + vocabArray.forEach(term => { + const df = tokenizedDocs.filter(tokens => tokens.includes(term)).length + documentFrequencies.set(term, df) + }) + + // Step 3: Calculate TF-IDF for each document + const tfidfMatrix: Map[] = [] + for (let docIndex = 0; docIndex < numDocs; docIndex++) { + const tokens = tokenizedDocs[docIndex] + const tfidfVector = new Map() + + // Calculate term frequencies for this document + const termFrequencies = new Map() + tokens.forEach(token => { + termFrequencies.set(token, (termFrequencies.get(token) || 0) + 1) + }) + + // Calculate TF-IDF for each term in vocabulary + vocabArray.forEach(term => { + const tf = termFrequencies.get(term) || 0 + const df = documentFrequencies.get(term) || 1 + const idf = Math.log(numDocs / df) + const tfidf = tf * idf + tfidfVector.set(term, tfidf) + }) + + tfidfMatrix.push(tfidfVector) + } + + return tfidfMatrix + } + + /** + * Calculate cosine similarity matrix + */ + private calculateCosineSimilarityMatrix(tfidfMatrix: Map[]): number[][] { + const numDocs = tfidfMatrix.length + const similarities: number[][] = [] + + for (let i = 0; i < numDocs; i++) { + const row: number[] = [] + for (let j = 0; j < numDocs; j++) { + const similarity = this.calculateCosineSimilarity(tfidfMatrix[i], tfidfMatrix[j]) + row.push(similarity) + } + similarities.push(row) + } + + return similarities + } + + /** + * Calculate cosine similarity between two TF-IDF vectors + */ + private calculateCosineSimilarity(vectorA: Map, vectorB: Map): number { + let dotProduct = 0 + let normA = 0 + let normB = 0 + + // Get all unique terms from both vectors + const allTerms = new Set([...vectorA.keys(), ...vectorB.keys()]) + + allTerms.forEach(term => { + const valueA = vectorA.get(term) || 0 + const valueB = vectorB.get(term) || 0 + + dotProduct += valueA * valueB + normA += valueA * valueA + normB += valueB * valueB + }) + + // Avoid division by zero + if (normA === 0 || normB === 0) { + return 0 + } + + return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB)) + } + + /** + * Tokenize document into terms (simple whitespace + punctuation splitting) + */ + private tokenizeDocument(document: string): string[] { + return document + .toLowerCase() + .replace(/[^\w\s]/g, ' ') // Replace punctuation with spaces + .split(/\s+/) // Split on whitespace + .filter(token => token.length > 2) // Filter out very short tokens + } + + /** + * Execute the complete guidelines generation pipeline + * https://code.amazon.com/packages/QIDEPersonalization/blobs/mainline/--/src/stylefile-gen.ipynb + */ + async executeGuidelinesGenerationPipeline(workspaceFolderUri: string): Promise<{ + discoveredFiles: Array<{ path: string; size: number }> + filesWithDissimilarity: Array<{ path: string; size: number; dissimilarity: number }> + formattedFilesString: string + rankedFilesList: string[] + }> { + try { + // Step 1: Discover all source files + // OPTIMIZATION: Prioritize common extensions first for faster discovery + const extensions = [ + '.ts', + '.js', + '.tsx', + '.jsx', + '.py', + '.java', + '.cpp', + '.c', + '.h', + '.cs', + '.go', + '.rs', + '.php', + '.rb', + '.swift', + '.kt', + '.scala', + ] + + const discoveredFiles = await this.discoverAllSourceFiles(workspaceFolderUri, extensions) + + if (discoveredFiles.length === 0) { + throw new Error('No source files found in workspace') + } + + // Filter out very large files to prevent conversation overflow + const MAX_FILE_SIZE_FOR_MEMORY_BANK = 20000 // 20KB limit + const reasonableSizedFiles = discoveredFiles.filter(file => file.size <= MAX_FILE_SIZE_FOR_MEMORY_BANK) + + this.features.logging.debug( + `Memory Bank analysis: filtered ${discoveredFiles.length - reasonableSizedFiles.length} files over ${MAX_FILE_SIZE_FOR_MEMORY_BANK} characters` + ) + + // Limit files to prevent memory exhaustion on large projects + const MAX_FILES_FOR_ANALYSIS = 200 + let filesToAnalyze: Array<{ path: string; size: number }> + + if (reasonableSizedFiles.length > MAX_FILES_FOR_ANALYSIS) { + const shuffled = [...reasonableSizedFiles].sort(() => Math.random() - 0.5) + filesToAnalyze = shuffled.slice(0, MAX_FILES_FOR_ANALYSIS) + this.features.logging.info( + `Memory Bank analysis: randomly selected ${filesToAnalyze.length} files (from ${reasonableSizedFiles.length} reasonable-sized files for ranking)` + ) + } else { + filesToAnalyze = reasonableSizedFiles + } + + // Step 2: Calculate lexical dissimilarity using TF-IDF + const filesWithDissimilarity = await this.calculateLexicalDissimilarity(filesToAnalyze) + + // Step 3: Sort by size + filesWithDissimilarity.sort((a, b) => b.size - a.size) + + // Step 4: Format files string for LLM ranking + const formattedFilesString = this.formatFilesForRanking(filesWithDissimilarity) + + // Step 5: Create fallback ranking (deterministic, for when LLM fails) + const rankedFilesList = filesWithDissimilarity + .sort((a, b) => b.dissimilarity - a.dissimilarity) + .slice(0, 10) + .map(f => f.path) + + return { + discoveredFiles: filesToAnalyze, + filesWithDissimilarity, + formattedFilesString, + rankedFilesList, + } + } catch (error) { + this.features.logging.error(`Memory Bank analysis pipeline failed: ${error}`) + throw error + } + } + + /** + * Format files for processing pipeline + */ + formatFilesForRanking(files: Array<{ path: string; size: number; dissimilarity: number }>): string { + // Files are already sorted by size in executeGuidelinesGenerationPipeline() + return files + .map( + f => + `${f.path} has ${f.size} lines and a mean lexical dissimilarity of ${f.dissimilarity.toFixed(6)} to the other files` + ) + .join('\n') + } + + /** + * Recursively discover source files with given extensions + */ + private async discoverSourceFiles(workspaceFolderUri: string, extensions: string[]): Promise { + const sourceFiles: string[] = [] + const traverseDirectory = async (dirPath: string): Promise => { + try { + const entries = await this.features.workspace.fs.readdir(dirPath) + + for (const entry of entries) { + const fullPath = `${dirPath}/${entry.name}` + + // Skip common directories that don't contain source code + if (entry.isDirectory() && this.shouldSkipDirectory(entry.name)) { + continue + } + + if (entry.isDirectory()) { + // Directory - recurse + await traverseDirectory(fullPath) + } else { + // File - check if it's a source file + if (extensions.some(ext => entry.name.endsWith(ext))) { + sourceFiles.push(fullPath) + } + } + } + } catch (error) { + this.features.logging.error(`Could not read directory ${dirPath}: ${error}`) + } + } + + await traverseDirectory(workspaceFolderUri) + + return sourceFiles + } + + /** + * Check if a directory should be skipped during source file discovery + */ + private shouldSkipDirectory(dirName: string): boolean { + // Comprehensive language-agnostic directory exclusions + const skipDirs = [ + // Version Control Systems + '.git', + '.svn', + '.hg', + '.bzr', + '.fossil-settings', + + // Package Managers & Dependencies + 'node_modules', + 'bower_components', + 'jspm_packages', + 'vendor', + 'packages', + 'deps', + '_deps', + 'third_party', + 'external', + 'Pods', + 'Carthage', + 'DerivedData', // iOS/macOS + 'venv', + 'env', + '.venv', + '.env', + 'virtualenv', + '__pycache__', + '.tox', // Python + 'gems', + '.bundle', // Ruby + 'composer', // PHP + 'node_modules', + 'elm-stuff', // Elm + 'target', + 'project/target', + 'project/project', // Scala/SBT + + // Build Outputs & Artifacts + 'build', + 'builds', + 'dist', + 'out', + 'output', + 'bin', + 'obj', + 'lib', + 'release', + 'debug', + 'Release', + 'Debug', + 'x64', + 'x86', + 'AnyCPU', + '.next', + '.nuxt', + '.output', + '.vercel', + '.netlify', // Web frameworks + 'public/build', + 'static/build', + 'assets/build', + 'cmake-build-debug', + 'cmake-build-release', // CMake + '_build', + 'ebin', + 'deps', // Erlang/Elixir + 'zig-cache', + 'zig-out', // Zig + + // IDE & Editor Directories + '.vscode', + '.idea', + '.vs', + '.vscode-test', + '.eclipse', + '.metadata', + '.settings', + '.project', + '.classpath', + '.atom', + '.sublime-project', + '.sublime-workspace', + '__pycache__', + '.mypy_cache', + '.dmypy.json', // Python + '.dart_tool', + '.flutter-plugins', + '.flutter-plugins-dependencies', // Dart/Flutter + + // Testing & Coverage + 'coverage', + '.coverage', + '.nyc_output', + '.pytest_cache', + '.cache', + 'htmlcov', + 'test-results', + 'test-reports', + 'allure-results', + 'junit', + 'xunit', + 'nunit', + 'TestResults', + '.jest', + 'jest_html_reporters.html', + + // Logs & Temporary Files + 'logs', + 'log', + 'tmp', + 'temp', + '.tmp', + '.temp', + 'crash-reports', + 'error-reports', + + // Documentation Build Outputs + '_site', + '.jekyll-cache', + '.jekyll-metadata', // Jekyll + 'docs/_build', + 'doc/_build', + 'documentation/_build', // Sphinx + '.docusaurus', + 'website/build', // Docusaurus + 'book', + '_book', // GitBook/mdBook + + // Language-Specific Caches & Artifacts + '.gradle', + 'gradle', // Gradle + '.m2', + '.ivy2', // Maven/Ivy + '.stack-work', + '.cabal-sandbox', + 'cabal.sandbox.config', // Haskell + '_opam', + '.opam', // OCaml + 'Cargo.lock', // Rust (keep Cargo.toml but skip lock in some cases) + '.cargo', // Rust cache + '.mix', + '_build', // Elixir + 'rebar3.crashdump', + '_checkouts', // Erlang + '.rebar', + '.rebar3', + 'priv/static', // Phoenix framework + + // OS-Specific + '.DS_Store', + 'Thumbs.db', + 'Desktop.ini', + '$RECYCLE.BIN', + '.Trash-*', + '.fuse_hidden*', + + // Cloud & Deployment + '.serverless', + '.aws-sam', + '.terraform', + '.pulumi', + 'cdk.out', + '.cdk.staging', + 'amplify', + + // Mobile Development + 'ios/build', + 'android/build', + 'android/.gradle', + 'ios/Pods', + 'android/app/build', + + // Game Development + 'Library', + 'Temp', + 'Obj', + 'Build', + 'Builds', // Unity + 'Intermediate', + 'Binaries', + 'DerivedDataCache', // Unreal + + // Database + '*.db-journal', + '*.sqlite-journal', + + // Backup & Archive + 'backup', + 'backups', + '.backup', + 'archive', + 'archives', + ] + + // Skip any directory starting with . (hidden directories) except some important ones + if (dirName.startsWith('.')) { + const allowedHiddenDirs = ['.github', '.gitlab', '.circleci', '.travis', '.azure', '.devcontainer'] + return !allowedHiddenDirs.includes(dirName) + } + + return skipDirs.includes(dirName) + } + + /** + * Check if memory bank exists in workspace + */ + async memoryBankExists(workspaceFolderUri: string): Promise { + try { + const normalizedWorkspacePath = normalizePathFromUri(workspaceFolderUri, this.features.logging) + const memoryBankPath = `${normalizedWorkspacePath}/${MEMORY_BANK_DIRECTORY}` + + this.features.logging.info(`Memory Bank: Checking existence at path: "${memoryBankPath}"`) + + const exists = await this.features.workspace.fs.exists(memoryBankPath) + if (!exists) { + this.features.logging.info(`Memory Bank: Directory does not exist: "${memoryBankPath}"`) + return false + } + + // Check if at least one memory bank file exists + const files = Object.values(MEMORY_BANK_FILES) + let foundFiles = 0 + for (const file of files) { + const filePath = `${memoryBankPath}/${file}` + const fileExists = await this.features.workspace.fs.exists(filePath) + if (fileExists) { + foundFiles++ + } + } + + const hasFiles = foundFiles > 0 + if (hasFiles) { + this.features.logging.info(`Memory Bank: Found ${foundFiles} existing memory bank files`) + } else { + this.features.logging.info(`Memory Bank: No existing memory bank files found`) + } + + return hasFiles + } catch (error) { + this.features.logging.error(`Error checking memory bank existence: ${error}`) + return false + } + } +} diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankPrompts.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankPrompts.ts new file mode 100644 index 0000000000..9013d17e94 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankPrompts.ts @@ -0,0 +1,153 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. + * All Rights Reserved. SPDX-License-Identifier: Apache-2.0 + */ + +export class MemoryBankPrompts { + /** + * File ranking prompt - Takes TF-IDF analysis results and asks LLM to rank files + */ + static getFileRankingPrompt(filesString: string, numberToExtract: number = 20): string { + return `I will provide a list of files and the number of lines each file has. + +Please output just a JSON list which contains exactly ${numberToExtract} of these absolute file paths which are the most important and representative of this list to mine. Copy the exact filepaths exactly as they appear from the input. + +Consider the following when curating this list: +- The file path: contains information about what type of file it is (src, test) +- The file path: contains semantic information about the responsibilities of the class (e.g., core logic, utilities, subsystem) +- The number of lines of code: indicates the size of code within the files +- The mean lexical dissimilarity score: a higher number indicates this file is more different and unique from the other files in the project and thus might provide more information + +The expected format is ["filename1", "filename2", "filename3", ...] + +ONLY PROVIDE THE REQUESTED JSON AND NO OTHER TEXT + +Do not: +- Provide any textual response besides the requested JSON +- Use any markdown tags to annotate your response + + +${filesString} +` + } + + /** + * Complete Memory Bank generation - Takes ranked files and generates all 4 memory bank files + */ + static getCompleteMemoryBankPrompt(rankedFiles: string[], rootPath: string): string { + return `** CRITICAL INSTRUCTION: ALWAYS REGENERATE - NEVER SKIP ** + +You MUST generate a complete Memory Bank for this project by analyzing the codebase structure and generating comprehensive documentation. + +**MANDATORY REGENERATION POLICY:** +- NEVER respond with "already created" or "already exists" messages +- IGNORE any existing Memory Bank files in context - treat this as a fresh creation +- Even if you see existing memory-bank/*.md files in the context, REGENERATE them completely +- The user expects NEW files to be generated every time, regardless of existing files +- This ensures documentation is always current with the latest codebase +- Do NOT reference or mention existing memory bank files - create fresh ones + +**MANDATORY FRESH EXPLORATION POLICY:** +- IGNORE ALL PREVIOUS CHAT HISTORY about this project +- Even if you've analyzed this project before in this conversation, START FRESH +- ALWAYS begin by exploring the current workspace with listDirectory and readFile tools +- This is REQUIRED even if you think you already know the project structure +- Start with the root directory to understand if this is a multi-package workspace +- Read key configuration files (package.json, README.md, etc.) to understand the project +- This ensures documentation reflects the CURRENT complete codebase structure + +**CRITICAL MESSAGING AND TOOL USAGE POLICY:** +- Send your own brief progress messages before using tools (e.g., "Creating product.md - project overview and capabilities...") +- Use ONLY fsWrite tool with command "create" for file creation +- NEVER use fsReplace, fsRead, or other tools for creating memory bank files +- Use tools with ONLY the required parameters: command, path, fileText +- NEVER include the optional "explanation" parameter in any tool call +- Tool calls should be silent - your progress messages provide the user feedback +- Keep progress messages brief and informative + +**Directory Structure Ready** +The .amazonq/rules/memory-bank/ directory has been prepared and cleaned at: ${rootPath}/.amazonq/rules/memory-bank/ + +You MUST create exactly 4 files using fsWrite tool with these EXACT paths: +- ${rootPath}/.amazonq/rules/memory-bank/product.md +- ${rootPath}/.amazonq/rules/memory-bank/structure.md +- ${rootPath}/.amazonq/rules/memory-bank/tech.md +- ${rootPath}/.amazonq/rules/memory-bank/guidelines.md + +**Part 1: Fresh Analysis and Documentation Creation** + +FIRST: Start by saying "Now I'll explore the project structure and create the Memory Bank documentation." + +THEN: Create these 4 files in exact order: + +**1. product.md** - Project overview with: +- Project purpose and value proposition +- Key features and capabilities +- Target users and use cases + +**2. structure.md** - Project organization with: +- Directory structure and explanations +- Core components and relationships +- Architectural patterns + +**3. tech.md** - Technology details with: +- Programming languages and versions +- Build systems and dependencies +- Development commands + +**4. guidelines.md** - Development patterns from code analysis (see Part 2 below for analysis process) + +Create files 1-3 immediately using fsWrite with command "create" and the exact paths shown above. + +**Part 2: Advanced Guidelines Generation Using Iterative Analysis** + +THEN: Say "Now I'll analyze the most representative files from the codebase to identify development patterns and create comprehensive guidelines." + +I have ${rankedFiles.length} representative files ranked by lexical dissimilarity analysis: +${rankedFiles.map((file, i) => `${i + 1}. ${file}`).join('\n')} + +Create comprehensive development guidelines by: + +1. **Iterative File Analysis**: + - Process files in chunks of 2 using readFile tool + - Build guidelines iteratively, analyzing patterns across chunks + - Each iteration should build upon previous findings + +2. **Pattern Analysis Structure**: + - Code Quality Standards Analysis + - Document commonly used code formatting patterns + - Identify structural conventions and specifically what this codebase adheres to + - Note textual standards (naming, documentation, etc.) + - Practices followed throughout the codebase + +3. **Semantic Patterns Overview**: + - List recurring implementation patterns + - Document common architectural approaches + - Highlight frequent design patterns + - Proper internal API usage and patterns (with code examples!) + - Frequently used code idioms + - Popular annotations + +**ITERATIVE PROCESSING INSTRUCTIONS:** +- Process the ranked files in chunks of 2 files at a time using readFile tool +- For each chunk, send: "Analyzing chunk X/Y - Processing 2 files..." +- Analyze patterns in each chunk and build upon previous findings +- Keep track of how many files exhibit each pattern (frequency analysis) +- Build comprehensive guidelines.md iteratively through this process +- When creating guidelines.md, send "Creating guidelines.md - development standards and patterns..." then use fsWrite tool +- Use fsWrite with command "create" and path: ${rootPath}/.amazonq/rules/memory-bank/guidelines.md + +**COMPLETION SUMMARY**: After generating all 4 files, provide a brief completion message (maximum 8 lines) that: +- Confirms successful generation of exactly 4 files: product.md, structure.md, tech.md, guidelines.md +- Lists each file with one-line description +- Mentions they're available in Rules panel +- Avoids detailed technical breakdowns + +**FORBIDDEN RESPONSES:** +- NEVER say "I've already generated a complete Memory Bank" +- NEVER say "The Memory Bank is located in..." +- NEVER say "These files are automatically loaded" +- NEVER mention existing files - always create new ones +- NEVER provide status about existing documentation` + } +} From 6d321ac6f318c27b01f9f97eee45a62798a60cf5 Mon Sep 17 00:00:00 2001 From: BlakeLazarine Date: Tue, 23 Sep 2025 09:51:13 -0700 Subject: [PATCH 101/158] fix(amazonq): removing a bracket from full review message (#2317) Co-authored-by: Blake Lazarine --- .../agenticChat/tools/qCodeAnalysis/codeReview.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts index 61a24652f4..b474a4a928 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts @@ -126,8 +126,8 @@ export class CodeReview { : `Reviewing uncommitted changes in ${path.basename(uploadResult.filePathsInZip.values().next().value as string)}...` } else { reviewMessage = setup.isFullReviewRequest - ? `Reviewing the code in ${nonRuleFiles} files}...` - : `Reviewing uncommitted changes in ${diffFiles} of ${nonRuleFiles} files}...` + ? `Reviewing the code in ${nonRuleFiles} files...` + : `Reviewing uncommitted changes in ${diffFiles} of ${nonRuleFiles} files...` } await chatStreamWriter?.write(reviewMessage) From 8f30ac0ec5f4f7b7c343f5e889aec64a282897ea Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Tue, 23 Sep 2025 11:59:05 -0700 Subject: [PATCH 102/158] fix: userTriggerDecision STE suggestionType validation error (#2313) --- .../aws-lsp-codewhisperer/src/shared/codeWhispererService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index ba02c9c4e9..7c8beec318 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -90,8 +90,8 @@ export interface ResponseContext { } export enum SuggestionType { - EDIT = 'EDIT', - COMPLETION = 'COMPLETION', + EDIT = 'EDITS', + COMPLETION = 'COMPLETIONS', } export interface GenerateSuggestionsResponse { From aa1a4827871a1cfa9fcd76f7ba420107a5d44b01 Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Tue, 23 Sep 2025 13:33:02 -0700 Subject: [PATCH 103/158] fix(amazonq): fix to emit event for same region profile switch (#2320) --- .../shared/amazonQServiceManager/AmazonQTokenServiceManager.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts index d5cee6db7c..77fd162d5d 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts @@ -430,6 +430,9 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< this.cachedStreamingClient.profileArn = newProfile.arn } + // Emit auth success event + ProfileStatusMonitor.emitAuthSuccess() + return } From a949ac0a9d7a4dbce5fb7c8480952cee0a674b55 Mon Sep 17 00:00:00 2001 From: chungjac Date: Tue, 23 Sep 2025 13:57:46 -0700 Subject: [PATCH 104/158] fix: emit error code on failed user messages (#2322) --- .../src/language-server/agenticChat/agenticChatController.ts | 3 ++- .../language-server/chat/telemetry/chatTelemetryController.ts | 4 +++- .../src/shared/telemetry/telemetryService.test.ts | 1 + .../src/shared/telemetry/telemetryService.ts | 2 ++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index ab73ca644f..a167841d49 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -3479,7 +3479,8 @@ export class AgenticChatController implements ChatHandlers { metric.metric.requestIds = [requestID] metric.metric.cwsprChatMessageId = errorMessageId metric.metric.cwsprChatConversationId = conversationId - await this.#telemetryController.emitAddMessageMetric(tabId, metric.metric, 'Failed', errorMessage) + const errorCode = err.code ?? '' + await this.#telemetryController.emitAddMessageMetric(tabId, metric.metric, 'Failed', errorMessage, errorCode) if (isUsageLimitError(err)) { if (this.#paidTierMode !== 'paidtier') { diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts index 797a1f640a..d803d8d17b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts @@ -298,7 +298,8 @@ export class ChatTelemetryController { tabId: string, metric: Partial, result?: string, - errorMessage?: string + errorMessage?: string, + errorCode?: string ) { const conversationId = this.getConversationId(tabId) // Store the customization value associated with the message @@ -355,6 +356,7 @@ export class ChatTelemetryController { experimentName: metric.experimentName, userVariation: metric.userVariation, errorMessage: errorMessage, + errorCode: errorCode, } ) } diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts index d66ada7707..8c7975c5ce 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts @@ -860,6 +860,7 @@ describe('TelemetryService', () => { cwsprChatPinnedFolderContextCount: undefined, cwsprChatPinnedPromptContextCount: undefined, errorMessage: undefined, + errorCode: undefined, }, }) }) diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts index 59375e8adc..797c011cf2 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts @@ -566,6 +566,7 @@ export class TelemetryService { experimentName?: string userVariation?: string errorMessage?: string + errorCode?: string }> ) { const timeBetweenChunks = params.timeBetweenChunks?.slice(0, 100) @@ -620,6 +621,7 @@ export class TelemetryService { experimentName: additionalParams.experimentName, userVariation: additionalParams.userVariation, errorMessage: additionalParams.errorMessage, + errorCode: additionalParams.errorCode, }, }) } From b31cf67ddc68a2ca2e0a4ebd9ee94d0545afc656 Mon Sep 17 00:00:00 2001 From: BlakeLazarine Date: Tue, 23 Sep 2025 15:26:11 -0700 Subject: [PATCH 105/158] fix(amazonq): reduce number of findings to 30 as a quick fix (#2318) Co-authored-by: Blake Lazarine --- .../agenticChat/tools/qCodeAnalysis/codeReview.ts | 2 +- .../agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts index b474a4a928..d15985c282 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts @@ -44,7 +44,7 @@ export class CodeReview { private static readonly POLLING_INTERVAL_MS = 10000 // 10 seconds private static readonly UPLOAD_INTENT = 'AGENTIC_CODE_REVIEW' private static readonly SCAN_SCOPE = 'AGENTIC' - private static readonly MAX_FINDINGS_COUNT = 40 + private static readonly MAX_FINDINGS_COUNT = 30 private static readonly ERROR_MESSAGES = { MISSING_CLIENT: 'CodeWhisperer client not available', diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts index 32e940d14c..cb458f20e3 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts @@ -181,7 +181,7 @@ export const CODE_REVIEW_TOOL_DESCRIPTION = [ 'The tool will generate some findings grouped by file', 'Use following format STRICTLY to display the result of this tool for different scenarios:', '- When findings are present, you must inform user that you have completed the review of {file name / folder name / workspace} and found several issues that need attention. To inspect the details, and get fixes for those issues use the Code Issues panel.', - ' - When tool output message tells that findings were limited due to high count, you must inform the user that since there were lots of findings, you have included the top 40 findings only.', + ' - When tool output message tells that findings were limited due to high count, you must inform the user that since there were lots of findings, you have included the top 30 findings only.', '- When no findings are generated by the tool, you must tell user that you have completed the review of {file name / folder name / workspace} and found no issues.', ].join('\n') From 68c6d1465a3325612052740496cc1e6e50f56b9a Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Wed, 24 Sep 2025 10:05:02 -0700 Subject: [PATCH 106/158] fix: inline latency telemetry should account for preprocess time (#2323) --- .../codeWhispererServer.test.ts | 1 + .../inline-completion/codeWhispererServer.ts | 11 +++++--- .../editCompletionHandler.ts | 7 ++++- .../session/sessionManager.test.ts | 2 ++ .../session/sessionManager.ts | 27 +++++++++++++++---- .../src/shared/codeWhispererService.ts | 4 +-- .../supplementalContextUtil.ts | 8 +++--- .../src/shared/telemetry/telemetryService.ts | 17 ++++++------ .../src/shared/testUtils.ts | 2 ++ 9 files changed, 55 insertions(+), 24 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts index 61fb867a02..428d5353ae 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts @@ -1479,6 +1479,7 @@ describe('CodeWhisperer Server', () => { const sessionData: SessionData = { document: TextDocument.create('file:///rightContext.cs', 'csharp', 1, HELLO_WORLD_IN_CSHARP), + startPreprocessTimestamp: 0, startPosition: { line: 0, character: 0 }, triggerType: 'OnDemand', language: 'csharp', diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts index e70727b12c..0c9df7b511 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts @@ -225,6 +225,8 @@ export const CodewhispererServerFactory = const maxResults = isAutomaticLspTriggerKind ? 1 : 5 const selectionRange = params.context.selectedCompletionInfo?.range + const startPreprocessTimestamp = Date.now() + // For Jupyter Notebook in VSC, the language server does not have access to // its internal states including current active cell index, etc // we rely on VSC to calculate file context @@ -256,7 +258,7 @@ export const CodewhispererServerFactory = const previousSession = completionSessionManager.getPreviousSession() // Only refer to decisions in the past 2 mins const previousDecisionForClassifier = - previousSession && performance.now() - previousSession.decisionMadeTimestamp <= 2 * 60 * 1000 + previousSession && Date.now() - previousSession.decisionMadeTimestamp <= 2 * 60 * 1000 ? previousSession.getAggregatedUserTriggerDecision() : undefined let ideCategory: string | undefined = '' @@ -357,6 +359,7 @@ export const CodewhispererServerFactory = const newSession = completionSessionManager.createSession({ document: textDocument, + startPreprocessTimestamp: startPreprocessTimestamp, startPosition: params.position, triggerType: isAutomaticLspTriggerKind ? 'AutoTrigger' : 'OnDemand', language: fileContext.programmingLanguage.languageName as CodewhispererLanguage, @@ -425,7 +428,7 @@ export const CodewhispererServerFactory = session.suggestions = suggestionResponse.suggestions session.responseContext = suggestionResponse.responseContext session.codewhispererSessionId = suggestionResponse.responseContext.codewhispererSessionId - session.timeToFirstRecommendation = new Date().getTime() - session.startTime + session.setTimeToFirstRecommendation() session.predictionType = SuggestionType.COMPLETION } else { session.suggestions = [...session.suggestions, ...suggestionResponse.suggestions] @@ -843,9 +846,9 @@ export const CodewhispererServerFactory = // Record last user modification time for any document if (lastUserModificationTime) { - timeSinceLastUserModification = new Date().getTime() - lastUserModificationTime + timeSinceLastUserModification = Date.now() - lastUserModificationTime } - lastUserModificationTime = new Date().getTime() + lastUserModificationTime = Date.now() documentChangedListener.onDocumentChanged(p) editCompletionHandler.documentChanged() diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts index a340365b9f..d2c358d84e 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts @@ -128,6 +128,7 @@ export class EditCompletionHandler { // Not ideally to rely on a state, should improve it and simply make it a debounced API this.isInProgress = true + const startPreprocessTimestamp = Date.now() if (params.partialResultToken && currentSession) { // Close ACTIVE session. We shouldn't record Discard trigger decision for trigger with nextToken. @@ -138,6 +139,7 @@ export class EditCompletionHandler { const newSession = this.sessionManager.createSession({ document: textDocument, startPosition: params.position, + startPreprocessTimestamp: startPreprocessTimestamp, triggerType: 'AutoTrigger', language: currentSession.language, requestContext: currentSession.requestContext, @@ -174,6 +176,7 @@ export class EditCompletionHandler { this.isWaiting = true const result = await this._invoke( params, + startPreprocessTimestamp, token, textDocument, inferredLanguageId, @@ -205,6 +208,7 @@ export class EditCompletionHandler { async _invoke( params: InlineCompletionWithReferencesParams, + startPreprocessTimestamp: number, token: CancellationToken, textDocument: TextDocument, inferredLanguageId: CodewhispererLanguage, @@ -298,6 +302,7 @@ export class EditCompletionHandler { const newSession = this.sessionManager.createSession({ document: textDocument, + startPreprocessTimestamp: startPreprocessTimestamp, startPosition: params.position, triggerType: isAutomaticLspTriggerKind ? 'AutoTrigger' : 'OnDemand', language: fileContext.programmingLanguage.languageName, @@ -340,7 +345,7 @@ export class EditCompletionHandler { session.suggestions = suggestionResponse.suggestions session.responseContext = suggestionResponse.responseContext session.codewhispererSessionId = suggestionResponse.responseContext.codewhispererSessionId - session.timeToFirstRecommendation = new Date().getTime() - session.startTime + session.setTimeToFirstRecommendation() session.predictionType = SuggestionType.EDIT } else { session.suggestions = [...session.suggestions, ...suggestionResponse.suggestions] diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.test.ts index ddf06ffd40..1b2da25263 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.test.ts @@ -28,6 +28,7 @@ describe('CodeWhispererSession', function () { const data: SessionData = { document: TextDocument.create('file:///rightContext.cs', 'csharp', 1, HELLO_WORLD_IN_CSHARP), + startPreprocessTimestamp: 0, startPosition: { line: 0, character: 0 }, triggerType: 'OnDemand', language: 'csharp', @@ -510,6 +511,7 @@ describe('SessionManager', function () { } const data: SessionData = { document: TextDocument.create('file:///rightContext.cs', 'csharp', 1, HELLO_WORLD_IN_CSHARP), + startPreprocessTimestamp: 0, startPosition: { line: 0, character: 0 }, triggerType: 'OnDemand', language: 'csharp', diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts index 3aeef8bc8d..cdeb441f80 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts @@ -25,6 +25,7 @@ interface CachedSuggestion extends Suggestion { export interface SessionData { document: TextDocument + startPreprocessTimestamp: number startPosition: Position triggerType: CodewhispererTriggerType autoTriggerType?: CodewhispererAutomatedTriggerType @@ -42,6 +43,13 @@ export class CodeWhispererSession { id: string document: TextDocument startTime: number + private _endPreprocessTimestamp: number + get endPreprocessTimestamp() { + return this._endPreprocessTimestamp + } + get preprocessLatency() { + return this.endPreprocessTimestamp - this.startTime + } // Time when Session was closed and final state of user decisions is recorded in suggestionsStates closeTime?: number = 0 private _state: SessionState @@ -77,7 +85,14 @@ export class CodeWhispererSession { language: CodewhispererLanguage requestContext: GenerateSuggestionsRequest supplementalMetadata?: CodeWhispererSupplementalContext - timeToFirstRecommendation: number = 0 + private _timeToFirstRecommendation: number = 0 + get timeToFirstRecommendation() { + return this._timeToFirstRecommendation + } + setTimeToFirstRecommendation() { + this._timeToFirstRecommendation = Date.now() - this.startTime + } + credentialStartUrl?: string completionSessionResult?: { [itemId: string]: InlineCompletionStates @@ -111,8 +126,9 @@ export class CodeWhispererSession { this.customizationArn = data.customizationArn this.supplementalMetadata = data.supplementalMetadata this._state = 'REQUESTING' - - this.startTime = new Date().getTime() + this.startTime = data.startPreprocessTimestamp + // Current implementation is the session will be created when preprocess is done + this._endPreprocessTimestamp = Date.now() } // This function makes it possible to stub uuidv4 calls in tests @@ -147,7 +163,7 @@ export class CodeWhispererSession { } } - this.closeTime = new Date().getTime() + this.closeTime = Date.now() this.state = 'CLOSED' } @@ -162,11 +178,12 @@ export class CodeWhispererSession { this.suggestionsStates.set(suggestion.itemId, 'Discard') } - this.closeTime = new Date().getTime() + this.closeTime = Date.now() this.state = 'DISCARD' } + // Should use epoch time for firstCompletionDisplayLatency, totalSessionDisplayTime setClientResultData( completionSessionResult: { [itemId: string]: InlineCompletionStates }, firstCompletionDisplayLatency?: number, diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index 7c8beec318..d0db76b2b3 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -482,7 +482,7 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { tokenRequest.customizationArn = this.customizationArn } - const beforeApiCall = performance.now() + const beforeApiCall = Date.now() let recentEditsLogStr = '' const recentEdits = tokenRequest.supplementalContexts?.filter(it => it.type === 'PreviousEditorState') if (recentEdits) { @@ -528,7 +528,7 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { "response.completions.length": ${response.completions?.length ?? 0}, "response.predictions.length": ${response.predictions?.length ?? 0}, "predictionType": ${tokenRequest.predictionTypes?.toString() ?? ''}, - "latency": ${performance.now() - beforeApiCall}, + "latency": ${Date.now() - beforeApiCall}, "response.nextToken": ${response.nextToken}, "firstSuggestion": ${firstSuggestionLogstr}` diff --git a/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/supplementalContextUtil.ts b/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/supplementalContextUtil.ts index 8e0902452f..18fb5a7686 100644 --- a/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/supplementalContextUtil.ts +++ b/server/aws-lsp-codewhisperer/src/shared/supplementalContextUtil/supplementalContextUtil.ts @@ -30,7 +30,7 @@ export async function fetchSupplementalContext( cancellationToken: CancellationToken, openTabFiles?: string[] ): Promise { - const timesBeforeFetching = performance.now() + const timesBeforeFetching = Date.now() const isUtg = unitTestIntentDetector.detectUnitTestIntent(document) @@ -55,7 +55,7 @@ export async function fetchSupplementalContext( }, ], contentsLength: srcContent.length, - latency: performance.now() - timesBeforeFetching, + latency: Date.now() - timesBeforeFetching, strategy: 'NEW_UTG', } } @@ -87,7 +87,7 @@ export async function fetchSupplementalContext( (acc, curr) => acc + curr.content.length, 0 ), - latency: performance.now() - timesBeforeFetching, + latency: Date.now() - timesBeforeFetching, strategy: supplementalContextValue.strategy, } @@ -119,7 +119,7 @@ export async function fetchSupplementalContext( isProcessTimeout: true, supplementalContextItems: [], contentsLength: 0, - latency: performance.now() - timesBeforeFetching, + latency: Date.now() - timesBeforeFetching, strategy: 'Empty', } } else { diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts index 797c011cf2..3fef1bec68 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts @@ -179,7 +179,8 @@ export class TelemetryService { if (this.modelId !== undefined) { request.modelId = this.modelId } - await this.getService().sendTelemetryEvent(request) + const r = await this.getService().sendTelemetryEvent(request) + this.logging.log(`SendTelemetryEvent succeeded, requestId: ${r.$response.requestId}`) } catch (error) { this.logSendTelemetryEventFailure(error) } @@ -199,7 +200,7 @@ export class TelemetryService { removedIdeDiagnostics?: IdeDiagnostic[], streakLength?: number ) { - session.decisionMadeTimestamp = performance.now() + session.decisionMadeTimestamp = Date.now() // Toolkit telemetry API if (this.enableTelemetryEventsToDestination) { const data: CodeWhispererUserTriggerDecisionEvent = { @@ -269,9 +270,7 @@ export class TelemetryService { completionType: session.suggestions.length > 0 ? getCompletionType(session.suggestions[0]).toUpperCase() : 'LINE', suggestionState: this.getSuggestionState(userTriggerDecision), - recommendationLatencyMilliseconds: session.firstCompletionDisplayLatency - ? session.firstCompletionDisplayLatency - : 0, + recommendationLatencyMilliseconds: session.firstCompletionDisplayLatency ?? 0, timestamp: new Date(Date.now()), triggerToResponseLatencyMilliseconds: session.timeToFirstRecommendation, suggestionReferenceCount: referenceCount, @@ -286,14 +285,16 @@ export class TelemetryService { streakLength: streakLength ?? 0, suggestionType: session.predictionType, } - this.logging.info(`Invoking SendTelemetryEvent:UserTriggerDecisionEvent with: + this.logging.info(`Invoking SendTelemetryEvent:UserTriggerDecisionEvent: "requestId": ${event.requestId} "suggestionState": ${event.suggestionState} "acceptedCharacterCount": ${event.acceptedCharacterCount} "addedCharacterCount": ${event.addedCharacterCount} "deletedCharacterCount": ${event.deletedCharacterCount} - "streakLength": ${event.streakLength} - "firstCompletionDisplayLatency: ${event.recommendationLatencyMilliseconds} + "streakLength": ${event.streakLength}, + "preprocessLatency": ${session.preprocessLatency}, + "triggerToResponseLatencyMilliseconds: ${event.triggerToResponseLatencyMilliseconds}", + "firstCompletionDisplayLatency: ${event.recommendationLatencyMilliseconds}, "suggestionType": ${event.suggestionType}`) return this.invokeSendTelemetryEvent({ userTriggerDecisionEvent: event, diff --git a/server/aws-lsp-codewhisperer/src/shared/testUtils.ts b/server/aws-lsp-codewhisperer/src/shared/testUtils.ts index 795cb465d4..374f347627 100644 --- a/server/aws-lsp-codewhisperer/src/shared/testUtils.ts +++ b/server/aws-lsp-codewhisperer/src/shared/testUtils.ts @@ -251,6 +251,7 @@ export const EMPTY_RESULT = { items: [], sessionId: '' } export const SAMPLE_SESSION_DATA: SessionData = { document: SOME_FILE, + startPreprocessTimestamp: 0, startPosition: { line: 0, character: 0, @@ -270,6 +271,7 @@ export const SAMPLE_SESSION_DATA: SessionData = { export const SAMPLE_SESSION_DATA_WITH_EXTRA_LEFT_CONTENT: SessionData = { document: SOME_INCOMPLETE_FILE, + startPreprocessTimestamp: 0, startPosition: { line: 1, character: 0, From 140a9c3c68b6994698978575a32fdf3566b51f75 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 11:10:23 -0700 Subject: [PATCH 107/158] chore(release): release packages from branch main (#2316) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .release-please-manifest.json | 4 ++-- chat-client/CHANGELOG.md | 7 +++++++ chat-client/package.json | 2 +- package-lock.json | 4 ++-- server/aws-lsp-codewhisperer/CHANGELOG.md | 17 +++++++++++++++++ server/aws-lsp-codewhisperer/package.json | 2 +- 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e1caa1ac4b..9bfb32d2da 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,8 +1,8 @@ { - "chat-client": "0.1.36", + "chat-client": "0.1.37", "core/aws-lsp-core": "0.0.15", "server/aws-lsp-antlr4": "0.1.19", - "server/aws-lsp-codewhisperer": "0.0.81", + "server/aws-lsp-codewhisperer": "0.0.82", "server/aws-lsp-json": "0.1.19", "server/aws-lsp-partiql": "0.0.18", "server/aws-lsp-yaml": "0.1.19" diff --git a/chat-client/CHANGELOG.md b/chat-client/CHANGELOG.md index fb94865004..93dd6d16a1 100644 --- a/chat-client/CHANGELOG.md +++ b/chat-client/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.1.37](https://github.com/aws/language-servers/compare/chat-client/v0.1.36...chat-client/v0.1.37) (2025-09-24) + + +### Features + +* memory bank support ([#2314](https://github.com/aws/language-servers/issues/2314)) ([0e215fc](https://github.com/aws/language-servers/commit/0e215fc0e475b4c40a8237492371716982d4d532)) + ## [0.1.36](https://github.com/aws/language-servers/compare/chat-client/v0.1.35...chat-client/v0.1.36) (2025-09-16) diff --git a/chat-client/package.json b/chat-client/package.json index a20d2cc5a1..7c31ff4c0e 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -1,6 +1,6 @@ { "name": "@aws/chat-client", - "version": "0.1.36", + "version": "0.1.37", "description": "AWS Chat Client", "main": "out/index.js", "repository": { diff --git a/package-lock.json b/package-lock.json index 59509ce1a6..7bec6ab90e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -251,7 +251,7 @@ }, "chat-client": { "name": "@aws/chat-client", - "version": "0.1.36", + "version": "0.1.37", "license": "Apache-2.0", "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", @@ -28677,7 +28677,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.81", + "version": "0.0.82", "bundleDependencies": [ "@amzn/codewhisperer-streaming", "@amzn/amazon-q-developer-streaming-client" diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index a9a9eaa131..6194b4ba1d 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## [0.0.82](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.81...lsp-codewhisperer/v0.0.82) (2025-09-24) + + +### Features + +* memory bank support ([#2314](https://github.com/aws/language-servers/issues/2314)) ([0e215fc](https://github.com/aws/language-servers/commit/0e215fc0e475b4c40a8237492371716982d4d532)) + + +### Bug Fixes + +* **amazonq:** fix to emit event for same region profile switch ([#2320](https://github.com/aws/language-servers/issues/2320)) ([aa1a482](https://github.com/aws/language-servers/commit/aa1a4827871a1cfa9fcd76f7ba420107a5d44b01)) +* **amazonq:** reduce number of findings to 30 as a quick fix ([#2318](https://github.com/aws/language-servers/issues/2318)) ([b31cf67](https://github.com/aws/language-servers/commit/b31cf67ddc68a2ca2e0a4ebd9ee94d0545afc656)) +* **amazonq:** removing a bracket from full review message ([#2317](https://github.com/aws/language-servers/issues/2317)) ([6d321ac](https://github.com/aws/language-servers/commit/6d321ac6f318c27b01f9f97eee45a62798a60cf5)) +* emit error code on failed user messages ([#2322](https://github.com/aws/language-servers/issues/2322)) ([a949ac0](https://github.com/aws/language-servers/commit/a949ac0a9d7a4dbce5fb7c8480952cee0a674b55)) +* inline latency telemetry should account for preprocess time ([#2323](https://github.com/aws/language-servers/issues/2323)) ([68c6d14](https://github.com/aws/language-servers/commit/68c6d1465a3325612052740496cc1e6e50f56b9a)) +* userTriggerDecision STE suggestionType validation error ([#2313](https://github.com/aws/language-servers/issues/2313)) ([8f30ac0](https://github.com/aws/language-servers/commit/8f30ac0ec5f4f7b7c343f5e889aec64a282897ea)) + ## [0.0.81](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.80...lsp-codewhisperer/v0.0.81) (2025-09-19) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 8d07e72a6d..ae2e55b2db 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.81", + "version": "0.0.82", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { From f0364c332e0e9c3e148019673f9667e8c10bcfe6 Mon Sep 17 00:00:00 2001 From: Tai Lai Date: Wed, 24 Sep 2025 16:13:56 -0700 Subject: [PATCH 108/158] chore: bump agentic version: 1.35.0 (#2332) Co-authored-by: aws-toolkit-automation <> --- app/aws-lsp-codewhisperer-runtimes/src/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/src/version.json b/app/aws-lsp-codewhisperer-runtimes/src/version.json index ea9cb1ee08..fcab28de2b 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/version.json +++ b/app/aws-lsp-codewhisperer-runtimes/src/version.json @@ -1,3 +1,3 @@ { - "agenticChat": "1.34.0" + "agenticChat": "1.35.0" } From 5eb3768bf020d61d0ade767d62e13839048146e4 Mon Sep 17 00:00:00 2001 From: Jayakrishna P Date: Thu, 25 Sep 2025 13:50:23 -0700 Subject: [PATCH 109/158] fix(amazonq): handle IAM credentials expiration field to be aws sdk versions compatible and add refresh logic to codewhisperer IAM client (#2349) ## Problem Chat and InlineSuggestions doesnt work in Sagemaker instances after initial credential expiration since refresh logic isnt using expiration field properly ## Solution - Standardizes IAM credentials expiration field handling across the codebase to support both AWS SDK v2 (`expireTime`) and v3 (`expiration`) formats - Add credential fetch and refresh lazy loading logic to Codewhisperer IAM client to ensure fresh credentials are used --- .../src/credentials/credentialsProvider.ts | 1 + .../ideCredentialsProvider.test.ts | 48 +++++++++++++++++++ .../src/credentials/ideCredentialsProvider.ts | 10 +++- .../AmazonQIAMServiceManager.ts | 9 +++- .../src/shared/codeWhispererService.ts | 41 +++++++++++++++- .../src/shared/streamingClientService.test.ts | 21 ++++---- .../src/shared/streamingClientService.ts | 15 ++++-- 7 files changed, 125 insertions(+), 20 deletions(-) create mode 100644 core/aws-lsp-core/src/credentials/ideCredentialsProvider.test.ts diff --git a/core/aws-lsp-core/src/credentials/credentialsProvider.ts b/core/aws-lsp-core/src/credentials/credentialsProvider.ts index a56be8e0ad..1f5186eea7 100644 --- a/core/aws-lsp-core/src/credentials/credentialsProvider.ts +++ b/core/aws-lsp-core/src/credentials/credentialsProvider.ts @@ -4,6 +4,7 @@ export interface IamCredentials { accessKeyId: string secretAccessKey: string sessionToken?: string + expiration?: Date // v3 format } export interface BearerToken { diff --git a/core/aws-lsp-core/src/credentials/ideCredentialsProvider.test.ts b/core/aws-lsp-core/src/credentials/ideCredentialsProvider.test.ts new file mode 100644 index 0000000000..a2fbb51834 --- /dev/null +++ b/core/aws-lsp-core/src/credentials/ideCredentialsProvider.test.ts @@ -0,0 +1,48 @@ +/*! + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as assert from 'assert' +import { IdeCredentialsProvider } from './ideCredentialsProvider' +import { IamCredentials } from './credentialsProvider' +import { Connection } from 'vscode-languageserver' +import * as sinon from 'sinon' + +describe('IdeCredentialsProvider', function () { + let provider: IdeCredentialsProvider + let mockConnection: sinon.SinonStubbedInstance + + beforeEach(function () { + mockConnection = { + console: { + info: sinon.stub(), + log: sinon.stub(), + warn: sinon.stub(), + error: sinon.stub(), + }, + } as any + provider = new IdeCredentialsProvider(mockConnection as any) + }) + + describe('validateIamCredentialsFields', function () { + it('throws error when accessKeyId is missing', function () { + const credentials = { + secretAccessKey: 'secret', + } as IamCredentials + + assert.throws(() => provider['validateIamCredentialsFields'](credentials), /Missing property: accessKeyId/) + }) + + it('throws error when secretAccessKey is missing', function () { + const credentials = { + accessKeyId: 'key', + } as IamCredentials + + assert.throws( + () => provider['validateIamCredentialsFields'](credentials), + /Missing property: secretAccessKey/ + ) + }) + }) +}) diff --git a/core/aws-lsp-core/src/credentials/ideCredentialsProvider.ts b/core/aws-lsp-core/src/credentials/ideCredentialsProvider.ts index 08231ad33d..6f389594b8 100644 --- a/core/aws-lsp-core/src/credentials/ideCredentialsProvider.ts +++ b/core/aws-lsp-core/src/credentials/ideCredentialsProvider.ts @@ -58,7 +58,15 @@ export class IdeCredentialsProvider implements CredentialsProvider { credentialsProtocolMethodNames.iamCredentialsUpdate, async (request: UpdateCredentialsRequest) => { try { - const iamCredentials = await this.decodeCredentialsRequestToken(request) + const rawCredentials = await this.decodeCredentialsRequestToken< + IamCredentials & { expireTime?: Date } + >(request) + + // Normalize legacy expireTime field to standard expiration field + const iamCredentials: IamCredentials = { + ...rawCredentials, + expiration: rawCredentials.expiration || rawCredentials.expireTime, + } this.validateIamCredentialsFields(iamCredentials) diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts index 774102a987..a29b65468f 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts @@ -78,8 +78,13 @@ export class AmazonQIAMServiceManager extends BaseAmazonQServiceManager< return this.cachedStreamingClient } - public handleOnCredentialsDeleted(_type: CredentialsType): void { - return + public handleOnCredentialsDeleted(type: CredentialsType): void { + if (type === 'iam') { + this.cachedCodewhispererService?.abortInflightRequests() + this.cachedCodewhispererService = undefined + this.cachedStreamingClient?.abortInflightRequests() + this.cachedStreamingClient = undefined + } } public override handleOnUpdateConfiguration( diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index d0db76b2b3..df193010de 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -234,7 +234,46 @@ export class CodeWhispererServiceIAM extends CodeWhispererServiceBase { region: this.codeWhispererRegion, endpoint: this.codeWhispererEndpoint, credentialProvider: new CredentialProviderChain([ - () => credentialsProvider.getCredentials('iam') as Credentials, + () => { + const credentials = new Credentials({ + accessKeyId: '', + secretAccessKey: '', + sessionToken: '', + }) + + credentials.get = callback => { + logging.info('CodeWhispererServiceIAM: Attempting to get credentials') + + Promise.resolve(credentialsProvider.getCredentials('iam')) + .then((creds: any) => { + logging.info('CodeWhispererServiceIAM: Successfully got credentials') + + credentials.accessKeyId = creds.accessKeyId as string + credentials.secretAccessKey = creds.secretAccessKey as string + credentials.sessionToken = creds.sessionToken as string + credentials.expireTime = creds.expiration as Date + callback() + }) + .catch(err => { + logging.error(`CodeWhispererServiceIAM: Failed to get credentials: ${err.message}`) + callback(err) + }) + } + + credentials.needsRefresh = () => { + return ( + !credentials.accessKeyId || + !credentials.secretAccessKey || + (credentials.expireTime && credentials.expireTime.getTime() - Date.now() < 60000) + ) // 1 min buffer + } + + credentials.refresh = callback => { + credentials.get(callback) + } + + return credentials + }, ]), } this.client = createCodeWhispererSigv4Client(options, sdkInitializator, logging) diff --git a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts index bbb6053f28..b12f1633df 100644 --- a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts @@ -272,7 +272,7 @@ describe('StreamingClientServiceIAM', () => { expect(streamingClientServiceIAM['inflightRequests'].size).to.eq(0) }) - it('uses expireTime from credentials when available', async () => { + it('uses expiration from credentials when available', async () => { // Get the credential provider function from the client config const credentialProvider = streamingClientServiceIAM.client.config.credentials expect(credentialProvider).to.not.be.undefined @@ -280,11 +280,11 @@ describe('StreamingClientServiceIAM', () => { // Reset call count on the stub features.credentialsProvider.getCredentials.resetHistory() - // Set up credentials with expireTime + // Set up credentials with expiration const futureDate = new Date(Date.now() + 3600000) // 1 hour in the future const CREDENTIALS_WITH_EXPIRY = { ...MOCKED_IAM_CREDENTIALS, - expireTime: futureDate.toISOString(), + expiration: futureDate, } features.credentialsProvider.getCredentials.withArgs('iam').returns(CREDENTIALS_WITH_EXPIRY) @@ -293,12 +293,12 @@ describe('StreamingClientServiceIAM', () => { await clock.tickAsync(TIME_TO_ADVANCE_MS) const credentials = await credentialsPromise - // Verify expiration is set to the expireTime from credentials + // Verify expiration is set to the expiration from credentials expect(credentials.expiration).to.be.instanceOf(Date) expect(credentials.expiration.getTime()).to.equal(futureDate.getTime()) }) - it('falls back to current date when expireTime is not available', async () => { + it('forces refresh when expiration is not available in credentials', async () => { // Get the credential provider function from the client config const credentialProvider = streamingClientServiceIAM.client.config.credentials expect(credentialProvider).to.not.be.undefined @@ -306,21 +306,16 @@ describe('StreamingClientServiceIAM', () => { // Reset call count on the stub features.credentialsProvider.getCredentials.resetHistory() - // Set up credentials without expireTime + // Set up credentials without expiration features.credentialsProvider.getCredentials.withArgs('iam').returns(MOCKED_IAM_CREDENTIALS) - // Set a fixed time for testing - const fixedNow = new Date() - clock.tick(0) // Ensure clock is at the fixed time - // Call the credential provider const credentialsPromise = (credentialProvider as any)() await clock.tickAsync(TIME_TO_ADVANCE_MS) const credentials = await credentialsPromise - // Verify expiration is set to current date when expireTime is missing + // Verify expiration is set to current date to force refresh when not provided in credentials expect(credentials.expiration).to.be.instanceOf(Date) - // The expiration should be very close to the current time - expect(credentials.expiration.getTime()).to.be.closeTo(fixedNow.getTime(), 100) + expect(credentials.expiration.getTime()).to.be.closeTo(Date.now(), 1000) }) }) diff --git a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts index 167f360f4c..d7c425c38f 100644 --- a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts @@ -12,7 +12,12 @@ import { SendMessageCommandInput as SendMessageCommandInputQDeveloperStreaming, SendMessageCommandOutput as SendMessageCommandOutputQDeveloperStreaming, } from '@amzn/amazon-q-developer-streaming-client' -import { CredentialsProvider, SDKInitializator, Logging } from '@aws/language-server-runtimes/server-interface' +import { + CredentialsProvider, + SDKInitializator, + Logging, + IamCredentials, +} from '@aws/language-server-runtimes/server-interface' import { getBearerTokenFromProvider, isUsageLimitError } from './utils' import { ConfiguredRetryStrategy } from '@aws-sdk/util-retry' import { CredentialProviderChain, Credentials } from 'aws-sdk' @@ -188,13 +193,17 @@ export class StreamingClientServiceIAM extends StreamingClientServiceBase { // Create a credential provider that fetches fresh credentials on each request const iamCredentialProvider: AwsCredentialIdentityProvider = async (): Promise => { - const creds = (await credentialsProvider.getCredentials('iam')) as Credentials + const creds = (await credentialsProvider.getCredentials('iam')) as IamCredentials logging.log(`Fetching new IAM credentials`) + if (!creds) { + logging.log('Failed to fetch IAM credentials: No IAM credentials found') + throw new Error('No IAM credentials found') + } return { accessKeyId: creds.accessKeyId, secretAccessKey: creds.secretAccessKey, sessionToken: creds.sessionToken, - expiration: creds.expireTime ? new Date(creds.expireTime) : new Date(), // Force refresh on each request if creds do not have expiration time + expiration: creds.expiration ? new Date(creds.expiration) : new Date(), // Force refresh if expiration field is not available } } From e7aa2a6545bcb1a8238abfde69a05432be0b6615 Mon Sep 17 00:00:00 2001 From: Jason Guo <81202082+jguoamz@users.noreply.github.com> Date: Mon, 29 Sep 2025 12:40:26 -0700 Subject: [PATCH 110/158] fix: improve history management (#2312) (#2357) Co-authored-by: aws-toolkit-automation <43144436+aws-toolkit-automation@users.noreply.github.com> --- .../agenticChat/agenticChatController.ts | 18 ++-- .../agenticChat/constants/constants.ts | 6 +- .../agenticChat/tools/chatDb/chatDb.ts | 90 +++---------------- 3 files changed, 21 insertions(+), 93 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index a167841d49..2f309981d0 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -137,7 +137,7 @@ import { AmazonQBaseServiceManager } from '../../shared/amazonQServiceManager/Ba import { AmazonQTokenServiceManager } from '../../shared/amazonQServiceManager/AmazonQTokenServiceManager' import { AmazonQWorkspaceConfig } from '../../shared/amazonQServiceManager/configurationUtils' import { TabBarController } from './tabBarController' -import { ChatDatabase, MaxOverallCharacters, ToolResultValidationError } from './tools/chatDb/chatDb' +import { ChatDatabase, ToolResultValidationError } from './tools/chatDb/chatDb' import { AgenticChatEventParser, ChatResultWithMetadata as AgenticChatResultWithMetadata, @@ -187,6 +187,8 @@ import { DEFAULT_WINDOW_REJECT_SHORTCUT, DEFAULT_MACOS_STOP_SHORTCUT, DEFAULT_WINDOW_STOP_SHORTCUT, + COMPACTION_CHARACTER_THRESHOLD, + MAX_OVERALL_CHARACTERS, } from './constants/constants' import { AgenticChatError, @@ -1179,8 +1181,7 @@ export class AgenticChatController implements ChatHandlers { * Runs the compaction, making requests and processing tool uses until completion */ #shouldCompact(currentRequestCount: number): boolean { - // 80% of 570K limit - if (currentRequestCount > 456_000) { + if (currentRequestCount > COMPACTION_CHARACTER_THRESHOLD) { this.#debug(`Current request total character count is: ${currentRequestCount}, prompting user to compact`) return true } else { @@ -1225,7 +1226,7 @@ export class AgenticChatController implements ChatHandlers { // Get and process the messages from history DB to maintain invariants for service requests try { const { history: historyMessages, historyCount: historyCharCount } = - this.#chatHistoryDb.fixAndGetHistory(tabId, conversationIdentifier ?? '', currentMessage, []) + this.#chatHistoryDb.fixAndGetHistory(tabId, currentMessage, []) messages = historyMessages characterCount = historyCharCount } catch (err) { @@ -1403,12 +1404,7 @@ export class AgenticChatController implements ChatHandlers { history: historyMessages, historyCount: historyCharacterCount, currentCount: currentInputCount, - } = this.#chatHistoryDb.fixAndGetHistory( - tabId, - conversationId, - currentMessage, - pinnedContextMessages - ) + } = this.#chatHistoryDb.fixAndGetHistory(tabId, currentMessage, pinnedContextMessages) messages = historyMessages currentRequestCount = currentInputCount + historyCharacterCount this.#debug(`Request total character count: ${currentRequestCount}`) @@ -2779,7 +2775,7 @@ export class AgenticChatController implements ChatHandlers { body: COMPACTION_HEADER_BODY, buttons, } as any - const body = COMPACTION_BODY(Math.round((characterCount / MaxOverallCharacters) * 100)) + const body = COMPACTION_BODY(Math.round((characterCount / MAX_OVERALL_CHARACTERS) * 100)) return { type: 'tool', messageId, diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts index b2ac428cfa..02fb0d855a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts @@ -1,5 +1,3 @@ -import { BedrockModel } from './modelSelection' - // Error message constants export const GENERIC_ERROR_MS = 'An unexpected error occurred, check the logs for more information.' export const OUTPUT_LIMIT_EXCEEDS_PARTIAL_MSG = 'output exceeds maximum character limit of' @@ -16,6 +14,10 @@ export const SERVICE_MANAGER_POLL_INTERVAL_MS = 100 export const GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT = 500_000 // Compaction +// Maximum number of characters per request used for compaction prompt +// 200K tokens * 3.5 = 700K characters, intentionally overestimating with 3.5:1 ratio +export const MAX_OVERALL_CHARACTERS = 700_000 +export const COMPACTION_CHARACTER_THRESHOLD = 0.7 * MAX_OVERALL_CHARACTERS export const COMPACTION_BODY = (threshold: number) => `The context window is almost full (${threshold}%) and exceeding it will clear your history. Amazon Q can compact your history instead.` export const COMPACTION_HEADER_BODY = 'Compact chat history?' diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts index f584d63b5f..e038c37228 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts @@ -45,11 +45,6 @@ export class ToolResultValidationError extends Error { } export const EMPTY_CONVERSATION_LIST_ID = 'empty' -// Maximum number of characters to keep in request -// (200K tokens - 8K output tokens - 2k system prompt) * 3 = 570K characters, intentionally overestimating with 3:1 ratio -export const MaxOverallCharacters = 570_000 -// Maximum number of history messages to include in each request to the LLM -const maxConversationHistoryMessages = 250 /** * A singleton database class that manages chat history persistence using LokiJS. @@ -708,15 +703,12 @@ export class ChatDatabase { /** * Prepare the history messages for service request and fix the persisted history in DB to maintain the following invariants: - * 1. The history contains at most MaxConversationHistoryMessages messages. Oldest messages are dropped. - * 2. The first message is from the user and without any tool usage results, and the last message is from the assistant. + * 1. The first message is from the user and without any tool usage results, and the last message is from the assistant. * The history contains alternating sequene of userMessage followed by assistantMessages - * 3. The toolUse and toolResult relationship is valid - * 4. The history character length is <= MaxConversationHistoryCharacters - newUserMessageCharacterCount. Oldest messages are dropped. + * 2. The toolUse and toolResult relationship is valid */ fixAndGetHistory( tabId: string, - conversationId: string, newUserMessage: ChatMessage, pinnedContextMessages: ChatMessage[] ): MessagesWithCharacterCount { @@ -732,18 +724,19 @@ export class ChatDatabase { this.#features.logging.info(`Fixing history: tabId=${tabId}`) - // 1. Make sure the length of the history messages don't exceed MaxConversationHistoryMessages - let allMessages = this.getMessages(tabId, maxConversationHistoryMessages) + let allMessages = this.getMessages(tabId) if (allMessages.length > 0) { - // 2. Fix history: Ensure messages in history is valid for server side checks + // 1. Fix history: Ensure messages in history is valid for server side checks this.ensureValidMessageSequence(tabId, allMessages) - // 3. Fix new user prompt: Ensure lastMessage in history toolUse and newMessage toolResult relationship is valid + // 2. Fix new user prompt: Ensure lastMessage in history toolUse and newMessage toolResult relationship is valid this.validateAndFixNewMessageToolResults(allMessages, newUserMessage) - // 4. NOTE: Keep this trimming logic at the end of the preprocess. - // Make sure max characters ≤ remaining Character Budget, must be put at the end of preprocessing - messagesWithCount = this.trimMessagesToMaxLength(allMessages, newUserInputCount, tabId, conversationId) + messagesWithCount = { + history: allMessages, + historyCount: this.calculateMessagesCharacterCount(allMessages), + currentCount: newUserInputCount, + } // Edge case: If the history is empty and the next message contains tool results, then we have to just abandon them. if ( @@ -772,74 +765,11 @@ export class ChatDatabase { return messagesWithCount } - /** - * Finds a suitable "break point" index in the message sequence. - * - * It ensures that the "break point" is at a clean conversation boundary where: - * 1. The message is from a user (type === 'prompt') - * 2. The message doesn't contain tool results that would break tool use/result pairs - * 3. The message has a non-empty body - * - * @param allMessages The array of conversation messages to search through - * @returns The index to trim from, or undefined if no suitable trimming point is found - */ - private findIndexToTrim(allMessages: Message[]): number | undefined { - for (let i = 2; i < allMessages.length; i++) { - const message = allMessages[i] - if (message.type === ('prompt' as ChatItemType) && this.isValidUserMessageWithoutToolResults(message)) { - return i - } - } - return undefined - } - private isValidUserMessageWithoutToolResults(message: Message): boolean { const ctx = message.userInputMessageContext return !!ctx && (!ctx.toolResults || ctx.toolResults.length === 0) && message.body !== '' } - private trimMessagesToMaxLength( - messages: Message[], - newUserInputCount: number, - tabId: string, - conversationId: string - ): MessagesWithCharacterCount { - let historyCharacterCount = this.calculateMessagesCharacterCount(messages) - const maxHistoryCharacterSize = Math.max(0, MaxOverallCharacters - newUserInputCount) - let trimmedHistory = false - this.#features.logging.debug( - `Current history character count: ${historyCharacterCount}, remaining history character budget: ${maxHistoryCharacterSize}` - ) - while (historyCharacterCount > maxHistoryCharacterSize && messages.length > 2) { - trimmedHistory = true - // Find the next valid user message to start from - const indexToTrim = this.findIndexToTrim(messages) - if (indexToTrim !== undefined && indexToTrim > 0) { - this.#features.logging.debug( - `Removing the first ${indexToTrim} elements in the history due to character count limit` - ) - messages.splice(0, indexToTrim) - } else { - this.#features.logging.debug( - 'Could not find a valid point to trim, reset history to reduce character count' - ) - this.replaceHistory(tabId, 'cwc', conversationId, []) - return { history: [], historyCount: 0, currentCount: newUserInputCount } - } - historyCharacterCount = this.calculateMessagesCharacterCount(messages) - this.#features.logging.debug(`History character count post trimming: ${historyCharacterCount}`) - } - - if (trimmedHistory) { - this.replaceHistory(tabId, 'cwc', conversationId, messages) - } - return { - history: messages, - historyCount: historyCharacterCount, - currentCount: newUserInputCount, - } - } - private calculateToolSpecCharacterCount(currentMessage: ChatMessage): number { let count = 0 if (currentMessage.userInputMessage?.userInputMessageContext?.tools) { From 961e6ca11b122481685f9f65b3da14c6a2497cc4 Mon Sep 17 00:00:00 2001 From: BlakeLazarine Date: Mon, 29 Sep 2025 13:21:54 -0700 Subject: [PATCH 111/158] fix(amazonq): send full finding details to plugin, partial to agent (#2356) * fix(amazonq): send full finding details to plugin, only send key fields to agent * fix(amazonq): add unit test --------- Co-authored-by: Blake Lazarine --- .../agenticChat/agenticChatController.ts | 36 +++++--- .../tools/qCodeAnalysis/codeReview.test.ts | 86 +++++++++++++++++++ .../tools/qCodeAnalysis/codeReview.ts | 23 ++++- .../qCodeAnalysis/codeReviewConstants.ts | 2 +- .../tools/qCodeAnalysis/codeReviewTypes.ts | 9 ++ 5 files changed, 137 insertions(+), 19 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 2f309981d0..c050cabfd1 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -2097,6 +2097,28 @@ export class AgenticChatController implements ChatHandlers { let toolResultContent: ToolResultContentBlock + if (toolUse.name === CodeReview.toolName) { + // no need to write tool result for code review, this is handled by model via chat + // Push result in message so that it is picked by IDE plugin to show in issues panel + const codeReviewResult = result as InvokeOutput + if ( + codeReviewResult?.output?.kind === 'json' && + codeReviewResult.output.success && + (codeReviewResult.output.content as any)?.findingsByFile + ) { + await chatResultStream.writeResultBlock({ + type: 'tool', + messageId: toolUse.toolUseId + CODE_REVIEW_FINDINGS_MESSAGE_SUFFIX, + body: (codeReviewResult.output.content as any).findingsByFile, + }) + codeReviewResult.output.content = { + codeReviewId: (codeReviewResult.output.content as any).codeReviewId, + message: (codeReviewResult.output.content as any).message, + findingsByFileSimplified: (codeReviewResult.output.content as any).findingsByFileSimplified, + } + } + } + if (typeof result === 'string') { toolResultContent = { text: result } } else if (Array.isArray(result)) { @@ -2182,20 +2204,6 @@ export class AgenticChatController implements ChatHandlers { await chatResultStream.writeResultBlock(chatResult) break case CodeReview.toolName: - // no need to write tool result for code review, this is handled by model via chat - // Push result in message so that it is picked by IDE plugin to show in issues panel - const codeReviewResult = result as InvokeOutput - if ( - codeReviewResult?.output?.kind === 'json' && - codeReviewResult.output.success && - (codeReviewResult.output.content as any)?.findingsByFile - ) { - await chatResultStream.writeResultBlock({ - type: 'tool', - messageId: toolUse.toolUseId + CODE_REVIEW_FINDINGS_MESSAGE_SUFFIX, - body: (codeReviewResult.output.content as any).findingsByFile, - }) - } break case DisplayFindings.toolName: // no need to write tool result for code review, this is handled by model via chat diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts index a6d346a469..4b53d3a71e 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts @@ -146,6 +146,92 @@ describe('CodeReview', () => { expect(result.output.kind).to.equal('json') }) + it('should return both full and simplified findings', async () => { + const mockFindings = [ + { + findingId: '1', + title: 'Test Issue', + description: { text: 'Test description', markdown: 'Test **description**' }, + startLine: 10, + endLine: 15, + severity: 'HIGH', + filePath: '/test/file.js', + detectorId: 'detector1', + detectorName: 'Test Detector', + ruleId: 'rule1', + relatedVulnerabilities: [], + recommendation: { text: 'Fix this', url: null }, + suggestedFixes: [], + comment: 'Test Issue: Test description', + scanJobId: 'job-123', + language: 'javascript', + autoDetected: false, + findingContext: 'Full', + }, + ] + + mockCodeWhispererClient.createUploadUrl.resolves({ + uploadUrl: 'https://upload.com', + uploadId: 'upload-123', + requestHeaders: {}, + }) + + mockCodeWhispererClient.startCodeAnalysis.resolves({ + jobId: 'job-123', + status: 'Pending', + }) + + mockCodeWhispererClient.getCodeAnalysis.resolves({ + status: 'Completed', + }) + + mockCodeWhispererClient.listCodeAnalysisFindings.resolves({ + codeAnalysisFindings: JSON.stringify(mockFindings), + nextToken: undefined, + }) + + sandbox.stub(CodeReviewUtils, 'uploadFileToPresignedUrl').resolves() + sandbox.stub(codeReview as any, 'prepareFilesAndFoldersForUpload').resolves({ + zipBuffer: Buffer.from('test'), + md5Hash: 'hash123', + isCodeDiffPresent: false, + programmingLanguages: new Set(['javascript']), + numberOfFilesInCustomerCodeZip: 1, + codeDiffFiles: new Set(), + filePathsInZip: new Set(['/test/file.js']), + }) + sandbox.stub(codeReview as any, 'parseFindings').returns(mockFindings) + sandbox.stub(codeReview as any, 'resolveFilePath').returns('/test/file.js') + + const result = await codeReview.execute(validInput, context) + + expect(result.output.success).to.be.true + expect(result.output.content).to.have.property('findingsByFile') + expect(result.output.content).to.have.property('findingsByFileSimplified') + + const fullFindings = JSON.parse((result.output.content as any).findingsByFile) + const simplifiedFindings = JSON.parse((result.output.content as any).findingsByFileSimplified) + + expect(fullFindings).to.have.length(1) + expect(simplifiedFindings).to.have.length(1) + + // Verify full findings structure + expect(fullFindings[0].issues[0]).to.have.property('findingId') + expect(fullFindings[0].issues[0]).to.have.property('description') + expect(fullFindings[0].issues[0]).to.have.property('detectorId') + + // Verify simplified findings structure (only 5 fields) + const simplifiedIssue = simplifiedFindings[0].issues[0] + expect(Object.keys(simplifiedIssue)).to.have.length(5) + expect(simplifiedIssue).to.have.property('filePath', '/test/file.js') + expect(simplifiedIssue).to.have.property('startLine', 10) + expect(simplifiedIssue).to.have.property('endLine', 15) + expect(simplifiedIssue).to.have.property('title', 'Test Issue') + expect(simplifiedIssue).to.have.property('severity', 'HIGH') + expect(simplifiedIssue).to.not.have.property('findingId') + expect(simplifiedIssue).to.not.have.property('description') + }) + it('should execute successfully and pass languageModelId and clientType to startCodeAnalysis', async () => { const inputWithModelId = { ...validInput, diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts index d15985c282..204bd31c42 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts @@ -29,6 +29,7 @@ import { CodeReviewFinding, FailedMetricName, SuccessMetricName, + CodeReviewFindingSimplified, } from './codeReviewTypes' import { CancellationError } from '@aws/lsp-core' import { Origin } from '@amzn/codewhisperer-streaming' @@ -44,7 +45,7 @@ export class CodeReview { private static readonly POLLING_INTERVAL_MS = 10000 // 10 seconds private static readonly UPLOAD_INTENT = 'AGENTIC_CODE_REVIEW' private static readonly SCAN_SCOPE = 'AGENTIC' - private static readonly MAX_FINDINGS_COUNT = 30 + private static readonly MAX_FINDINGS_COUNT = 300 private static readonly ERROR_MESSAGES = { MISSING_CLIENT: 'CodeWhisperer client not available', @@ -477,9 +478,18 @@ export class CodeReview { ) this.logging.info('Findings count grouped by file') + let aggregatedCodeScanIssueListSimplified: { filePath: string; issues: CodeReviewFindingSimplified[] }[] = [] aggregatedCodeScanIssueList.forEach(item => { this.logging.info(`File path - ${item.filePath} Findings count - ${item.issues.length}`) - item.issues.forEach(issue => + let simplifiedIssues: CodeReviewFindingSimplified[] = [] + item.issues.forEach(issue => { + simplifiedIssues.push({ + filePath: issue.filePath, + startLine: issue.startLine, + endLine: issue.endLine, + title: issue.title, + severity: issue.severity, + }) CodeReviewUtils.emitMetric( { reason: SuccessMetricName.IssuesDetected, @@ -496,7 +506,11 @@ export class CodeReview { this.logging, this.telemetry ) - ) + }) + aggregatedCodeScanIssueListSimplified.push({ + filePath: item.filePath, + issues: simplifiedIssues, + }) }) let scopeMessage = this.overrideDiffScan @@ -505,8 +519,9 @@ export class CodeReview { return { codeReviewId: jobId, - message: `${CODE_REVIEW_TOOL_NAME} tool completed successfully. ${scopeMessage} ${findingsExceededLimit ? ` Inform the user that we are limiting findings to top ${CodeReview.MAX_FINDINGS_COUNT} based on severity.` : ''}`, + message: `${CODE_REVIEW_TOOL_NAME} tool completed successfully. Please inform the user to use the explain and fix buttons in the Code Issues Panel to get the best information about particular findings. ${scopeMessage} ${findingsExceededLimit ? ` Inform the user that we are limiting findings to top ${CodeReview.MAX_FINDINGS_COUNT} based on severity.` : ''}`, findingsByFile: JSON.stringify(aggregatedCodeScanIssueList), + findingsByFileSimplified: JSON.stringify(aggregatedCodeScanIssueListSimplified), } } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts index cb458f20e3..442ac0f19a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewConstants.ts @@ -181,7 +181,7 @@ export const CODE_REVIEW_TOOL_DESCRIPTION = [ 'The tool will generate some findings grouped by file', 'Use following format STRICTLY to display the result of this tool for different scenarios:', '- When findings are present, you must inform user that you have completed the review of {file name / folder name / workspace} and found several issues that need attention. To inspect the details, and get fixes for those issues use the Code Issues panel.', - ' - When tool output message tells that findings were limited due to high count, you must inform the user that since there were lots of findings, you have included the top 30 findings only.', + ' - When tool output message tells that findings were limited due to high count, you must inform the user that since there were lots of findings, you have included the top 300 findings only.', '- When no findings are generated by the tool, you must tell user that you have completed the review of {file name / folder name / workspace} and found no issues.', ].join('\n') diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts index ea7aa33bf6..8f67ebab08 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts @@ -43,6 +43,7 @@ export type CodeReviewResult = { codeReviewId: string message: string findingsByFile: string + findingsByFileSimplified: string } export type CodeReviewFinding = { @@ -66,6 +67,14 @@ export type CodeReviewFinding = { findingContext: string | null | undefined } +export type CodeReviewFindingSimplified = { + filePath: string + startLine: number + endLine: number + title: string + severity: string +} + export type CodeReviewMetric = | { reason: SuccessMetricName From d8733a75487f74815302b838802eccbf3ffec55e Mon Sep 17 00:00:00 2001 From: chungjac Date: Mon, 29 Sep 2025 17:07:49 -0700 Subject: [PATCH 112/158] fix: trim new line when emitting error message (#2359) --- .../src/language-server/agenticChat/agenticChatController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index c050cabfd1..684de84c99 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -3473,7 +3473,7 @@ export class AgenticChatController implements ChatHandlers { metric: Metric, agenticCodingMode: boolean ): Promise> { - const errorMessage = getErrorMsg(err) ?? GENERIC_ERROR_MS + const errorMessage = (getErrorMsg(err) ?? GENERIC_ERROR_MS).replace(/[\r\n]+/g, ' ') // replace new lines with empty space const requestID = getRequestID(err) ?? '' metric.setDimension('cwsprChatResponseCode', getHttpStatusCode(err) ?? 0) metric.setDimension('languageServerVersion', this.#features.runtime.serverInfo.version) From d56bfa191954fac8068e2bf390c2d0b88ef8b168 Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 30 Sep 2025 09:50:15 -0700 Subject: [PATCH 113/158] fix: private package mapping during artifact generation (#2348) * fix: mapping of private packages to reference list * fix: relative path comparison to the lowercase on in artifact reference * fix: packages being filtered in the artifact generation --- .../netTransform/artifactManager.ts | 18 +--- ...nager.createRequirementJsonContent.test.ts | 24 ----- .../tests/artifactManager.general.test.ts | 4 - ...factManager.processPrivatePackages.test.ts | 101 ++++++++++-------- 4 files changed, 62 insertions(+), 85 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts index 2f3fe47373..7530dc647c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/artifactManager.ts @@ -26,10 +26,7 @@ const customTransformationFolderName = 'customTransformation' const filteredExtensions = ['.suo', '.meta', '.user', '.obj', '.tmp', '.log', '.dbmdl', '.jfm', '.pdb'] const filteredDirectories = ['.git', 'bin', 'obj', '.idea', '.vs', 'artifactworkspace', 'node_modules', 'nuget.config'] const failedCopies: string[] = [] -const filteredPathRegex: RegExp[] = [ - /\\users\\[^\\]+\\appdata/i, // IgnoreCase flag with 'i' - /.+\.(vspscc|vssscc)$/, -] +const filteredPathRegex: RegExp[] = [/.+\.(vspscc|vssscc)$/] export class ArtifactManager { private workspace: Workspace @@ -210,7 +207,7 @@ export class ArtifactManager { relativePath: relativePath, isThirdPartyPackage: false, } - await this.processPrivatePackages(request, reference, artifactReference) + await this.processPrivatePackages(request, artifactReference) references.push(artifactReference) } catch (error) { this.logging.log('Failed to process file: ' + error + reference.AssemblyFullPath) @@ -230,8 +227,6 @@ export class ArtifactManager { for (const pkg of request.PackageReferences) { if (!pkg.NetCompatiblePackageFilePath) { continue - } else if (this.shouldFilterFile(pkg.NetCompatiblePackageFilePath)) { - continue } try { const packageRelativePath = this.normalizePackageFileRelativePath(pkg.NetCompatiblePackageFilePath) @@ -261,16 +256,13 @@ export class ArtifactManager { } as RequirementJson } - async processPrivatePackages( - request: StartTransformRequest, - reference: ExternalReference, - artifactReference: References - ): Promise { + async processPrivatePackages(request: StartTransformRequest, artifactReference: References): Promise { if (!request.PackageReferences) { return } var thirdPartyPackage = request.PackageReferences.find( - p => p.IsPrivatePackage && reference.RelativePath.includes(p.Id) + // should be toLower because we to lower case the reference paths + p => p.IsPrivatePackage && artifactReference.relativePath.includes(p.Id.concat('.dll').toLowerCase()) ) if (thirdPartyPackage) { artifactReference.isThirdPartyPackage = true diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.createRequirementJsonContent.test.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.createRequirementJsonContent.test.ts index 4bf5a31f29..fba0da6729 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.createRequirementJsonContent.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.createRequirementJsonContent.test.ts @@ -158,30 +158,6 @@ describe('ArtifactManager - createRequirementJsonContent', () => { // Should only include .dll reference, not .pdb expect(result.Projects[0].references).to.have.length(1) }) - - it('should filter package references with filtered extensions', async () => { - const request = setupRequest({ - PackageReferences: [ - { - Id: 'ValidPackage', - Versions: ['1.0.0'], - IsPrivatePackage: false, - NetCompatiblePackageFilePath: path.join('C:', 'packages', 'valid.nupkg'), - }, - { - Id: 'FilteredPackage', - Versions: ['1.0.0'], - IsPrivatePackage: false, - NetCompatiblePackageFilePath: path.join('C:', 'packages', 'filtered.pdb'), // Should be filtered - }, - ], - }) - - const result = await artifactManager.createRequirementJsonContent(request) - - // Should only include valid package, not filtered one - expect((result as any).Packages).to.have.length(1) - }) }) describe('Error handling', () => { diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.general.test.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.general.test.ts index 7a5299a620..1982259594 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.general.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.general.test.ts @@ -268,15 +268,11 @@ describe('ArtifactManager - Complete Coverage', () => { it('should filter regex', async () => { const unfilteredString = '\\users\\test\\dataApp\\test.cs' const unfilteredStringWithExtraDir = '\\users\\extraDir\\test\\appData\\test.cs' - const filteredString = '\\users\\test\\appdata\\test.cs' - const filteredStringWithCasing = '\\USERS\\test\\APPdata\\test.cs' const filteredExtension = '\\users\\test\\project.vspscc' const filteredExtensionTwo = '\\users\\test\\project.vssscc' expect(artifactManager.shouldFilterFile(unfilteredString)).to.be.false expect(artifactManager.shouldFilterFile(unfilteredStringWithExtraDir)).to.be.false - expect(artifactManager.shouldFilterFile(filteredString)).to.be.true - expect(artifactManager.shouldFilterFile(filteredStringWithCasing)).to.be.true expect(artifactManager.shouldFilterFile(filteredExtension)).to.be.true expect(artifactManager.shouldFilterFile(filteredExtensionTwo)).to.be.true }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.processPrivatePackages.test.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.processPrivatePackages.test.ts index 848744504e..130da1da70 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.processPrivatePackages.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/artifactManager.processPrivatePackages.test.ts @@ -10,7 +10,6 @@ describe('ArtifactManager - processPrivatePackages', () => { let workspace: StubbedInstance let artifactManager: ArtifactManager let sampleStartTransformRequest: StartTransformRequest - let sampleExternalReference: ExternalReference let sampleArtifactReference: References const mockedLogging = stubInterface() @@ -30,12 +29,6 @@ describe('ArtifactManager - processPrivatePackages', () => { // Setup initial test data sampleStartTransformRequest = EXAMPLE_REQUEST - sampleExternalReference = { - ProjectPath: '', - RelativePath: '', - AssemblyFullPath: '', - IncludedInArtifact: true, - } sampleArtifactReference = { includedInArtifact: true, relativePath: '', @@ -45,11 +38,7 @@ describe('ArtifactManager - processPrivatePackages', () => { it('should do nothing when PackageReferences is undefined', async () => { sampleStartTransformRequest.PackageReferences = undefined - artifactManager.processPrivatePackages( - sampleStartTransformRequest, - sampleExternalReference, - sampleArtifactReference - ) + artifactManager.processPrivatePackages(sampleStartTransformRequest, sampleArtifactReference) expect(sampleArtifactReference.isThirdPartyPackage).to.equal(false) expect(sampleArtifactReference.netCompatibleRelativePath).to.equal(undefined) expect(sampleArtifactReference.netCompatibleVersion).to.equal(undefined) @@ -66,24 +55,20 @@ describe('ArtifactManager - processPrivatePackages', () => { Id: 'test-package', Versions: [], IsPrivatePackage: true, - NetCompatibleAssemblyRelativePath: 'path/to/assembly', - NetCompatibleAssemblyPath: 'full/path/to/assembly', + NetCompatibleAssemblyRelativePath: 'path/to/test-package.dll', + NetCompatibleAssemblyPath: 'full/path/to/test-package.dll', NetCompatiblePackageVersion: '2.0.0', } sampleStartTransformRequest.PackageReferences = [privatePackage] - sampleExternalReference.RelativePath = 'some/path/test-package/more/path' + sampleArtifactReference.relativePath = 'some/path/test-package/more/path/test-package.dll' - await artifactManager.processPrivatePackages( - sampleStartTransformRequest, - sampleExternalReference, - sampleArtifactReference - ) + await artifactManager.processPrivatePackages(sampleStartTransformRequest, sampleArtifactReference) expect(copyFileCalled).to.be.true expect(sampleArtifactReference.isThirdPartyPackage).to.equal(true) expect(sampleArtifactReference.netCompatibleRelativePath).to.equal( - path.join('references', 'thirdpartypackages', 'path/to/assembly').toLowerCase() + path.join('references', 'thirdpartypackages', 'path/to/test-package.dll').toLowerCase() ) expect(sampleArtifactReference.netCompatibleVersion).to.equal('2.0.0') }) @@ -98,20 +83,16 @@ describe('ArtifactManager - processPrivatePackages', () => { const nonPrivatePackage = { Id: 'test-package', IsPrivatePackage: false, - NetCompatibleAssemblyRelativePath: 'path/to/assembly', - NetCompatibleAssemblyPath: 'full/path/to/assembly', + NetCompatibleAssemblyRelativePath: 'path/to/test-package.dll', + NetCompatibleAssemblyPath: 'full/path/to/test-package.dll', NetCompatiblePackageVersion: '1.0.0', Versions: [], } sampleStartTransformRequest.PackageReferences = [nonPrivatePackage] - sampleExternalReference.RelativePath = 'some/path/test-package/more/path' + sampleArtifactReference.relativePath = 'some/path/test-package/more/path/test-package.dll' - artifactManager.processPrivatePackages( - sampleStartTransformRequest, - sampleExternalReference, - sampleArtifactReference - ) + artifactManager.processPrivatePackages(sampleStartTransformRequest, sampleArtifactReference) expect(copyFileCalled).to.be.false expect(sampleArtifactReference.isThirdPartyPackage).to.equal(false) @@ -119,7 +100,7 @@ describe('ArtifactManager - processPrivatePackages', () => { expect(sampleArtifactReference.netCompatibleVersion).to.equal(undefined) }) - it('should not process when package ID is not in reference path', async () => { + it('should not process when assembly is not in reference path', async () => { let copyFileCalled = false artifactManager.copyFile = async (source: string, destination: string): Promise => { copyFileCalled = true @@ -129,20 +110,16 @@ describe('ArtifactManager - processPrivatePackages', () => { const privatePackage = { Id: 'test-package', IsPrivatePackage: true, - NetCompatibleAssemblyRelativePath: 'path/to/assembly', - NetCompatibleAssemblyPath: 'full/path/to/assembly', + NetCompatibleAssemblyRelativePath: 'path/to/test-package.dll', + NetCompatibleAssemblyPath: 'full/path/to/test-package.dll', NetCompatiblePackageVersion: '1.0.0', Versions: [], } sampleStartTransformRequest.PackageReferences = [privatePackage] - sampleExternalReference.RelativePath = 'some/path/different-package/more/path' + sampleArtifactReference.relativePath = 'some/path/different-package/more/path/test-package2.dll' - artifactManager.processPrivatePackages( - sampleStartTransformRequest, - sampleExternalReference, - sampleArtifactReference - ) + artifactManager.processPrivatePackages(sampleStartTransformRequest, sampleArtifactReference) expect(copyFileCalled).to.be.false expect(sampleArtifactReference.isThirdPartyPackage).to.equal(false) @@ -150,6 +127,46 @@ describe('ArtifactManager - processPrivatePackages', () => { expect(sampleArtifactReference.netCompatibleVersion).to.equal(undefined) }) + it('should handle multiple packages with same substring', async () => { + const privatePackage1: PackageReferenceMetadata = { + Id: 'PNMAC.Core', + Versions: ['2.27.0', '2.30.0'], + IsPrivatePackage: true, + NetCompatibleAssemblyRelativePath: 'PNMAC.Core/lib/net8.0/PNMAC.Core.dll', + NetCompatibleAssemblyPath: + 'C:/Users/user/AppData/Local/Temp/AwsToolkit/Transforms/Packages/PNMAC.Core/lib/net8.0/PNMAC.Core.dll', + NetCompatiblePackageVersion: '5.4.1', + } + + const privatePackage2: PackageReferenceMetadata = { + Id: 'PNMAC.Core.EntityService', + Versions: ['2.2.0'], + IsPrivatePackage: true, + NetCompatibleAssemblyRelativePath: 'PNMAC.Core.EntityService/lib/net8.0/PNMAC.Core.EntityService.dll', + NetCompatibleAssemblyPath: + 'C:/Users/user/AppData/Local/Temp/AwsToolkit/Transforms/Packages/PNMAC.Core.EntityService/lib/net8.0/PNMAC.Core.EntityService.dll', + NetCompatiblePackageVersion: '4.1.0.4', + } + + sampleStartTransformRequest.PackageReferences = [privatePackage1, privatePackage2] + sampleArtifactReference.relativePath = + 'references/packages/pnmac.core.entityservice.2.2.0/lib/pnmac.core.entityservice.dll' + + await artifactManager.processPrivatePackages(sampleStartTransformRequest, sampleArtifactReference) + + expect(sampleArtifactReference.isThirdPartyPackage).to.equal(true) + expect(sampleArtifactReference.packageId).to.equal('PNMAC.Core.EntityService') + expect(sampleArtifactReference.netCompatibleVersion).to.equal('4.1.0.4') + + sampleArtifactReference.relativePath = 'references/packages/pnmac.core.2.30.0/lib/pnmac.core.dll' + + await artifactManager.processPrivatePackages(sampleStartTransformRequest, sampleArtifactReference) + + expect(sampleArtifactReference.isThirdPartyPackage).to.equal(true) + expect(sampleArtifactReference.packageId).to.equal('PNMAC.Core') + expect(sampleArtifactReference.netCompatibleVersion).to.equal('5.4.1') + }) + it('should mark as third party package but not copy when paths are null', async () => { let copyFileCalled = false artifactManager.copyFile = async (source: string, destination: string): Promise => { @@ -167,13 +184,9 @@ describe('ArtifactManager - processPrivatePackages', () => { } sampleStartTransformRequest.PackageReferences = [privatePackage] - sampleExternalReference.RelativePath = 'some/path/test-package/more/path' + sampleArtifactReference.relativePath = 'some/path/test-package/more/test-package.dll' - await artifactManager.processPrivatePackages( - sampleStartTransformRequest, - sampleExternalReference, - sampleArtifactReference - ) + await artifactManager.processPrivatePackages(sampleStartTransformRequest, sampleArtifactReference) expect(copyFileCalled).to.be.false expect(sampleArtifactReference.isThirdPartyPackage).to.equal(true) From 45b86bef1a93cf9ced6fbf0c222cf5410de04c81 Mon Sep 17 00:00:00 2001 From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> Date: Tue, 30 Sep 2025 11:08:45 -0700 Subject: [PATCH 114/158] fix(amazonq): escaping user input to mitigate xss issue (#2360) * fix(amazonq): escaping user input to mitigate xss issue * fix: adding conditional check for applying sanitizeinput --- package-lock.json | 1 - server/aws-lsp-codewhisperer/package.json | 3 +-- .../language-server/agenticChat/agenticChatController.ts | 5 ++--- .../src/language-server/agenticChat/tools/chatDb/chatDb.ts | 2 -- .../src/language-server/agenticChat/tools/chatDb/util.ts | 3 +-- server/aws-lsp-codewhisperer/src/shared/utils.ts | 7 +++++-- server/aws-lsp-codewhisperer/src/types/unescape.d.ts | 4 ---- 7 files changed, 9 insertions(+), 16 deletions(-) delete mode 100644 server/aws-lsp-codewhisperer/src/types/unescape.d.ts diff --git a/package-lock.json b/package-lock.json index 7bec6ab90e..ddb4074b11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28717,7 +28717,6 @@ "picomatch": "^4.0.2", "shlex": "2.1.2", "typescript-collections": "^1.3.3", - "unescape-html": "^1.1.0", "uuid": "^11.0.5", "vscode-uri": "^3.1.0", "ws": "^8.18.0", diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index ae2e55b2db..0f5e7d0ff1 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -67,8 +67,7 @@ "vscode-uri": "^3.1.0", "ws": "^8.18.0", "xml2js": "^0.6.2", - "xmlbuilder2": "^3.1.1", - "unescape-html": "^1.1.0" + "xmlbuilder2": "^3.1.1" }, "devDependencies": { "@types/adm-zip": "^0.5.5", diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 684de84c99..3dc5671992 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -231,7 +231,6 @@ import { CodeWhispererServiceToken } from '../../shared/codeWhispererService' import { DisplayFindings } from './tools/qCodeAnalysis/displayFindings' import { IDE } from '../../shared/constants' import { IdleWorkspaceManager } from '../workspaceContext/IdleWorkspaceManager' -import escapeHTML = require('escape-html') import { SemanticSearch } from './tools/workspaceContext/semanticSearch' import { MemoryBankController } from './context/memorybank/memoryBankController' @@ -834,7 +833,7 @@ export class AgenticChatController implements ChatHandlers { async onChatPrompt(params: ChatParams, token: CancellationToken): Promise> { // Phase 1: Initial Setup - This happens only once - params.prompt.prompt = sanitizeInput(params.prompt.prompt || '') + params.prompt.prompt = sanitizeInput(params.prompt.prompt || '', true) IdleWorkspaceManager.recordActivityTimestamp() @@ -1451,7 +1450,7 @@ export class AgenticChatController implements ChatHandlers { this.#debug('Skipping adding user message to history - cancelled by user') } else { this.#chatHistoryDb.addMessage(tabId, 'cwc', conversationIdentifier, { - body: escapeHTML(currentMessage.userInputMessage?.content ?? ''), + body: currentMessage.userInputMessage?.content ?? '', type: 'prompt' as any, userIntent: currentMessage.userInputMessage?.userIntent, origin: currentMessage.userInputMessage?.origin, diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts index e038c37228..2282046243 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts @@ -35,7 +35,6 @@ import { ChatItemType } from '@aws/mynah-ui' import { getUserHomeDir } from '@aws/lsp-core/out/util/path' import { ChatHistoryMaintainer } from './chatHistoryMaintainer' import { existsSync, renameSync } from 'fs' -import escapeHTML = require('escape-html') export class ToolResultValidationError extends Error { constructor(message?: string) { @@ -689,7 +688,6 @@ export class ChatDatabase { } return { ...message, - body: escapeHTML(message.body), userInputMessageContext: { // keep falcon context when inputMessage is not a toolResult message editorState: hasToolResults ? undefined : message.userInputMessageContext?.editorState, diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/util.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/util.ts index e03c90bead..77496cd96b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/util.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/util.ts @@ -28,7 +28,6 @@ import { activeFileCmd } from '../../context/additionalContextProvider' import { PriorityQueue } from 'typescript-collections' import { Features } from '@aws/language-server-runtimes/server-interface/server' import * as crypto from 'crypto' -import unescapeHTML = require('unescape-html') // Ported from https://github.com/aws/aws-toolkit-vscode/blob/master/packages/core/src/shared/db/chatDb/util.ts @@ -173,7 +172,7 @@ export function messageToStreamingMessage(msg: Message): StreamingMessage { export function messageToChatMessage(msg: Message): ChatMessage[] { const chatMessages: ChatMessage[] = [ { - body: unescapeHTML(msg.body), + body: msg.body, type: msg.type, codeReference: msg.codeReference, relatedContent: diff --git a/server/aws-lsp-codewhisperer/src/shared/utils.ts b/server/aws-lsp-codewhisperer/src/shared/utils.ts index 9169be165f..3602153ad6 100644 --- a/server/aws-lsp-codewhisperer/src/shared/utils.ts +++ b/server/aws-lsp-codewhisperer/src/shared/utils.ts @@ -29,9 +29,9 @@ import { ServiceException } from '@smithy/smithy-client' import { promises as fs } from 'fs' import * as fg from 'fast-glob' import { getAuthFollowUpType } from '../language-server/chat/utils' -import ignore = require('ignore') import { InitializeParams } from '@aws/language-server-runtimes/server-interface' import { QClientCapabilities } from '../language-server/configuration/qConfigurationServer' +import escapeHTML = require('escape-html') export function isAwsError(error: unknown): error is AWSError { if (error === undefined) { @@ -610,10 +610,13 @@ export function getFileExtensionName(filepath: string): string { * @param input The input string to sanitize * @returns The sanitized string with dangerous characters removed */ -export function sanitizeInput(input: string): string { +export function sanitizeInput(input: string, enableEscapingHTML: boolean = false): string { if (!input) { return input } + if (enableEscapingHTML) { + input = escapeHTML(input) + } // Remove Unicode tag characters (U+E0000-U+E007F) used in ASCII smuggling // Remove other invisible/control characters that could hide content diff --git a/server/aws-lsp-codewhisperer/src/types/unescape.d.ts b/server/aws-lsp-codewhisperer/src/types/unescape.d.ts deleted file mode 100644 index 1fe801704e..0000000000 --- a/server/aws-lsp-codewhisperer/src/types/unescape.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module 'unescape-html' { - function unescapeHTML(str: string): string - export = unescapeHTML -} From 1d9afd410e19624223e300ca06ea7d08a112cc82 Mon Sep 17 00:00:00 2001 From: Aseem sharma <198968351+aseemxs@users.noreply.github.com> Date: Tue, 30 Sep 2025 11:19:36 -0700 Subject: [PATCH 115/158] fix(amazonq): Fix mock fs clean; Node version upgrade (#2324) * fix: update the node version to 24 * Fix mock-fs Windows compatibility by using relative cache paths * style: fix code formatting for mock-fs test files * fix: use fake timers in chat-client tests for Node.js 24 compatibility Node.js 24 has stricter timer handling that caused setTimeout calls in production code to hang tests. Using fake timers ensures proper test isolation and prevents timeouts. * style: fix prettier formatting for chat-client test * fix: stub handleChatPrompt in mynahUi test to prevent timeout * fix: update test assertion to match stubbed behavior * fix: use proper module reference for handleChatPrompt stub * fix: make test async and wait for setTimeout calls to complete * fix: stub setTimeout to execute immediately and increase test timeout * fix: add setTimeout stubs to all sendGenericCommand tests --------- Co-authored-by: laileni --- .github/workflows/create-agent-standalone.yml | 2 +- .../create-agentic-github-prerelease.yml | 2 +- .../create-release-candidate-branch.yml | 2 +- .github/workflows/integration-tests.yml | 2 +- .github/workflows/lsp-ci.yaml | 8 ++--- .github/workflows/npm-packaging.yaml | 2 +- .github/workflows/release-please.yaml | 2 +- chat-client/src/client/mynahUi.test.ts | 33 ++++++++++++++++--- .../content/cache/uriCacheRepository.test.ts | 8 ++--- .../handlers/cachedContentHandler.test.ts | 4 +-- 10 files changed, 45 insertions(+), 20 deletions(-) diff --git a/.github/workflows/create-agent-standalone.yml b/.github/workflows/create-agent-standalone.yml index afde98b14a..12a8fdfb12 100644 --- a/.github/workflows/create-agent-standalone.yml +++ b/.github/workflows/create-agent-standalone.yml @@ -19,7 +19,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '24' cache: 'npm' - name: Install dependencies diff --git a/.github/workflows/create-agentic-github-prerelease.yml b/.github/workflows/create-agentic-github-prerelease.yml index e5f98178dc..48873b7503 100644 --- a/.github/workflows/create-agentic-github-prerelease.yml +++ b/.github/workflows/create-agentic-github-prerelease.yml @@ -101,7 +101,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '24' cache: 'npm' # To run a ts script to create the manifest diff --git a/.github/workflows/create-release-candidate-branch.yml b/.github/workflows/create-release-candidate-branch.yml index b447f11803..7c6b449a94 100644 --- a/.github/workflows/create-release-candidate-branch.yml +++ b/.github/workflows/create-release-candidate-branch.yml @@ -42,7 +42,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '24' cache: 'npm' # Needed to format the json file being checked in diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 3226ca9fde..48da971401 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -37,7 +37,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 24 - name: Download build artifacts uses: actions/download-artifact@v4 with: diff --git a/.github/workflows/lsp-ci.yaml b/.github/workflows/lsp-ci.yaml index 15f87d2428..814c198f05 100644 --- a/.github/workflows/lsp-ci.yaml +++ b/.github/workflows/lsp-ci.yaml @@ -15,7 +15,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 24 - name: Build run: | npm ci @@ -38,7 +38,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 24 - name: Build run: | npm ci @@ -63,7 +63,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 24 - name: Build run: | npm ci @@ -79,7 +79,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 24 - name: Build run: | npm ci diff --git a/.github/workflows/npm-packaging.yaml b/.github/workflows/npm-packaging.yaml index d4ce77e07c..4b509d9294 100644 --- a/.github/workflows/npm-packaging.yaml +++ b/.github/workflows/npm-packaging.yaml @@ -15,7 +15,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 24 - name: Install dependencies run: npm ci - name: Build all monorepo packages diff --git a/.github/workflows/release-please.yaml b/.github/workflows/release-please.yaml index a8574c045c..e35abe9de0 100644 --- a/.github/workflows/release-please.yaml +++ b/.github/workflows/release-please.yaml @@ -50,7 +50,7 @@ jobs: - name: Setup Nodejs uses: actions/setup-node@v4 with: - node-version: '20.x' + node-version: '24.x' registry-url: 'https://registry.npmjs.org' scope: '@aws' if: ${{ fromJson(steps.release.outputs.releases_created) }} diff --git a/chat-client/src/client/mynahUi.test.ts b/chat-client/src/client/mynahUi.test.ts index 727805ebbc..8524ab7713 100644 --- a/chat-client/src/client/mynahUi.test.ts +++ b/chat-client/src/client/mynahUi.test.ts @@ -246,9 +246,16 @@ describe('MynahUI', () => { }) describe('sendGenericCommand', () => { - it('should create a new tab if none exits', () => { + it('should create a new tab if none exits', function () { + this.timeout(10000) // Increase timeout to 10 seconds // clear create tab stub since set up process calls it twice createTabStub.resetHistory() + // Stub setTimeout to execute immediately + const setTimeoutStub = sinon.stub(global, 'setTimeout').callsFake((fn: Function) => { + fn() + return {} as any + }) + const genericCommand = 'Explain' const selection = 'const x = 5;' const tabId = '' @@ -258,12 +265,18 @@ describe('MynahUI', () => { sinon.assert.calledOnceWithExactly(createTabStub, false) sinon.assert.calledThrice(updateStoreSpy) + setTimeoutStub.restore() }) - it('should create a new tab if current tab is loading', function (done) { - this.timeout(8000) + it('should create a new tab if current tab is loading', function () { + this.timeout(10000) // clear create tab stub since set up process calls it twice createTabStub.resetHistory() + // Stub setTimeout to execute immediately + const setTimeoutStub = sinon.stub(global, 'setTimeout').callsFake((fn: Function) => { + fn() + return {} as any + }) getAllTabsStub.returns({ 'tab-1': { store: { loadingChat: true } } }) const genericCommand = 'Explain' @@ -275,11 +288,16 @@ describe('MynahUI', () => { sinon.assert.calledOnceWithExactly(createTabStub, false) sinon.assert.calledThrice(updateStoreSpy) - done() + setTimeoutStub.restore() }) it('should not create a new tab if one exists already', () => { createTabStub.resetHistory() + // Stub setTimeout to execute immediately + const setTimeoutStub = sinon.stub(global, 'setTimeout').callsFake((fn: Function) => { + fn() + return {} as any + }) const genericCommand = 'Explain' const selection = 'const x = 5;' const tabId = 'tab-1' @@ -289,9 +307,15 @@ describe('MynahUI', () => { sinon.assert.notCalled(createTabStub) sinon.assert.calledOnce(updateStoreSpy) + setTimeoutStub.restore() }) it('should call handleChatPrompt when sendGenericCommand is called', () => { + // Stub setTimeout to execute immediately + const setTimeoutStub = sinon.stub(global, 'setTimeout').callsFake((fn: Function) => { + fn() + return {} as any + }) const genericCommand = 'Explain' const selection = 'const x = 5;' const tabId = 'tab-1' @@ -321,6 +345,7 @@ describe('MynahUI', () => { loadingChat: true, promptInputDisabledState: false, }) + setTimeoutStub.restore() }) }) diff --git a/core/aws-lsp-core/src/content/cache/uriCacheRepository.test.ts b/core/aws-lsp-core/src/content/cache/uriCacheRepository.test.ts index 695a49995c..8487e886bd 100644 --- a/core/aws-lsp-core/src/content/cache/uriCacheRepository.test.ts +++ b/core/aws-lsp-core/src/content/cache/uriCacheRepository.test.ts @@ -12,7 +12,7 @@ import path = require('path') describe('Test UriCacheRepository', async () => { const sampleUri = URI.parse('https://aws.amazon.com/') const currentTimeMs = 1234 - const metadataPath = '//cache/cachedUris/metadata' + const metadataPath = 'cache/cachedUris/metadata' let timeProviderStub: SinonStubbedInstance @@ -20,7 +20,7 @@ describe('Test UriCacheRepository', async () => { beforeEach(async () => { mockfs({ - '//cache': { + cache: { cachedUris: { metadata: '{}', }, @@ -30,7 +30,7 @@ describe('Test UriCacheRepository', async () => { timeProviderStub = stub(new TimeProvider()) timeProviderStub.currentMilliseconds.returns(currentTimeMs) - sut = new UriCacheRepository('//cache', timeProviderStub) + sut = new UriCacheRepository('cache', timeProviderStub) }) afterEach(async () => { @@ -89,7 +89,7 @@ describe('Test UriCacheRepository', async () => { }) function getCachePath(uri: URI): string { - return path.join('//cache/cachedUris', getHash(uri)) + return path.join('cache/cachedUris', getHash(uri)) } function getHash(uri: URI): string { diff --git a/core/aws-lsp-core/src/content/handlers/cachedContentHandler.test.ts b/core/aws-lsp-core/src/content/handlers/cachedContentHandler.test.ts index ade872313f..aaf316c6d6 100644 --- a/core/aws-lsp-core/src/content/handlers/cachedContentHandler.test.ts +++ b/core/aws-lsp-core/src/content/handlers/cachedContentHandler.test.ts @@ -43,7 +43,7 @@ describe('Test CachedContentHandler', async () => { beforeEach(async () => { mockfs({ - '//cache': { + cache: { cachedUris: { metadata: '{}', }, @@ -54,7 +54,7 @@ describe('Test CachedContentHandler', async () => { timeProviderStub = stub(new TimeProvider()) timeProviderStub.currentMilliseconds.returns(currentTimeMs) - cacheRepository = new UriCacheRepository('//cache', timeProviderStub) + cacheRepository = new UriCacheRepository('cache', timeProviderStub) sut = new CachedContentHandler({ cacheRepository, timeProvider: timeProviderStub, From 692e77bc99770ac7d676928e95e3dc43bb91e7f0 Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Tue, 30 Sep 2025 16:12:46 -0700 Subject: [PATCH 116/158] fix(amazonq): fix to add opt-out header to streaming client (#2365) --- .../chat/chatSessionService.ts | 1 - .../AmazonQIAMServiceManager.ts | 3 + .../AmazonQTokenServiceManager.ts | 3 + .../BaseAmazonQServiceManager.ts | 11 ++ .../src/shared/streamingClientService.test.ts | 104 ++++++++++++++++++ .../src/shared/streamingClientService.ts | 23 +++- 6 files changed, 142 insertions(+), 3 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts index 13c198a949..770de98340 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts @@ -38,7 +38,6 @@ type DeferredHandler = { reject: (err: Error) => void } export class ChatSessionService { - public shareCodeWhispererContentWithAWS = false public pairProgrammingMode: boolean = true public contextListSent: boolean = false public modelId: string | undefined diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts index a29b65468f..bf27a599a2 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts @@ -74,6 +74,9 @@ export class AmazonQIAMServiceManager extends BaseAmazonQServiceManager< this.region, this.endpoint ) + this.cachedStreamingClient.shareCodeWhispererContentWithAWS = this.configurationCache.getProperty( + 'shareCodeWhispererContentWithAWS' + ) } return this.cachedStreamingClient } diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts index 77fd162d5d..5cd43f3cc7 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts @@ -584,6 +584,9 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< this.getCustomUserAgent() ) streamingClient.profileArn = this.activeIdcProfile?.arn + streamingClient.shareCodeWhispererContentWithAWS = this.configurationCache.getProperty( + 'shareCodeWhispererContentWithAWS' + ) this.logging.debug(`Created streaming client instance region=${region}, endpoint=${endpoint}`) return streamingClient diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts index cc21cd8766..1cd4f254be 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts @@ -157,6 +157,17 @@ export abstract class BaseAmazonQServiceManager< ) this.cachedCodewhispererService.shareCodeWhispererContentWithAWS = shareCodeWhispererContentWithAWS } + + if (this.cachedStreamingClient) { + const shareCodeWhispererContentWithAWS = this.configurationCache.getProperty( + 'shareCodeWhispererContentWithAWS' + ) + this.logging.debug( + 'Update shareCodeWhispererContentWithAWS setting on cachedStreamingClient to ' + + shareCodeWhispererContentWithAWS + ) + this.cachedStreamingClient.shareCodeWhispererContentWithAWS = shareCodeWhispererContentWithAWS + } } private async notifyDidChangeConfigurationListeners(): Promise { diff --git a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts index b12f1633df..5b1f08d851 100644 --- a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts @@ -12,6 +12,8 @@ import { } from '@amzn/codewhisperer-streaming' import { QDeveloperStreaming } from '@amzn/amazon-q-developer-streaming-client' import { rejects } from 'assert' +import { initBaseTestServiceManager, TestAmazonQServiceManager } from './amazonQServiceManager/testUtils' +import { stubCodeWhispererService } from './testUtils' const TIME_TO_ADVANCE_MS = 100 @@ -113,6 +115,33 @@ describe('StreamingClientServiceToken', () => { sinon.assert.match(sendMessageStub.firstCall.firstArg, expectedRequest) }) + it('creates client with shareCodeWhispererContentWithAWS parameter', () => { + const streamingClientServiceWithOptout = new StreamingClientServiceToken( + features.credentialsProvider, + features.sdkInitializator, + features.logging, + DEFAULT_AWS_Q_REGION, + DEFAULT_AWS_Q_ENDPOINT_URL, + 'some-user-agent' + ) + streamingClientServiceWithOptout.shareCodeWhispererContentWithAWS = false + + expect(streamingClientServiceWithOptout['shareCodeWhispererContentWithAWS']).to.equal(false) + }) + + it('creates client without shareCodeWhispererContentWithAWS parameter', () => { + const streamingClientServiceDefault = new StreamingClientServiceToken( + features.credentialsProvider, + features.sdkInitializator, + features.logging, + DEFAULT_AWS_Q_REGION, + DEFAULT_AWS_Q_ENDPOINT_URL, + 'some-user-agent' + ) + + expect(streamingClientServiceDefault['shareCodeWhispererContentWithAWS']).to.be.undefined + }) + describe('generateAssistantResponse', () => { const MOCKED_GENERATE_RESPONSE_REQUEST = { conversationState: { @@ -318,4 +347,79 @@ describe('StreamingClientServiceIAM', () => { expect(credentials.expiration).to.be.instanceOf(Date) expect(credentials.expiration.getTime()).to.be.closeTo(Date.now(), 1000) }) + + it('creates client with shareCodeWhispererContentWithAWS parameter', () => { + const streamingClientServiceWithOptout = new StreamingClientServiceIAM( + features.credentialsProvider, + features.sdkInitializator, + features.logging, + DEFAULT_AWS_Q_REGION, + DEFAULT_AWS_Q_ENDPOINT_URL + ) + streamingClientServiceWithOptout.shareCodeWhispererContentWithAWS = false + + expect(streamingClientServiceWithOptout['shareCodeWhispererContentWithAWS']).to.equal(false) + }) + + it('creates client without shareCodeWhispererContentWithAWS parameter', () => { + const streamingClientServiceDefault = new StreamingClientServiceIAM( + features.credentialsProvider, + features.sdkInitializator, + features.logging, + DEFAULT_AWS_Q_REGION, + DEFAULT_AWS_Q_ENDPOINT_URL + ) + + expect(streamingClientServiceDefault['shareCodeWhispererContentWithAWS']).to.be.undefined + }) +}) + +describe('BaseAmazonQServiceManager streaming client cache updates', () => { + let features: TestFeatures + let serviceManager: TestAmazonQServiceManager + let streamingClientMock: StreamingClientServiceToken + + beforeEach(() => { + features = new TestFeatures() + const serviceStub = stubCodeWhispererService() + + streamingClientMock = Object.assign(sinon.createStubInstance(StreamingClientServiceToken), { + region: DEFAULT_AWS_Q_REGION, + endpoint: DEFAULT_AWS_Q_ENDPOINT_URL, + }) as unknown as StreamingClientServiceToken + serviceManager = initBaseTestServiceManager(features, serviceStub, streamingClientMock) + }) + + afterEach(() => { + sinon.restore() + TestAmazonQServiceManager.resetInstance() + }) + + it('updates shareCodeWhispererContentWithAWS on cached streaming client when configuration changes', async () => { + // Set initial configuration + features.lsp.workspace.getConfiguration.resolves({ shareCodeWhispererContentWithAWS: true }) + + await serviceManager.handleDidChangeConfiguration() + + expect(streamingClientMock.shareCodeWhispererContentWithAWS).to.equal(true) + + // Change configuration + features.lsp.workspace.getConfiguration.resolves({ shareCodeWhispererContentWithAWS: false }) + + await serviceManager.handleDidChangeConfiguration() + + expect(streamingClientMock.shareCodeWhispererContentWithAWS).to.equal(false) + }) + + it('does not update streaming client when no cached client exists', async () => { + TestAmazonQServiceManager.resetInstance() + const serviceManagerWithoutClient = initBaseTestServiceManager(features, stubCodeWhispererService()) + + features.lsp.workspace.getConfiguration.resolves({ shareCodeWhispererContentWithAWS: false }) + + // Should not throw when no cached streaming client exists + await serviceManagerWithoutClient.handleDidChangeConfiguration() + + expect(serviceManagerWithoutClient['cachedStreamingClient']).to.be.undefined + }) }) diff --git a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts index d7c425c38f..88071f357d 100644 --- a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts @@ -39,6 +39,7 @@ export type ChatCommandOutput = SendMessageCommandOutput | GenerateAssistantResp export abstract class StreamingClientServiceBase { protected readonly region protected readonly endpoint + public shareCodeWhispererContentWithAWS?: boolean inflightRequests: Set = new Set() @@ -65,6 +66,7 @@ export abstract class StreamingClientServiceBase { export class StreamingClientServiceToken extends StreamingClientServiceBase { client: CodeWhispererStreaming public profileArn?: string + constructor( credentialsProvider: CredentialsProvider, sdkInitializator: SDKInitializator, @@ -74,6 +76,7 @@ export class StreamingClientServiceToken extends StreamingClientServiceBase { customUserAgent: string ) { super(region, endpoint) + const tokenProvider = async () => { const token = getBearerTokenFromProvider(credentialsProvider) // without setting expiration, the tokenProvider will only be called once @@ -95,11 +98,15 @@ export class StreamingClientServiceToken extends StreamingClientServiceBase { }) this.client.middlewareStack.add( - (next, context) => args => { + (next, context) => (args: any) => { if (credentialsProvider.getConnectionType() === 'external_idp') { - // @ts-ignore args.request.headers['TokenType'] = 'EXTERNAL_IDP' } + if (this.shareCodeWhispererContentWithAWS !== undefined) { + args.request.headers['x-amzn-codewhisperer-optout'] = `${!this.shareCodeWhispererContentWithAWS}` + } + // Log headers for debugging + logging.debug(`StreamingClient headers: ${JSON.stringify(args.request.headers)}`) return next(args) }, { @@ -213,6 +220,18 @@ export class StreamingClientServiceIAM extends StreamingClientServiceBase { credentials: iamCredentialProvider, retryStrategy: new ConfiguredRetryStrategy(0, (attempt: number) => 500 + attempt ** 10), }) + + this.client.middlewareStack.add( + (next, context) => (args: any) => { + if (this.shareCodeWhispererContentWithAWS !== undefined) { + args.request.headers['x-amzn-codewhisperer-optout'] = `${!this.shareCodeWhispererContentWithAWS}` + } + return next(args) + }, + { + step: 'build', + } + ) } public async sendMessage( From b29478fa1ecc58e331ff330ff79f46b0d8c38d9e Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Tue, 30 Sep 2025 18:52:19 -0700 Subject: [PATCH 117/158] revert: fix to add opt-out header to streaming client (#2365) (#2370) This reverts commit 692e77bc99770ac7d676928e95e3dc43bb91e7f0. --- .../chat/chatSessionService.ts | 1 + .../AmazonQIAMServiceManager.ts | 3 - .../AmazonQTokenServiceManager.ts | 3 - .../BaseAmazonQServiceManager.ts | 11 -- .../src/shared/streamingClientService.test.ts | 104 ------------------ .../src/shared/streamingClientService.ts | 23 +--- 6 files changed, 3 insertions(+), 142 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts index 770de98340..13c198a949 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts @@ -38,6 +38,7 @@ type DeferredHandler = { reject: (err: Error) => void } export class ChatSessionService { + public shareCodeWhispererContentWithAWS = false public pairProgrammingMode: boolean = true public contextListSent: boolean = false public modelId: string | undefined diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts index bf27a599a2..a29b65468f 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts @@ -74,9 +74,6 @@ export class AmazonQIAMServiceManager extends BaseAmazonQServiceManager< this.region, this.endpoint ) - this.cachedStreamingClient.shareCodeWhispererContentWithAWS = this.configurationCache.getProperty( - 'shareCodeWhispererContentWithAWS' - ) } return this.cachedStreamingClient } diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts index 5cd43f3cc7..77fd162d5d 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts @@ -584,9 +584,6 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< this.getCustomUserAgent() ) streamingClient.profileArn = this.activeIdcProfile?.arn - streamingClient.shareCodeWhispererContentWithAWS = this.configurationCache.getProperty( - 'shareCodeWhispererContentWithAWS' - ) this.logging.debug(`Created streaming client instance region=${region}, endpoint=${endpoint}`) return streamingClient diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts index 1cd4f254be..cc21cd8766 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts @@ -157,17 +157,6 @@ export abstract class BaseAmazonQServiceManager< ) this.cachedCodewhispererService.shareCodeWhispererContentWithAWS = shareCodeWhispererContentWithAWS } - - if (this.cachedStreamingClient) { - const shareCodeWhispererContentWithAWS = this.configurationCache.getProperty( - 'shareCodeWhispererContentWithAWS' - ) - this.logging.debug( - 'Update shareCodeWhispererContentWithAWS setting on cachedStreamingClient to ' + - shareCodeWhispererContentWithAWS - ) - this.cachedStreamingClient.shareCodeWhispererContentWithAWS = shareCodeWhispererContentWithAWS - } } private async notifyDidChangeConfigurationListeners(): Promise { diff --git a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts index 5b1f08d851..b12f1633df 100644 --- a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts @@ -12,8 +12,6 @@ import { } from '@amzn/codewhisperer-streaming' import { QDeveloperStreaming } from '@amzn/amazon-q-developer-streaming-client' import { rejects } from 'assert' -import { initBaseTestServiceManager, TestAmazonQServiceManager } from './amazonQServiceManager/testUtils' -import { stubCodeWhispererService } from './testUtils' const TIME_TO_ADVANCE_MS = 100 @@ -115,33 +113,6 @@ describe('StreamingClientServiceToken', () => { sinon.assert.match(sendMessageStub.firstCall.firstArg, expectedRequest) }) - it('creates client with shareCodeWhispererContentWithAWS parameter', () => { - const streamingClientServiceWithOptout = new StreamingClientServiceToken( - features.credentialsProvider, - features.sdkInitializator, - features.logging, - DEFAULT_AWS_Q_REGION, - DEFAULT_AWS_Q_ENDPOINT_URL, - 'some-user-agent' - ) - streamingClientServiceWithOptout.shareCodeWhispererContentWithAWS = false - - expect(streamingClientServiceWithOptout['shareCodeWhispererContentWithAWS']).to.equal(false) - }) - - it('creates client without shareCodeWhispererContentWithAWS parameter', () => { - const streamingClientServiceDefault = new StreamingClientServiceToken( - features.credentialsProvider, - features.sdkInitializator, - features.logging, - DEFAULT_AWS_Q_REGION, - DEFAULT_AWS_Q_ENDPOINT_URL, - 'some-user-agent' - ) - - expect(streamingClientServiceDefault['shareCodeWhispererContentWithAWS']).to.be.undefined - }) - describe('generateAssistantResponse', () => { const MOCKED_GENERATE_RESPONSE_REQUEST = { conversationState: { @@ -347,79 +318,4 @@ describe('StreamingClientServiceIAM', () => { expect(credentials.expiration).to.be.instanceOf(Date) expect(credentials.expiration.getTime()).to.be.closeTo(Date.now(), 1000) }) - - it('creates client with shareCodeWhispererContentWithAWS parameter', () => { - const streamingClientServiceWithOptout = new StreamingClientServiceIAM( - features.credentialsProvider, - features.sdkInitializator, - features.logging, - DEFAULT_AWS_Q_REGION, - DEFAULT_AWS_Q_ENDPOINT_URL - ) - streamingClientServiceWithOptout.shareCodeWhispererContentWithAWS = false - - expect(streamingClientServiceWithOptout['shareCodeWhispererContentWithAWS']).to.equal(false) - }) - - it('creates client without shareCodeWhispererContentWithAWS parameter', () => { - const streamingClientServiceDefault = new StreamingClientServiceIAM( - features.credentialsProvider, - features.sdkInitializator, - features.logging, - DEFAULT_AWS_Q_REGION, - DEFAULT_AWS_Q_ENDPOINT_URL - ) - - expect(streamingClientServiceDefault['shareCodeWhispererContentWithAWS']).to.be.undefined - }) -}) - -describe('BaseAmazonQServiceManager streaming client cache updates', () => { - let features: TestFeatures - let serviceManager: TestAmazonQServiceManager - let streamingClientMock: StreamingClientServiceToken - - beforeEach(() => { - features = new TestFeatures() - const serviceStub = stubCodeWhispererService() - - streamingClientMock = Object.assign(sinon.createStubInstance(StreamingClientServiceToken), { - region: DEFAULT_AWS_Q_REGION, - endpoint: DEFAULT_AWS_Q_ENDPOINT_URL, - }) as unknown as StreamingClientServiceToken - serviceManager = initBaseTestServiceManager(features, serviceStub, streamingClientMock) - }) - - afterEach(() => { - sinon.restore() - TestAmazonQServiceManager.resetInstance() - }) - - it('updates shareCodeWhispererContentWithAWS on cached streaming client when configuration changes', async () => { - // Set initial configuration - features.lsp.workspace.getConfiguration.resolves({ shareCodeWhispererContentWithAWS: true }) - - await serviceManager.handleDidChangeConfiguration() - - expect(streamingClientMock.shareCodeWhispererContentWithAWS).to.equal(true) - - // Change configuration - features.lsp.workspace.getConfiguration.resolves({ shareCodeWhispererContentWithAWS: false }) - - await serviceManager.handleDidChangeConfiguration() - - expect(streamingClientMock.shareCodeWhispererContentWithAWS).to.equal(false) - }) - - it('does not update streaming client when no cached client exists', async () => { - TestAmazonQServiceManager.resetInstance() - const serviceManagerWithoutClient = initBaseTestServiceManager(features, stubCodeWhispererService()) - - features.lsp.workspace.getConfiguration.resolves({ shareCodeWhispererContentWithAWS: false }) - - // Should not throw when no cached streaming client exists - await serviceManagerWithoutClient.handleDidChangeConfiguration() - - expect(serviceManagerWithoutClient['cachedStreamingClient']).to.be.undefined - }) }) diff --git a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts index 88071f357d..d7c425c38f 100644 --- a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts @@ -39,7 +39,6 @@ export type ChatCommandOutput = SendMessageCommandOutput | GenerateAssistantResp export abstract class StreamingClientServiceBase { protected readonly region protected readonly endpoint - public shareCodeWhispererContentWithAWS?: boolean inflightRequests: Set = new Set() @@ -66,7 +65,6 @@ export abstract class StreamingClientServiceBase { export class StreamingClientServiceToken extends StreamingClientServiceBase { client: CodeWhispererStreaming public profileArn?: string - constructor( credentialsProvider: CredentialsProvider, sdkInitializator: SDKInitializator, @@ -76,7 +74,6 @@ export class StreamingClientServiceToken extends StreamingClientServiceBase { customUserAgent: string ) { super(region, endpoint) - const tokenProvider = async () => { const token = getBearerTokenFromProvider(credentialsProvider) // without setting expiration, the tokenProvider will only be called once @@ -98,15 +95,11 @@ export class StreamingClientServiceToken extends StreamingClientServiceBase { }) this.client.middlewareStack.add( - (next, context) => (args: any) => { + (next, context) => args => { if (credentialsProvider.getConnectionType() === 'external_idp') { + // @ts-ignore args.request.headers['TokenType'] = 'EXTERNAL_IDP' } - if (this.shareCodeWhispererContentWithAWS !== undefined) { - args.request.headers['x-amzn-codewhisperer-optout'] = `${!this.shareCodeWhispererContentWithAWS}` - } - // Log headers for debugging - logging.debug(`StreamingClient headers: ${JSON.stringify(args.request.headers)}`) return next(args) }, { @@ -220,18 +213,6 @@ export class StreamingClientServiceIAM extends StreamingClientServiceBase { credentials: iamCredentialProvider, retryStrategy: new ConfiguredRetryStrategy(0, (attempt: number) => 500 + attempt ** 10), }) - - this.client.middlewareStack.add( - (next, context) => (args: any) => { - if (this.shareCodeWhispererContentWithAWS !== undefined) { - args.request.headers['x-amzn-codewhisperer-optout'] = `${!this.shareCodeWhispererContentWithAWS}` - } - return next(args) - }, - { - step: 'build', - } - ) } public async sendMessage( From bde961fc3da1de33552e61de0e94e3a86a2948fd Mon Sep 17 00:00:00 2001 From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> Date: Wed, 1 Oct 2025 08:24:36 -0700 Subject: [PATCH 118/158] refactor: removing some redundant code (#2364) --- .../agenticChat/agenticChatController.ts | 6 +-- .../agenticChat/tools/chatDb/chatDb.test.ts | 24 ---------- .../agenticChat/tools/chatDb/chatDb.ts | 44 ------------------- 3 files changed, 3 insertions(+), 71 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 3dc5671992..f7e4605622 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -1331,7 +1331,7 @@ export class AgenticChatController implements ChatHandlers { if (result.data?.chatResult.body !== undefined) { this.#chatHistoryDb.replaceWithSummary(tabId, 'cwc', conversationIdentifier ?? '', { body: result.data?.chatResult.body, - type: 'prompt' as any, + type: 'prompt' as ChatMessage['type'], shouldDisplayMessage: true, timestamp: new Date(), }) @@ -1451,7 +1451,7 @@ export class AgenticChatController implements ChatHandlers { } else { this.#chatHistoryDb.addMessage(tabId, 'cwc', conversationIdentifier, { body: currentMessage.userInputMessage?.content ?? '', - type: 'prompt' as any, + type: 'prompt' as ChatMessage['type'], userIntent: currentMessage.userInputMessage?.userIntent, origin: currentMessage.userInputMessage?.origin, userInputMessageContext: currentMessage.userInputMessage?.userInputMessageContext, @@ -1527,7 +1527,7 @@ export class AgenticChatController implements ChatHandlers { } else { this.#chatHistoryDb.addMessage(tabId, 'cwc', conversationIdentifier ?? '', { body: result.data?.chatResult.body, - type: 'answer' as any, + type: 'answer' as ChatMessage['type'], codeReference: result.data.chatResult.codeReference, relatedContent: result.data.chatResult.relatedContent?.content && diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.test.ts index aed5a30643..2c0e07baff 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.test.ts @@ -91,30 +91,6 @@ describe('ChatDatabase', () => { }) }) - describe('replaceHistory', () => { - it('should replace history with messages', async () => { - await chatDb.databaseInitialize(0) - const tabId = 'tab-1' - const tabType = 'cwc' - const conversationId = 'conv-1' - const messages = [ - { body: 'Test', type: 'prompt' as any, timestamp: new Date() }, - { body: 'Thinking...', type: 'answer', timestamp: new Date() }, - ] - - // Call the method - chatDb.replaceHistory(tabId, tabType, conversationId, messages) - - // Verify the messages array contains the summary and a dummy response - const messagesFromDb = chatDb.getMessages(tabId, 250) - assert.strictEqual(messagesFromDb.length, 2) - assert.strictEqual(messagesFromDb[0].body, 'Test') - assert.strictEqual(messagesFromDb[0].type, 'prompt') - assert.strictEqual(messagesFromDb[1].body, 'Thinking...') - assert.strictEqual(messagesFromDb[1].type, 'answer') - }) - }) - describe('ensureValidMessageSequence', () => { it('should preserve valid alternating sequence', () => { const messages: Message[] = [ diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts index 2282046243..abd49a52eb 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/chatDb/chatDb.ts @@ -636,50 +636,6 @@ export class ChatDatabase { } } - /** - * Replace history with summary/dummyResponse pair within a specified tab. - * - * This method manages chat messages by creating a new history with compacted summary and dummy response pairs - */ - replaceHistory(tabId: string, tabType: TabType, conversationId: string, messages: Message[]) { - if (this.isInitialized()) { - const clientType = this.#features.lsp.getClientInitializeParams()?.clientInfo?.name || 'unknown' - const tabCollection = this.#db.getCollection(TabCollection) - - this.#features.logging.log( - `Update history with new messages: tabId=${tabId}, tabType=${tabType}, conversationId=${conversationId}` - ) - - const oldHistoryId = this.getOrCreateHistoryId(tabId) - // create a new historyId to start fresh - const historyId = this.createHistoryId(tabId) - - const tabData = historyId ? tabCollection.findOne({ historyId }) : undefined - const tabTitle = tabData?.title || 'Amazon Q Chat' - messages = messages.map(msg => this.formatChatHistoryMessage(msg)) - this.#features.logging.log(`Overriding tab with new historyId=${historyId}`) - tabCollection.insert({ - historyId, - updatedAt: new Date(), - isOpen: true, - tabType: tabType, - title: tabTitle, - conversations: [ - { - conversationId, - clientType, - updatedAt: new Date(), - messages: messages, - }, - ], - }) - - if (oldHistoryId) { - tabCollection.findAndRemove({ historyId: oldHistoryId }) - } - } - } - formatChatHistoryMessage(message: Message): Message { if (message.type === ('prompt' as ChatItemType)) { let hasToolResults = false From 9f2f306f18c3ef703cab23d942408bdcd841fc11 Mon Sep 17 00:00:00 2001 From: Sherry Lu <75588211+XiaoxuanLu@users.noreply.github.com> Date: Wed, 1 Oct 2025 09:47:28 -0700 Subject: [PATCH 119/158] chore: merge agentic version 1.36.0 (#2371) * chore: bump agentic version: 1.36.0 * fix(amazonq): fix to add opt-out header to streaming client (#2365) (#2369) --------- Co-authored-by: aws-toolkit-automation <> Co-authored-by: invictus <149003065+ashishrp-aws@users.noreply.github.com> --- .../src/version.json | 2 +- .../chat/chatSessionService.ts | 1 - .../AmazonQIAMServiceManager.ts | 3 + .../AmazonQTokenServiceManager.ts | 3 + .../BaseAmazonQServiceManager.ts | 11 ++ .../src/shared/streamingClientService.test.ts | 104 ++++++++++++++++++ .../src/shared/streamingClientService.ts | 23 +++- 7 files changed, 143 insertions(+), 4 deletions(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/src/version.json b/app/aws-lsp-codewhisperer-runtimes/src/version.json index fcab28de2b..ee9ac885e6 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/version.json +++ b/app/aws-lsp-codewhisperer-runtimes/src/version.json @@ -1,3 +1,3 @@ { - "agenticChat": "1.35.0" + "agenticChat": "1.36.0" } diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts index 13c198a949..770de98340 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts @@ -38,7 +38,6 @@ type DeferredHandler = { reject: (err: Error) => void } export class ChatSessionService { - public shareCodeWhispererContentWithAWS = false public pairProgrammingMode: boolean = true public contextListSent: boolean = false public modelId: string | undefined diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts index a29b65468f..bf27a599a2 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQIAMServiceManager.ts @@ -74,6 +74,9 @@ export class AmazonQIAMServiceManager extends BaseAmazonQServiceManager< this.region, this.endpoint ) + this.cachedStreamingClient.shareCodeWhispererContentWithAWS = this.configurationCache.getProperty( + 'shareCodeWhispererContentWithAWS' + ) } return this.cachedStreamingClient } diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts index 77fd162d5d..5cd43f3cc7 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts @@ -584,6 +584,9 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< this.getCustomUserAgent() ) streamingClient.profileArn = this.activeIdcProfile?.arn + streamingClient.shareCodeWhispererContentWithAWS = this.configurationCache.getProperty( + 'shareCodeWhispererContentWithAWS' + ) this.logging.debug(`Created streaming client instance region=${region}, endpoint=${endpoint}`) return streamingClient diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts index cc21cd8766..1cd4f254be 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts @@ -157,6 +157,17 @@ export abstract class BaseAmazonQServiceManager< ) this.cachedCodewhispererService.shareCodeWhispererContentWithAWS = shareCodeWhispererContentWithAWS } + + if (this.cachedStreamingClient) { + const shareCodeWhispererContentWithAWS = this.configurationCache.getProperty( + 'shareCodeWhispererContentWithAWS' + ) + this.logging.debug( + 'Update shareCodeWhispererContentWithAWS setting on cachedStreamingClient to ' + + shareCodeWhispererContentWithAWS + ) + this.cachedStreamingClient.shareCodeWhispererContentWithAWS = shareCodeWhispererContentWithAWS + } } private async notifyDidChangeConfigurationListeners(): Promise { diff --git a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts index b12f1633df..5b1f08d851 100644 --- a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.test.ts @@ -12,6 +12,8 @@ import { } from '@amzn/codewhisperer-streaming' import { QDeveloperStreaming } from '@amzn/amazon-q-developer-streaming-client' import { rejects } from 'assert' +import { initBaseTestServiceManager, TestAmazonQServiceManager } from './amazonQServiceManager/testUtils' +import { stubCodeWhispererService } from './testUtils' const TIME_TO_ADVANCE_MS = 100 @@ -113,6 +115,33 @@ describe('StreamingClientServiceToken', () => { sinon.assert.match(sendMessageStub.firstCall.firstArg, expectedRequest) }) + it('creates client with shareCodeWhispererContentWithAWS parameter', () => { + const streamingClientServiceWithOptout = new StreamingClientServiceToken( + features.credentialsProvider, + features.sdkInitializator, + features.logging, + DEFAULT_AWS_Q_REGION, + DEFAULT_AWS_Q_ENDPOINT_URL, + 'some-user-agent' + ) + streamingClientServiceWithOptout.shareCodeWhispererContentWithAWS = false + + expect(streamingClientServiceWithOptout['shareCodeWhispererContentWithAWS']).to.equal(false) + }) + + it('creates client without shareCodeWhispererContentWithAWS parameter', () => { + const streamingClientServiceDefault = new StreamingClientServiceToken( + features.credentialsProvider, + features.sdkInitializator, + features.logging, + DEFAULT_AWS_Q_REGION, + DEFAULT_AWS_Q_ENDPOINT_URL, + 'some-user-agent' + ) + + expect(streamingClientServiceDefault['shareCodeWhispererContentWithAWS']).to.be.undefined + }) + describe('generateAssistantResponse', () => { const MOCKED_GENERATE_RESPONSE_REQUEST = { conversationState: { @@ -318,4 +347,79 @@ describe('StreamingClientServiceIAM', () => { expect(credentials.expiration).to.be.instanceOf(Date) expect(credentials.expiration.getTime()).to.be.closeTo(Date.now(), 1000) }) + + it('creates client with shareCodeWhispererContentWithAWS parameter', () => { + const streamingClientServiceWithOptout = new StreamingClientServiceIAM( + features.credentialsProvider, + features.sdkInitializator, + features.logging, + DEFAULT_AWS_Q_REGION, + DEFAULT_AWS_Q_ENDPOINT_URL + ) + streamingClientServiceWithOptout.shareCodeWhispererContentWithAWS = false + + expect(streamingClientServiceWithOptout['shareCodeWhispererContentWithAWS']).to.equal(false) + }) + + it('creates client without shareCodeWhispererContentWithAWS parameter', () => { + const streamingClientServiceDefault = new StreamingClientServiceIAM( + features.credentialsProvider, + features.sdkInitializator, + features.logging, + DEFAULT_AWS_Q_REGION, + DEFAULT_AWS_Q_ENDPOINT_URL + ) + + expect(streamingClientServiceDefault['shareCodeWhispererContentWithAWS']).to.be.undefined + }) +}) + +describe('BaseAmazonQServiceManager streaming client cache updates', () => { + let features: TestFeatures + let serviceManager: TestAmazonQServiceManager + let streamingClientMock: StreamingClientServiceToken + + beforeEach(() => { + features = new TestFeatures() + const serviceStub = stubCodeWhispererService() + + streamingClientMock = Object.assign(sinon.createStubInstance(StreamingClientServiceToken), { + region: DEFAULT_AWS_Q_REGION, + endpoint: DEFAULT_AWS_Q_ENDPOINT_URL, + }) as unknown as StreamingClientServiceToken + serviceManager = initBaseTestServiceManager(features, serviceStub, streamingClientMock) + }) + + afterEach(() => { + sinon.restore() + TestAmazonQServiceManager.resetInstance() + }) + + it('updates shareCodeWhispererContentWithAWS on cached streaming client when configuration changes', async () => { + // Set initial configuration + features.lsp.workspace.getConfiguration.resolves({ shareCodeWhispererContentWithAWS: true }) + + await serviceManager.handleDidChangeConfiguration() + + expect(streamingClientMock.shareCodeWhispererContentWithAWS).to.equal(true) + + // Change configuration + features.lsp.workspace.getConfiguration.resolves({ shareCodeWhispererContentWithAWS: false }) + + await serviceManager.handleDidChangeConfiguration() + + expect(streamingClientMock.shareCodeWhispererContentWithAWS).to.equal(false) + }) + + it('does not update streaming client when no cached client exists', async () => { + TestAmazonQServiceManager.resetInstance() + const serviceManagerWithoutClient = initBaseTestServiceManager(features, stubCodeWhispererService()) + + features.lsp.workspace.getConfiguration.resolves({ shareCodeWhispererContentWithAWS: false }) + + // Should not throw when no cached streaming client exists + await serviceManagerWithoutClient.handleDidChangeConfiguration() + + expect(serviceManagerWithoutClient['cachedStreamingClient']).to.be.undefined + }) }) diff --git a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts index d7c425c38f..88071f357d 100644 --- a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts @@ -39,6 +39,7 @@ export type ChatCommandOutput = SendMessageCommandOutput | GenerateAssistantResp export abstract class StreamingClientServiceBase { protected readonly region protected readonly endpoint + public shareCodeWhispererContentWithAWS?: boolean inflightRequests: Set = new Set() @@ -65,6 +66,7 @@ export abstract class StreamingClientServiceBase { export class StreamingClientServiceToken extends StreamingClientServiceBase { client: CodeWhispererStreaming public profileArn?: string + constructor( credentialsProvider: CredentialsProvider, sdkInitializator: SDKInitializator, @@ -74,6 +76,7 @@ export class StreamingClientServiceToken extends StreamingClientServiceBase { customUserAgent: string ) { super(region, endpoint) + const tokenProvider = async () => { const token = getBearerTokenFromProvider(credentialsProvider) // without setting expiration, the tokenProvider will only be called once @@ -95,11 +98,15 @@ export class StreamingClientServiceToken extends StreamingClientServiceBase { }) this.client.middlewareStack.add( - (next, context) => args => { + (next, context) => (args: any) => { if (credentialsProvider.getConnectionType() === 'external_idp') { - // @ts-ignore args.request.headers['TokenType'] = 'EXTERNAL_IDP' } + if (this.shareCodeWhispererContentWithAWS !== undefined) { + args.request.headers['x-amzn-codewhisperer-optout'] = `${!this.shareCodeWhispererContentWithAWS}` + } + // Log headers for debugging + logging.debug(`StreamingClient headers: ${JSON.stringify(args.request.headers)}`) return next(args) }, { @@ -213,6 +220,18 @@ export class StreamingClientServiceIAM extends StreamingClientServiceBase { credentials: iamCredentialProvider, retryStrategy: new ConfiguredRetryStrategy(0, (attempt: number) => 500 + attempt ** 10), }) + + this.client.middlewareStack.add( + (next, context) => (args: any) => { + if (this.shareCodeWhispererContentWithAWS !== undefined) { + args.request.headers['x-amzn-codewhisperer-optout'] = `${!this.shareCodeWhispererContentWithAWS}` + } + return next(args) + }, + { + step: 'build', + } + ) } public async sendMessage( From 1f6b7f7f6aca898c8950e896b06ef214afcd5c4f Mon Sep 17 00:00:00 2001 From: atontb <104926752+atonaamz@users.noreply.github.com> Date: Wed, 1 Oct 2025 10:04:36 -0700 Subject: [PATCH 120/158] chore(amazonq): refactor inline completion codes (#2367) --- .../chat/telemetry/chatTelemetryController.ts | 2 +- .../codeWhispererServer.test.ts | 4 +- .../inline-completion/codeWhispererServer.ts | 12 +- .../{ => contants}/constants.ts | 0 .../editCompletionHandler.ts | 4 +- .../inline-completion/mergeRightUtils.test.ts | 270 ------------------ .../inline-completion/mergeRightUtils.ts | 132 --------- .../{ => telemetry}/telemetry.ts | 13 +- .../{ => tracker}/codeDiffTracker.test.ts | 0 .../{ => tracker}/codeDiffTracker.ts | 6 +- .../tracker/codeEditTracker.ts | 10 +- .../codePercentageTracker.test.ts} | 4 +- .../codePercentageTracker.ts} | 6 +- .../{ => utils}/diffUtils.ts | 4 +- .../utils/mergeRightUtils.test.ts | 74 +++++ .../utils/mergeRightUtils.ts | 107 +++++++ .../src/shared/codeWhispererService.ts | 2 +- .../src/shared/testUtils.ts | 28 -- 18 files changed, 213 insertions(+), 465 deletions(-) rename server/aws-lsp-codewhisperer/src/language-server/inline-completion/{ => contants}/constants.ts (100%) delete mode 100644 server/aws-lsp-codewhisperer/src/language-server/inline-completion/mergeRightUtils.test.ts delete mode 100644 server/aws-lsp-codewhisperer/src/language-server/inline-completion/mergeRightUtils.ts rename server/aws-lsp-codewhisperer/src/language-server/inline-completion/{ => telemetry}/telemetry.ts (94%) rename server/aws-lsp-codewhisperer/src/language-server/inline-completion/{ => tracker}/codeDiffTracker.test.ts (100%) rename server/aws-lsp-codewhisperer/src/language-server/inline-completion/{ => tracker}/codeDiffTracker.ts (97%) rename server/aws-lsp-codewhisperer/src/language-server/inline-completion/{codePercentage.test.ts => tracker/codePercentageTracker.test.ts} (98%) rename server/aws-lsp-codewhisperer/src/language-server/inline-completion/{codePercentage.ts => tracker/codePercentageTracker.ts} (96%) rename server/aws-lsp-codewhisperer/src/language-server/inline-completion/{ => utils}/diffUtils.ts (98%) create mode 100644 server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.ts diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts index d803d8d17b..a197ee3934 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts @@ -20,7 +20,7 @@ import { ToolUse, UserIntent } from '@amzn/codewhisperer-streaming' import { TriggerContext } from '../contexts/triggerContext' import { CredentialsProvider, Logging } from '@aws/language-server-runtimes/server-interface' -import { AcceptedSuggestionEntry, CodeDiffTracker } from '../../inline-completion/codeDiffTracker' +import { AcceptedSuggestionEntry, CodeDiffTracker } from '../../inline-completion/tracker/codeDiffTracker' import { TelemetryService } from '../../../shared/telemetry/telemetryService' import { getEndPositionForAcceptedSuggestion, getTelemetryReasonDesc } from '../../../shared/utils' import { CodewhispererLanguage } from '../../../shared/languageDetection' diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts index 428d5353ae..a2028d3708 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts @@ -52,7 +52,7 @@ import { SPECIAL_CHARACTER_HELLO_WORLD, stubCodeWhispererService, } from '../../shared/testUtils' -import { CodeDiffTracker } from './codeDiffTracker' +import { CodeDiffTracker } from './tracker/codeDiffTracker' import { TelemetryService } from '../../shared/telemetry/telemetryService' import { initBaseTestServiceManager, TestAmazonQServiceManager } from '../../shared/amazonQServiceManager/testUtils' import * as utils from '../../shared/utils' @@ -61,7 +61,7 @@ import { URI } from 'vscode-uri' import { INVALID_TOKEN } from '../../shared/constants' import { AmazonQError } from '../../shared/amazonQServiceManager/errors' import * as path from 'path' -import { CONTEXT_CHARACTERS_LIMIT } from './constants' +import { CONTEXT_CHARACTERS_LIMIT } from './contants/constants' import { IdleWorkspaceManager } from '../workspaceContext/IdleWorkspaceManager' const updateConfiguration = async ( diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts index 0c9df7b511..db7970f6eb 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts @@ -26,14 +26,14 @@ import { SuggestionType, } from '../../shared/codeWhispererService' import { CodewhispererLanguage, getSupportedLanguageId } from '../../shared/languageDetection' -import { truncateOverlapWithRightContext } from './mergeRightUtils' +import { truncateOverlapWithRightContext } from './utils/mergeRightUtils' import { CodeWhispererSession, SessionManager } from './session/sessionManager' -import { CodePercentageTracker } from './codePercentage' +import { CodePercentageTracker } from './tracker/codePercentageTracker' import { getCompletionType, getEndPositionForAcceptedSuggestion, getErrorMessage, safeGet } from '../../shared/utils' import { getIdeCategory, makeUserContextObject } from '../../shared/telemetryUtils' import { textUtils } from '@aws/lsp-core' import { TelemetryService } from '../../shared/telemetry/telemetryService' -import { AcceptedInlineSuggestionEntry, CodeDiffTracker } from './codeDiffTracker' +import { AcceptedInlineSuggestionEntry, CodeDiffTracker } from './tracker/codeDiffTracker' import { AmazonQError, AmazonQServiceConnectionExpiredError, @@ -50,16 +50,16 @@ import { RecentEditTracker, RecentEditTrackerDefaultConfig } from './tracker/cod import { CursorTracker } from './tracker/cursorTracker' import { RejectedEditTracker, DEFAULT_REJECTED_EDIT_TRACKER_CONFIG } from './tracker/rejectedEditTracker' import { StreakTracker } from './tracker/streakTracker' -import { getAddedAndDeletedLines, getCharacterDifferences } from './diffUtils' +import { getAddedAndDeletedLines, getCharacterDifferences } from './utils/diffUtils' import { emitPerceivedLatencyTelemetry, emitServiceInvocationFailure, emitServiceInvocationTelemetry, emitUserTriggerDecisionTelemetry, -} from './telemetry' +} from './telemetry/telemetry' import { DocumentChangedListener } from './documentChangedListener' import { EditCompletionHandler } from './editCompletionHandler' -import { EMPTY_RESULT, ABAP_EXTENSIONS } from './constants' +import { EMPTY_RESULT, ABAP_EXTENSIONS } from './contants/constants' import { IdleWorkspaceManager } from '../workspaceContext/IdleWorkspaceManager' import { URI } from 'vscode-uri' import { isUsingIAMAuth } from '../../shared/utils' diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/constants.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/contants/constants.ts similarity index 100% rename from server/aws-lsp-codewhisperer/src/language-server/inline-completion/constants.ts rename to server/aws-lsp-codewhisperer/src/language-server/inline-completion/contants/constants.ts diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts index d2c358d84e..ae7ddfb065 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts @@ -28,7 +28,7 @@ import { emitServiceInvocationFailure, emitServiceInvocationTelemetry, emitUserTriggerDecisionTelemetry, -} from './telemetry' +} from './telemetry/telemetry' import { TelemetryService } from '../../shared/telemetry/telemetryService' import { textUtils } from '@aws/lsp-core' import { AmazonQBaseServiceManager } from '../../shared/amazonQServiceManager/BaseAmazonQServiceManager' @@ -36,7 +36,7 @@ import { RejectedEditTracker } from './tracker/rejectedEditTracker' import { getErrorMessage, hasConnectionExpired } from '../../shared/utils' import { AmazonQError, AmazonQServiceConnectionExpiredError } from '../../shared/amazonQServiceManager/errors' import { DocumentChangedListener } from './documentChangedListener' -import { EMPTY_RESULT, EDIT_DEBOUNCE_INTERVAL_MS } from './constants' +import { EMPTY_RESULT, EDIT_DEBOUNCE_INTERVAL_MS } from './contants/constants' import { StreakTracker } from './tracker/streakTracker' export class EditCompletionHandler { diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/mergeRightUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/mergeRightUtils.test.ts deleted file mode 100644 index d7a0147a85..0000000000 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/mergeRightUtils.test.ts +++ /dev/null @@ -1,270 +0,0 @@ -import { - getPrefixOverlapLastIndex, - getPrefixSuffixOverlap, - mergeEditSuggestionsWithFileContext, - truncateOverlapWithRightContext, -} from './mergeRightUtils' -import { - HELLO_WORLD_IN_CSHARP, - HELLO_WORLD_WITH_WINDOWS_ENDING, - INCOMPLETE_HELLO_WORLD_IN_CSHARP, - SAMPLE_SESSION_DATA_WITH_EXTRA_LEFT_CONTENT, -} from '../../shared/testUtils' -import assert = require('assert') -import { CodeWhispererSession } from './session/sessionManager' -import { TextDocument } from '@aws/language-server-runtimes/server-interface' - -describe('Merge Right Utils', () => { - const HELLO_WORLD = `Console.WriteLine("Hello World!");` - - it('get prefix suffix overlap works as expected', () => { - const result = getPrefixSuffixOverlap('adwg31', '31ggrs') - assert.deepEqual(result, '31') - }) - - it('get prefix prefix overlap index works as expected', () => { - const result1 = getPrefixOverlapLastIndex('static void', 'static') - assert.deepEqual(result1, 6) - const result2 = getPrefixOverlapLastIndex('static void', 'void') - assert.deepEqual(result2, 11) - const result3 = getPrefixOverlapLastIndex('static void', 'staic') - assert.deepEqual(result3, 3) - }) - - it('should return empty suggestion when right context equals line content ', () => { - const result = truncateOverlapWithRightContext(HELLO_WORLD, HELLO_WORLD) - assert.deepEqual(result, '') - }) - - it('should return empty suggestion when right context equals file content', () => { - // Without trimStart, this test would fail because the function doesn't trim leading new line from right context - const result = truncateOverlapWithRightContext(HELLO_WORLD_IN_CSHARP.trimStart(), HELLO_WORLD_IN_CSHARP) - assert.deepEqual(result, '') - }) - - it('should not handle the case where right context fully matches suggestion but starts with a newline ', () => { - const result = truncateOverlapWithRightContext('\n' + HELLO_WORLD_IN_CSHARP, HELLO_WORLD_IN_CSHARP) - // Even though right context and suggestion are equal, the newline of right context doesn't get trimmed while the newline of suggestion gets trimmed - // As a result, we end up with no overlap - assert.deepEqual(result, HELLO_WORLD_IN_CSHARP) - }) - - it('should return truncated suggestion when right context matches end of the suggestion', () => { - // File contents will be `nsole.WriteLine("Hello World!");` - // Suggestion will be the full HELLO_WORLD - // Final truncated result should be the first two letters of HELLO_WORLD - const result = truncateOverlapWithRightContext(HELLO_WORLD.substring(2), HELLO_WORLD) - - assert.deepEqual(result, HELLO_WORLD.substring(0, 2)) - }) - - it('should trim right-context tabs and whitespaces until first newline', () => { - const suggestion = '{\n return a + b;\n }' - const rightContent = ' \n }\n\n }\n}' - const expected_result = '{\n return a + b;' - const result = truncateOverlapWithRightContext(rightContent, suggestion) - - assert.deepEqual(result, expected_result) - }) - - it('should handle different line endings', () => { - const suggestion = '{\n return a + b;\n }' - const rightContent = '\r\n }\r\n}\r\n}' - const expected_result = '{\n return a + b;' - const result = truncateOverlapWithRightContext(rightContent, suggestion) - - assert.deepEqual(result, expected_result) - }) - - it('should handle windows line endings for files', () => { - const result = truncateOverlapWithRightContext( - HELLO_WORLD_WITH_WINDOWS_ENDING, - HELLO_WORLD_WITH_WINDOWS_ENDING.replaceAll('\r', '') - ) - assert.deepEqual(result, '') - }) -}) - -describe('mergeEditSuggestionsWithFileContext', function () { - const PREVIOUS_SESSION = new CodeWhispererSession(SAMPLE_SESSION_DATA_WITH_EXTRA_LEFT_CONTENT) - const SUGGESTION_CONTENT = - '--- file:///incomplete.cs\t1750894867455\n' + - '+++ file:///incomplete.cs\t1750894887671\n' + - '@@ -1,4 +1,9 @@\n' + - 'class HelloWorld\n' + - '+{\n' + - '+ static void Main(string[] args)\n' + - '+ {\n' + - '+ Console.WriteLine(\"Hello World!\");\n' + - '+ }\n' + - '+}\n' + - ' \n' + - '}\n' + - '\\ No newline at end of file\n' - - beforeEach(() => { - PREVIOUS_SESSION.suggestions = [{ content: SUGGESTION_CONTENT, itemId: 'itemId' }] - }) - - it('should return non-empty suggestion if user input matches prefix of the suggestion', () => { - const userEdit = '{' - const currentTextDocument = TextDocument.create( - 'file:///incomplete.cs', - 'csharp', - 1, - INCOMPLETE_HELLO_WORLD_IN_CSHARP + userEdit - ) - const fileContext = { - filename: currentTextDocument.uri, - programmingLanguage: { languageName: 'csharp' }, - leftFileContent: INCOMPLETE_HELLO_WORLD_IN_CSHARP + userEdit, - rightFileContent: '', - } - const expectedNewDiff = - '@@ -1,2 +1,8 @@\n' + - ' class HelloWorld\n' + - '-' + - userEdit + - '\n' + - '\\ No newline at end of file\n' + - '+' + - userEdit + - '\n' + - '+ static void Main(string[] args)\n' + - '+ {\n' + - '+ Console.WriteLine("Hello World!");\n' + - '+ }\n' + - '+}\n' + - '+ \n' + - '\\ No newline at end of file\n' - const mergedSuggestions = mergeEditSuggestionsWithFileContext( - PREVIOUS_SESSION, - currentTextDocument, - fileContext - ) - assert.deepEqual(mergedSuggestions.length, 1) - const insertText = (mergedSuggestions[0].insertText as string).split('\n').slice(2).join('\n') - assert.deepEqual(insertText, expectedNewDiff) - }) - - it('should return non-empty suggestion if user input contains extra white space prefix', () => { - const userEdit = ' {' - const currentTextDocument = TextDocument.create( - 'file:///incomplete.cs', - 'csharp', - 1, - INCOMPLETE_HELLO_WORLD_IN_CSHARP + userEdit - ) - const fileContext = { - filename: currentTextDocument.uri, - programmingLanguage: { languageName: 'csharp' }, - leftFileContent: INCOMPLETE_HELLO_WORLD_IN_CSHARP + userEdit, - rightFileContent: '', - } - const expectedNewDiff = - '@@ -1,2 +1,8 @@\n' + - ' class HelloWorld\n' + - '-' + - userEdit + - '\n' + - '\\ No newline at end of file\n' + - '+' + - userEdit + - '\n' + - '+ static void Main(string[] args)\n' + - '+ {\n' + - '+ Console.WriteLine("Hello World!");\n' + - '+ }\n' + - '+}\n' + - '+ \n' + - '\\ No newline at end of file\n' - const mergedSuggestions = mergeEditSuggestionsWithFileContext( - PREVIOUS_SESSION, - currentTextDocument, - fileContext - ) - assert.deepEqual(mergedSuggestions.length, 1) - const insertText = (mergedSuggestions[0].insertText as string).split('\n').slice(2).join('\n') - assert.deepEqual(insertText, expectedNewDiff) - }) - - it('should return empty suggestion if user input contains a deletion', () => { - const currentTextDocument = TextDocument.create( - 'file:///incomplete.cs', - 'csharp', - 1, - INCOMPLETE_HELLO_WORLD_IN_CSHARP.substring(0, -3) - ) - const fileContext = { - filename: currentTextDocument.uri, - programmingLanguage: { languageName: 'csharp' }, - leftFileContent: INCOMPLETE_HELLO_WORLD_IN_CSHARP.substring(0, -3), - rightFileContent: '', - } - const mergedSuggestions = mergeEditSuggestionsWithFileContext( - PREVIOUS_SESSION, - currentTextDocument, - fileContext - ) - assert.deepEqual(mergedSuggestions.length, 0) - }) - - it('should return empty suggestion if user input contains a line break', () => { - const userEdit = '\n' - const currentTextDocument = TextDocument.create( - 'file:///incomplete.cs', - 'csharp', - 1, - INCOMPLETE_HELLO_WORLD_IN_CSHARP.substring(0, -3) - ) - const fileContext = { - filename: currentTextDocument.uri, - programmingLanguage: { languageName: 'csharp' }, - leftFileContent: INCOMPLETE_HELLO_WORLD_IN_CSHARP + userEdit, - rightFileContent: '', - } - const mergedSuggestions = mergeEditSuggestionsWithFileContext( - PREVIOUS_SESSION, - currentTextDocument, - fileContext - ) - assert.deepEqual(mergedSuggestions.length, 0) - }) - - it('should return non-empty suggestion if user input matches a part of the suggestion', () => { - const userEdit = '{\n void' - const currentTextDocument = TextDocument.create( - 'file:///incomplete.cs', - 'csharp', - 1, - INCOMPLETE_HELLO_WORLD_IN_CSHARP + userEdit - ) - const fileContext = { - filename: currentTextDocument.uri, - programmingLanguage: { languageName: 'csharp' }, - leftFileContent: INCOMPLETE_HELLO_WORLD_IN_CSHARP + userEdit, - rightFileContent: '', - } - const expectedNewDiff = - '@@ -1,3 +1,8 @@\n' + - ' class HelloWorld\n' + - ' {\n' + - '- void\n' + - '\\ No newline at end of file\n' + - '+ void Main(string[] args)\n' + - '+ {\n' + - '+ Console.WriteLine("Hello World!");\n' + - '+ }\n' + - '+}\n' + - '+ \n' + - '\\ No newline at end of file\n' - const mergedSuggestions = mergeEditSuggestionsWithFileContext( - PREVIOUS_SESSION, - currentTextDocument, - fileContext - ) - assert.deepEqual(mergedSuggestions.length, 1) - const insertText = (mergedSuggestions[0].insertText as string).split('\n').slice(2).join('\n') - assert.deepEqual(insertText, expectedNewDiff) - }) -}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/mergeRightUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/mergeRightUtils.ts deleted file mode 100644 index 9091139e7e..0000000000 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/mergeRightUtils.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { InlineCompletionItemWithReferences, TextDocument } from '@aws/language-server-runtimes/server-interface' -import { CodeWhispererSession } from './session/sessionManager' -import { applyUnifiedDiff, generateUnifiedDiffWithTimestamps } from './diffUtils' -import { FileContext } from '../../shared/codeWhispererService' - -/** - * Returns the longest overlap between the Suffix of firstString and Prefix of second string - * getPrefixSuffixOverlap("adwg31", "31ggrs") = "31" - */ -export function getPrefixSuffixOverlap(firstString: string, secondString: string) { - let i = Math.min(firstString.length, secondString.length) - while (i > 0) { - if (secondString.slice(0, i) === firstString.slice(-i)) { - break - } - i-- - } - return secondString.slice(0, i) -} - -/** - * Returns the last index of the longest overlap between the first string and the second string - * @param targetString the target string - * @param searchString the search string - * @returns last index of the longest overlap between the first string and the second string - * @example getPrefixOverlapLastIndex("public static void", "static") = 13 - */ -export function getPrefixOverlapLastIndex(targetString: string, searchString: string) { - let i = searchString.length - let idx = -1 - while (i > 0) { - idx = targetString.indexOf(searchString.slice(0, i)) - if (idx != -1) { - return idx + i - } - i-- - } - return idx -} - -export function truncateOverlapWithRightContext( - rightFileContent: string, - suggestion: string, - userEdit?: string -): string { - const trimmedSuggestion = suggestion.trim() - // limit of 5000 for right context matching - const rightContext = rightFileContent - .substring(0, 5000) - .replaceAll('\r\n', '\n') - .replace(/^[^\S\n]+/, '') // remove leading tabs and whitespaces - let prefixOverlapLastIndex = 0 - if (userEdit) { - const trimmpedUserEdit = userEdit.trim() - prefixOverlapLastIndex = getPrefixOverlapLastIndex(trimmedSuggestion, trimmpedUserEdit) - if (prefixOverlapLastIndex == -1) { - return '' - } - } - const prefixSuffixOverlap = getPrefixSuffixOverlap(trimmedSuggestion, rightContext) - const prefixSuffixOverlapIndex = suggestion.lastIndexOf(prefixSuffixOverlap) - if (prefixSuffixOverlapIndex >= 0) { - const truncated = suggestion.slice(prefixOverlapLastIndex, prefixSuffixOverlapIndex) - return truncated.trim().length ? truncated : '' - } else { - return suggestion - } -} - -/** - * Merge Edit suggestions with current file context. - * @param currentSession current session that contains previous suggestions - * @param currentTextDocument current text document - * @param currentFileContext current file context that contains the cursor position - * @returns InlineCompletionItemWithReferences[] with merged edit suggestions and new diff content in insertText field - */ -export function mergeEditSuggestionsWithFileContext( - currentSession: CodeWhispererSession, - currentTextDocument: TextDocument, - currentFileContext: FileContext -): InlineCompletionItemWithReferences[] { - return currentSession.suggestions - .map(suggestion => { - // generate the previous suggested file content by applying previous suggestion to previous doc content - const previousTextDocument = currentSession.document - const suggestedFileContent = applyUnifiedDiff(previousTextDocument.getText(), suggestion.content) - const currentLeftFileContent = currentFileContext.leftFileContent - const currentRightFileContent = currentFileContext.rightFileContent - const previousLeftFileContent = currentSession.requestContext.fileContext.leftFileContent - const userEdit = currentLeftFileContent.substring(previousLeftFileContent.length) - // if the user moves the cursor backward, deletes some contents, or goes to the next line, discard the suggestion - if (previousLeftFileContent.length > currentLeftFileContent.length || userEdit.includes('\n')) { - return { - insertText: '', - isInlineEdit: true, - itemId: suggestion.itemId, - } - } - // find the first overlap between the user input and the previous suggestion - const mergedRightContent = truncateOverlapWithRightContext( - currentRightFileContent, - suggestedFileContent, - userEdit - ) - // if the merged right content is empty, discard the suggestion - if (!mergedRightContent) { - return { - insertText: '', - isInlineEdit: true, - itemId: suggestion.itemId, - } - } - // generate new diff from the merged content - const newDiff = generateUnifiedDiffWithTimestamps( - currentTextDocument.uri, - currentSession.document.uri, - currentTextDocument.getText(), - currentLeftFileContent + mergedRightContent, - Date.now(), - Date.now() - ) - suggestion.content = newDiff - currentSession.requestContext.fileContext = currentFileContext - currentSession.document = currentTextDocument - return { - insertText: newDiff, - isInlineEdit: true, - itemId: suggestion.itemId, - } - }) - .filter(item => item.insertText !== '') -} diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry/telemetry.ts similarity index 94% rename from server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts rename to server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry/telemetry.ts index 4847072122..5272983b61 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry/telemetry.ts @@ -1,10 +1,13 @@ import { Telemetry, IdeDiagnostic } from '@aws/language-server-runtimes/server-interface' import { AWSError } from 'aws-sdk' -import { CodeWhispererSession, UserTriggerDecision } from './session/sessionManager' -import { CodeWhispererPerceivedLatencyEvent, CodeWhispererServiceInvocationEvent } from '../../shared/telemetry/types' -import { getCompletionType, isAwsError } from '../../shared/utils' -import { TelemetryService } from '../../shared/telemetry/telemetryService' -import { SuggestionType } from '../../shared/codeWhispererService' +import { CodeWhispererSession, UserTriggerDecision } from '../session/sessionManager' +import { + CodeWhispererPerceivedLatencyEvent, + CodeWhispererServiceInvocationEvent, +} from '../../../shared/telemetry/types' +import { getCompletionType, isAwsError } from '../../../shared/utils' +import { TelemetryService } from '../../../shared/telemetry/telemetryService' +import { SuggestionType } from '../../../shared/codeWhispererService' export const emitServiceInvocationTelemetry = ( telemetry: Telemetry, diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeDiffTracker.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/codeDiffTracker.test.ts similarity index 100% rename from server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeDiffTracker.test.ts rename to server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/codeDiffTracker.test.ts diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeDiffTracker.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/codeDiffTracker.ts similarity index 97% rename from server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeDiffTracker.ts rename to server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/codeDiffTracker.ts index 5e8072cc1f..8e93c6ec4f 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeDiffTracker.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/codeDiffTracker.ts @@ -1,8 +1,8 @@ import { distance } from 'fastest-levenshtein' import { Position } from '@aws/language-server-runtimes/server-interface' -import { Features } from '../types' -import { getErrorMessage, getUnmodifiedAcceptedTokens } from '../../shared/utils' -import { CodewhispererLanguage } from '../../shared/languageDetection' +import { Features } from '../../types' +import { getErrorMessage, getUnmodifiedAcceptedTokens } from '../../../shared/utils' +import { CodewhispererLanguage } from '../../../shared/languageDetection' export interface AcceptedSuggestionEntry { fileUrl: string diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/codeEditTracker.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/codeEditTracker.ts index 070b6695bc..90c9d9fdcb 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/codeEditTracker.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/codeEditTracker.ts @@ -3,15 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { - TextDocumentItem, - InitializeParams, - Logging, - Disposable, - TextDocument, -} from '@aws/language-server-runtimes/server-interface' +import { TextDocumentItem, Logging, Disposable, TextDocument } from '@aws/language-server-runtimes/server-interface' import { CodeWhispererSupplementalContext, DocumentSnapshot, FileSnapshotContent } from '../../../shared/models/model' -import { generateDiffContexts } from '../diffUtils' +import { generateDiffContexts } from '../utils/diffUtils' /** * Configuration for the RecentEditTracker diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codePercentage.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/codePercentageTracker.test.ts similarity index 98% rename from server/aws-lsp-codewhisperer/src/language-server/inline-completion/codePercentage.test.ts rename to server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/codePercentageTracker.test.ts index 74c192c8f4..8bb79626ee 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codePercentage.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/codePercentageTracker.test.ts @@ -1,6 +1,6 @@ import sinon, { StubbedInstance, stubInterface } from 'ts-sinon' -import { CodePercentageTracker } from './codePercentage' -import { TelemetryService } from '../../shared/telemetry/telemetryService' +import { CodePercentageTracker } from './codePercentageTracker' +import { TelemetryService } from '../../../shared/telemetry/telemetryService' describe('CodePercentage', () => { const LANGUAGE_ID = 'python' diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codePercentage.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/codePercentageTracker.ts similarity index 96% rename from server/aws-lsp-codewhisperer/src/language-server/inline-completion/codePercentage.ts rename to server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/codePercentageTracker.ts index 0513443a35..d32089598b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codePercentage.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/tracker/codePercentageTracker.ts @@ -1,6 +1,6 @@ -import { CodeWhispererCodePercentageEvent } from '../../shared/telemetry/types' -import { TelemetryService } from '../../shared/telemetry/telemetryService' -import { CodewhispererLanguage } from '../../shared/languageDetection' +import { CodeWhispererCodePercentageEvent } from '../../../shared/telemetry/types' +import { TelemetryService } from '../../../shared/telemetry/telemetryService' +import { CodewhispererLanguage } from '../../../shared/languageDetection' const CODE_PERCENTAGE_INTERVAL = 5 * 60 * 1000 const INSERT_CUTOFF_THRESHOLD = 50 diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/diffUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.ts similarity index 98% rename from server/aws-lsp-codewhisperer/src/language-server/inline-completion/diffUtils.ts rename to server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.ts index 0899dd5e46..5a8d05977e 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/diffUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.ts @@ -4,8 +4,8 @@ */ import * as diff from 'diff' -import { CodeWhispererSupplementalContext, CodeWhispererSupplementalContextItem } from '../../shared/models/model' -import { trimSupplementalContexts } from '../../shared/supplementalContextUtil/supplementalContextUtil' +import { CodeWhispererSupplementalContext, CodeWhispererSupplementalContextItem } from '../../../shared/models/model' +import { trimSupplementalContexts } from '../../../shared/supplementalContextUtil/supplementalContextUtil' /** * Generates a unified diff format between old and new file contents diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.test.ts new file mode 100644 index 0000000000..b0c92eb415 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.test.ts @@ -0,0 +1,74 @@ +import { getPrefixOverlapLastIndex, getPrefixSuffixOverlap, truncateOverlapWithRightContext } from './mergeRightUtils' +import { HELLO_WORLD_IN_CSHARP, HELLO_WORLD_WITH_WINDOWS_ENDING } from '../../../shared/testUtils' +import assert = require('assert') + +describe('Merge Right Utils', () => { + const HELLO_WORLD = `Console.WriteLine("Hello World!");` + + it('get prefix suffix overlap works as expected', () => { + const result = getPrefixSuffixOverlap('adwg31', '31ggrs') + assert.deepEqual(result, '31') + }) + + it('get prefix prefix overlap index works as expected', () => { + const result1 = getPrefixOverlapLastIndex('static void', 'static') + assert.deepEqual(result1, 6) + const result2 = getPrefixOverlapLastIndex('static void', 'void') + assert.deepEqual(result2, 11) + const result3 = getPrefixOverlapLastIndex('static void', 'staic') + assert.deepEqual(result3, 3) + }) + + it('should return empty suggestion when right context equals line content ', () => { + const result = truncateOverlapWithRightContext(HELLO_WORLD, HELLO_WORLD) + assert.deepEqual(result, '') + }) + + it('should return empty suggestion when right context equals file content', () => { + // Without trimStart, this test would fail because the function doesn't trim leading new line from right context + const result = truncateOverlapWithRightContext(HELLO_WORLD_IN_CSHARP.trimStart(), HELLO_WORLD_IN_CSHARP) + assert.deepEqual(result, '') + }) + + it('should not handle the case where right context fully matches suggestion but starts with a newline ', () => { + const result = truncateOverlapWithRightContext('\n' + HELLO_WORLD_IN_CSHARP, HELLO_WORLD_IN_CSHARP) + // Even though right context and suggestion are equal, the newline of right context doesn't get trimmed while the newline of suggestion gets trimmed + // As a result, we end up with no overlap + assert.deepEqual(result, HELLO_WORLD_IN_CSHARP) + }) + + it('should return truncated suggestion when right context matches end of the suggestion', () => { + // File contents will be `nsole.WriteLine("Hello World!");` + // Suggestion will be the full HELLO_WORLD + // Final truncated result should be the first two letters of HELLO_WORLD + const result = truncateOverlapWithRightContext(HELLO_WORLD.substring(2), HELLO_WORLD) + + assert.deepEqual(result, HELLO_WORLD.substring(0, 2)) + }) + + it('should trim right-context tabs and whitespaces until first newline', () => { + const suggestion = '{\n return a + b;\n }' + const rightContent = ' \n }\n\n }\n}' + const expected_result = '{\n return a + b;' + const result = truncateOverlapWithRightContext(rightContent, suggestion) + + assert.deepEqual(result, expected_result) + }) + + it('should handle different line endings', () => { + const suggestion = '{\n return a + b;\n }' + const rightContent = '\r\n }\r\n}\r\n}' + const expected_result = '{\n return a + b;' + const result = truncateOverlapWithRightContext(rightContent, suggestion) + + assert.deepEqual(result, expected_result) + }) + + it('should handle windows line endings for files', () => { + const result = truncateOverlapWithRightContext( + HELLO_WORLD_WITH_WINDOWS_ENDING, + HELLO_WORLD_WITH_WINDOWS_ENDING.replaceAll('\r', '') + ) + assert.deepEqual(result, '') + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.ts new file mode 100644 index 0000000000..95daadb15e --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.ts @@ -0,0 +1,107 @@ +import { InlineCompletionItemWithReferences, Range } from '@aws/language-server-runtimes/server-interface' +import { Suggestion } from '../../../shared/codeWhispererService' + +/** + * Returns the longest overlap between the Suffix of firstString and Prefix of second string + * getPrefixSuffixOverlap("adwg31", "31ggrs") = "31" + */ +export function getPrefixSuffixOverlap(firstString: string, secondString: string) { + let i = Math.min(firstString.length, secondString.length) + while (i > 0) { + if (secondString.slice(0, i) === firstString.slice(-i)) { + break + } + i-- + } + return secondString.slice(0, i) +} + +/** + * Returns the last index of the longest overlap between the first string and the second string + * @param targetString the target string + * @param searchString the search string + * @returns last index of the longest overlap between the first string and the second string + * @example getPrefixOverlapLastIndex("public static void", "static") = 13 + */ +export function getPrefixOverlapLastIndex(targetString: string, searchString: string) { + let i = searchString.length + let idx = -1 + while (i > 0) { + idx = targetString.indexOf(searchString.slice(0, i)) + if (idx != -1) { + return idx + i + } + i-- + } + return idx +} + +export function truncateOverlapWithRightContext( + rightFileContent: string, + suggestion: string, + userEdit?: string +): string { + const trimmedSuggestion = suggestion.trim() + // limit of 5000 for right context matching + const rightContext = rightFileContent + .substring(0, 5000) + .replaceAll('\r\n', '\n') + .replace(/^[^\S\n]+/, '') // remove leading tabs and whitespaces + let prefixOverlapLastIndex = 0 + if (userEdit) { + const trimmpedUserEdit = userEdit.trim() + prefixOverlapLastIndex = getPrefixOverlapLastIndex(trimmedSuggestion, trimmpedUserEdit) + if (prefixOverlapLastIndex == -1) { + return '' + } + } + const prefixSuffixOverlap = getPrefixSuffixOverlap(trimmedSuggestion, rightContext) + const prefixSuffixOverlapIndex = suggestion.lastIndexOf(prefixSuffixOverlap) + if (prefixSuffixOverlapIndex >= 0) { + const truncated = suggestion.slice(prefixOverlapLastIndex, prefixSuffixOverlapIndex) + return truncated.trim().length ? truncated : '' + } else { + return suggestion + } +} + +export const mergeSuggestionsWithRightContext = ( + rightFileContext: string, + suggestions: Suggestion[], + includeImportsWithSuggestions: boolean, + range?: Range +): InlineCompletionItemWithReferences[] => { + return suggestions.map(suggestion => { + const insertText: string = truncateOverlapWithRightContext(rightFileContext, suggestion.content) + let references = suggestion.references + ?.filter( + ref => + !( + ref.recommendationContentSpan?.start && insertText.length <= ref.recommendationContentSpan.start + ) && insertText.length + ) + .map(r => { + return { + licenseName: r.licenseName, + referenceUrl: r.url, + referenceName: r.repository, + position: r.recommendationContentSpan && { + startCharacter: r.recommendationContentSpan.start, + endCharacter: r.recommendationContentSpan.end + ? Math.min(r.recommendationContentSpan.end, insertText.length - 1) + : r.recommendationContentSpan.end, + }, + } + }) + + return { + itemId: suggestion.itemId, + insertText: insertText, + range, + references: references?.length ? references : undefined, + mostRelevantMissingImports: includeImportsWithSuggestions + ? suggestion.mostRelevantMissingImports + : undefined, + } + }) +} diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index df193010de..9c229ccd86 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -40,7 +40,7 @@ import { CONTEXT_CHARACTERS_LIMIT, FILE_URI_CHARS_LIMIT, FILENAME_CHARS_LIMIT, -} from '../language-server/inline-completion/constants' +} from '../language-server/inline-completion/contants/constants' // Type guards for request classification export function isTokenRequest(request: BaseGenerateSuggestionsRequest): request is GenerateTokenSuggestionsRequest { diff --git a/server/aws-lsp-codewhisperer/src/shared/testUtils.ts b/server/aws-lsp-codewhisperer/src/shared/testUtils.ts index 374f347627..451f3ae2c3 100644 --- a/server/aws-lsp-codewhisperer/src/shared/testUtils.ts +++ b/server/aws-lsp-codewhisperer/src/shared/testUtils.ts @@ -2,7 +2,6 @@ import { TextDocument } from 'vscode-languageserver-textdocument' import { CodeWhispererServiceBase, ResponseContext, Suggestion } from './codeWhispererService' import { TestFeatures } from '@aws/language-server-runtimes/testing' import { stubInterface } from 'ts-sinon' -import { StreamingClientServiceBase } from './streamingClientService' import { SessionData } from '../language-server/inline-completion/session/sessionManager' import { WorkspaceFolder } from '@aws/language-server-runtimes/protocol' import { SsoConnectionType } from '@aws/language-server-runtimes/server-interface' @@ -15,7 +14,6 @@ export const HELLO_WORLD_IN_CSHARP = `class HelloWorld } }` -export const INCOMPLETE_HELLO_WORLD_IN_CSHARP = `class HelloWorld\n` export const SPECIAL_CHARACTER_HELLO_WORLD = `{class HelloWorld` export const HELLO_WORLD_WITH_WINDOWS_ENDING = HELLO_WORLD_IN_CSHARP.replaceAll('\n', '\r\n') @@ -28,12 +26,6 @@ export const SOME_FILE_WITH_ALT_CASED_LANGUAGE_ID = TextDocument.create( 1, HELLO_WORLD_IN_CSHARP ) -export const SOME_INCOMPLETE_FILE = TextDocument.create( - 'file:///incomplete.cs', - 'csharp', - 1, - INCOMPLETE_HELLO_WORLD_IN_CSHARP -) export const SOME_CLOSED_FILE = TextDocument.create('file:///closed.cs', 'csharp', 1, HELLO_WORLD_IN_CSHARP) export const SOME_UNSUPPORTED_FILE = TextDocument.create( 'file:///hopper.fm', @@ -269,26 +261,6 @@ export const SAMPLE_SESSION_DATA: SessionData = { }, } -export const SAMPLE_SESSION_DATA_WITH_EXTRA_LEFT_CONTENT: SessionData = { - document: SOME_INCOMPLETE_FILE, - startPreprocessTimestamp: 0, - startPosition: { - line: 1, - character: 0, - }, - triggerType: 'OnDemand', - language: 'csharp', - requestContext: { - fileContext: { - filename: SOME_FILE.uri, - programmingLanguage: { languageName: 'csharp' }, - leftFileContent: INCOMPLETE_HELLO_WORLD_IN_CSHARP, - rightFileContent: '', - }, - maxResults: 5, - }, -} - export const createIterableResponse = (data: T[]): AsyncIterable => { let index = 0 From 3057d56e4a3047d1715d6e3560e9f934d1de469c Mon Sep 17 00:00:00 2001 From: tsmithsz <84354541+tsmithsz@users.noreply.github.com> Date: Wed, 1 Oct 2025 12:52:58 -0700 Subject: [PATCH 121/158] fix: optimize memory bank token usage and add new tab support (#2366) --- chat-client/src/client/features/rules.test.ts | 11 ++++- chat-client/src/client/features/rules.ts | 49 +++++++++++++++---- .../agenticChat/agenticChatController.ts | 38 ++++++++++---- .../agenticChat/constants/constants.ts | 10 ++++ .../memorybank/memoryBankController.ts | 10 ++-- .../agenticChat/tools/fsRead.ts | 23 ++++++--- .../chat/chatSessionService.ts | 1 + 7 files changed, 113 insertions(+), 29 deletions(-) diff --git a/chat-client/src/client/features/rules.test.ts b/chat-client/src/client/features/rules.test.ts index cc0817b443..e37be8cdb8 100644 --- a/chat-client/src/client/features/rules.test.ts +++ b/chat-client/src/client/features/rules.test.ts @@ -16,6 +16,9 @@ describe('rules', () => { mynahUi = { openTopBarButtonOverlay: sinon.stub(), showCustomForm: sinon.stub(), + getAllTabs: sinon.stub().returns({}), + updateStore: sinon.stub().returns('new-tab-id'), + notify: sinon.stub(), } as unknown as MynahUI openTopBarButtonOverlayStub = mynahUi.openTopBarButtonOverlay as sinon.SinonStub showCustomFormStub = mynahUi.showCustomForm as sinon.SinonStub @@ -23,6 +26,7 @@ describe('rules', () => { messager = { onRuleClick: sinon.stub(), onChatPrompt: sinon.stub(), + onTabAdd: sinon.stub(), } as unknown as Messager rulesList = new RulesList(mynahUi, messager) @@ -151,12 +155,17 @@ describe('rules', () => { onItemClick(createMemoryBankItem) - // Should send a chat prompt + // Should create new tab and send chat prompt + sinon.assert.calledOnce(messager.onTabAdd as sinon.SinonStub) sinon.assert.calledOnce(messager.onChatPrompt as sinon.SinonStub) + const tabAddArgs = (messager.onTabAdd as sinon.SinonStub).getCall(0).args[0] + assert.equal(tabAddArgs, 'new-tab-id') + const chatPromptArgs = (messager.onChatPrompt as sinon.SinonStub).getCall(0).args[0] assert.equal(chatPromptArgs.prompt.prompt, 'Generate a Memory Bank for this project') assert.equal(chatPromptArgs.prompt.escapedPrompt, 'Generate a Memory Bank for this project') + assert.equal(chatPromptArgs.tabId, 'new-tab-id') }) it('calls messager when regular rule is clicked', () => { diff --git a/chat-client/src/client/features/rules.ts b/chat-client/src/client/features/rules.ts index 0b47cc1f93..585b33144c 100644 --- a/chat-client/src/client/features/rules.ts +++ b/chat-client/src/client/features/rules.ts @@ -1,4 +1,11 @@ -import { MynahIconsType, MynahUI, DetailedListItem, DetailedListItemGroup, MynahIcons } from '@aws/mynah-ui' +import { + MynahIconsType, + MynahUI, + DetailedListItem, + DetailedListItemGroup, + MynahIcons, + NotificationType, +} from '@aws/mynah-ui' import { Messager } from '../messager' import { ListRulesResult } from '@aws/language-server-runtimes-types' import { RulesFolder } from '@aws/language-server-runtimes-types' @@ -82,14 +89,38 @@ export class RulesList { // Close the rules list first this.rulesList?.close() - // Use the current tab, the tabId should be the same as the one used for the rules list - this.messager.onChatPrompt({ - prompt: { - prompt: 'Generate a Memory Bank for this project', - escapedPrompt: 'Generate a Memory Bank for this project', - }, - tabId: this.tabId, - }) + // Check if we're at the tab limit (10 tabs max) + const currentTabCount = Object.keys(this.mynahUi.getAllTabs()).length + if (currentTabCount >= 10) { + // Show notification that max tabs reached + this.mynahUi.notify({ + content: 'You can only open ten conversation tabs at a time.', + type: NotificationType.WARNING, + }) + return + } + + // Create a new tab for the memory bank generation + const newTabId = this.mynahUi.updateStore('', { tabTitle: 'Memory Bank' }) + if (newTabId) { + // Add the new tab and switch to it + this.messager.onTabAdd(newTabId) + + // Send the chat prompt to the new tab + this.messager.onChatPrompt({ + prompt: { + prompt: 'Generate a Memory Bank for this project', + escapedPrompt: 'Generate a Memory Bank for this project', + }, + tabId: newTabId, + }) + } else { + // Show error notification if tab creation failed + this.mynahUi.notify({ + content: 'Failed to create new tab for Memory Bank generation.', + type: NotificationType.ERROR, + }) + } } showLoading(tabId: string) { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index f7e4605622..cdd328c901 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -189,6 +189,8 @@ import { DEFAULT_WINDOW_STOP_SHORTCUT, COMPACTION_CHARACTER_THRESHOLD, MAX_OVERALL_CHARACTERS, + FSREAD_MEMORY_BANK_MAX_PER_FILE, + FSREAD_MEMORY_BANK_MAX_TOTAL, } from './constants/constants' import { AgenticChatError, @@ -837,9 +839,17 @@ export class AgenticChatController implements ChatHandlers { IdleWorkspaceManager.recordActivityTimestamp() + const sessionResult = this.#chatSessionManagementService.getSession(params.tabId) + const { data: session, success } = sessionResult + + if (!success) { + return new ResponseError(ErrorCodes.InternalError, sessionResult.error) + } + // Memory Bank Creation Flow - Delegate to MemoryBankController if (this.#memoryBankController.isMemoryBankCreationRequest(params.prompt.prompt)) { this.#features.logging.info(`Memory Bank creation request detected for tabId: ${params.tabId}`) + session.isMemoryBankGeneration = true // Store original prompt to prevent data loss on failure const originalPrompt = params.prompt.prompt @@ -921,6 +931,8 @@ export class AgenticChatController implements ChatHandlers { this.#features.logging.error(`Memory Bank preparation failed: ${error}`) // Restore original prompt to ensure no data loss params.prompt.prompt = originalPrompt + // Reset memory bank flag since preparation failed + session.isMemoryBankGeneration = false } } @@ -929,14 +941,6 @@ export class AgenticChatController implements ChatHandlers { return maybeDefaultResponse } - const sessionResult = this.#chatSessionManagementService.getSession(params.tabId) - - const { data: session, success } = sessionResult - - if (!success) { - return new ResponseError(ErrorCodes.InternalError, sessionResult.error) - } - const compactIds = session.getAllDeferredCompactMessageIds() await this.#invalidateCompactCommand(params.tabId, compactIds) session.rejectAllDeferredToolExecutions(new ToolApprovalException('Command ignored: new prompt', false)) @@ -1930,7 +1934,14 @@ export class AgenticChatController implements ChatHandlers { } const { Tool } = toolMap[toolUse.name as keyof typeof toolMap] - const tool = new Tool(this.#features) + const tool = + toolUse.name === FS_READ && session.isMemoryBankGeneration + ? new Tool( + this.#features, + FSREAD_MEMORY_BANK_MAX_PER_FILE, + FSREAD_MEMORY_BANK_MAX_TOTAL + ) + : new Tool(this.#features) // For MCP tools, get the permission from McpManager // const permission = McpManager.instance.getToolPerm('Built-in', toolUse.name) @@ -3458,6 +3469,9 @@ export class AgenticChatController implements ChatHandlers { }, }) + // Reset memory bank flag after completion + session.isMemoryBankGeneration = false + return chatResultStream.getResult() } @@ -3485,6 +3499,12 @@ export class AgenticChatController implements ChatHandlers { const errorCode = err.code ?? '' await this.#telemetryController.emitAddMessageMetric(tabId, metric.metric, 'Failed', errorMessage, errorCode) + // Reset memory bank flag on request error + const sessionResult = this.#chatSessionManagementService.getSession(tabId) + if (sessionResult.success) { + sessionResult.data.isMemoryBankGeneration = false + } + if (isUsageLimitError(err)) { if (this.#paidTierMode !== 'paidtier') { this.setPaidTierMode(tabId, 'freetier-limit') diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts index 02fb0d855a..e37bc508ef 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts @@ -81,6 +81,16 @@ The summary should have following main sections: ` +// FsRead limits +export const FSREAD_MAX_PER_FILE = 200_000 +export const FSREAD_MAX_TOTAL = 400_000 +export const FSREAD_MEMORY_BANK_MAX_PER_FILE = 20_000 +export const FSREAD_MEMORY_BANK_MAX_TOTAL = 100_000 + +// Memory Bank constants +// Temporarily reduced from recommended 20 to 5 for token optimization +export const MAX_NUMBER_OF_FILES_FOR_MEMORY_BANK_RANKING = 5 + // shortcut constant export const DEFAULT_MACOS_RUN_SHORTCUT = '⇧ ⌘ ↵' export const DEFAULT_WINDOW_RUN_SHORTCUT = 'Ctrl + ⇧ + ↵' diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankController.ts index ebbcd27290..f552c91e91 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/memorybank/memoryBankController.ts @@ -6,6 +6,7 @@ import { Features } from '@aws/language-server-runtimes/server-interface/server' import { MemoryBankPrompts } from './memoryBankPrompts' import { normalizePathFromUri } from '../../tools/mcp/mcpUtils' +import { MAX_NUMBER_OF_FILES_FOR_MEMORY_BANK_RANKING } from '../../constants/constants' const MEMORY_BANK_DIRECTORY = '.amazonq/rules/memory-bank' const MEMORY_BANK_FILES = { @@ -71,7 +72,10 @@ export class MemoryBankController { const analysisResults = await this.executeGuidelinesGenerationPipeline(workspaceFolderUri) // Step 3: Make LLM call for file ranking - const rankingPrompt = MemoryBankPrompts.getFileRankingPrompt(analysisResults.formattedFilesString, 10) + const rankingPrompt = MemoryBankPrompts.getFileRankingPrompt( + analysisResults.formattedFilesString, + MAX_NUMBER_OF_FILES_FOR_MEMORY_BANK_RANKING + ) const rankedFilesResponse = await llmCallFunction(rankingPrompt) // Step 4: Parse ranked files @@ -111,7 +115,7 @@ export class MemoryBankController { this.features.logging.warn( `Memory Bank: failed to parse LLM ranking response, using TF-IDF fallback: ${error}` ) - rankedFilesList = analysisResults.rankedFilesList.slice(0, 10) + rankedFilesList = analysisResults.rankedFilesList.slice(0, MAX_NUMBER_OF_FILES_FOR_MEMORY_BANK_RANKING) } this.features.logging.info( @@ -477,7 +481,7 @@ export class MemoryBankController { // Step 5: Create fallback ranking (deterministic, for when LLM fails) const rankedFilesList = filesWithDissimilarity .sort((a, b) => b.dissimilarity - a.dissimilarity) - .slice(0, 10) + .slice(0, MAX_NUMBER_OF_FILES_FOR_MEMORY_BANK_RANKING) .map(f => f.path) return { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/fsRead.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/fsRead.ts index aeca19013b..f322e570ee 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/fsRead.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/fsRead.ts @@ -1,6 +1,7 @@ import { sanitize } from '@aws/lsp-core/out/util/path' import { CommandValidation, InvokeOutput, requiresPathAcceptance, validatePath } from './toolShared' import { Features } from '@aws/language-server-runtimes/server-interface/server' +import { FSREAD_MAX_PER_FILE, FSREAD_MAX_TOTAL } from '../constants/constants' export interface FsReadParams { paths: string[] @@ -13,16 +14,24 @@ export interface FileReadResult { } export class FsRead { - static maxResponseSize = 200_000 - static maxResponseSizeTotal = 400_000 + static maxResponseSize = FSREAD_MAX_PER_FILE + static maxResponseSizeTotal = FSREAD_MAX_TOTAL private readonly logging: Features['logging'] private readonly workspace: Features['workspace'] private readonly lsp: Features['lsp'] + private readonly maxPerFile: number + private readonly maxTotal: number - constructor(features: Pick & Partial) { + constructor( + features: Pick & Partial, + maxPerFile?: number, + maxTotal?: number + ) { this.logging = features.logging this.workspace = features.workspace this.lsp = features.lsp + this.maxPerFile = maxPerFile ?? FsRead.maxResponseSize + this.maxTotal = maxTotal ?? FsRead.maxResponseSizeTotal } public async validate(params: FsReadParams): Promise { @@ -62,16 +71,16 @@ export class FsRead { private createOutput(fileResult: FileReadResult[]): InvokeOutput { let totalSize = 0 for (const result of fileResult) { - const exceedsMaxSize = result.content.length > FsRead.maxResponseSize + const exceedsMaxSize = result.content.length > this.maxPerFile if (exceedsMaxSize) { - this.logging.info(`FsRead: truncating ${result.path} to first ${FsRead.maxResponseSize} characters`) - result.content = result.content.substring(0, FsRead.maxResponseSize - 3) + '...' + this.logging.info(`FsRead: truncating ${result.path} to first ${this.maxPerFile} characters`) + result.content = result.content.substring(0, this.maxPerFile - 3) + '...' result.truncated = true } totalSize += result.content.length } - if (totalSize > FsRead.maxResponseSizeTotal) { + if (totalSize > this.maxTotal) { throw Error('Files are too large, please break the file read into smaller chunks') } diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts index 770de98340..c5cac3b8c4 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts @@ -41,6 +41,7 @@ export class ChatSessionService { public pairProgrammingMode: boolean = true public contextListSent: boolean = false public modelId: string | undefined + public isMemoryBankGeneration: boolean = false #lsp?: Features['lsp'] #abortController?: AbortController #currentPromptId?: string From 31cd87ba6378824862bcd7df7f311e250698a3ac Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 14:18:50 -0700 Subject: [PATCH 122/158] chore(release): release packages from branch main (#2351) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .release-please-manifest.json | 12 +++++------ chat-client/CHANGELOG.md | 8 +++++++ chat-client/package.json | 2 +- core/aws-lsp-core/CHANGELOG.md | 8 +++++++ core/aws-lsp-core/package.json | 2 +- package-lock.json | 20 ++++++++--------- server/aws-lsp-antlr4/CHANGELOG.md | 9 ++++++++ server/aws-lsp-antlr4/package.json | 4 ++-- server/aws-lsp-codewhisperer/CHANGELOG.md | 26 +++++++++++++++++++++++ server/aws-lsp-codewhisperer/package.json | 4 ++-- server/aws-lsp-json/CHANGELOG.md | 9 ++++++++ server/aws-lsp-json/package.json | 4 ++-- server/aws-lsp-yaml/CHANGELOG.md | 9 ++++++++ server/aws-lsp-yaml/package.json | 4 ++-- 14 files changed, 95 insertions(+), 26 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 9bfb32d2da..3b135d3905 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,9 +1,9 @@ { - "chat-client": "0.1.37", - "core/aws-lsp-core": "0.0.15", - "server/aws-lsp-antlr4": "0.1.19", - "server/aws-lsp-codewhisperer": "0.0.82", - "server/aws-lsp-json": "0.1.19", + "chat-client": "0.1.38", + "core/aws-lsp-core": "0.0.16", + "server/aws-lsp-antlr4": "0.1.20", + "server/aws-lsp-codewhisperer": "0.0.83", + "server/aws-lsp-json": "0.1.20", "server/aws-lsp-partiql": "0.0.18", - "server/aws-lsp-yaml": "0.1.19" + "server/aws-lsp-yaml": "0.1.20" } diff --git a/chat-client/CHANGELOG.md b/chat-client/CHANGELOG.md index 93dd6d16a1..06a614f1bd 100644 --- a/chat-client/CHANGELOG.md +++ b/chat-client/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.1.38](https://github.com/aws/language-servers/compare/chat-client/v0.1.37...chat-client/v0.1.38) (2025-10-01) + + +### Bug Fixes + +* **amazonq:** Fix mock fs clean; Node version upgrade ([#2324](https://github.com/aws/language-servers/issues/2324)) ([1d9afd4](https://github.com/aws/language-servers/commit/1d9afd410e19624223e300ca06ea7d08a112cc82)) +* optimize memory bank token usage and add new tab support ([#2366](https://github.com/aws/language-servers/issues/2366)) ([3057d56](https://github.com/aws/language-servers/commit/3057d56e4a3047d1715d6e3560e9f934d1de469c)) + ## [0.1.37](https://github.com/aws/language-servers/compare/chat-client/v0.1.36...chat-client/v0.1.37) (2025-09-24) diff --git a/chat-client/package.json b/chat-client/package.json index 7c31ff4c0e..aa079f4fd6 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -1,6 +1,6 @@ { "name": "@aws/chat-client", - "version": "0.1.37", + "version": "0.1.38", "description": "AWS Chat Client", "main": "out/index.js", "repository": { diff --git a/core/aws-lsp-core/CHANGELOG.md b/core/aws-lsp-core/CHANGELOG.md index 7b08b5c071..935777970e 100644 --- a/core/aws-lsp-core/CHANGELOG.md +++ b/core/aws-lsp-core/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.0.16](https://github.com/aws/language-servers/compare/lsp-core/v0.0.15...lsp-core/v0.0.16) (2025-10-01) + + +### Bug Fixes + +* **amazonq:** Fix mock fs clean; Node version upgrade ([#2324](https://github.com/aws/language-servers/issues/2324)) ([1d9afd4](https://github.com/aws/language-servers/commit/1d9afd410e19624223e300ca06ea7d08a112cc82)) +* **amazonq:** handle IAM credentials expiration field to be aws sdk versions compatible and add refresh logic to codewhisperer IAM client ([#2349](https://github.com/aws/language-servers/issues/2349)) ([5eb3768](https://github.com/aws/language-servers/commit/5eb3768bf020d61d0ade767d62e13839048146e4)) + ## [0.0.15](https://github.com/aws/language-servers/compare/lsp-core/v0.0.14...lsp-core/v0.0.15) (2025-09-09) diff --git a/core/aws-lsp-core/package.json b/core/aws-lsp-core/package.json index d005da5751..d1dcc51ee4 100644 --- a/core/aws-lsp-core/package.json +++ b/core/aws-lsp-core/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-core", - "version": "0.0.15", + "version": "0.0.16", "description": "Core library, contains common code and utilities", "main": "out/index.js", "repository": { diff --git a/package-lock.json b/package-lock.json index ddb4074b11..ebbfc8606b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -251,7 +251,7 @@ }, "chat-client": { "name": "@aws/chat-client", - "version": "0.1.37", + "version": "0.1.38", "license": "Apache-2.0", "dependencies": { "@aws/chat-client-ui-types": "^0.1.56", @@ -293,7 +293,7 @@ }, "core/aws-lsp-core": { "name": "@aws/lsp-core", - "version": "0.0.15", + "version": "0.0.16", "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes": "^0.2.129", @@ -28612,11 +28612,11 @@ }, "server/aws-lsp-antlr4": { "name": "@aws/lsp-antlr4", - "version": "0.1.19", + "version": "0.1.20", "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes": "^0.2.129", - "@aws/lsp-core": "^0.0.15" + "@aws/lsp-core": "^0.0.16" }, "devDependencies": { "@babel/plugin-transform-modules-commonjs": "^7.24.1", @@ -28677,7 +28677,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.82", + "version": "0.0.83", "bundleDependencies": [ "@amzn/codewhisperer-streaming", "@amzn/amazon-q-developer-streaming-client" @@ -28691,7 +28691,7 @@ "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", "@aws/language-server-runtimes": "^0.2.129", - "@aws/lsp-core": "^0.0.15", + "@aws/lsp-core": "^0.0.16", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", "adm-zip": "^0.5.10", @@ -28893,11 +28893,11 @@ }, "server/aws-lsp-json": { "name": "@aws/lsp-json", - "version": "0.1.19", + "version": "0.1.20", "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes": "^0.2.129", - "@aws/lsp-core": "^0.0.15", + "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" }, @@ -29023,12 +29023,12 @@ }, "server/aws-lsp-yaml": { "name": "@aws/lsp-yaml", - "version": "0.1.19", + "version": "0.1.20", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes": "^0.2.129", - "@aws/lsp-core": "^0.0.15", + "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", "yaml-language-server": "1.13.0" diff --git a/server/aws-lsp-antlr4/CHANGELOG.md b/server/aws-lsp-antlr4/CHANGELOG.md index 64cab4eec1..a928a4900b 100644 --- a/server/aws-lsp-antlr4/CHANGELOG.md +++ b/server/aws-lsp-antlr4/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [0.1.20](https://github.com/aws/language-servers/compare/lsp-antlr4/v0.1.19...lsp-antlr4/v0.1.20) (2025-10-01) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @aws/lsp-core bumped from ^0.0.15 to ^0.0.16 + ## [0.1.19](https://github.com/aws/language-servers/compare/lsp-antlr4/v0.1.18...lsp-antlr4/v0.1.19) (2025-09-09) diff --git a/server/aws-lsp-antlr4/package.json b/server/aws-lsp-antlr4/package.json index 668c58742d..38758b8335 100644 --- a/server/aws-lsp-antlr4/package.json +++ b/server/aws-lsp-antlr4/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-antlr4", - "version": "0.1.19", + "version": "0.1.20", "description": "ANTLR4 language server", "main": "out/index.js", "repository": { @@ -29,7 +29,7 @@ }, "dependencies": { "@aws/language-server-runtimes": "^0.2.129", - "@aws/lsp-core": "^0.0.15" + "@aws/lsp-core": "^0.0.16" }, "peerDependencies": { "antlr4-c3": ">=3.4 < 4", diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index 6194b4ba1d..3f2fd79c58 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog +## [0.0.83](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.82...lsp-codewhisperer/v0.0.83) (2025-10-01) + + +### Bug Fixes + +* **amazonq:** escaping user input to mitigate xss issue ([#2360](https://github.com/aws/language-servers/issues/2360)) ([45b86be](https://github.com/aws/language-servers/commit/45b86bef1a93cf9ced6fbf0c222cf5410de04c81)) +* **amazonq:** fix to add opt-out header to streaming client ([#2365](https://github.com/aws/language-servers/issues/2365)) ([692e77b](https://github.com/aws/language-servers/commit/692e77bc99770ac7d676928e95e3dc43bb91e7f0)) +* **amazonq:** handle IAM credentials expiration field to be aws sdk versions compatible and add refresh logic to codewhisperer IAM client ([#2349](https://github.com/aws/language-servers/issues/2349)) ([5eb3768](https://github.com/aws/language-servers/commit/5eb3768bf020d61d0ade767d62e13839048146e4)) +* **amazonq:** send full finding details to plugin, partial to agent ([#2356](https://github.com/aws/language-servers/issues/2356)) ([961e6ca](https://github.com/aws/language-servers/commit/961e6ca11b122481685f9f65b3da14c6a2497cc4)) +* improve history management ([#2312](https://github.com/aws/language-servers/issues/2312)) ([#2357](https://github.com/aws/language-servers/issues/2357)) ([e7aa2a6](https://github.com/aws/language-servers/commit/e7aa2a6545bcb1a8238abfde69a05432be0b6615)) +* optimize memory bank token usage and add new tab support ([#2366](https://github.com/aws/language-servers/issues/2366)) ([3057d56](https://github.com/aws/language-servers/commit/3057d56e4a3047d1715d6e3560e9f934d1de469c)) +* private package mapping during artifact generation ([#2348](https://github.com/aws/language-servers/issues/2348)) ([d56bfa1](https://github.com/aws/language-servers/commit/d56bfa191954fac8068e2bf390c2d0b88ef8b168)) +* trim new line when emitting error message ([#2359](https://github.com/aws/language-servers/issues/2359)) ([d8733a7](https://github.com/aws/language-servers/commit/d8733a75487f74815302b838802eccbf3ffec55e)) + + +### Reverts + +* fix to add opt-out header to streaming client ([#2365](https://github.com/aws/language-servers/issues/2365)) ([#2370](https://github.com/aws/language-servers/issues/2370)) ([b29478f](https://github.com/aws/language-servers/commit/b29478fa1ecc58e331ff330ff79f46b0d8c38d9e)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @aws/lsp-core bumped from ^0.0.15 to ^0.0.16 + ## [0.0.82](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.81...lsp-codewhisperer/v0.0.82) (2025-09-24) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 0f5e7d0ff1..6219fc5798 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.82", + "version": "0.0.83", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { @@ -37,7 +37,7 @@ "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.56", "@aws/language-server-runtimes": "^0.2.129", - "@aws/lsp-core": "^0.0.15", + "@aws/lsp-core": "^0.0.16", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", "adm-zip": "^0.5.10", diff --git a/server/aws-lsp-json/CHANGELOG.md b/server/aws-lsp-json/CHANGELOG.md index de134b8f6e..4d7881502c 100644 --- a/server/aws-lsp-json/CHANGELOG.md +++ b/server/aws-lsp-json/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [0.1.20](https://github.com/aws/language-servers/compare/lsp-json/v0.1.19...lsp-json/v0.1.20) (2025-10-01) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @aws/lsp-core bumped from ^0.0.15 to ^0.0.16 + ## [0.1.19](https://github.com/aws/language-servers/compare/lsp-json/v0.1.18...lsp-json/v0.1.19) (2025-09-09) diff --git a/server/aws-lsp-json/package.json b/server/aws-lsp-json/package.json index 919fb24959..e4c5b50679 100644 --- a/server/aws-lsp-json/package.json +++ b/server/aws-lsp-json/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-json", - "version": "0.1.19", + "version": "0.1.20", "description": "JSON Language Server", "main": "out/index.js", "repository": { @@ -27,7 +27,7 @@ }, "dependencies": { "@aws/language-server-runtimes": "^0.2.129", - "@aws/lsp-core": "^0.0.15", + "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" }, diff --git a/server/aws-lsp-yaml/CHANGELOG.md b/server/aws-lsp-yaml/CHANGELOG.md index c43fc8f8f3..bedb0ee095 100644 --- a/server/aws-lsp-yaml/CHANGELOG.md +++ b/server/aws-lsp-yaml/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [0.1.20](https://github.com/aws/language-servers/compare/lsp-yaml/v0.1.19...lsp-yaml/v0.1.20) (2025-10-01) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @aws/lsp-core bumped from ^0.0.15 to ^0.0.16 + ## [0.1.19](https://github.com/aws/language-servers/compare/lsp-yaml/v0.1.18...lsp-yaml/v0.1.19) (2025-09-09) diff --git a/server/aws-lsp-yaml/package.json b/server/aws-lsp-yaml/package.json index c6f4b5267c..719f94bf6e 100644 --- a/server/aws-lsp-yaml/package.json +++ b/server/aws-lsp-yaml/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-yaml", - "version": "0.1.19", + "version": "0.1.20", "description": "YAML Language Server", "main": "out/index.js", "repository": { @@ -27,7 +27,7 @@ }, "dependencies": { "@aws/language-server-runtimes": "^0.2.129", - "@aws/lsp-core": "^0.0.15", + "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", "yaml-language-server": "1.13.0" From 8a2aa3409d7b63197459440e0fc4344ba6cd37d7 Mon Sep 17 00:00:00 2001 From: Sherry Lu <75588211+XiaoxuanLu@users.noreply.github.com> Date: Wed, 1 Oct 2025 18:28:49 -0700 Subject: [PATCH 123/158] chore: bump agentic version: 1.37.0 (#2379) Co-authored-by: aws-toolkit-automation <> --- app/aws-lsp-codewhisperer-runtimes/src/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/src/version.json b/app/aws-lsp-codewhisperer-runtimes/src/version.json index ee9ac885e6..2be2534d8f 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/version.json +++ b/app/aws-lsp-codewhisperer-runtimes/src/version.json @@ -1,3 +1,3 @@ { - "agenticChat": "1.36.0" + "agenticChat": "1.37.0" } From 9f745a3ca6fef1ec2c80982b316749ab60b4a394 Mon Sep 17 00:00:00 2001 From: atontb <104926752+atonaamz@users.noreply.github.com> Date: Thu, 2 Oct 2025 13:44:27 -0700 Subject: [PATCH 124/158] chore(amazonq): refactor codeWhispereServer.ts (#2373) --- .../codeWhispererServer.test.ts | 1 - .../inline-completion/codeWhispererServer.ts | 724 ++---------------- .../{ => handler}/editCompletionHandler.ts | 32 +- .../handler/inlineCompletionHandler.test.ts | 146 ++++ .../handler/inlineCompletionHandler.ts | 512 +++++++++++++ .../handler/sessionResultsHandler.test.ts | 182 +++++ .../handler/sessionResultsHandler.ts | 162 ++++ .../userTriggerDecision.test.ts | 12 +- 8 files changed, 1083 insertions(+), 688 deletions(-) rename server/aws-lsp-codewhisperer/src/language-server/inline-completion/{ => handler}/editCompletionHandler.ts (94%) create mode 100644 server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.ts rename server/aws-lsp-codewhisperer/src/language-server/inline-completion/{ => telemetry}/userTriggerDecision.test.ts (99%) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts index a2028d3708..149177f60e 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts @@ -27,7 +27,6 @@ import { EXPECTED_REFERENCE, EXPECTED_RESPONSE_CONTEXT, EXPECTED_RESULT, - EXPECTED_RESULT_EDITS, EXPECTED_RESULT_WITHOUT_IMPORTS, EXPECTED_RESULT_WITHOUT_REFERENCES, EXPECTED_RESULT_WITH_IMPORTS, diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts index db7970f6eb..7071d8821b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts @@ -1,109 +1,35 @@ import { CancellationToken, InitializeParams, - InlineCompletionItemWithReferences, InlineCompletionListWithReferences, - InlineCompletionTriggerKind, InlineCompletionWithReferencesParams, - LogInlineCompletionSessionResultsParams, - Range, Server, - TextDocument, - ResponseError, - LSPErrorCodes, } from '@aws/language-server-runtimes/server-interface' -import { autoTrigger, getAutoTriggerType, getNormalizeOsName, triggerType } from './auto-trigger/autoTrigger' -import { - FileContext, - BaseGenerateSuggestionsRequest, - CodeWhispererServiceToken, - GenerateIAMSuggestionsRequest, - GenerateTokenSuggestionsRequest, - GenerateSuggestionsRequest, - GenerateSuggestionsResponse, - getFileContext, - Suggestion, - SuggestionType, -} from '../../shared/codeWhispererService' -import { CodewhispererLanguage, getSupportedLanguageId } from '../../shared/languageDetection' -import { truncateOverlapWithRightContext } from './utils/mergeRightUtils' -import { CodeWhispererSession, SessionManager } from './session/sessionManager' +import { getSupportedLanguageId } from '../../shared/languageDetection' +import { SessionManager } from './session/sessionManager' import { CodePercentageTracker } from './tracker/codePercentageTracker' -import { getCompletionType, getEndPositionForAcceptedSuggestion, getErrorMessage, safeGet } from '../../shared/utils' -import { getIdeCategory, makeUserContextObject } from '../../shared/telemetryUtils' -import { textUtils } from '@aws/lsp-core' +import { safeGet } from '../../shared/utils' +import { makeUserContextObject } from '../../shared/telemetryUtils' import { TelemetryService } from '../../shared/telemetry/telemetryService' import { AcceptedInlineSuggestionEntry, CodeDiffTracker } from './tracker/codeDiffTracker' -import { - AmazonQError, - AmazonQServiceConnectionExpiredError, - AmazonQServiceInitializationError, -} from '../../shared/amazonQServiceManager/errors' +import { AmazonQServiceInitializationError } from '../../shared/amazonQServiceManager/errors' import { AmazonQBaseServiceManager } from '../../shared/amazonQServiceManager/BaseAmazonQServiceManager' import { getOrThrowBaseTokenServiceManager } from '../../shared/amazonQServiceManager/AmazonQTokenServiceManager' import { AmazonQWorkspaceConfig } from '../../shared/amazonQServiceManager/configurationUtils' -import { hasConnectionExpired } from '../../shared/utils' import { getOrThrowBaseIAMServiceManager } from '../../shared/amazonQServiceManager/AmazonQIAMServiceManager' -import { WorkspaceFolderManager } from '../workspaceContext/workspaceFolderManager' import { UserWrittenCodeTracker } from '../../shared/userWrittenCodeTracker' import { RecentEditTracker, RecentEditTrackerDefaultConfig } from './tracker/codeEditTracker' import { CursorTracker } from './tracker/cursorTracker' import { RejectedEditTracker, DEFAULT_REJECTED_EDIT_TRACKER_CONFIG } from './tracker/rejectedEditTracker' import { StreakTracker } from './tracker/streakTracker' -import { getAddedAndDeletedLines, getCharacterDifferences } from './utils/diffUtils' -import { - emitPerceivedLatencyTelemetry, - emitServiceInvocationFailure, - emitServiceInvocationTelemetry, - emitUserTriggerDecisionTelemetry, -} from './telemetry/telemetry' import { DocumentChangedListener } from './documentChangedListener' -import { EditCompletionHandler } from './editCompletionHandler' -import { EMPTY_RESULT, ABAP_EXTENSIONS } from './contants/constants' -import { IdleWorkspaceManager } from '../workspaceContext/IdleWorkspaceManager' -import { URI } from 'vscode-uri' +import { EditCompletionHandler } from './handler/editCompletionHandler' +import { InlineCompletionHandler } from './handler/inlineCompletionHandler' +import { SessionResultsHandler } from './handler/sessionResultsHandler' import { isUsingIAMAuth } from '../../shared/utils' - -const mergeSuggestionsWithRightContext = ( - rightFileContext: string, - suggestions: Suggestion[], - includeImportsWithSuggestions: boolean, - range?: Range -): InlineCompletionItemWithReferences[] => { - return suggestions.map(suggestion => { - const insertText: string = truncateOverlapWithRightContext(rightFileContext, suggestion.content) - let references = suggestion.references - ?.filter( - ref => - !( - ref.recommendationContentSpan?.start && insertText.length <= ref.recommendationContentSpan.start - ) && insertText.length - ) - .map(r => { - return { - licenseName: r.licenseName, - referenceUrl: r.url, - referenceName: r.repository, - position: r.recommendationContentSpan && { - startCharacter: r.recommendationContentSpan.start, - endCharacter: r.recommendationContentSpan.end - ? Math.min(r.recommendationContentSpan.end, insertText.length - 1) - : r.recommendationContentSpan.end, - }, - } - }) - - return { - itemId: suggestion.itemId, - insertText: insertText, - range, - references: references?.length ? references : undefined, - mostRelevantMissingImports: includeImportsWithSuggestions - ? suggestion.mostRelevantMissingImports - : undefined, - } - }) -} +import { TextDocument } from '@aws/language-server-runtimes/server-interface' +import { ABAP_EXTENSIONS } from './contants/constants' +import { URI } from 'vscode-uri' export const CodewhispererServerFactory = (serviceManager: (credentialsProvider?: any) => AmazonQBaseServiceManager): Server => @@ -129,6 +55,7 @@ export const CodewhispererServerFactory = let userWrittenCodeTracker: UserWrittenCodeTracker | undefined let codeDiffTracker: CodeDiffTracker let editCompletionHandler: EditCompletionHandler + let inlineCompletionHandler: InlineCompletionHandler // Trackers for monitoring edits and cursor position. const recentEditTracker = RecentEditTracker.getInstance(logging, RecentEditTrackerDefaultConfig) @@ -136,7 +63,6 @@ export const CodewhispererServerFactory = const rejectedEditTracker = RejectedEditTracker.getInstance(logging, DEFAULT_REJECTED_EDIT_TRACKER_CONFIG) const streakTracker = StreakTracker.getInstance() let editsEnabled = false - let isOnInlineCompletionHandlerInProgress = false const documentChangedListener = new DocumentChangedListener() @@ -144,577 +70,10 @@ export const CodewhispererServerFactory = params: InlineCompletionWithReferencesParams, token: CancellationToken ): Promise => { - // this handle should not run concurrently because - // 1. it would create a high volume of traffic, causing throttling - // 2. it is not designed to handle concurrent changes to these state variables. - // when one handler is at the API call stage, it has not yet update the session state - // but another request can start, causing the state to be incorrect. - IdleWorkspaceManager.recordActivityTimestamp() - - if (isOnInlineCompletionHandlerInProgress) { - logging.log(`Skip concurrent inline completion`) - return EMPTY_RESULT - } - - // Add this check to ensure service manager is initialized - if (!amazonQServiceManager) { - logging.log('Amazon Q Service Manager not initialized yet') - return EMPTY_RESULT - } - - isOnInlineCompletionHandlerInProgress = true - - try { - // On every new completion request close current inflight session. - const currentSession = completionSessionManager.getCurrentSession() - if (currentSession && currentSession.state == 'REQUESTING' && !params.partialResultToken) { - // this REQUESTING state only happens when the session is initialized, which is rare - currentSession.discardInflightSessionOnNewInvocation = true - } - - if (cursorTracker) { - cursorTracker.trackPosition(params.textDocument.uri, params.position) - } - const textDocument = await getTextDocument(params.textDocument.uri, workspace, logging) - - const codeWhispererService = amazonQServiceManager.getCodewhispererService() - const authType = codeWhispererService instanceof CodeWhispererServiceToken ? 'token' : 'iam' - logging.debug( - `[INLINE_COMPLETION] Service ready - auth: ${authType}, partial token: ${!!params.partialResultToken}` - ) - if (params.partialResultToken && currentSession) { - // subsequent paginated requests for current session - try { - const suggestionResponse = await codeWhispererService.generateSuggestions({ - ...currentSession.requestContext, - fileContext: { - ...currentSession.requestContext.fileContext, - }, - nextToken: `${params.partialResultToken}`, - }) - return await processSuggestionResponse( - suggestionResponse, - currentSession, - false, - params.context.selectedCompletionInfo?.range - ) - } catch (error) { - return handleSuggestionsErrors(error as Error, currentSession) - } - } else { - // request for new session - if (!textDocument) { - logging.log(`textDocument [${params.textDocument.uri}] not found`) - return EMPTY_RESULT - } - - let inferredLanguageId = getSupportedLanguageId(textDocument) - if (params.fileContextOverride?.programmingLanguage) { - inferredLanguageId = params.fileContextOverride?.programmingLanguage as CodewhispererLanguage - } - if (!inferredLanguageId) { - logging.log( - `textDocument [${params.textDocument.uri}] with languageId [${textDocument.languageId}] not supported` - ) - return EMPTY_RESULT - } - - // Build request context - const isAutomaticLspTriggerKind = - params.context.triggerKind == InlineCompletionTriggerKind.Automatic - const maxResults = isAutomaticLspTriggerKind ? 1 : 5 - const selectionRange = params.context.selectedCompletionInfo?.range - - const startPreprocessTimestamp = Date.now() - - // For Jupyter Notebook in VSC, the language server does not have access to - // its internal states including current active cell index, etc - // we rely on VSC to calculate file context - let fileContext: FileContext | undefined = undefined - if (params.fileContextOverride) { - fileContext = { - leftFileContent: params.fileContextOverride.leftFileContent, - rightFileContent: params.fileContextOverride.rightFileContent, - filename: params.fileContextOverride.filename, - fileUri: params.fileContextOverride.fileUri, - programmingLanguage: { - languageName: inferredLanguageId, - }, - } - } else { - fileContext = getFileContext({ - textDocument, - inferredLanguageId, - position: params.position, - workspaceFolder: workspace.getWorkspaceFolder(textDocument.uri), - }) - } - - const workspaceState = WorkspaceFolderManager.getInstance()?.getWorkspaceState() - const workspaceId = workspaceState?.webSocketClient?.isConnected() - ? workspaceState.workspaceId - : undefined - - const previousSession = completionSessionManager.getPreviousSession() - // Only refer to decisions in the past 2 mins - const previousDecisionForClassifier = - previousSession && Date.now() - previousSession.decisionMadeTimestamp <= 2 * 60 * 1000 - ? previousSession.getAggregatedUserTriggerDecision() - : undefined - let ideCategory: string | undefined = '' - const initializeParams = lsp.getClientInitializeParams() - if (initializeParams !== undefined) { - ideCategory = getIdeCategory(initializeParams) - } - - // auto trigger code path - let codewhispererAutoTriggerType = undefined - let triggerCharacters = '' - let autoTriggerResult = undefined - - if (isAutomaticLspTriggerKind) { - // Reference: https://github.com/aws/aws-toolkit-vscode/blob/amazonq/v1.74.0/packages/core/src/codewhisperer/service/classifierTrigger.ts#L477 - if ( - params.documentChangeParams?.contentChanges && - params.documentChangeParams.contentChanges.length > 0 && - params.documentChangeParams.contentChanges[0].text !== undefined - ) { - triggerCharacters = params.documentChangeParams.contentChanges[0].text - codewhispererAutoTriggerType = getAutoTriggerType( - params.documentChangeParams.contentChanges - ) - } else { - // if the client does not emit document change for the trigger, use left most character. - triggerCharacters = fileContext.leftFileContent.trim().at(-1) ?? '' - codewhispererAutoTriggerType = triggerType(fileContext) - } - // See: https://github.com/aws/aws-toolkit-vscode/blob/amazonq/v1.74.0/packages/core/src/codewhisperer/service/keyStrokeHandler.ts#L132 - // In such cases, do not auto trigger. - if (codewhispererAutoTriggerType === undefined) { - return EMPTY_RESULT - } - - autoTriggerResult = autoTrigger( - { - fileContext, // The left/right file context and programming language - lineNum: params.position.line, // the line number of the invocation, this is the line of the cursor - char: triggerCharacters, // Add the character just inserted, if any, before the invication position - ide: ideCategory ?? '', - os: getNormalizeOsName(), - previousDecision: previousDecisionForClassifier, // The last decision by the user on the previous invocation - triggerType: codewhispererAutoTriggerType, // The 2 trigger types currently influencing the Auto-Trigger are SpecialCharacter and Enter - }, - logging - ) - - if (codewhispererAutoTriggerType === 'Classifier' && !autoTriggerResult.shouldTrigger) { - return EMPTY_RESULT - } - } - - let requestContext: GenerateSuggestionsRequest = { - fileContext, - maxResults, - } - - const supplementalContext = await codeWhispererService.constructSupplementalContext( - textDocument, - params.position, - workspace, - recentEditTracker, - logging, - token, - params.openTabFilepaths, - { includeRecentEdits: false } - ) - - if (supplementalContext?.items) { - requestContext.supplementalContexts = supplementalContext.items - } - - // Close ACTIVE session and record Discard trigger decision immediately - if (currentSession && currentSession.state === 'ACTIVE') { - // Emit user trigger decision at session close time for active session - // TODO: yuxqiang workaround to exclude JB from this logic because JB and VSC handle a - // bit differently in the case when there's a new trigger while a reject/discard event is sent - // for the previous trigger - if (ideCategory !== 'JETBRAINS') { - completionSessionManager.discardSession(currentSession) - const streakLength = editsEnabled ? streakTracker.getAndUpdateStreakLength(false) : 0 - await emitUserTriggerDecisionTelemetry( - telemetry, - telemetryService, - currentSession, - timeSinceLastUserModification, - 0, - 0, - [], - [], - streakLength - ) - } - } - - const supplementalMetadata = supplementalContext?.supContextData - - const newSession = completionSessionManager.createSession({ - document: textDocument, - startPreprocessTimestamp: startPreprocessTimestamp, - startPosition: params.position, - triggerType: isAutomaticLspTriggerKind ? 'AutoTrigger' : 'OnDemand', - language: fileContext.programmingLanguage.languageName as CodewhispererLanguage, - requestContext: requestContext, - autoTriggerType: isAutomaticLspTriggerKind ? codewhispererAutoTriggerType : undefined, - triggerCharacter: triggerCharacters, - classifierResult: autoTriggerResult?.classifierResult, - classifierThreshold: autoTriggerResult?.classifierThreshold, - credentialStartUrl: credentialsProvider.getConnectionMetadata?.()?.sso?.startUrl ?? undefined, - supplementalMetadata: supplementalMetadata, - customizationArn: textUtils.undefinedIfEmpty(codeWhispererService.customizationArn), - }) - - // Add extra context to request context - const { extraContext } = amazonQServiceManager.getConfiguration().inlineSuggestions - if (extraContext) { - requestContext.fileContext.leftFileContent = - extraContext + '\n' + requestContext.fileContext.leftFileContent - } - - // Create the appropriate request based on service type - let generateCompletionReq: BaseGenerateSuggestionsRequest - - if (codeWhispererService instanceof CodeWhispererServiceToken) { - const tokenRequest = requestContext as GenerateTokenSuggestionsRequest - generateCompletionReq = { - ...tokenRequest, - ...(workspaceId ? { workspaceId } : {}), - } - } else { - const iamRequest = requestContext as GenerateIAMSuggestionsRequest - generateCompletionReq = { - ...iamRequest, - } - } - - try { - const authType = codeWhispererService instanceof CodeWhispererServiceToken ? 'token' : 'iam' - logging.debug(`[INLINE_COMPLETION] API call - generateSuggestions (new session, ${authType})`) - const suggestionResponse = await codeWhispererService.generateSuggestions(generateCompletionReq) - return await processSuggestionResponse(suggestionResponse, newSession, true, selectionRange) - } catch (error) { - return handleSuggestionsErrors(error as Error, newSession) - } - } - } finally { - isOnInlineCompletionHandlerInProgress = false - } - } - - const processSuggestionResponse = async ( - suggestionResponse: GenerateSuggestionsResponse, - session: CodeWhispererSession, - isNewSession: boolean, - selectionRange?: Range, - textDocument?: TextDocument - ): Promise => { - codePercentageTracker.countInvocation(session.language) - - userWrittenCodeTracker?.recordUsageCount(session.language) - session.includeImportsWithSuggestions = - amazonQServiceManager.getConfiguration().includeImportsWithSuggestions - - if (isNewSession) { - // Populate the session with information from codewhisperer response - session.suggestions = suggestionResponse.suggestions - session.responseContext = suggestionResponse.responseContext - session.codewhispererSessionId = suggestionResponse.responseContext.codewhispererSessionId - session.setTimeToFirstRecommendation() - session.predictionType = SuggestionType.COMPLETION - } else { - session.suggestions = [...session.suggestions, ...suggestionResponse.suggestions] - } - - // Emit service invocation telemetry for every request sent to backend - emitServiceInvocationTelemetry(telemetry, session, suggestionResponse.responseContext.requestId) - - // Discard previous inflight API response due to new trigger - if (session.discardInflightSessionOnNewInvocation) { - session.discardInflightSessionOnNewInvocation = false - completionSessionManager.discardSession(session) - const streakLength = editsEnabled ? streakTracker.getAndUpdateStreakLength(false) : 0 - await emitUserTriggerDecisionTelemetry( - telemetry, - telemetryService, - session, - timeSinceLastUserModification, - 0, - 0, - [], - [], - streakLength - ) - } - - // session was closed by user already made decisions consequent completion request before new paginated API response was received - if ( - session.predictionType !== SuggestionType.EDIT && // TODO: this is a shorterm fix to allow Edits tabtabtab experience, however the real solution is to manage such sessions correctly - (session.state === 'CLOSED' || session.state === 'DISCARD') - ) { - return EMPTY_RESULT - } - - // API response was recieved, we can activate session now - completionSessionManager.activateSession(session) - - // Process suggestions to apply Empty or Filter filters - const filteredSuggestions = suggestionResponse.suggestions - // Empty suggestion filter - .filter(suggestion => { - if (suggestion.content === '') { - session.setSuggestionState(suggestion.itemId, 'Empty') - return false - } - - return true - }) - // References setting filter - .filter(suggestion => { - // State to track whether code with references should be included in - // the response. No locking or concurrency controls, filtering is done - // right before returning and is only guaranteed to be consistent within - // the context of a single response. - const { includeSuggestionsWithCodeReferences } = amazonQServiceManager.getConfiguration() - if (includeSuggestionsWithCodeReferences) { - return true - } - - if (suggestion.references == null || suggestion.references.length === 0) { - return true - } - - // Filter out suggestions that have references when includeSuggestionsWithCodeReferences setting is true - session.setSuggestionState(suggestion.itemId, 'Filter') - return false - }) - - const { includeImportsWithSuggestions } = amazonQServiceManager.getConfiguration() - const suggestionsWithRightContext = mergeSuggestionsWithRightContext( - session.requestContext.fileContext.rightFileContent, - filteredSuggestions, - includeImportsWithSuggestions, - selectionRange - ).filter(suggestion => { - // Discard suggestions that have empty string insertText after right context merge and can't be displayed anymore - if (suggestion.insertText === '') { - session.setSuggestionState(suggestion.itemId, 'Discard') - return false - } - - return true - }) - - suggestionsWithRightContext.forEach(suggestion => { - const cachedSuggestion = session.suggestions.find(s => s.itemId === suggestion.itemId) - if (cachedSuggestion) cachedSuggestion.insertText = suggestion.insertText.toString() - }) - - // TODO: need dedupe after right context merging but I don't see one - session.suggestionsAfterRightContextMerge.push(...suggestionsWithRightContext) - - session.codewhispererSuggestionImportCount = - session.codewhispererSuggestionImportCount + - suggestionsWithRightContext.reduce((total, suggestion) => { - return total + (suggestion.mostRelevantMissingImports?.length || 0) - }, 0) - - // If after all server-side filtering no suggestions can be displayed, and there is no nextToken - // close session and return empty results - if ( - session.suggestionsAfterRightContextMerge.length === 0 && - !suggestionResponse.responseContext.nextToken - ) { - completionSessionManager.closeSession(session) - await emitUserTriggerDecisionTelemetry( - telemetry, - telemetryService, - session, - timeSinceLastUserModification - ) - - return EMPTY_RESULT - } - - return { - items: suggestionsWithRightContext, - sessionId: session.id, - partialResultToken: suggestionResponse.responseContext.nextToken, - } - } - - const handleSuggestionsErrors = ( - error: Error, - session: CodeWhispererSession - ): InlineCompletionListWithReferences => { - logging.log('Recommendation failure: ' + error) - - emitServiceInvocationFailure(telemetry, session, error) - - // UTDE telemetry is not needed here because in error cases we don't care about UTDE for errored out sessions - completionSessionManager.closeSession(session) - - let translatedError = error - - if (hasConnectionExpired(error)) { - translatedError = new AmazonQServiceConnectionExpiredError(getErrorMessage(error)) - } - - if (translatedError instanceof AmazonQError) { - throw new ResponseError( - LSPErrorCodes.RequestFailed, - translatedError.message || 'Error processing suggestion requests', - { - awsErrorCode: translatedError.code, - } - ) - } - - return EMPTY_RESULT - } - - // Schedule tracker for UserModification Telemetry event - const enqueueCodeDiffEntry = ( - session: CodeWhispererSession, - acceptedSuggestion: Suggestion, - addedCharactersForEdit?: string - ) => { - const endPosition = getEndPositionForAcceptedSuggestion(acceptedSuggestion.content, session.startPosition) - // use the addedCharactersForEdit if it is EDIT suggestion type - const originalString = addedCharactersForEdit ? addedCharactersForEdit : acceptedSuggestion.content - - codeDiffTracker.enqueue({ - sessionId: session.codewhispererSessionId || '', - requestId: session.responseContext?.requestId || '', - fileUrl: session.document.uri, - languageId: session.language, - time: Date.now(), - originalString: originalString, - startPosition: session.startPosition, - endPosition: endPosition, - customizationArn: session.customizationArn, - completionType: getCompletionType(acceptedSuggestion), - triggerType: session.triggerType, - credentialStartUrl: session.credentialStartUrl, - }) + return await inlineCompletionHandler.onInlineCompletion(params, token) } - const onLogInlineCompletionSessionResultsHandler = async (params: LogInlineCompletionSessionResultsParams) => { - const { - sessionId, - completionSessionResult, - firstCompletionDisplayLatency, - totalSessionDisplayTime, - typeaheadLength, - isInlineEdit, - addedDiagnostics, - removedDiagnostics, - } = params - - const sessionManager = params.isInlineEdit ? editSessionManager : completionSessionManager - - const session = sessionManager.getSessionById(sessionId) - if (!session) { - logging.log(`ERROR: Session ID ${sessionId} was not found`) - return - } - - if (session.state !== 'ACTIVE') { - logging.log( - `ERROR: Trying to record trigger decision for not-active session ${sessionId} with wrong state ${session.state}` - ) - return - } - - const acceptedItemId = Object.keys(params.completionSessionResult).find( - k => params.completionSessionResult[k].accepted - ) - const isAccepted = acceptedItemId ? true : false - const acceptedSuggestion = session.suggestions.find(s => s.itemId === acceptedItemId) - let addedLengthForEdits = 0 - let deletedLengthForEdits = 0 - if (acceptedSuggestion) { - codePercentageTracker.countSuccess(session.language) - if (session.predictionType === SuggestionType.EDIT && acceptedSuggestion.content) { - // [acceptedSuggestion.insertText] will be undefined for NEP suggestion. Use [acceptedSuggestion.content] instead. - // Since [acceptedSuggestion.content] is in the form of a diff, transform the content into addedCharacters and deletedCharacters. - const { addedLines, deletedLines } = getAddedAndDeletedLines(acceptedSuggestion.content) - const charDiffResult = getCharacterDifferences(addedLines, deletedLines) - addedLengthForEdits = charDiffResult.charactersAdded - deletedLengthForEdits = charDiffResult.charactersRemoved - - codePercentageTracker.countAcceptedTokensUsingCount( - session.language, - charDiffResult.charactersAdded - ) - codePercentageTracker.addTotalTokensForEdits(session.language, charDiffResult.charactersAdded) - enqueueCodeDiffEntry(session, acceptedSuggestion, addedLines.join('\n')) - } else if (acceptedSuggestion.insertText) { - codePercentageTracker.countAcceptedTokens(session.language, acceptedSuggestion.insertText) - codePercentageTracker.countTotalTokens(session.language, acceptedSuggestion.insertText, true) - - enqueueCodeDiffEntry(session, acceptedSuggestion) - } - } - - // Handle rejected edit predictions - if (isInlineEdit && !isAccepted) { - // Find all rejected suggestions in this session - const rejectedSuggestions = session.suggestions.filter(suggestion => { - const result = completionSessionResult[suggestion.itemId] - return result && result.seen && !result.accepted - }) - - // Record each rejected edit - for (const rejectedSuggestion of rejectedSuggestions) { - if (rejectedSuggestion.content) { - rejectedEditTracker.recordRejectedEdit({ - content: rejectedSuggestion.content, - timestamp: Date.now(), - documentUri: session.document.uri, - position: session.startPosition, - }) - - logging.debug( - `[EDIT_PREDICTION] Recorded rejected edit: ${rejectedSuggestion.content.substring(0, 20)}...` - ) - } - } - } - - session.setClientResultData( - completionSessionResult, - firstCompletionDisplayLatency, - totalSessionDisplayTime, - typeaheadLength - ) - - if (firstCompletionDisplayLatency) emitPerceivedLatencyTelemetry(telemetry, session) - - // Always emit user trigger decision at session close - sessionManager.closeSession(session) - const streakLength = editsEnabled ? streakTracker.getAndUpdateStreakLength(isAccepted) : 0 - await emitUserTriggerDecisionTelemetry( - telemetry, - telemetryService, - session, - timeSinceLastUserModification, - addedLengthForEdits, - deletedLengthForEdits, - addedDiagnostics, - removedDiagnostics, - streakLength, - Object.keys(params.completionSessionResult)[0] - ) - } + let sessionResultsHandler: SessionResultsHandler const updateConfiguration = (updatedConfig: AmazonQWorkspaceConfig) => { logging.debug('Updating configuration of inline complete server.') @@ -804,6 +163,39 @@ export const CodewhispererServerFactory = telemetryService, credentialsProvider ) + + inlineCompletionHandler = new InlineCompletionHandler( + logging, + workspace, + amazonQServiceManager, + completionSessionManager, + codePercentageTracker, + userWrittenCodeTracker, + recentEditTracker, + cursorTracker, + streakTracker, + telemetry, + telemetryService, + credentialsProvider, + () => editsEnabled, + () => timeSinceLastUserModification, + lsp, + getTextDocument + ) + + sessionResultsHandler = new SessionResultsHandler( + logging, + telemetry, + telemetryService, + completionSessionManager, + editSessionManager, + codePercentageTracker, + codeDiffTracker, + rejectedEditTracker, + streakTracker, + () => editsEnabled, + () => timeSinceLastUserModification + ) } const onEditCompletion = async ( @@ -815,7 +207,9 @@ export const CodewhispererServerFactory = lsp.extensions.onInlineCompletionWithReferences(onInlineCompletionHandler) lsp.extensions.onEditCompletion(onEditCompletion) - lsp.extensions.onLogInlineCompletionSessionResults(onLogInlineCompletionSessionResultsHandler) + lsp.extensions.onLogInlineCompletionSessionResults(async params => { + await sessionResultsHandler.handleSessionResults(params) + }) lsp.onInitialized(onInitializedHandler) lsp.onDidChangeTextDocument(async p => { @@ -908,14 +302,6 @@ export const CodewhispererServerFactory = } } -// Dynamic service manager factory that detects auth type at runtime -export const CodeWhispererServer = CodewhispererServerFactory((credentialsProvider?: any) => { - return isUsingIAMAuth(credentialsProvider) ? getOrThrowBaseIAMServiceManager() : getOrThrowBaseTokenServiceManager() -}) - -export const CodeWhispererServerIAM = CodewhispererServerFactory(getOrThrowBaseIAMServiceManager) -export const CodeWhispererServerToken = CodewhispererServerFactory(getOrThrowBaseTokenServiceManager) - export const getLanguageIdFromUri = (uri: string, logging?: any): string => { try { if (uri.startsWith('vscode-notebook-cell:')) { @@ -930,7 +316,7 @@ export const getLanguageIdFromUri = (uri: string, logging?: any): string => { } } -const getTextDocument = async (uri: string, workspace: any, logging: any): Promise => { +export const getTextDocument = async (uri: string, workspace: any, logging: any): Promise => { let textDocument = await workspace.getTextDocument(uri) if (!textDocument) { try { @@ -943,3 +329,11 @@ const getTextDocument = async (uri: string, workspace: any, logging: any): Promi } return textDocument } + +// Dynamic service manager factory that detects auth type at runtime +export const CodeWhispererServer = CodewhispererServerFactory((credentialsProvider?: any) => { + return isUsingIAMAuth(credentialsProvider) ? getOrThrowBaseIAMServiceManager() : getOrThrowBaseTokenServiceManager() +}) + +export const CodeWhispererServerIAM = CodewhispererServerFactory(getOrThrowBaseIAMServiceManager) +export const CodeWhispererServerToken = CodewhispererServerFactory(getOrThrowBaseTokenServiceManager) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts similarity index 94% rename from server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts rename to server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts index ae7ddfb065..badd538143 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts @@ -9,7 +9,7 @@ import { ResponseError, TextDocument, } from '@aws/language-server-runtimes/protocol' -import { RecentEditTracker } from './tracker/codeEditTracker' +import { RecentEditTracker } from '../tracker/codeEditTracker' import { CredentialsProvider, Logging, Telemetry, Workspace } from '@aws/language-server-runtimes/server-interface' import { CodeWhispererServiceToken, @@ -17,27 +17,27 @@ import { GenerateSuggestionsResponse, getFileContext, SuggestionType, -} from '../../shared/codeWhispererService' -import { CodeWhispererSession, SessionManager } from './session/sessionManager' -import { CursorTracker } from './tracker/cursorTracker' -import { CodewhispererLanguage, getSupportedLanguageId } from '../../shared/languageDetection' -import { WorkspaceFolderManager } from '../workspaceContext/workspaceFolderManager' -import { shouldTriggerEdits } from './trigger' +} from '../../../shared/codeWhispererService' +import { CodeWhispererSession, SessionManager } from '../session/sessionManager' +import { CursorTracker } from '../tracker/cursorTracker' +import { CodewhispererLanguage, getSupportedLanguageId } from '../../../shared/languageDetection' +import { WorkspaceFolderManager } from '../../workspaceContext/workspaceFolderManager' +import { shouldTriggerEdits } from '../trigger' import { emitEmptyUserTriggerDecisionTelemetry, emitServiceInvocationFailure, emitServiceInvocationTelemetry, emitUserTriggerDecisionTelemetry, -} from './telemetry/telemetry' -import { TelemetryService } from '../../shared/telemetry/telemetryService' +} from '../telemetry/telemetry' +import { TelemetryService } from '../../../shared/telemetry/telemetryService' import { textUtils } from '@aws/lsp-core' -import { AmazonQBaseServiceManager } from '../../shared/amazonQServiceManager/BaseAmazonQServiceManager' -import { RejectedEditTracker } from './tracker/rejectedEditTracker' -import { getErrorMessage, hasConnectionExpired } from '../../shared/utils' -import { AmazonQError, AmazonQServiceConnectionExpiredError } from '../../shared/amazonQServiceManager/errors' -import { DocumentChangedListener } from './documentChangedListener' -import { EMPTY_RESULT, EDIT_DEBOUNCE_INTERVAL_MS } from './contants/constants' -import { StreakTracker } from './tracker/streakTracker' +import { AmazonQBaseServiceManager } from '../../../shared/amazonQServiceManager/BaseAmazonQServiceManager' +import { RejectedEditTracker } from '../tracker/rejectedEditTracker' +import { getErrorMessage, hasConnectionExpired } from '../../../shared/utils' +import { AmazonQError, AmazonQServiceConnectionExpiredError } from '../../../shared/amazonQServiceManager/errors' +import { DocumentChangedListener } from '../documentChangedListener' +import { EMPTY_RESULT, EDIT_DEBOUNCE_INTERVAL_MS } from '../contants/constants' +import { StreakTracker } from '../tracker/streakTracker' export class EditCompletionHandler { private readonly editsEnabled: boolean diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.test.ts new file mode 100644 index 0000000000..894095a0b5 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.test.ts @@ -0,0 +1,146 @@ +import * as assert from 'assert' +import * as sinon from 'sinon' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { InlineCompletionHandler } from './inlineCompletionHandler' +import { SessionManager } from '../session/sessionManager' +import { CodePercentageTracker } from '../tracker/codePercentageTracker' +import { RecentEditTracker } from '../tracker/codeEditTracker' +import { CursorTracker } from '../tracker/cursorTracker' +import { StreakTracker } from '../tracker/streakTracker' +import { TelemetryService } from '../../../shared/telemetry/telemetryService' +import { UserWrittenCodeTracker } from '../../../shared/userWrittenCodeTracker' +import { InlineCompletionTriggerKind, CancellationToken } from '@aws/language-server-runtimes/server-interface' +import { EMPTY_RESULT } from '../contants/constants' +import * as IdleWorkspaceManagerModule from '../../workspaceContext/IdleWorkspaceManager' +import * as telemetryModule from '../telemetry/telemetry' + +describe('InlineCompletionHandler', () => { + const testDocument = TextDocument.create('file:///test.cs', 'csharp', 1, 'test content') + + const completionParams = { + textDocument: { uri: testDocument.uri }, + position: { line: 0, character: 0 }, + context: { triggerKind: InlineCompletionTriggerKind.Invoked }, + } + + let handler: InlineCompletionHandler + let completionSessionManager: SessionManager + let amazonQServiceManager: any + let codePercentageTracker: sinon.SinonStubbedInstance + let userWrittenCodeTracker: sinon.SinonStubbedInstance + let recentEditTracker: sinon.SinonStubbedInstance + let cursorTracker: sinon.SinonStubbedInstance + let streakTracker: sinon.SinonStubbedInstance + let telemetryService: sinon.SinonStubbedInstance + let lsp: any + let telemetry: any + let credentialsProvider: any + let workspace: any + let logging: any + let getTextDocument: sinon.SinonStub + + beforeEach(() => { + SessionManager.reset() + completionSessionManager = SessionManager.getInstance('COMPLETIONS') + + amazonQServiceManager = { + getCodewhispererService: sinon.stub(), + getConfiguration: sinon.stub().returns({ inlineSuggestions: {} }), + } + codePercentageTracker = sinon.createStubInstance(CodePercentageTracker) + userWrittenCodeTracker = sinon.createStubInstance(UserWrittenCodeTracker) + recentEditTracker = sinon.createStubInstance(RecentEditTracker) + cursorTracker = sinon.createStubInstance(CursorTracker) + streakTracker = sinon.createStubInstance(StreakTracker) + telemetryService = sinon.createStubInstance(TelemetryService) + + workspace = { getWorkspaceFolder: sinon.stub() } + logging = { log: sinon.stub(), debug: sinon.stub() } + getTextDocument = sinon.stub().resolves(testDocument) + lsp = { getClientInitializeParams: sinon.stub() } as any + telemetry = { emitMetric: sinon.stub() } as any + credentialsProvider = { getConnectionMetadata: sinon.stub() } as any + + // Stub IdleWorkspaceManager and telemetry functions + sinon.stub(IdleWorkspaceManagerModule.IdleWorkspaceManager, 'recordActivityTimestamp') + sinon.stub(telemetryModule, 'emitServiceInvocationTelemetry') + sinon.stub(telemetryModule, 'emitServiceInvocationFailure') + sinon.stub(telemetryModule, 'emitUserTriggerDecisionTelemetry') + + handler = new InlineCompletionHandler( + logging, + workspace, + amazonQServiceManager, + completionSessionManager, + codePercentageTracker, + userWrittenCodeTracker, + recentEditTracker, + cursorTracker, + streakTracker, + telemetry, + telemetryService, + credentialsProvider, + () => false, + () => 1000, + lsp, + getTextDocument + ) + }) + + afterEach(() => { + sinon.restore() + }) + + it('should return empty result when concurrent request is in progress', async () => { + // Make handler busy + handler['isOnInlineCompletionHandlerInProgress'] = true + + const result = await handler.onInlineCompletion(completionParams, CancellationToken.None) + + assert.deepEqual(result, EMPTY_RESULT) + sinon.assert.calledWith(logging.log, 'Skip concurrent inline completion') + }) + + it('should return empty result when service manager not initialized', async () => { + handler = new InlineCompletionHandler( + logging, + workspace, + null as any, + completionSessionManager, + codePercentageTracker, + userWrittenCodeTracker, + recentEditTracker, + cursorTracker, + streakTracker, + { emitMetric: sinon.stub() } as any, + telemetryService, + { getConnectionMetadata: sinon.stub() } as any, + () => false, + () => 1000, + { getClientInitializeParams: sinon.stub() } as any, + getTextDocument + ) + + const result = await handler.onInlineCompletion(completionParams, CancellationToken.None) + + assert.deepEqual(result, EMPTY_RESULT) + sinon.assert.calledWith(logging.log, 'Amazon Q Service Manager not initialized yet') + }) + + it('should return empty result when text document not found', async () => { + getTextDocument.resolves(null) + + const result = await handler.onInlineCompletion(completionParams, CancellationToken.None) + + assert.deepEqual(result, EMPTY_RESULT) + sinon.assert.calledWith(logging.log, `textDocument [${testDocument.uri}] not found`) + }) + + it('should track cursor position when cursor tracker available', async () => { + getTextDocument.resolves(null) // Will return early + + await handler.onInlineCompletion(completionParams, CancellationToken.None) + + sinon.assert.calledWith(cursorTracker.trackPosition, testDocument.uri, completionParams.position) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts new file mode 100644 index 0000000000..deb6d89752 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts @@ -0,0 +1,512 @@ +import { + CancellationToken, + InlineCompletionListWithReferences, + InlineCompletionTriggerKind, + InlineCompletionWithReferencesParams, + Range, + TextDocument, + ResponseError, + LSPErrorCodes, + Logging, + Telemetry, + Workspace, + CredentialsProvider, + Lsp, +} from '@aws/language-server-runtimes/server-interface' +import { autoTrigger, getAutoTriggerType, getNormalizeOsName, triggerType } from '../auto-trigger/autoTrigger' +import { + FileContext, + BaseGenerateSuggestionsRequest, + CodeWhispererServiceToken, + GenerateIAMSuggestionsRequest, + GenerateTokenSuggestionsRequest, + GenerateSuggestionsRequest, + GenerateSuggestionsResponse, + getFileContext, + SuggestionType, +} from '../../../shared/codeWhispererService' +import { CodewhispererLanguage, getSupportedLanguageId } from '../../../shared/languageDetection' +import { CodeWhispererSession, SessionManager } from '../session/sessionManager' +import { CodePercentageTracker } from '../tracker/codePercentageTracker' +import { getErrorMessage } from '../../../shared/utils' +import { getIdeCategory } from '../../../shared/telemetryUtils' +import { textUtils } from '@aws/lsp-core' +import { TelemetryService } from '../../../shared/telemetry/telemetryService' +import { UserWrittenCodeTracker } from '../../../shared/userWrittenCodeTracker' +import { RecentEditTracker } from '../tracker/codeEditTracker' +import { CursorTracker } from '../tracker/cursorTracker' +import { StreakTracker } from '../tracker/streakTracker' +import { AmazonQError, AmazonQServiceConnectionExpiredError } from '../../../shared/amazonQServiceManager/errors' +import { AmazonQBaseServiceManager } from '../../../shared/amazonQServiceManager/BaseAmazonQServiceManager' +import { hasConnectionExpired } from '../../../shared/utils' +import { WorkspaceFolderManager } from '../../workspaceContext/workspaceFolderManager' +import { + emitServiceInvocationFailure, + emitServiceInvocationTelemetry, + emitUserTriggerDecisionTelemetry, +} from '../telemetry/telemetry' +import { EMPTY_RESULT } from '../contants/constants' +import { IdleWorkspaceManager } from '../../workspaceContext/IdleWorkspaceManager' +import { mergeSuggestionsWithRightContext } from '../utils/mergeRightUtils' + +export class InlineCompletionHandler { + private isOnInlineCompletionHandlerInProgress = false + + constructor( + private readonly logging: Logging, + private readonly workspace: Workspace, + private readonly amazonQServiceManager: AmazonQBaseServiceManager, + private readonly completionSessionManager: SessionManager, + private readonly codePercentageTracker: CodePercentageTracker, + private readonly userWrittenCodeTracker: UserWrittenCodeTracker | undefined, + private readonly recentEditTracker: RecentEditTracker, + private readonly cursorTracker: CursorTracker, + private readonly streakTracker: StreakTracker, + private readonly telemetry: Telemetry, + private readonly telemetryService: TelemetryService, + private readonly credentialsProvider: CredentialsProvider, + private readonly getEditsEnabled: () => boolean, + private readonly getTimeSinceLastUserModification: () => number, + private readonly lsp: Lsp, + private readonly getTextDocument: ( + uri: string, + workspace: any, + logging: any + ) => Promise + ) {} + + async onInlineCompletion( + params: InlineCompletionWithReferencesParams, + token: CancellationToken + ): Promise { + // this handle should not run concurrently because + // 1. it would create a high volume of traffic, causing throttling + // 2. it is not designed to handle concurrent changes to these state variables. + // when one handler is at the API call stage, it has not yet update the session state + // but another request can start, causing the state to be incorrect. + IdleWorkspaceManager.recordActivityTimestamp() + + if (this.isOnInlineCompletionHandlerInProgress) { + this.logging.log(`Skip concurrent inline completion`) + return EMPTY_RESULT + } + + // Add this check to ensure service manager is initialized + if (!this.amazonQServiceManager) { + this.logging.log('Amazon Q Service Manager not initialized yet') + return EMPTY_RESULT + } + + this.isOnInlineCompletionHandlerInProgress = true + + try { + // On every new completion request close current inflight session. + const currentSession = this.completionSessionManager.getCurrentSession() + if (currentSession && currentSession.state == 'REQUESTING' && !params.partialResultToken) { + // this REQUESTING state only happens when the session is initialized, which is rare + currentSession.discardInflightSessionOnNewInvocation = true + } + + if (this.cursorTracker) { + this.cursorTracker.trackPosition(params.textDocument.uri, params.position) + } + const textDocument = await this.getTextDocument(params.textDocument.uri, this.workspace, this.logging) + + const codeWhispererService = this.amazonQServiceManager.getCodewhispererService() + const authType = codeWhispererService instanceof CodeWhispererServiceToken ? 'token' : 'iam' + this.logging.debug( + `[INLINE_COMPLETION] Service ready - auth: ${authType}, partial token: ${!!params.partialResultToken}` + ) + + if (params.partialResultToken && currentSession) { + // subsequent paginated requests for current session + try { + const suggestionResponse = await codeWhispererService.generateSuggestions({ + ...currentSession.requestContext, + fileContext: { + ...currentSession.requestContext.fileContext, + }, + nextToken: `${params.partialResultToken}`, + }) + return await this.processSuggestionResponse( + suggestionResponse, + currentSession, + false, + params.context.selectedCompletionInfo?.range + ) + } catch (error) { + return this.handleSuggestionsErrors(error as Error, currentSession) + } + } else { + return await this.processNewCompletionRequest(params, textDocument, token) + } + } finally { + this.isOnInlineCompletionHandlerInProgress = false + } + } + + private async processNewCompletionRequest( + params: InlineCompletionWithReferencesParams, + textDocument: TextDocument | undefined, + token: CancellationToken + ): Promise { + // request for new session + if (!textDocument) { + this.logging.log(`textDocument [${params.textDocument.uri}] not found`) + return EMPTY_RESULT + } + + let inferredLanguageId = getSupportedLanguageId(textDocument) + if (params.fileContextOverride?.programmingLanguage) { + inferredLanguageId = params.fileContextOverride?.programmingLanguage as CodewhispererLanguage + } + if (!inferredLanguageId) { + this.logging.log( + `textDocument [${params.textDocument.uri}] with languageId [${textDocument.languageId}] not supported` + ) + return EMPTY_RESULT + } + + // Build request context + const isAutomaticLspTriggerKind = params.context.triggerKind == InlineCompletionTriggerKind.Automatic + const maxResults = isAutomaticLspTriggerKind ? 1 : 5 + const selectionRange = params.context.selectedCompletionInfo?.range + + const startPreprocessTimestamp = Date.now() + + // For Jupyter Notebook in VSC, the language server does not have access to + // its internal states including current active cell index, etc + // we rely on VSC to calculate file context + let fileContext: FileContext | undefined = undefined + if (params.fileContextOverride) { + fileContext = { + leftFileContent: params.fileContextOverride.leftFileContent, + rightFileContent: params.fileContextOverride.rightFileContent, + filename: params.fileContextOverride.filename, + fileUri: params.fileContextOverride.fileUri, + programmingLanguage: { + languageName: inferredLanguageId, + }, + } + } else { + fileContext = getFileContext({ + textDocument, + inferredLanguageId, + position: params.position, + workspaceFolder: this.workspace.getWorkspaceFolder(textDocument.uri), + }) + } + + const workspaceState = WorkspaceFolderManager.getInstance()?.getWorkspaceState() + const workspaceId = workspaceState?.webSocketClient?.isConnected() ? workspaceState.workspaceId : undefined + + const previousSession = this.completionSessionManager.getPreviousSession() + // Only refer to decisions in the past 2 mins + const previousDecisionForClassifier = + previousSession && Date.now() - previousSession.decisionMadeTimestamp <= 2 * 60 * 1000 + ? previousSession.getAggregatedUserTriggerDecision() + : undefined + let ideCategory: string | undefined = '' + const initializeParams = this.lsp.getClientInitializeParams() + if (initializeParams !== undefined) { + ideCategory = getIdeCategory(initializeParams) + } + + // auto trigger code path + let codewhispererAutoTriggerType = undefined + let triggerCharacters = '' + let autoTriggerResult = undefined + + if (isAutomaticLspTriggerKind) { + // Reference: https://github.com/aws/aws-toolkit-vscode/blob/amazonq/v1.74.0/packages/core/src/codewhisperer/service/classifierTrigger.ts#L477 + if ( + params.documentChangeParams?.contentChanges && + params.documentChangeParams.contentChanges.length > 0 && + params.documentChangeParams.contentChanges[0].text !== undefined + ) { + triggerCharacters = params.documentChangeParams.contentChanges[0].text + codewhispererAutoTriggerType = getAutoTriggerType(params.documentChangeParams.contentChanges) + } else { + // if the client does not emit document change for the trigger, use left most character. + triggerCharacters = fileContext.leftFileContent.trim().at(-1) ?? '' + codewhispererAutoTriggerType = triggerType(fileContext) + } + // See: https://github.com/aws/aws-toolkit-vscode/blob/amazonq/v1.74.0/packages/core/src/codewhisperer/service/keyStrokeHandler.ts#L132 + // In such cases, do not auto trigger. + if (codewhispererAutoTriggerType === undefined) { + return EMPTY_RESULT + } + + autoTriggerResult = autoTrigger( + { + fileContext, // The left/right file context and programming language + lineNum: params.position.line, // the line number of the invocation, this is the line of the cursor + char: triggerCharacters, // Add the character just inserted, if any, before the invication position + ide: ideCategory ?? '', + os: getNormalizeOsName(), + previousDecision: previousDecisionForClassifier, // The last decision by the user on the previous invocation + triggerType: codewhispererAutoTriggerType, // The 2 trigger types currently influencing the Auto-Trigger are SpecialCharacter and Enter + }, + this.logging + ) + + if (codewhispererAutoTriggerType === 'Classifier' && !autoTriggerResult.shouldTrigger) { + return EMPTY_RESULT + } + } + + let requestContext: GenerateSuggestionsRequest = { + fileContext, + maxResults, + } + + const codeWhispererService = this.amazonQServiceManager.getCodewhispererService() + const supplementalContext = await codeWhispererService.constructSupplementalContext( + textDocument, + params.position, + this.workspace, + this.recentEditTracker, + this.logging, + token, + params.openTabFilepaths, + { includeRecentEdits: false } + ) + + if (supplementalContext?.items) { + requestContext.supplementalContexts = supplementalContext.items + } + + // Close ACTIVE session and record Discard trigger decision immediately + const currentSession = this.completionSessionManager.getCurrentSession() + if (currentSession && currentSession.state === 'ACTIVE') { + // Emit user trigger decision at session close time for active session + // TODO: yuxqiang workaround to exclude JB from this logic because JB and VSC handle a + // bit differently in the case when there's a new trigger while a reject/discard event is sent + // for the previous trigger + if (ideCategory !== 'JETBRAINS') { + this.completionSessionManager.discardSession(currentSession) + const streakLength = this.getEditsEnabled() ? this.streakTracker.getAndUpdateStreakLength(false) : 0 + await emitUserTriggerDecisionTelemetry( + this.telemetry, + this.telemetryService, + currentSession, + this.getTimeSinceLastUserModification(), + 0, + 0, + [], + [], + streakLength + ) + } + } + + const supplementalMetadata = supplementalContext?.supContextData + + const newSession = this.completionSessionManager.createSession({ + document: textDocument, + startPreprocessTimestamp: startPreprocessTimestamp, + startPosition: params.position, + triggerType: isAutomaticLspTriggerKind ? 'AutoTrigger' : 'OnDemand', + language: fileContext.programmingLanguage.languageName as CodewhispererLanguage, + requestContext: requestContext, + autoTriggerType: isAutomaticLspTriggerKind ? codewhispererAutoTriggerType : undefined, + triggerCharacter: triggerCharacters, + classifierResult: autoTriggerResult?.classifierResult, + classifierThreshold: autoTriggerResult?.classifierThreshold, + credentialStartUrl: this.credentialsProvider.getConnectionMetadata?.()?.sso?.startUrl ?? undefined, + supplementalMetadata: supplementalMetadata, + customizationArn: textUtils.undefinedIfEmpty(codeWhispererService.customizationArn), + }) + + // Add extra context to request context + const { extraContext } = this.amazonQServiceManager.getConfiguration().inlineSuggestions + if (extraContext) { + requestContext.fileContext.leftFileContent = + extraContext + '\n' + requestContext.fileContext.leftFileContent + } + + // Create the appropriate request based on service type + let generateCompletionReq: BaseGenerateSuggestionsRequest + + if (codeWhispererService instanceof CodeWhispererServiceToken) { + const tokenRequest = requestContext as GenerateTokenSuggestionsRequest + generateCompletionReq = { + ...tokenRequest, + ...(workspaceId ? { workspaceId } : {}), + } + } else { + const iamRequest = requestContext as GenerateIAMSuggestionsRequest + generateCompletionReq = { + ...iamRequest, + } + } + + try { + const authType = codeWhispererService instanceof CodeWhispererServiceToken ? 'token' : 'iam' + this.logging.debug(`[INLINE_COMPLETION] API call - generateSuggestions (new session, ${authType})`) + const suggestionResponse = await codeWhispererService.generateSuggestions(generateCompletionReq) + return await this.processSuggestionResponse(suggestionResponse, newSession, true, selectionRange) + } catch (error) { + return this.handleSuggestionsErrors(error as Error, newSession) + } + } + + private async processSuggestionResponse( + suggestionResponse: GenerateSuggestionsResponse, + session: CodeWhispererSession, + isNewSession: boolean, + selectionRange?: Range + ): Promise { + this.codePercentageTracker.countInvocation(session.language) + + this.userWrittenCodeTracker?.recordUsageCount(session.language) + session.includeImportsWithSuggestions = + this.amazonQServiceManager.getConfiguration().includeImportsWithSuggestions + + if (isNewSession) { + // Populate the session with information from codewhisperer response + session.suggestions = suggestionResponse.suggestions + session.responseContext = suggestionResponse.responseContext + session.codewhispererSessionId = suggestionResponse.responseContext.codewhispererSessionId + session.setTimeToFirstRecommendation() + session.predictionType = SuggestionType.COMPLETION + } else { + session.suggestions = [...session.suggestions, ...suggestionResponse.suggestions] + } + + // Emit service invocation telemetry for every request sent to backend + emitServiceInvocationTelemetry(this.telemetry, session, suggestionResponse.responseContext.requestId) + + // Discard previous inflight API response due to new trigger + if (session.discardInflightSessionOnNewInvocation) { + session.discardInflightSessionOnNewInvocation = false + this.completionSessionManager.discardSession(session) + const streakLength = this.getEditsEnabled() ? this.streakTracker.getAndUpdateStreakLength(false) : 0 + await emitUserTriggerDecisionTelemetry( + this.telemetry, + this.telemetryService, + session, + this.getTimeSinceLastUserModification(), + 0, + 0, + [], + [], + streakLength + ) + } + + // session was closed by user already made decisions consequent completion request before new paginated API response was received + if ( + session.predictionType !== SuggestionType.EDIT && // TODO: this is a shorterm fix to allow Edits tabtabtab experience, however the real solution is to manage such sessions correctly + (session.state === 'CLOSED' || session.state === 'DISCARD') + ) { + return EMPTY_RESULT + } + + // API response was recieved, we can activate session now + this.completionSessionManager.activateSession(session) + + // Process suggestions to apply Empty or Filter filters + const filteredSuggestions = suggestionResponse.suggestions + // Empty suggestion filter + .filter(suggestion => { + if (suggestion.content === '') { + session.setSuggestionState(suggestion.itemId, 'Empty') + return false + } + return true + }) + // References setting filter + .filter(suggestion => { + // State to track whether code with references should be included in + // the response. No locking or concurrency controls, filtering is done + // right before returning and is only guaranteed to be consistent within + // the context of a single response. + const { includeSuggestionsWithCodeReferences } = this.amazonQServiceManager.getConfiguration() + if (includeSuggestionsWithCodeReferences) { + return true + } + if (suggestion.references == null || suggestion.references.length === 0) { + return true + } + // Filter out suggestions that have references when includeSuggestionsWithCodeReferences setting is true + session.setSuggestionState(suggestion.itemId, 'Filter') + return false + }) + + const { includeImportsWithSuggestions } = this.amazonQServiceManager.getConfiguration() + const suggestionsWithRightContext = mergeSuggestionsWithRightContext( + session.requestContext.fileContext.rightFileContent, + filteredSuggestions, + includeImportsWithSuggestions, + selectionRange + ).filter(suggestion => { + // Discard suggestions that have empty string insertText after right context merge and can't be displayed anymore + if (suggestion.insertText === '') { + session.setSuggestionState(suggestion.itemId, 'Discard') + return false + } + return true + }) + + suggestionsWithRightContext.forEach(suggestion => { + const cachedSuggestion = session.suggestions.find(s => s.itemId === suggestion.itemId) + if (cachedSuggestion) cachedSuggestion.insertText = suggestion.insertText.toString() + }) + + // TODO: need dedupe after right context merging but I don't see one + session.suggestionsAfterRightContextMerge.push(...suggestionsWithRightContext) + + session.codewhispererSuggestionImportCount = + session.codewhispererSuggestionImportCount + + suggestionsWithRightContext.reduce((total, suggestion) => { + return total + (suggestion.mostRelevantMissingImports?.length || 0) + }, 0) + + // If after all server-side filtering no suggestions can be displayed, and there is no nextToken + // close session and return empty results + if (session.suggestionsAfterRightContextMerge.length === 0 && !suggestionResponse.responseContext.nextToken) { + this.completionSessionManager.closeSession(session) + await emitUserTriggerDecisionTelemetry( + this.telemetry, + this.telemetryService, + session, + this.getTimeSinceLastUserModification() + ) + return EMPTY_RESULT + } + + return { + items: suggestionsWithRightContext, + sessionId: session.id, + partialResultToken: suggestionResponse.responseContext.nextToken, + } + } + + private handleSuggestionsErrors(error: Error, session: CodeWhispererSession): InlineCompletionListWithReferences { + this.logging.log('Recommendation failure: ' + error) + + emitServiceInvocationFailure(this.telemetry, session, error) + + // UTDE telemetry is not needed here because in error cases we don't care about UTDE for errored out sessions + this.completionSessionManager.closeSession(session) + + let translatedError = error + + if (hasConnectionExpired(error)) { + translatedError = new AmazonQServiceConnectionExpiredError(getErrorMessage(error)) + } + + if (translatedError instanceof AmazonQError) { + throw new ResponseError( + LSPErrorCodes.RequestFailed, + translatedError.message || 'Error processing suggestion requests', + { + awsErrorCode: translatedError.code, + } + ) + } + + return EMPTY_RESULT + } +} diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.test.ts new file mode 100644 index 0000000000..97732743f3 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.test.ts @@ -0,0 +1,182 @@ +import * as assert from 'assert' +import * as sinon from 'sinon' +import { TextDocument } from 'vscode-languageserver-textdocument' +import { SessionResultsHandler } from './sessionResultsHandler' +import { SessionManager, SessionData } from '../session/sessionManager' +import { CodePercentageTracker } from '../tracker/codePercentageTracker' +import { RejectedEditTracker } from '../tracker/rejectedEditTracker' +import { StreakTracker } from '../tracker/streakTracker' +import { TelemetryService } from '../../../shared/telemetry/telemetryService' +import { AcceptedInlineSuggestionEntry, CodeDiffTracker } from '../tracker/codeDiffTracker' +import { SuggestionType } from '../../../shared/codeWhispererService' + +describe('SessionResultsHandler', () => { + const sessionData: SessionData = { + document: TextDocument.create('file:///test.cs', 'csharp', 1, 'test content'), + startPreprocessTimestamp: 0, + startPosition: { line: 0, character: 0 }, + triggerType: 'OnDemand', + language: 'csharp', + requestContext: { + maxResults: 5, + fileContext: { + filename: 'test.cs', + programmingLanguage: { languageName: 'csharp' }, + leftFileContent: 'left', + rightFileContent: 'right', + }, + }, + } + + const sessionResultData = { + sessionId: 'test-session-id', + completionSessionResult: { + 'item-1': { seen: true, accepted: false, discarded: false }, + }, + firstCompletionDisplayLatency: 50, + totalSessionDisplayTime: 1000, + typeaheadLength: 10, + isInlineEdit: false, + addedDiagnostics: [], + removedDiagnostics: [], + } + + let handler: SessionResultsHandler + let completionSessionManager: SessionManager + let editSessionManager: SessionManager + let codePercentageTracker: sinon.SinonStubbedInstance + let codeDiffTracker: sinon.SinonStubbedInstance> + let rejectedEditTracker: sinon.SinonStubbedInstance + let streakTracker: sinon.SinonStubbedInstance + let telemetryService: sinon.SinonStubbedInstance + let telemetry: { emitMetric: sinon.SinonStub; onClientTelemetry: sinon.SinonStub } + let logging: { + log: sinon.SinonStub + debug: sinon.SinonStub + error: sinon.SinonStub + warn: sinon.SinonStub + info: sinon.SinonStub + } + + beforeEach(() => { + SessionManager.reset() + completionSessionManager = SessionManager.getInstance('COMPLETIONS') + editSessionManager = SessionManager.getInstance('EDITS') + + codePercentageTracker = sinon.createStubInstance(CodePercentageTracker) + codeDiffTracker = sinon.createStubInstance(CodeDiffTracker) + rejectedEditTracker = sinon.createStubInstance(RejectedEditTracker) + streakTracker = sinon.createStubInstance(StreakTracker) + telemetryService = sinon.createStubInstance(TelemetryService) + + telemetry = { emitMetric: sinon.stub(), onClientTelemetry: sinon.stub() } + logging = { + log: sinon.stub(), + debug: sinon.stub(), + error: sinon.stub(), + warn: sinon.stub(), + info: sinon.stub(), + } + + handler = new SessionResultsHandler( + logging, + telemetry, + telemetryService, + completionSessionManager, + editSessionManager, + codePercentageTracker, + codeDiffTracker, + rejectedEditTracker, + streakTracker, + () => false, + () => 1000 + ) + }) + + it('should close session when results are processed', async () => { + const session = completionSessionManager.createSession(sessionData) + completionSessionManager.activateSession(session) + session.id = 'test-session-id' + + await handler.handleSessionResults(sessionResultData) + + assert.equal(session.state, 'CLOSED') + }) + + it('should log error when session not found', async () => { + await handler.handleSessionResults(sessionResultData) + + sinon.assert.calledWith(logging.log, 'ERROR: Session ID test-session-id was not found') + }) + + it('should log error when session not active', async () => { + const session = completionSessionManager.createSession(sessionData) + session.id = 'test-session-id' + session.close() + + await handler.handleSessionResults(sessionResultData) + + sinon.assert.calledWith( + logging.log, + 'ERROR: Trying to record trigger decision for not-active session test-session-id with wrong state CLOSED' + ) + }) + + it('should handle accepted completions suggestion', async () => { + const session = completionSessionManager.createSession(sessionData) + completionSessionManager.activateSession(session) + session.id = 'test-session-id' + session.suggestions = [{ itemId: 'item-1', content: 'test', insertText: 'test' }] + + const acceptedData = { + ...sessionResultData, + completionSessionResult: { 'item-1': { seen: true, accepted: true, discarded: false } }, + } + + await handler.handleSessionResults(acceptedData) + + sinon.assert.calledWith(codePercentageTracker.countSuccess, 'csharp') + sinon.assert.calledWith(codePercentageTracker.countAcceptedTokens, 'csharp', 'test') + sinon.assert.calledWith(codePercentageTracker.countTotalTokens, 'csharp', 'test', true) + sinon.assert.called(codeDiffTracker.enqueue) + assert.equal(session.state, 'CLOSED') + }) + + it('should handle accepted edits suggestions', async () => { + const session = completionSessionManager.createSession(sessionData) + completionSessionManager.activateSession(session) + session.id = 'test-session-id' + session.predictionType = SuggestionType.EDIT + session.suggestions = [{ itemId: 'item-1', content: '-int\n+int = 5' }] + + const acceptedData = { + ...sessionResultData, + completionSessionResult: { 'item-1': { seen: true, accepted: true, discarded: false } }, + } + + await handler.handleSessionResults(acceptedData) + + sinon.assert.calledWith(codePercentageTracker.countSuccess, 'csharp') + sinon.assert.calledWith(codePercentageTracker.countAcceptedTokensUsingCount, 'csharp', 4) + sinon.assert.calledWith(codePercentageTracker.addTotalTokensForEdits, 'csharp', 4) + sinon.assert.called(codeDiffTracker.enqueue) + assert.equal(session.state, 'CLOSED') + }) + + it('should handle rejected edits suggestions', async () => { + const session = editSessionManager.createSession(sessionData) + editSessionManager.activateSession(session) + session.id = 'test-session-id' + session.suggestions = [{ itemId: 'item-1', content: 'rejected' }] + + const rejectedData = { + ...sessionResultData, + isInlineEdit: true, + } + + await handler.handleSessionResults(rejectedData) + + sinon.assert.called(rejectedEditTracker.recordRejectedEdit) + assert.equal(session.state, 'CLOSED') + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.ts new file mode 100644 index 0000000000..7ad1389377 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.ts @@ -0,0 +1,162 @@ +import { + Logging, + LogInlineCompletionSessionResultsParams, + Telemetry, +} from '@aws/language-server-runtimes/server-interface' +import { SessionManager } from '../session/sessionManager' +import { CodePercentageTracker } from '../tracker/codePercentageTracker' +import { RejectedEditTracker } from '../tracker/rejectedEditTracker' +import { StreakTracker } from '../tracker/streakTracker' +import { TelemetryService } from '../../../shared/telemetry/telemetryService' +import { AcceptedInlineSuggestionEntry, CodeDiffTracker } from '../tracker/codeDiffTracker' +import { SuggestionType, Suggestion } from '../../../shared/codeWhispererService' +import { getAddedAndDeletedLines, getCharacterDifferences } from '../utils/diffUtils' +import { getCompletionType, getEndPositionForAcceptedSuggestion } from '../../../shared/utils' +import { emitPerceivedLatencyTelemetry, emitUserTriggerDecisionTelemetry } from '../telemetry/telemetry' + +export class SessionResultsHandler { + constructor( + private readonly logging: Logging, + private readonly telemetry: Telemetry, + private readonly telemetryService: TelemetryService, + private readonly completionSessionManager: SessionManager, + private readonly editSessionManager: SessionManager, + private readonly codePercentageTracker: CodePercentageTracker, + private readonly codeDiffTracker: CodeDiffTracker, + private readonly rejectedEditTracker: RejectedEditTracker, + private readonly streakTracker: StreakTracker, + private readonly getEditsEnabled: () => boolean, + private readonly getTimeSinceLastUserModification: () => number + ) {} + + // Schedule tracker for UserModification Telemetry event + private enqueueCodeDiffEntry(session: any, acceptedSuggestion: Suggestion, addedCharactersForEdit?: string) { + const endPosition = getEndPositionForAcceptedSuggestion(acceptedSuggestion.content, session.startPosition) + // use the addedCharactersForEdit if it is EDIT suggestion type + const originalString = addedCharactersForEdit ? addedCharactersForEdit : acceptedSuggestion.content + + this.codeDiffTracker.enqueue({ + sessionId: session.codewhispererSessionId || '', + requestId: session.responseContext?.requestId || '', + fileUrl: session.document.uri, + languageId: session.language, + time: Date.now(), + originalString: originalString, + startPosition: session.startPosition, + endPosition: endPosition, + customizationArn: session.customizationArn, + completionType: getCompletionType(acceptedSuggestion), + triggerType: session.triggerType, + credentialStartUrl: session.credentialStartUrl, + }) + } + + async handleSessionResults(params: LogInlineCompletionSessionResultsParams) { + const { + sessionId, + completionSessionResult, + firstCompletionDisplayLatency, + totalSessionDisplayTime, + typeaheadLength, + isInlineEdit, + addedDiagnostics, + removedDiagnostics, + } = params + + const sessionManager = params.isInlineEdit ? this.editSessionManager : this.completionSessionManager + + const session = sessionManager.getSessionById(sessionId) + if (!session) { + this.logging.log(`ERROR: Session ID ${sessionId} was not found`) + return + } + + if (session.state !== 'ACTIVE') { + this.logging.log( + `ERROR: Trying to record trigger decision for not-active session ${sessionId} with wrong state ${session.state}` + ) + return + } + + const acceptedItemId = Object.keys(params.completionSessionResult).find( + k => params.completionSessionResult[k].accepted + ) + const isAccepted = acceptedItemId ? true : false + const acceptedSuggestion = session.suggestions.find(s => s.itemId === acceptedItemId) + let addedLengthForEdits = 0 + let deletedLengthForEdits = 0 + + if (acceptedSuggestion) { + this.codePercentageTracker.countSuccess(session.language) + if (session.predictionType === SuggestionType.EDIT && acceptedSuggestion.content) { + // [acceptedSuggestion.insertText] will be undefined for NEP suggestion. Use [acceptedSuggestion.content] instead. + // Since [acceptedSuggestion.content] is in the form of a diff, transform the content into addedCharacters and deletedCharacters. + const { addedLines, deletedLines } = getAddedAndDeletedLines(acceptedSuggestion.content) + const charDiffResult = getCharacterDifferences(addedLines, deletedLines) + addedLengthForEdits = charDiffResult.charactersAdded + deletedLengthForEdits = charDiffResult.charactersRemoved + + this.codePercentageTracker.countAcceptedTokensUsingCount( + session.language, + charDiffResult.charactersAdded + ) + this.codePercentageTracker.addTotalTokensForEdits(session.language, charDiffResult.charactersAdded) + this.enqueueCodeDiffEntry(session, acceptedSuggestion, addedLines.join('\n')) + } else if (acceptedSuggestion.insertText) { + this.codePercentageTracker.countAcceptedTokens(session.language, acceptedSuggestion.insertText) + this.codePercentageTracker.countTotalTokens(session.language, acceptedSuggestion.insertText, true) + this.enqueueCodeDiffEntry(session, acceptedSuggestion) + } + } + + // Handle rejected edit predictions + if (isInlineEdit && !isAccepted) { + // Find all rejected suggestions in this session + const rejectedSuggestions = session.suggestions.filter(suggestion => { + const result = completionSessionResult[suggestion.itemId] + return result && result.seen && !result.accepted + }) + + // Record each rejected edit + for (const rejectedSuggestion of rejectedSuggestions) { + if (rejectedSuggestion.content) { + this.rejectedEditTracker.recordRejectedEdit({ + content: rejectedSuggestion.content, + timestamp: Date.now(), + documentUri: session.document.uri, + position: session.startPosition, + }) + + this.logging.debug( + `[EDIT_PREDICTION] Recorded rejected edit: ${rejectedSuggestion.content.substring(0, 20)}...` + ) + } + } + } + + session.setClientResultData( + completionSessionResult, + firstCompletionDisplayLatency, + totalSessionDisplayTime, + typeaheadLength + ) + + if (firstCompletionDisplayLatency) emitPerceivedLatencyTelemetry(this.telemetry, session) + + // Always emit user trigger decision at session close + sessionManager.closeSession(session) + const streakLength = this.getEditsEnabled() ? this.streakTracker.getAndUpdateStreakLength(isAccepted) : 0 + await emitUserTriggerDecisionTelemetry( + this.telemetry, + this.telemetryService, + session, + this.getTimeSinceLastUserModification(), + addedLengthForEdits, + deletedLengthForEdits, + addedDiagnostics, + removedDiagnostics, + streakLength, + Object.keys(params.completionSessionResult)[0] + ) + } +} diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/userTriggerDecision.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry/userTriggerDecision.test.ts similarity index 99% rename from server/aws-lsp-codewhisperer/src/language-server/inline-completion/userTriggerDecision.test.ts rename to server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry/userTriggerDecision.test.ts index 21c398d56a..cb5d12ef91 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/userTriggerDecision.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry/userTriggerDecision.test.ts @@ -9,17 +9,17 @@ import { TestFeatures } from '@aws/language-server-runtimes/testing' import * as assert from 'assert' import sinon, { StubbedInstance, stubInterface } from 'ts-sinon' import { TextDocument } from 'vscode-languageserver-textdocument' -import { CodewhispererServerFactory } from './codeWhispererServer' +import { CodewhispererServerFactory } from '../codeWhispererServer' import { CodeWhispererServiceBase, ResponseContext, Suggestion, SuggestionType, -} from '../../shared/codeWhispererService' -import { CodeWhispererSession, SessionManager } from './session/sessionManager' -import { TelemetryService } from '../../shared/telemetry/telemetryService' -import { initBaseTestServiceManager, TestAmazonQServiceManager } from '../../shared/amazonQServiceManager/testUtils' -import { getNormalizeOsName } from './auto-trigger/autoTrigger' +} from '../../../shared/codeWhispererService' +import { CodeWhispererSession, SessionManager } from '../session/sessionManager' +import { TelemetryService } from '../../../shared/telemetry/telemetryService' +import { initBaseTestServiceManager, TestAmazonQServiceManager } from '../../../shared/amazonQServiceManager/testUtils' +import { getNormalizeOsName } from '../auto-trigger/autoTrigger' describe('Telemetry', () => { const sandbox = sinon.createSandbox() From 09803514d1ce31ca77a532161e071e1d037e3fb1 Mon Sep 17 00:00:00 2001 From: Nora Xia <69574282+ruotingx@users.noreply.github.com> Date: Fri, 3 Oct 2025 10:09:00 -0700 Subject: [PATCH 125/158] feat(amazonq): support JupyterLab conversation history on refresh (#2325) Allow multiple loadChats() calls in JupyterLab environment. Co-authored-by: ruotingx --- .../agenticChat/tabBarController.test.ts | 19 ++++++++++++++- .../agenticChat/tabBarController.ts | 23 +++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.test.ts index fecbdebe13..5aa341d232 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.test.ts @@ -50,6 +50,7 @@ describe('TabBarController', () => { afterEach(() => { sinon.restore() clock.restore() + delete process.env.JUPYTER_LAB // Clean up JupyterLab environment variables testFeatures.dispose() }) @@ -540,7 +541,7 @@ describe('TabBarController', () => { }) }) - it('should only load chats once', async () => { + it('should only load chats once in non-JupyterLab environments', async () => { const mockTabs = [{ historyId: 'history1', conversations: [{ messages: [] }] }] as unknown as Tab[] ;(chatHistoryDb.getOpenTabs as sinon.SinonStub).returns(mockTabs) @@ -559,6 +560,22 @@ describe('TabBarController', () => { result: 'Succeeded', }) }) + + it('should allow multiple loads in JupyterLab environment', async () => { + // Set JupyterLab environment + process.env.JUPYTER_LAB = 'true' + + const mockTabs = [{ historyId: 'history1', conversations: [{ messages: [] }] }] as unknown as Tab[] + ;(chatHistoryDb.getOpenTabs as sinon.SinonStub).returns(mockTabs) + + const restoreTabStub = sinon.stub(tabBarController, 'restoreTab') + + await tabBarController.loadChats() + await tabBarController.loadChats() // Second call should NOT be ignored in JupyterLab + + sinon.assert.calledTwice(restoreTabStub) + sinon.assert.calledTwice(telemetryService.emitLoadHistory as sinon.SinonStub) + }) }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.ts index 62f5b2ab0b..4531a9c589 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.ts @@ -313,10 +313,17 @@ export class TabBarController { * When IDE is opened, restore chats that were previously open in IDE for the current workspace. */ async loadChats() { - if (this.#loadedChats) { + const isJupyterLab = this.isJupyterLabEnvironment() + + // For non-JupyterLab environments, prevent multiple loads + if (!isJupyterLab && this.#loadedChats) { return } - this.#loadedChats = true + + if (!isJupyterLab) { + this.#loadedChats = true + } + const openConversations = this.#chatHistoryDb.getOpenTabs() if (openConversations) { for (const conversation of openConversations) { @@ -332,6 +339,18 @@ export class TabBarController { } } + /** + * Determines if the environment is JupyterLab. + */ + private isJupyterLabEnvironment(): boolean { + try { + return process.env.JUPYTER_LAB === 'true' + } catch (error) { + this.#features.logging.error(`Failed to read JUPYTER_LAB environment variable: ${error}`) + return false + } + } + public static enableChatExport(params?: InitializeParams) { if (params?.initializationOptions?.aws?.awsClientCapabilities?.window?.showSaveFileDialog) { // Export Chat UX flow relies on show Save File dialog protocol supported by client From 46643ba4da8f8b4dff11e5dcfc8ea5644abdf951 Mon Sep 17 00:00:00 2001 From: atontb <104926752+atonaamz@users.noreply.github.com> Date: Fri, 3 Oct 2025 10:58:49 -0700 Subject: [PATCH 126/158] chore(amazonq): move getTextDocument to textDocumentUtils and add test (#2382) --- .../codeWhispererServer.test.ts | 50 +------- .../inline-completion/codeWhispererServer.ts | 34 +----- .../handler/inlineCompletionHandler.test.ts | 17 ++- .../handler/inlineCompletionHandler.ts | 10 +- .../utils/textDocumentUtils.test.ts | 113 ++++++++++++++++++ .../utils/textDocumentUtils.ts | 31 +++++ 6 files changed, 157 insertions(+), 98 deletions(-) create mode 100644 server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/textDocumentUtils.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/textDocumentUtils.ts diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts index 149177f60e..18a68d1676 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts @@ -12,7 +12,7 @@ import { TestFeatures } from '@aws/language-server-runtimes/testing' import * as assert from 'assert' import { AWSError } from 'aws-sdk' import sinon, { StubbedInstance } from 'ts-sinon' -import { CodeWhispererServer, CodewhispererServerFactory, getLanguageIdFromUri } from './codeWhispererServer' +import { CodeWhispererServer, CodewhispererServerFactory } from './codeWhispererServer' import { CodeWhispererServiceBase, CodeWhispererServiceToken, @@ -2463,54 +2463,6 @@ describe('CodeWhisperer Server', () => { }) }) - describe('getLanguageIdFromUri', () => { - it('should return python for notebook cell URIs', () => { - const uri = 'vscode-notebook-cell:/some/path/notebook.ipynb#cell1' - assert.strictEqual(getLanguageIdFromUri(uri), 'python') - }) - - it('should return abap for files with ABAP extensions', () => { - const uris = ['file:///path/to/file.asprog'] - - uris.forEach(uri => { - assert.strictEqual(getLanguageIdFromUri(uri), 'abap') - }) - }) - - it('should return empty string for non-ABAP files', () => { - const uris = ['file:///path/to/file.js', 'file:///path/to/file.ts', 'file:///path/to/file.py'] - - uris.forEach(uri => { - assert.strictEqual(getLanguageIdFromUri(uri), '') - }) - }) - - it('should return empty string for invalid URIs', () => { - const invalidUris = ['', 'invalid-uri', 'file:///'] - - invalidUris.forEach(uri => { - assert.strictEqual(getLanguageIdFromUri(uri), '') - }) - }) - - it('should log errors when provided with a logging object', () => { - const mockLogger = { - log: sinon.spy(), - } - - const invalidUri = {} as string // Force type error - getLanguageIdFromUri(invalidUri, mockLogger) - - sinon.assert.calledOnce(mockLogger.log) - sinon.assert.calledWith(mockLogger.log, sinon.match(/Error parsing URI to determine language:.*/)) - }) - - it('should handle URIs without extensions', () => { - const uri = 'file:///path/to/file' - assert.strictEqual(getLanguageIdFromUri(uri), '') - }) - }) - describe('Dynamic Service Manager Selection', () => { it('should use Token service manager when not using IAM auth', async () => { // Create isolated stubs for this test only diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts index 7071d8821b..3e8461a576 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts @@ -27,9 +27,6 @@ import { EditCompletionHandler } from './handler/editCompletionHandler' import { InlineCompletionHandler } from './handler/inlineCompletionHandler' import { SessionResultsHandler } from './handler/sessionResultsHandler' import { isUsingIAMAuth } from '../../shared/utils' -import { TextDocument } from '@aws/language-server-runtimes/server-interface' -import { ABAP_EXTENSIONS } from './contants/constants' -import { URI } from 'vscode-uri' export const CodewhispererServerFactory = (serviceManager: (credentialsProvider?: any) => AmazonQBaseServiceManager): Server => @@ -179,8 +176,7 @@ export const CodewhispererServerFactory = credentialsProvider, () => editsEnabled, () => timeSinceLastUserModification, - lsp, - getTextDocument + lsp ) sessionResultsHandler = new SessionResultsHandler( @@ -302,34 +298,6 @@ export const CodewhispererServerFactory = } } -export const getLanguageIdFromUri = (uri: string, logging?: any): string => { - try { - if (uri.startsWith('vscode-notebook-cell:')) { - // use python for now as lsp does not support JL cell language detection - return 'python' - } - const extension = uri.split('.').pop()?.toLowerCase() - return ABAP_EXTENSIONS.has(extension || '') ? 'abap' : '' - } catch (err) { - logging?.log(`Error parsing URI to determine language: ${uri}: ${err}`) - return '' - } -} - -export const getTextDocument = async (uri: string, workspace: any, logging: any): Promise => { - let textDocument = await workspace.getTextDocument(uri) - if (!textDocument) { - try { - const content = await workspace.fs.readFile(URI.parse(uri).fsPath) - const languageId = getLanguageIdFromUri(uri) - textDocument = TextDocument.create(uri, languageId, 0, content) - } catch (err) { - logging.log(`Unable to load from ${uri}: ${err}`) - } - } - return textDocument -} - // Dynamic service manager factory that detects auth type at runtime export const CodeWhispererServer = CodewhispererServerFactory((credentialsProvider?: any) => { return isUsingIAMAuth(credentialsProvider) ? getOrThrowBaseIAMServiceManager() : getOrThrowBaseTokenServiceManager() diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.test.ts index 894095a0b5..923d3135de 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.test.ts @@ -13,6 +13,7 @@ import { InlineCompletionTriggerKind, CancellationToken } from '@aws/language-se import { EMPTY_RESULT } from '../contants/constants' import * as IdleWorkspaceManagerModule from '../../workspaceContext/IdleWorkspaceManager' import * as telemetryModule from '../telemetry/telemetry' +import * as textDocumentUtils from '../utils/textDocumentUtils' describe('InlineCompletionHandler', () => { const testDocument = TextDocument.create('file:///test.cs', 'csharp', 1, 'test content') @@ -37,7 +38,7 @@ describe('InlineCompletionHandler', () => { let credentialsProvider: any let workspace: any let logging: any - let getTextDocument: sinon.SinonStub + let getTextDocumentStub: sinon.SinonStub beforeEach(() => { SessionManager.reset() @@ -56,16 +57,16 @@ describe('InlineCompletionHandler', () => { workspace = { getWorkspaceFolder: sinon.stub() } logging = { log: sinon.stub(), debug: sinon.stub() } - getTextDocument = sinon.stub().resolves(testDocument) lsp = { getClientInitializeParams: sinon.stub() } as any telemetry = { emitMetric: sinon.stub() } as any credentialsProvider = { getConnectionMetadata: sinon.stub() } as any - // Stub IdleWorkspaceManager and telemetry functions + // Stub IdleWorkspaceManager, telemetry functions, and textDocumentUtils sinon.stub(IdleWorkspaceManagerModule.IdleWorkspaceManager, 'recordActivityTimestamp') sinon.stub(telemetryModule, 'emitServiceInvocationTelemetry') sinon.stub(telemetryModule, 'emitServiceInvocationFailure') sinon.stub(telemetryModule, 'emitUserTriggerDecisionTelemetry') + getTextDocumentStub = sinon.stub(textDocumentUtils, 'getTextDocument') handler = new InlineCompletionHandler( logging, @@ -82,8 +83,7 @@ describe('InlineCompletionHandler', () => { credentialsProvider, () => false, () => 1000, - lsp, - getTextDocument + lsp ) }) @@ -117,8 +117,7 @@ describe('InlineCompletionHandler', () => { { getConnectionMetadata: sinon.stub() } as any, () => false, () => 1000, - { getClientInitializeParams: sinon.stub() } as any, - getTextDocument + { getClientInitializeParams: sinon.stub() } as any ) const result = await handler.onInlineCompletion(completionParams, CancellationToken.None) @@ -128,7 +127,7 @@ describe('InlineCompletionHandler', () => { }) it('should return empty result when text document not found', async () => { - getTextDocument.resolves(null) + getTextDocumentStub.resolves(null) const result = await handler.onInlineCompletion(completionParams, CancellationToken.None) @@ -137,7 +136,7 @@ describe('InlineCompletionHandler', () => { }) it('should track cursor position when cursor tracker available', async () => { - getTextDocument.resolves(null) // Will return early + getTextDocumentStub.resolves(null) // Will return early await handler.onInlineCompletion(completionParams, CancellationToken.None) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts index deb6d89752..ed125e08ac 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts @@ -48,6 +48,7 @@ import { import { EMPTY_RESULT } from '../contants/constants' import { IdleWorkspaceManager } from '../../workspaceContext/IdleWorkspaceManager' import { mergeSuggestionsWithRightContext } from '../utils/mergeRightUtils' +import { getTextDocument } from '../utils/textDocumentUtils' export class InlineCompletionHandler { private isOnInlineCompletionHandlerInProgress = false @@ -67,12 +68,7 @@ export class InlineCompletionHandler { private readonly credentialsProvider: CredentialsProvider, private readonly getEditsEnabled: () => boolean, private readonly getTimeSinceLastUserModification: () => number, - private readonly lsp: Lsp, - private readonly getTextDocument: ( - uri: string, - workspace: any, - logging: any - ) => Promise + private readonly lsp: Lsp ) {} async onInlineCompletion( @@ -110,7 +106,7 @@ export class InlineCompletionHandler { if (this.cursorTracker) { this.cursorTracker.trackPosition(params.textDocument.uri, params.position) } - const textDocument = await this.getTextDocument(params.textDocument.uri, this.workspace, this.logging) + const textDocument = await getTextDocument(params.textDocument.uri, this.workspace, this.logging) const codeWhispererService = this.amazonQServiceManager.getCodewhispererService() const authType = codeWhispererService instanceof CodeWhispererServiceToken ? 'token' : 'iam' diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/textDocumentUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/textDocumentUtils.test.ts new file mode 100644 index 0000000000..3aad7dbcd7 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/textDocumentUtils.test.ts @@ -0,0 +1,113 @@ +import assert = require('assert') +import { getLanguageIdFromUri, getTextDocument } from './textDocumentUtils' +import { TextDocument } from '@aws/language-server-runtimes/server-interface' +import sinon from 'ts-sinon' + +describe('textDocumentUtils', () => { + describe('getLanguageIdFromUri', () => { + it('should return python for notebook cell URIs', () => { + const uri = 'vscode-notebook-cell:/some/path/notebook.ipynb#cell1' + assert.strictEqual(getLanguageIdFromUri(uri), 'python') + }) + + it('should return abap for files with ABAP extensions', () => { + const uris = ['file:///path/to/file.asprog'] + + uris.forEach(uri => { + assert.strictEqual(getLanguageIdFromUri(uri), 'abap') + }) + }) + + it('should return empty string for non-ABAP files', () => { + const uris = ['file:///path/to/file.js', 'file:///path/to/file.ts', 'file:///path/to/file.py'] + + uris.forEach(uri => { + assert.strictEqual(getLanguageIdFromUri(uri), '') + }) + }) + + it('should return empty string for invalid URIs', () => { + const invalidUris = ['', 'invalid-uri', 'file:///'] + + invalidUris.forEach(uri => { + assert.strictEqual(getLanguageIdFromUri(uri), '') + }) + }) + + it('should log errors when provided with a logging object', () => { + const mockLogger = { + log: sinon.spy(), + } + + const invalidUri = {} as string // Force type error + getLanguageIdFromUri(invalidUri, mockLogger) + + sinon.assert.calledOnce(mockLogger.log) + sinon.assert.calledWith(mockLogger.log, sinon.match(/Error parsing URI to determine language:.*/)) + }) + + it('should handle URIs without extensions', () => { + const uri = 'file:///path/to/file' + assert.strictEqual(getLanguageIdFromUri(uri), '') + }) + }) + + describe('getTextDocument', () => { + let mockWorkspace: any + let mockLogging: any + + beforeEach(() => { + mockWorkspace = { + getTextDocument: sinon.stub(), + fs: { + readFile: sinon.stub(), + }, + } + mockLogging = { + log: sinon.stub(), + } + }) + + it('should return existing text document from workspace', async () => { + const existingDoc = TextDocument.create('file:///test.js', 'javascript', 1, 'content') + mockWorkspace.getTextDocument.resolves(existingDoc) + + const result = await getTextDocument('file:///test.js', mockWorkspace, mockLogging) + + assert.strictEqual(result, existingDoc) + sinon.assert.calledOnceWithExactly(mockWorkspace.getTextDocument, 'file:///test.js') + sinon.assert.notCalled(mockWorkspace.fs.readFile) + }) + + it('should create text document from file system when not in workspace', async () => { + mockWorkspace.getTextDocument.resolves(null) + mockWorkspace.fs.readFile.resolves('file content') + + const result = await getTextDocument('file:///test.py', mockWorkspace, mockLogging) + + assert.strictEqual(result?.uri, 'file:///test.py') + assert.strictEqual(result?.getText(), 'file content') + assert.strictEqual(result?.languageId, '') + sinon.assert.calledOnce(mockWorkspace.fs.readFile) + }) + + it('should handle file system read errors', async () => { + mockWorkspace.getTextDocument.resolves(null) + mockWorkspace.fs.readFile.rejects(new Error('File not found')) + + const result = await getTextDocument('file:///missing.js', mockWorkspace, mockLogging) + + assert.strictEqual(result, null) + sinon.assert.calledWith(mockLogging.log, sinon.match(/Unable to load from.*File not found/)) + }) + + it('should use correct language ID for ABAP files', async () => { + mockWorkspace.getTextDocument.resolves(null) + mockWorkspace.fs.readFile.resolves('ABAP content') + + const result = await getTextDocument('file:///test.asprog', mockWorkspace, mockLogging) + + assert.strictEqual(result?.languageId, 'abap') + }) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/textDocumentUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/textDocumentUtils.ts new file mode 100644 index 0000000000..8813dd5736 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/textDocumentUtils.ts @@ -0,0 +1,31 @@ +import { TextDocument } from '@aws/language-server-runtimes/server-interface' +import { ABAP_EXTENSIONS } from '../contants/constants' +import { URI } from 'vscode-uri' + +export const getLanguageIdFromUri = (uri: string, logging?: any): string => { + try { + if (uri.startsWith('vscode-notebook-cell:')) { + // use python for now as lsp does not support JL cell language detection + return 'python' + } + const extension = uri.split('.').pop()?.toLowerCase() + return ABAP_EXTENSIONS.has(extension || '') ? 'abap' : '' + } catch (err) { + logging?.log(`Error parsing URI to determine language: ${uri}: ${err}`) + return '' + } +} + +export const getTextDocument = async (uri: string, workspace: any, logging: any): Promise => { + let textDocument = await workspace.getTextDocument(uri) + if (!textDocument) { + try { + const content = await workspace.fs.readFile(URI.parse(uri).fsPath) + const languageId = getLanguageIdFromUri(uri) + textDocument = TextDocument.create(uri, languageId, 0, content) + } catch (err) { + logging.log(`Unable to load from ${uri}: ${err}`) + } + } + return textDocument +} From 35f0795fa5d09f3610e6a29cb72d49f32cc5534e Mon Sep 17 00:00:00 2001 From: tsmithsz <84354541+tsmithsz@users.noreply.github.com> Date: Fri, 3 Oct 2025 16:20:00 -0700 Subject: [PATCH 127/158] fix: add in-loop compaction (#2387) --- .../agenticChat/agenticChatController.test.ts | 22 +++-- .../agenticChat/agenticChatController.ts | 97 +++++++++++++++++-- .../agenticChat/constants/constants.ts | 2 + .../context/agenticChatTriggerContext.ts | 5 +- .../chat/chatSessionService.ts | 1 + .../chat/telemetry/chatTelemetryController.ts | 12 +++ .../src/shared/telemetry/types.ts | 9 ++ 7 files changed, 132 insertions(+), 16 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts index 288eb2c20f..4ab9587d1c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts @@ -1185,15 +1185,21 @@ describe('AgenticChatController', () => { it('truncate input to 500k character ', async function () { const input = 'X'.repeat(GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT + 10) - generateAssistantResponseStub.restore() - generateAssistantResponseStub = sinon.stub(CodeWhispererStreaming.prototype, 'generateAssistantResponse') - generateAssistantResponseStub.callsFake(() => {}) - await chatController.onChatPrompt({ tabId: mockTabId, prompt: { prompt: input } }, mockCancellationToken) - assert.ok(generateAssistantResponseStub.called) - const calledRequestInput: GenerateAssistantResponseCommandInput = - generateAssistantResponseStub.firstCall.firstArg + const request: GenerateAssistantResponseCommandInput = { + conversationState: { + currentMessage: { + userInputMessage: { + content: input, + }, + }, + chatTriggerType: undefined, + }, + } + + chatController.truncateRequest(request) + assert.deepStrictEqual( - calledRequestInput.conversationState?.currentMessage?.userInputMessage?.content?.length, + request.conversationState?.currentMessage?.userInputMessage?.content?.length, GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT ) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index cdd328c901..374e0a9060 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -191,6 +191,8 @@ import { MAX_OVERALL_CHARACTERS, FSREAD_MEMORY_BANK_MAX_PER_FILE, FSREAD_MEMORY_BANK_MAX_TOTAL, + MID_LOOP_COMPACTION_HANDOFF_PROMPT, + COMPACTION_PROMPT, } from './constants/constants' import { AgenticChatError, @@ -943,6 +945,11 @@ export class AgenticChatController implements ChatHandlers { const compactIds = session.getAllDeferredCompactMessageIds() await this.#invalidateCompactCommand(params.tabId, compactIds) + // Set compactionDeclined flag if there were pending compaction requests + // This prevents endless compaction warning loops when user declines compaction once + if (compactIds.length > 0) { + session.compactionDeclined = true + } session.rejectAllDeferredToolExecutions(new ToolApprovalException('Command ignored: new prompt', false)) await this.#invalidateAllShellCommands(params.tabId, session) @@ -978,6 +985,10 @@ export class AgenticChatController implements ChatHandlers { session.abortRequest() const compactIds = session.getAllDeferredCompactMessageIds() await this.#invalidateCompactCommand(params.tabId, compactIds) + // Set compactionDeclined flag if there were pending compaction requests + if (compactIds.length > 0) { + session.compactionDeclined = true + } void this.#invalidateAllShellCommands(params.tabId, session) session.rejectAllDeferredToolExecutions(new CancellationError('user')) @@ -1087,7 +1098,7 @@ export class AgenticChatController implements ChatHandlers { } // Result Handling - This happens only once - return await this.#handleFinalResult( + const result = await this.#handleFinalResult( finalResult, session, params.tabId, @@ -1096,6 +1107,13 @@ export class AgenticChatController implements ChatHandlers { isNewConversation, chatResultStream ) + + // Reset compactionDeclined flag after successful completion + if (session.compactionDeclined) { + session.compactionDeclined = false + } + + return result } catch (err) { // HACK: the chat-client needs to have a partial event with the associated messageId sent before it can accept the final result. // Without this, the `working` indicator never goes away. @@ -1167,7 +1185,7 @@ export class AgenticChatController implements ChatHandlers { /** * Prepares the initial request input for the chat prompt */ - #getCompactionRequestInput(session: ChatSessionService): ChatCommandInput { + #getCompactionRequestInput(session: ChatSessionService, toolResults?: any[]): ChatCommandInput { this.#debug('Preparing compaction request input') // Get profileArn from the service manager if available const profileArn = this.#serviceManager?.getActiveProfileArn() @@ -1175,7 +1193,8 @@ export class AgenticChatController implements ChatHandlers { profileArn, this.#getTools(session), session.modelId, - this.#origin + this.#origin, + toolResults ) return requestInput } @@ -1183,9 +1202,12 @@ export class AgenticChatController implements ChatHandlers { /** * Runs the compaction, making requests and processing tool uses until completion */ - #shouldCompact(currentRequestCount: number): boolean { - if (currentRequestCount > COMPACTION_CHARACTER_THRESHOLD) { - this.#debug(`Current request total character count is: ${currentRequestCount}, prompting user to compact`) + #shouldCompact(currentRequestCount: number, session: ChatSessionService): boolean { + const EFFECTIVE_COMPACTION_THRESHOLD = COMPACTION_CHARACTER_THRESHOLD - COMPACTION_PROMPT.length + if (currentRequestCount > EFFECTIVE_COMPACTION_THRESHOLD && !session.compactionDeclined) { + this.#debug( + `Current request total character count is: ${currentRequestCount}, prompting user to compact (threshold: ${EFFECTIVE_COMPACTION_THRESHOLD})` + ) return true } else { return false @@ -1368,6 +1390,10 @@ export class AgenticChatController implements ChatHandlers { let currentRequestCount = 0 const pinnedContext = additionalContext?.filter(item => item.pinned) + // Store initial non-empty prompt for compaction handoff + const initialPrompt = + initialRequestInput.conversationState?.currentMessage?.userInputMessage?.content?.trim() || '' + metric.recordStart() this.logSystemInformation() while (true) { @@ -1432,6 +1458,63 @@ export class AgenticChatController implements ChatHandlers { this.#llmRequestStartTime = Date.now() // Phase 3: Request Execution currentRequestInput = sanitizeRequestInput(currentRequestInput) + + if (this.#shouldCompact(currentRequestCount, session)) { + this.#features.logging.info( + `Entering mid-loop compaction at iteration ${iterationCount} with ${currentRequestCount} characters` + ) + this.#telemetryController.emitMidLoopCompaction( + currentRequestCount, + iterationCount, + this.#features.runtime.serverInfo.version ?? '' + ) + const messageId = this.#getMessageIdForCompact(uuid()) + const confirmationResult = this.#processCompactConfirmation(messageId, currentRequestCount) + const cachedButtonBlockId = await chatResultStream.writeResultBlock(confirmationResult) + await this.waitForCompactApproval(messageId, chatResultStream, cachedButtonBlockId, session) + + // Run compaction + const toolResults = + currentRequestInput.conversationState?.currentMessage?.userInputMessage?.userInputMessageContext + ?.toolResults || [] + const compactionRequestInput = this.#getCompactionRequestInput(session, toolResults) + const compactionResult = await this.#runCompaction( + compactionRequestInput, + session, + metric, + chatResultStream, + tabId, + promptId, + CompactHistoryActionType.Nudge, + session.conversationId, + token, + documentReference + ) + + if (!compactionResult.success) { + this.#features.logging.error(`Compaction failed: ${compactionResult.error}`) + return compactionResult + } + + // Show compaction summary to user before continuing + await chatResultStream.writeResultBlock({ + type: 'answer', + body: + (compactionResult.data?.chatResult.body || '') + + '\n\nConversation history has been compacted successfully!', + messageId: uuid(), + }) + + currentRequestInput = this.#updateRequestInputWithToolResults( + currentRequestInput, + [], + MID_LOOP_COMPACTION_HANDOFF_PROMPT + initialPrompt + ) + shouldDisplayMessage = false + this.#features.logging.info(`Completed mid-loop compaction, restarting loop with handoff prompt`) + continue + } + // Note: these logs are very noisy, but contain information redacted on the backend. this.#debug( `generateAssistantResponse/SendMessage Request: ${JSON.stringify(currentRequestInput, this.#imageReplacer, 2)}` @@ -1660,7 +1743,7 @@ export class AgenticChatController implements ChatHandlers { currentRequestInput = this.#updateRequestInputWithToolResults(currentRequestInput, toolResults, content) } - if (this.#shouldCompact(currentRequestCount)) { + if (this.#shouldCompact(currentRequestCount, session)) { this.#telemetryController.emitCompactNudge( currentRequestCount, this.#features.runtime.serverInfo.version ?? '' diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts index e37bc508ef..f01d4a4b0a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts @@ -18,6 +18,8 @@ export const GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT = 500_000 // 200K tokens * 3.5 = 700K characters, intentionally overestimating with 3.5:1 ratio export const MAX_OVERALL_CHARACTERS = 700_000 export const COMPACTION_CHARACTER_THRESHOLD = 0.7 * MAX_OVERALL_CHARACTERS +// TODO: We need to carefully craft a prompt for this supported by the science team +export const MID_LOOP_COMPACTION_HANDOFF_PROMPT = `CONTEXT HANDOFF: Previous conversation was compacted. Continue with user's request: ` export const COMPACTION_BODY = (threshold: number) => `The context window is almost full (${threshold}%) and exceeding it will clear your history. Amazon Q can compact your history instead.` export const COMPACTION_HEADER_BODY = 'Compact chat history?' diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/agenticChatTriggerContext.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/agenticChatTriggerContext.ts index 9baa192ea5..1eddf3afa5 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/agenticChatTriggerContext.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/agenticChatTriggerContext.ts @@ -113,13 +113,15 @@ export class AgenticChatTriggerContext { * @param tools Optional Bedrock tools * @param modelId Optional model ID * @param origin Optional origin + * @param toolResults Optional tool results to include in compaction context * @returns ChatCommandInput - which is either SendMessageInput or GenerateAssistantResponseInput */ getCompactionChatCommandInput( profileArn?: string, tools: BedrockTools = [], modelId?: string, - origin?: Origin + origin?: Origin, + toolResults?: any[] ): ChatCommandInput { const data: ChatCommandInput = { conversationState: { @@ -130,6 +132,7 @@ export class AgenticChatTriggerContext { userInputMessageContext: { tools, envState: this.#mapPlatformToEnvState(process.platform), + toolResults: toolResults, }, userIntent: undefined, origin: origin ? origin : 'IDE', diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts index c5cac3b8c4..0b92d13e12 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts @@ -42,6 +42,7 @@ export class ChatSessionService { public contextListSent: boolean = false public modelId: string | undefined public isMemoryBankGeneration: boolean = false + public compactionDeclined: boolean = false #lsp?: Features['lsp'] #abortController?: AbortController #currentPromptId?: string diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts index a197ee3934..2088b31dcf 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts @@ -243,6 +243,18 @@ export class ChatTelemetryController { }) } + public emitMidLoopCompaction(characters: number, iterationCount: number, languageServerVersion: string) { + this.#telemetry.emitMetric({ + name: ChatTelemetryEventName.MidLoopCompaction, + data: { + characters, + iterationCount, + credentialStartUrl: this.#credentialsProvider.getConnectionMetadata()?.sso?.startUrl, + languageServerVersion: languageServerVersion, + }, + }) + } + public emitToolUseSuggested( toolUse: ToolUse, conversationId: string, diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts index 5bf9fea185..fa07ff1036 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts @@ -207,6 +207,7 @@ export enum ChatTelemetryEventName { LoadHistory = 'amazonq_loadHistory', CompactHistory = 'amazonq_compactHistory', CompactNudge = 'amazonq_compactNudge', + MidLoopCompaction = 'amazonq_midLoopCompaction', ChatHistoryAction = 'amazonq_performChatHistoryAction', ExportTab = 'amazonq_exportTab', UiClick = 'ui_click', @@ -233,6 +234,7 @@ export interface ChatTelemetryEventMap { [ChatTelemetryEventName.LoadHistory]: LoadHistoryEvent [ChatTelemetryEventName.CompactHistory]: CompactHistoryEvent [ChatTelemetryEventName.CompactNudge]: CompactNudgeEvent + [ChatTelemetryEventName.MidLoopCompaction]: MidLoopCompactionEvent [ChatTelemetryEventName.ChatHistoryAction]: ChatHistoryActionEvent [ChatTelemetryEventName.ExportTab]: ExportTabEvent [ChatTelemetryEventName.UiClick]: UiClickEvent @@ -404,6 +406,13 @@ export type CompactNudgeEvent = { languageServerVersion?: string } +export type MidLoopCompactionEvent = { + characters: number + iterationCount: number + credentialStartUrl?: string + languageServerVersion?: string +} + export type ChatHistoryActionEvent = { action: ChatHistoryActionType result: Result From e4a1717fc30390be7686c1de7c977472fbd42983 Mon Sep 17 00:00:00 2001 From: atontb <104926752+atonaamz@users.noreply.github.com> Date: Mon, 6 Oct 2025 10:53:43 -0700 Subject: [PATCH 128/158] test(amazonq): add tests for inline utils files (#2385) --- .../handler/editCompletionHandler.ts | 2 +- .../inline-completion/utils/diffUtils.test.ts | 85 +++++++ .../inline-completion/utils/diffUtils.ts | 124 ---------- .../utils/mergeRightUtils.test.ts | 223 +++++++++++++----- .../utils/mergeRightUtils.ts | 42 +--- .../utils/triggerUtils.test.ts | 178 ++++++++++++++ .../{trigger.ts => utils/triggerUtils.ts} | 10 +- 7 files changed, 441 insertions(+), 223 deletions(-) create mode 100644 server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.test.ts rename server/aws-lsp-codewhisperer/src/language-server/inline-completion/{trigger.ts => utils/triggerUtils.ts} (85%) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts index badd538143..bbfd441699 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts @@ -22,7 +22,7 @@ import { CodeWhispererSession, SessionManager } from '../session/sessionManager' import { CursorTracker } from '../tracker/cursorTracker' import { CodewhispererLanguage, getSupportedLanguageId } from '../../../shared/languageDetection' import { WorkspaceFolderManager } from '../../workspaceContext/workspaceFolderManager' -import { shouldTriggerEdits } from '../trigger' +import { shouldTriggerEdits } from '../utils/triggerUtils' import { emitEmptyUserTriggerDecisionTelemetry, emitServiceInvocationFailure, diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.test.ts new file mode 100644 index 0000000000..40caa458a5 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.test.ts @@ -0,0 +1,85 @@ +import * as assert from 'assert' +import { getAddedAndDeletedLines, getCharacterDifferences, generateDiffContexts } from './diffUtils' + +describe('diffUtils', () => { + describe('getAddedAndDeletedLines', () => { + const SAMPLE_UNIFIED_DIFF = `--- a/file.txt ++++ b/file.txt +@@ -1,3 +1,3 @@ + line1 +-old line ++new line + line3` + it('should extract added and deleted lines from unified diff', () => { + const result = getAddedAndDeletedLines(SAMPLE_UNIFIED_DIFF) + + assert.deepEqual(result.addedLines, ['new line']) + assert.deepEqual(result.deletedLines, ['old line']) + }) + + it('should handle empty diff', () => { + const result = getAddedAndDeletedLines('') + assert.deepEqual(result.addedLines, []) + assert.deepEqual(result.deletedLines, []) + }) + }) + + describe('getCharacterDifferences', () => { + const ADDED_LINES = ['hello world'] + const DELETED_LINES = ['hello there'] + it('should calculate character differences using LCS', () => { + const result = getCharacterDifferences(ADDED_LINES, DELETED_LINES) + + assert.equal(result.charactersAdded, 4) + assert.equal(result.charactersRemoved, 4) + }) + + it('should handle empty added lines', () => { + const result = getCharacterDifferences([], DELETED_LINES) + + assert.equal(result.charactersAdded, 0) + assert.equal(result.charactersRemoved, 11) // 'hello there' = 11 chars + }) + + it('should handle empty deleted lines', () => { + const result = getCharacterDifferences(ADDED_LINES, []) + + assert.equal(result.charactersAdded, 11) // 'hello world' = 11 chars + assert.equal(result.charactersRemoved, 0) + }) + }) + + describe('generateDiffContexts', () => { + const TEST_FILE_PATH = '/test/file.ts' + const CURRENT_CONTENT = 'current content' + const OLD_CONTENT = 'old content' + const MAX_CONTEXTS = 5 + const SNAPSHOT_CONTENTS = [ + { + filePath: TEST_FILE_PATH, + content: OLD_CONTENT, + timestamp: Date.now() - 1000, + }, + ] + it('should generate diff contexts from snapshots', () => { + const result = generateDiffContexts(TEST_FILE_PATH, CURRENT_CONTENT, SNAPSHOT_CONTENTS, MAX_CONTEXTS) + + assert.equal(result.isUtg, false) + assert.equal(result.isProcessTimeout, false) + assert.equal(result.strategy, 'recentEdits') + assert.equal(typeof result.latency, 'number') + assert.equal(typeof result.contentsLength, 'number') + }) + + it('should return empty context for no snapshots', () => { + const result = generateDiffContexts(TEST_FILE_PATH, 'content', [], MAX_CONTEXTS) + + assert.equal(result.isUtg, false) + assert.equal(result.isProcessTimeout, false) + assert.equal(result.supplementalContextItems.length, 0) + assert.equal(result.contentsLength, 0) + assert.equal(result.latency, 0) + assert.equal(result.strategy, 'recentEdits') + }) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.ts index 5a8d05977e..77e6c28e6c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.ts @@ -131,88 +131,6 @@ export function generateDiffContexts( } } -/** src: https://github.com/aws/aws-toolkit-vscode/blob/3921457b0a2094b831beea0d66cc2cbd2a833890/packages/amazonq/src/app/inline/EditRendering/diffUtils.ts#L18 - * Apply a unified diff to original code to generate modified code - * @param originalCode The original code as a string - * @param unifiedDiff The unified diff content - * @returns The modified code after applying the diff - */ -export function applyUnifiedDiff(docText: string, unifiedDiff: string): string { - try { - // First try the standard diff package - try { - const result = diff.applyPatch(docText, unifiedDiff) - if (result !== false) { - return result - } - } catch (error) {} - - // Parse the unified diff to extract the changes - const diffLines = unifiedDiff.split('\n') - let result = docText - - // Find all hunks in the diff - const hunkStarts = diffLines - .map((line, index) => (line.startsWith('@@ ') ? index : -1)) - .filter(index => index !== -1) - - // Process each hunk - for (const hunkStart of hunkStarts) { - // Parse the hunk header - const hunkHeader = diffLines[hunkStart] - const match = hunkHeader.match(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/) - - if (!match) { - continue - } - - const oldStart = parseInt(match[1]) - const oldLines = parseInt(match[2]) - - // Extract the content lines for this hunk - let i = hunkStart + 1 - const contentLines = [] - while (i < diffLines.length && !diffLines[i].startsWith('@@')) { - contentLines.push(diffLines[i]) - i++ - } - - // Build the old and new text - let oldText = '' - let newText = '' - - for (const line of contentLines) { - if (line.startsWith('-')) { - oldText += line.substring(1) + '\n' - } else if (line.startsWith('+')) { - newText += line.substring(1) + '\n' - } else if (line.startsWith(' ')) { - oldText += line.substring(1) + '\n' - newText += line.substring(1) + '\n' - } - } - - // Remove trailing newline if it was added - oldText = oldText.replace(/\n$/, '') - newText = newText.replace(/\n$/, '') - - // Find the text to replace in the document - const docLines = docText.split('\n') - const startLine = oldStart - 1 // Convert to 0-based - const endLine = startLine + oldLines - - // Extract the text that should be replaced - const textToReplace = docLines.slice(startLine, endLine).join('\n') - - // Replace the text - result = result.replace(textToReplace, newText) - } - return result - } catch (error) { - return docText // Return original text if all methods fail - } -} - export function getAddedAndDeletedLines(unifiedDiff: string): { addedLines: string[]; deletedLines: string[] } { const lines = unifiedDiff.split('\n') const addedLines = lines.filter(line => line.startsWith('+') && !line.startsWith('+++')).map(line => line.slice(1)) @@ -225,48 +143,6 @@ export function getAddedAndDeletedLines(unifiedDiff: string): { addedLines: stri } } -// src https://github.com/aws/aws-toolkit-vscode/blob/3921457b0a2094b831beea0d66cc2cbd2a833890/packages/amazonq/src/app/inline/EditRendering/diffUtils.ts#L147 -export function getAddedAndDeletedChars(unifiedDiff: string): { - addedCharacters: string - deletedCharacters: string -} { - let addedCharacters = '' - let deletedCharacters = '' - const lines = unifiedDiff.split('\n') - for (let i = 0; i < lines.length; i++) { - const line = lines[i] - if (line.startsWith('+') && !line.startsWith('+++')) { - addedCharacters += line.slice(1) - } else if (line.startsWith('-') && !line.startsWith('---')) { - const removedLine = line.slice(1) - - // Check if this is a modified line rather than a pure deletion - const nextLine = lines[i + 1] - if (nextLine && nextLine.startsWith('+') && !nextLine.startsWith('+++')) { - // This is a modified line, not a pure deletion - // We've already counted the deletion, so we'll just increment i to skip the next line - // since we'll process the addition on the next iteration - const addedLine = nextLine.slice(1) - const changes = diff.diffChars(removedLine, addedLine) - for (const part of changes) { - if (part.removed) { - deletedCharacters += part.value - } else if (part.added) { - addedCharacters += part.value - } - } - i += 1 - } else { - deletedCharacters += removedLine - } - } - } - return { - addedCharacters, - deletedCharacters, - } -} - /** * Calculate character differences between added and deleted text blocks using LCS */ diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.test.ts index b0c92eb415..5fbcb0d717 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.test.ts @@ -1,74 +1,185 @@ -import { getPrefixOverlapLastIndex, getPrefixSuffixOverlap, truncateOverlapWithRightContext } from './mergeRightUtils' +import * as assert from 'assert' +import { + getPrefixSuffixOverlap, + truncateOverlapWithRightContext, + mergeSuggestionsWithRightContext, +} from './mergeRightUtils' +import { Suggestion } from '../../../shared/codeWhispererService' import { HELLO_WORLD_IN_CSHARP, HELLO_WORLD_WITH_WINDOWS_ENDING } from '../../../shared/testUtils' -import assert = require('assert') -describe('Merge Right Utils', () => { - const HELLO_WORLD = `Console.WriteLine("Hello World!");` +describe('mergeRightUtils', () => { + describe('getPrefixSuffixOverlap', () => { + it('should find overlap between suffix and prefix', () => { + const result = getPrefixSuffixOverlap('adwg31', '31ggrs') + assert.equal(result, '31') + }) - it('get prefix suffix overlap works as expected', () => { - const result = getPrefixSuffixOverlap('adwg31', '31ggrs') - assert.deepEqual(result, '31') - }) + it('should return empty string when no overlap', () => { + const result = getPrefixSuffixOverlap('hello', 'world') + assert.equal(result, '') + }) - it('get prefix prefix overlap index works as expected', () => { - const result1 = getPrefixOverlapLastIndex('static void', 'static') - assert.deepEqual(result1, 6) - const result2 = getPrefixOverlapLastIndex('static void', 'void') - assert.deepEqual(result2, 11) - const result3 = getPrefixOverlapLastIndex('static void', 'staic') - assert.deepEqual(result3, 3) - }) + it('should handle empty strings', () => { + const result = getPrefixSuffixOverlap('', 'test') + assert.equal(result, '') + }) - it('should return empty suggestion when right context equals line content ', () => { - const result = truncateOverlapWithRightContext(HELLO_WORLD, HELLO_WORLD) - assert.deepEqual(result, '') + it('should find full overlap when second string is prefix of first', () => { + const result = getPrefixSuffixOverlap('hello', 'hello world') + assert.equal(result, 'hello') + }) }) - it('should return empty suggestion when right context equals file content', () => { - // Without trimStart, this test would fail because the function doesn't trim leading new line from right context - const result = truncateOverlapWithRightContext(HELLO_WORLD_IN_CSHARP.trimStart(), HELLO_WORLD_IN_CSHARP) - assert.deepEqual(result, '') - }) + describe('truncateOverlapWithRightContext', () => { + const HELLO_WORLD = 'Console.WriteLine("Hello World!");' + it('should truncate overlap with right context', () => { + const rightContext = '");' + const result = truncateOverlapWithRightContext(rightContext, HELLO_WORLD) + assert.equal(result, 'Console.WriteLine("Hello World!') + }) - it('should not handle the case where right context fully matches suggestion but starts with a newline ', () => { - const result = truncateOverlapWithRightContext('\n' + HELLO_WORLD_IN_CSHARP, HELLO_WORLD_IN_CSHARP) - // Even though right context and suggestion are equal, the newline of right context doesn't get trimmed while the newline of suggestion gets trimmed - // As a result, we end up with no overlap - assert.deepEqual(result, HELLO_WORLD_IN_CSHARP) - }) + it('should return original suggestion when no overlap', () => { + const rightContext = 'different content' + const result = truncateOverlapWithRightContext(rightContext, HELLO_WORLD) + assert.equal(result, HELLO_WORLD) + }) - it('should return truncated suggestion when right context matches end of the suggestion', () => { - // File contents will be `nsole.WriteLine("Hello World!");` - // Suggestion will be the full HELLO_WORLD - // Final truncated result should be the first two letters of HELLO_WORLD - const result = truncateOverlapWithRightContext(HELLO_WORLD.substring(2), HELLO_WORLD) + it('should handle right context with leading whitespace', () => { + const suggestion = 'const x = 1;' + const rightContext = ' ; // comment' + const result = truncateOverlapWithRightContext(rightContext, suggestion) + assert.equal(result, 'const x = 1') + }) - assert.deepEqual(result, HELLO_WORLD.substring(0, 2)) - }) + it('should return empty suggestion when right context equals line content ', () => { + const result1 = truncateOverlapWithRightContext(HELLO_WORLD, HELLO_WORLD) + assert.deepEqual(result1, '') + // Without trimStart, this test would fail because the function doesn't trim leading new line from right context + const result2 = truncateOverlapWithRightContext(HELLO_WORLD_IN_CSHARP.trimStart(), HELLO_WORLD_IN_CSHARP) + assert.deepEqual(result2, '') + }) - it('should trim right-context tabs and whitespaces until first newline', () => { - const suggestion = '{\n return a + b;\n }' - const rightContent = ' \n }\n\n }\n}' - const expected_result = '{\n return a + b;' - const result = truncateOverlapWithRightContext(rightContent, suggestion) + it('should not handle the case where right context fully matches suggestion but starts with a newline ', () => { + const result = truncateOverlapWithRightContext('\n' + HELLO_WORLD_IN_CSHARP, HELLO_WORLD_IN_CSHARP) + // Even though right context and suggestion are equal, the newline of right context doesn't get trimmed while the newline of suggestion gets trimmed + // As a result, we end up with no overlap + assert.deepEqual(result, HELLO_WORLD_IN_CSHARP) + }) - assert.deepEqual(result, expected_result) - }) + it('should return truncated suggestion when right context matches end of the suggestion', () => { + // File contents will be `nsole.WriteLine("Hello World!");` + // Suggestion will be the full HELLO_WORLD + // Final truncated result should be the first two letters of HELLO_WORLD + const result = truncateOverlapWithRightContext(HELLO_WORLD.substring(2), HELLO_WORLD) - it('should handle different line endings', () => { - const suggestion = '{\n return a + b;\n }' - const rightContent = '\r\n }\r\n}\r\n}' - const expected_result = '{\n return a + b;' - const result = truncateOverlapWithRightContext(rightContent, suggestion) + assert.deepEqual(result, HELLO_WORLD.substring(0, 2)) + }) - assert.deepEqual(result, expected_result) + it('should trim right-context tabs and whitespaces until first newline', () => { + const suggestion = '{\n return a + b;\n }' + const rightContent = ' \n }\n\n }\n}' + const expected_result = '{\n return a + b;' + const result = truncateOverlapWithRightContext(rightContent, suggestion) + + assert.deepEqual(result, expected_result) + }) + + it('should handle different line endings', () => { + const suggestion = '{\n return a + b;\n }' + const rightContent = '\r\n }\r\n}\r\n}' + const expected_result = '{\n return a + b;' + const result = truncateOverlapWithRightContext(rightContent, suggestion) + + assert.deepEqual(result, expected_result) + }) + + it('should handle windows line endings for files', () => { + const result = truncateOverlapWithRightContext( + HELLO_WORLD_WITH_WINDOWS_ENDING, + HELLO_WORLD_WITH_WINDOWS_ENDING.replaceAll('\r', '') + ) + assert.deepEqual(result, '') + }) }) - it('should handle windows line endings for files', () => { - const result = truncateOverlapWithRightContext( - HELLO_WORLD_WITH_WINDOWS_ENDING, - HELLO_WORLD_WITH_WINDOWS_ENDING.replaceAll('\r', '') - ) - assert.deepEqual(result, '') + describe('mergeSuggestionsWithRightContext', () => { + const mockSuggestions: Suggestion[] = [ + { + itemId: 'item1', + content: 'console.log("test");', + references: [ + { + licenseName: 'MIT', + url: 'https://example.com', + repository: 'test-repo', + recommendationContentSpan: { start: 0, end: 10 }, + }, + ], + mostRelevantMissingImports: [ + { + statement: 'import { test } from "test"', + }, + ], + }, + ] + + it('should merge suggestions with right context', () => { + const rightContext = '");' + const result = mergeSuggestionsWithRightContext(rightContext, mockSuggestions, false) + + assert.equal(result.length, 1) + assert.equal(result[0].itemId, 'item1') + assert.equal(result[0].insertText, 'console.log("test') + assert.equal(result[0].mostRelevantMissingImports, undefined) + }) + + it('should include imports when enabled', () => { + const rightContext = '' + const result = mergeSuggestionsWithRightContext(rightContext, mockSuggestions, true) + + assert.equal(result[0].mostRelevantMissingImports?.length, 1) + assert.equal(result[0].mostRelevantMissingImports?.[0].statement, 'import { test } from "test"') + }) + + it('should filter references based on insert text length', () => { + const suggestions: Suggestion[] = [ + { + itemId: 'item1', + content: 'short', + references: [ + { + licenseName: 'MIT', + url: 'https://example.com', + repository: 'test-repo', + recommendationContentSpan: { start: 10, end: 20 }, // start > insertText.length + }, + ], + }, + ] + + const result = mergeSuggestionsWithRightContext('', suggestions, false) + + assert.equal(result[0].references, undefined) + }) + + it('should include range when provided', () => { + const range = { start: { line: 0, character: 0 }, end: { line: 0, character: 5 } } + const result = mergeSuggestionsWithRightContext('', mockSuggestions, false, range) + + assert.deepEqual(result[0].range, range) + }) + + it('should handle suggestions with no references', () => { + const suggestions: Suggestion[] = [ + { + itemId: 'item1', + content: 'test content', + }, + ] + + const result = mergeSuggestionsWithRightContext('', suggestions, false) + + assert.equal(result[0].references, undefined) + }) }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.ts index 95daadb15e..b0634a7748 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.ts @@ -16,49 +16,17 @@ export function getPrefixSuffixOverlap(firstString: string, secondString: string return secondString.slice(0, i) } -/** - * Returns the last index of the longest overlap between the first string and the second string - * @param targetString the target string - * @param searchString the search string - * @returns last index of the longest overlap between the first string and the second string - * @example getPrefixOverlapLastIndex("public static void", "static") = 13 - */ -export function getPrefixOverlapLastIndex(targetString: string, searchString: string) { - let i = searchString.length - let idx = -1 - while (i > 0) { - idx = targetString.indexOf(searchString.slice(0, i)) - if (idx != -1) { - return idx + i - } - i-- - } - return idx -} - -export function truncateOverlapWithRightContext( - rightFileContent: string, - suggestion: string, - userEdit?: string -): string { +export function truncateOverlapWithRightContext(rightFileContent: string, suggestion: string): string { const trimmedSuggestion = suggestion.trim() // limit of 5000 for right context matching const rightContext = rightFileContent .substring(0, 5000) .replaceAll('\r\n', '\n') .replace(/^[^\S\n]+/, '') // remove leading tabs and whitespaces - let prefixOverlapLastIndex = 0 - if (userEdit) { - const trimmpedUserEdit = userEdit.trim() - prefixOverlapLastIndex = getPrefixOverlapLastIndex(trimmedSuggestion, trimmpedUserEdit) - if (prefixOverlapLastIndex == -1) { - return '' - } - } - const prefixSuffixOverlap = getPrefixSuffixOverlap(trimmedSuggestion, rightContext) - const prefixSuffixOverlapIndex = suggestion.lastIndexOf(prefixSuffixOverlap) - if (prefixSuffixOverlapIndex >= 0) { - const truncated = suggestion.slice(prefixOverlapLastIndex, prefixSuffixOverlapIndex) + const overlap = getPrefixSuffixOverlap(trimmedSuggestion, rightContext) + const overlapIndex = suggestion.lastIndexOf(overlap) + if (overlapIndex >= 0) { + const truncated = suggestion.slice(0, overlapIndex) return truncated.trim().length ? truncated : '' } else { return suggestion diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.test.ts new file mode 100644 index 0000000000..5683d50f1d --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.test.ts @@ -0,0 +1,178 @@ +import * as assert from 'assert' +import * as sinon from 'sinon' +import { shouldTriggerEdits, NepTrigger } from './triggerUtils' +import { SessionManager } from '../session/sessionManager' +import { CursorTracker } from '../tracker/cursorTracker' +import { RecentEditTracker } from '../tracker/codeEditTracker' +import { + CodeWhispererServiceToken, + CodeWhispererServiceIAM, + ClientFileContext, +} from '../../../shared/codeWhispererService' +import * as editPredictionAutoTrigger from '../auto-trigger/editPredictionAutoTrigger' +import { InlineCompletionWithReferencesParams } from '@aws/language-server-runtimes/server-interface' + +describe('triggerUtils', () => { + let service: sinon.SinonStubbedInstance + let iamService: sinon.SinonStubbedInstance + let cursorTracker: sinon.SinonStubbedInstance + let recentEditsTracker: sinon.SinonStubbedInstance + let sessionManager: sinon.SinonStubbedInstance + let editPredictionAutoTriggerStub: sinon.SinonStub + + const fileContext = { + leftFileContent: 'const x = 1;', + rightFileContent: '', + filename: 'test.ts', + programmingLanguage: { languageName: 'typescript' }, + } as ClientFileContext + + const inlineParams = { + textDocument: { uri: 'file:///test.ts' }, + position: { line: 0, character: 12 }, + context: { triggerKind: 1 }, + documentChangeParams: { + contentChanges: [{ text: ';' }], + }, + } as InlineCompletionWithReferencesParams + + beforeEach(() => { + service = sinon.createStubInstance(CodeWhispererServiceToken) + iamService = sinon.createStubInstance(CodeWhispererServiceIAM) + cursorTracker = sinon.createStubInstance(CursorTracker) + recentEditsTracker = sinon.createStubInstance(RecentEditTracker) + sessionManager = sinon.createStubInstance(SessionManager) + editPredictionAutoTriggerStub = sinon.stub(editPredictionAutoTrigger, 'editPredictionAutoTrigger') + }) + + afterEach(() => { + sinon.restore() + }) + + describe('shouldTriggerEdits', () => { + it('should return undefined when edits not enabled', () => { + const result = shouldTriggerEdits( + service, + fileContext, + inlineParams, + cursorTracker, + recentEditsTracker, + sessionManager, + false + ) + + assert.equal(result, undefined) + }) + + it('should return undefined when service is not token-based', () => { + const result = shouldTriggerEdits( + iamService, + fileContext, + inlineParams, + cursorTracker, + recentEditsTracker, + sessionManager, + true + ) + + assert.equal(result, undefined) + }) + + it('should return NepTrigger when auto trigger returns shouldTrigger true', () => { + editPredictionAutoTriggerStub.returns({ shouldTrigger: true }) + sessionManager.getPreviousSession.returns(undefined) + + const result = shouldTriggerEdits( + service, + fileContext, + inlineParams, + cursorTracker, + recentEditsTracker, + sessionManager, + true + ) + + assert.ok(result instanceof NepTrigger) + sinon.assert.calledWith(editPredictionAutoTriggerStub, { + fileContext, + lineNum: 0, + char: ';', + previousDecision: '', + cursorHistory: cursorTracker, + recentEdits: recentEditsTracker, + }) + }) + + it('should return undefined when auto trigger returns shouldTrigger false', () => { + editPredictionAutoTriggerStub.returns({ shouldTrigger: false }) + sessionManager.getPreviousSession.returns(undefined) + + const result = shouldTriggerEdits( + service, + fileContext, + inlineParams, + cursorTracker, + recentEditsTracker, + sessionManager, + true + ) + + assert.equal(result, undefined) + }) + + it('should use last character from file content when no document change', () => { + const paramsWithoutDocChange = { + ...inlineParams, + documentChangeParams: undefined, + } + editPredictionAutoTriggerStub.returns({ shouldTrigger: true }) + sessionManager.getPreviousSession.returns(undefined) + + shouldTriggerEdits( + service, + fileContext, + paramsWithoutDocChange, + cursorTracker, + recentEditsTracker, + sessionManager, + true + ) + + sinon.assert.calledWith(editPredictionAutoTriggerStub, { + fileContext, + lineNum: 0, + char: ';', + previousDecision: '', + cursorHistory: cursorTracker, + recentEdits: recentEditsTracker, + }) + }) + + it('should use previous session decision when available', () => { + const mockSession = { + getAggregatedUserTriggerDecision: sinon.stub().returns('Accept'), + } + sessionManager.getPreviousSession.returns(mockSession as any) + editPredictionAutoTriggerStub.returns({ shouldTrigger: true }) + + shouldTriggerEdits( + service, + fileContext, + inlineParams, + cursorTracker, + recentEditsTracker, + sessionManager, + true + ) + + sinon.assert.calledWith(editPredictionAutoTriggerStub, { + fileContext, + lineNum: 0, + char: ';', + previousDecision: 'Accept', + cursorHistory: cursorTracker, + recentEdits: recentEditsTracker, + }) + }) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/trigger.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.ts similarity index 85% rename from server/aws-lsp-codewhisperer/src/language-server/inline-completion/trigger.ts rename to server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.ts index 305b9b6e5c..ce113143ae 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/trigger.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.ts @@ -1,13 +1,13 @@ -import { SessionManager } from './session/sessionManager' +import { SessionManager } from '../session/sessionManager' import { InlineCompletionWithReferencesParams } from '@aws/language-server-runtimes/protocol' -import { editPredictionAutoTrigger } from './auto-trigger/editPredictionAutoTrigger' -import { CursorTracker } from './tracker/cursorTracker' -import { RecentEditTracker } from './tracker/codeEditTracker' +import { editPredictionAutoTrigger } from '../auto-trigger/editPredictionAutoTrigger' +import { CursorTracker } from '../tracker/cursorTracker' +import { RecentEditTracker } from '../tracker/codeEditTracker' import { CodeWhispererServiceBase, CodeWhispererServiceToken, ClientFileContext, -} from '../../shared/codeWhispererService' +} from '../../../shared/codeWhispererService' export class NepTrigger {} From ed8c6dda1312f728e9ee7472f7ca447196ad9d84 Mon Sep 17 00:00:00 2001 From: chungjac Date: Mon, 6 Oct 2025 16:37:21 -0700 Subject: [PATCH 129/158] feat: add model description to dropdown (#2374) * feat: add model description to dropdown * fix: bump up mynah version to enable hover --- chat-client/package.json | 4 +-- chat-client/src/client/mynahUi.test.ts | 10 ++++-- chat-client/src/client/mynahUi.ts | 6 +++- .../src/client/texts/modelSelection.ts | 11 ++++--- client/vscode/package.json | 2 +- package-lock.json | 31 +++++++++---------- server/aws-lsp-codewhisperer/package.json | 2 +- .../agenticChat/agenticChatController.test.ts | 24 +++++++++----- .../agenticChat/agenticChatController.ts | 5 +-- .../constants/modelSelection.test.ts | 7 ++--- .../agenticChat/constants/modelSelection.ts | 12 ++++--- 11 files changed, 66 insertions(+), 48 deletions(-) diff --git a/chat-client/package.json b/chat-client/package.json index aa079f4fd6..aff0948d16 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -24,10 +24,10 @@ "package": "webpack" }, "dependencies": { - "@aws/chat-client-ui-types": "^0.1.56", + "@aws/chat-client-ui-types": "^0.1.57", "@aws/language-server-runtimes": "^0.2.129", "@aws/language-server-runtimes-types": "^0.1.50", - "@aws/mynah-ui": "^4.36.6" + "@aws/mynah-ui": "^4.36.8" }, "devDependencies": { "@types/jsdom": "^21.1.6", diff --git a/chat-client/src/client/mynahUi.test.ts b/chat-client/src/client/mynahUi.test.ts index 8524ab7713..3a13772926 100644 --- a/chat-client/src/client/mynahUi.test.ts +++ b/chat-client/src/client/mynahUi.test.ts @@ -571,7 +571,7 @@ describe('MynahUI', () => { // Simulate the response from the server const models = [ { id: 'CLAUDE_3_7_SONNET_20250219_V1_0', name: 'Claude Sonnet 3.7' }, - { id: 'CLAUDE_SONNET_4_20250514_V1_0', name: 'Claude Sonnet 4' }, + { id: 'CLAUDE_SONNET_4_20250514_V1_0', name: 'Claude Sonnet 4', description: 'Test description' }, ] const result: ListAvailableModelsResult = { @@ -589,8 +589,12 @@ describe('MynahUI', () => { { id: 'model-selection', options: [ - { value: 'CLAUDE_3_7_SONNET_20250219_V1_0', label: 'Claude Sonnet 3.7' }, - { value: 'CLAUDE_SONNET_4_20250514_V1_0', label: 'Claude Sonnet 4' }, + { value: 'CLAUDE_3_7_SONNET_20250219_V1_0', label: 'Claude Sonnet 3.7', description: '' }, + { + value: 'CLAUDE_SONNET_4_20250514_V1_0', + label: 'Claude Sonnet 4', + description: 'Test description', + }, ], type: 'select', value: 'CLAUDE_3_7_SONNET_20250219_V1_0', diff --git a/chat-client/src/client/mynahUi.ts b/chat-client/src/client/mynahUi.ts index e2ce161f6f..0bcdf9bacd 100644 --- a/chat-client/src/client/mynahUi.ts +++ b/chat-client/src/client/mynahUi.ts @@ -1737,7 +1737,11 @@ ${params.message}`, ? { ...option, type: 'select', - options: params.models.map(model => ({ value: model.id, label: model.name })), + options: params.models.map(model => ({ + value: model.id, + label: model.name, + description: model.description ?? '', + })), value: params.selectedModelId, } : option diff --git a/chat-client/src/client/texts/modelSelection.ts b/chat-client/src/client/texts/modelSelection.ts index a1d0247875..6cfd25b7fe 100644 --- a/chat-client/src/client/texts/modelSelection.ts +++ b/chat-client/src/client/texts/modelSelection.ts @@ -5,21 +5,24 @@ import { ChatItem, ChatItemFormItem, ChatItemType } from '@aws/mynah-ui' */ export enum BedrockModel { CLAUDE_SONNET_4_20250514_V1_0 = 'CLAUDE_SONNET_4_20250514_V1_0', - CLAUDE_3_7_SONNET_20250219_V1_0 = 'CLAUDE_3_7_SONNET_20250219_V1_0', } type ModelDetails = { label: string + description: string } const modelRecord: Record = { - [BedrockModel.CLAUDE_3_7_SONNET_20250219_V1_0]: { label: 'Claude 3.7 Sonnet' }, - [BedrockModel.CLAUDE_SONNET_4_20250514_V1_0]: { label: 'Claude Sonnet 4' }, + [BedrockModel.CLAUDE_SONNET_4_20250514_V1_0]: { + label: 'Claude Sonnet 4', + description: 'Hybrid reasoning and coding for regular use', + }, } -const modelOptions = Object.entries(modelRecord).map(([value, { label }]) => ({ +const modelOptions = Object.entries(modelRecord).map(([value, { label, description }]) => ({ value, label, + description, })) export const modelSelection: ChatItemFormItem = { diff --git a/client/vscode/package.json b/client/vscode/package.json index a943422cfa..baeeb80cfe 100644 --- a/client/vscode/package.json +++ b/client/vscode/package.json @@ -351,7 +351,7 @@ "devDependencies": { "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", - "@aws/chat-client-ui-types": "^0.1.56", + "@aws/chat-client-ui-types": "^0.1.57", "@aws/language-server-runtimes": "^0.2.129", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", diff --git a/package-lock.json b/package-lock.json index ebbfc8606b..638493ff16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -254,10 +254,10 @@ "version": "0.1.38", "license": "Apache-2.0", "dependencies": { - "@aws/chat-client-ui-types": "^0.1.56", + "@aws/chat-client-ui-types": "^0.1.57", "@aws/language-server-runtimes": "^0.2.129", "@aws/language-server-runtimes-types": "^0.1.50", - "@aws/mynah-ui": "^4.36.6" + "@aws/mynah-ui": "^4.36.8" }, "devDependencies": { "@types/jsdom": "^21.1.6", @@ -279,7 +279,7 @@ "devDependencies": { "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", - "@aws/chat-client-ui-types": "^0.1.56", + "@aws/chat-client-ui-types": "^0.1.57", "@aws/language-server-runtimes": "^0.2.129", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", @@ -4019,12 +4019,11 @@ "link": true }, "node_modules/@aws/chat-client-ui-types": { - "version": "0.1.56", - "resolved": "https://registry.npmjs.org/@aws/chat-client-ui-types/-/chat-client-ui-types-0.1.56.tgz", - "integrity": "sha512-5FAFyzo0KzqnVBbZuhN4drCmLnREbb4IpAzb/OS8omNLf1/yUsP89DBCNoW6WxqFuWSASwaPEffmQOuMT3bWIg==", - "license": "Apache-2.0", + "version": "0.1.63", + "resolved": "https://registry.npmjs.org/@aws/chat-client-ui-types/-/chat-client-ui-types-0.1.63.tgz", + "integrity": "sha512-LTiDodg/9jXJSoTmbPa056zRtKjz4Z4szAb7loZa7J7uOMpJ8ah/MxdpOKltW9PgcZ3F7u7585U5LuNPuoY+2A==", "dependencies": { - "@aws/language-server-runtimes-types": "^0.1.50" + "@aws/language-server-runtimes-types": "^0.1.57" } }, "node_modules/@aws/hello-world-lsp": { @@ -4068,10 +4067,9 @@ } }, "node_modules/@aws/language-server-runtimes-types": { - "version": "0.1.56", - "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.56.tgz", - "integrity": "sha512-Md/L750JShCHUsCQUJva51Ofkn/GDBEX8PpZnWUIVqkpddDR00SLQS2smNf4UHtKNJ2fefsfks/Kqfuatjkjvg==", - "license": "Apache-2.0", + "version": "0.1.57", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes-types/-/language-server-runtimes-types-0.1.57.tgz", + "integrity": "sha512-Poy8BW4njSBt6jf3ATnc3YRZQTFnNvFcYs/wcCAvPj314XRdDCS731y3EESVVdXfXlTIqLZrnHsvQgtbNm59Tw==", "dependencies": { "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5" @@ -4204,11 +4202,10 @@ "link": true }, "node_modules/@aws/mynah-ui": { - "version": "4.36.6", - "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.36.6.tgz", - "integrity": "sha512-RIFKIasIgO00dYmRM+JS7dij1hzrNZchhf0+CyUNDUpw2Hcc86/8lP90F1F5rJIOtqtnguiPQ7XwmXxf+Tw5jQ==", + "version": "4.36.8", + "resolved": "https://registry.npmjs.org/@aws/mynah-ui/-/mynah-ui-4.36.8.tgz", + "integrity": "sha512-1IDUjzX42ASOuf6DD+uv/MYlIB50U0wZxX3Rqpc0aR4KFHpoX5mUIwGvqS/uHj42aySFN2QL+T6vUEvD0l6v1A==", "hasInstallScript": true, - "license": "Apache License 2.0", "dependencies": { "escape-html": "^1.0.3", "highlight.js": "^11.11.0", @@ -28689,7 +28686,7 @@ "@amzn/codewhisperer-streaming": "file:../../core/codewhisperer-streaming/amzn-codewhisperer-streaming-1.0.0.tgz", "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", - "@aws/chat-client-ui-types": "^0.1.56", + "@aws/chat-client-ui-types": "^0.1.57", "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.16", "@modelcontextprotocol/sdk": "^1.15.0", diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 6219fc5798..bd6432040d 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -35,7 +35,7 @@ "@amzn/codewhisperer-streaming": "file:../../core/codewhisperer-streaming/amzn-codewhisperer-streaming-1.0.0.tgz", "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", - "@aws/chat-client-ui-types": "^0.1.56", + "@aws/chat-client-ui-types": "^0.1.57", "@aws/language-server-runtimes": "^0.2.129", "@aws/lsp-core": "^0.0.16", "@modelcontextprotocol/sdk": "^1.15.0", diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts index 4ab9587d1c..367870e3e7 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts @@ -3043,8 +3043,8 @@ ${' '.repeat(8)}} isCachedModelsValidStub.returns(true) const cachedData = { models: [ - { id: 'model1', name: 'Model 1' }, - { id: 'model2', name: 'Model 2' }, + { id: 'model1', name: 'Model 1', description: 'Test description 1' }, + { id: 'model2', name: 'Model 2', description: 'Test description 2' }, ], defaultModelId: 'model1', timestamp: Date.now(), @@ -3128,8 +3128,16 @@ ${' '.repeat(8)}} const mockApiResponse = { models: { - 'claude-3-sonnet': { modelId: 'claude-3-sonnet' }, - 'claude-4-sonnet': { modelId: 'claude-4-sonnet' }, + 'claude-3-sonnet': { + modelId: 'claude-3-sonnet', + modelName: 'Claude 3 Sonnet', + description: 'Advanced AI model', + }, + 'claude-4-sonnet': { + modelId: 'claude-4-sonnet', + modelName: 'Claude 4 Sonnet', + description: 'Latest AI model', + }, }, defaultModel: { modelId: 'claude-3-sonnet' }, } @@ -3147,8 +3155,8 @@ ${' '.repeat(8)}} assert.strictEqual(result.tabId, mockTabId) assert.strictEqual(result.models.length, 2) assert.deepStrictEqual(result.models, [ - { id: 'claude-3-sonnet', name: 'claude-3-sonnet' }, - { id: 'claude-4-sonnet', name: 'claude-4-sonnet' }, + { id: 'claude-3-sonnet', name: 'Claude 3 Sonnet', description: 'Advanced AI model' }, + { id: 'claude-4-sonnet', name: 'Claude 4 Sonnet', description: 'Latest AI model' }, ]) // Verify cache was updated @@ -3163,7 +3171,7 @@ ${' '.repeat(8)}} // Verify fallback to FALLBACK_MODEL_OPTIONS assert.strictEqual(result.tabId, mockTabId) - assert.strictEqual(result.models.length, 2) // FALLBACK_MODEL_OPTIONS length + assert.strictEqual(result.models.length, 1) // FALLBACK_MODEL_OPTIONS length // Verify cache was not updated due to error sinon.assert.notCalled(setCachedModelsStub) @@ -3230,7 +3238,7 @@ ${' '.repeat(8)}} it('should fall back to default model when session has no modelId and no defaultModelId in cache', async () => { getCachedModelsStub.returns({ - models: [{ id: 'model1', name: 'Model 1' }], + models: [{ id: 'model1', name: 'Model 1', description: 'Test model' }], defaultModelId: undefined, // No default model timestamp: Date.now(), }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 374e0a9060..005101b715 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -726,9 +726,10 @@ export class AgenticChatController implements ChatHandlers { // Wait for the response to be completed before proceeding this.#log('Model Response: ', JSON.stringify(responseResult, null, 2)) - models = Object.values(responseResult.models).map(({ modelId, modelName }) => ({ + models = Object.values(responseResult.models).map(({ modelId, modelName, description }) => ({ id: modelId, name: modelName ?? modelId, + description: description ?? '', })) defaultModelId = responseResult.defaultModel?.modelId @@ -765,7 +766,7 @@ export class AgenticChatController implements ChatHandlers { const { models, defaultModelId, errorFromAPI } = await this.#fetchModelsWithCache() // Get the first fallback model option as default - const defaultModelOption = FALLBACK_MODEL_OPTIONS[1] + const defaultModelOption = FALLBACK_MODEL_OPTIONS[0] const DEFAULT_MODEL_ID = defaultModelId || defaultModelOption?.id const sessionResult = this.#chatSessionManagementService.getSession(params.tabId) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.test.ts index f037470bec..211cf52dfe 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.test.ts @@ -5,27 +5,26 @@ describe('modelSelection', () => { describe('modelOptions', () => { it('should contain the correct model options', () => { assert.ok(Array.isArray(FALLBACK_MODEL_OPTIONS), 'modelOptions should be an array') - assert.strictEqual(FALLBACK_MODEL_OPTIONS.length, 2, 'modelOptions should have 2 items') + assert.strictEqual(FALLBACK_MODEL_OPTIONS.length, 1, 'modelOptions should have 1 item') // Check that the array contains the expected models const modelIds = FALLBACK_MODEL_OPTIONS.map(model => model.id) assert.ok(modelIds.includes('CLAUDE_SONNET_4_20250514_V1_0'), 'Should include claude-sonnet-4') - assert.ok(modelIds.includes('CLAUDE_3_7_SONNET_20250219_V1_0'), 'Should include claude-3.7-sonnet') // Check that each model has the required properties FALLBACK_MODEL_OPTIONS.forEach(model => { assert.ok('id' in model, 'Model should have id property') assert.ok('name' in model, 'Model should have name property') + assert.ok('description' in model, 'Model should have description property') assert.strictEqual(typeof model.id, 'string', 'Model id should be a string') assert.strictEqual(typeof model.name, 'string', 'Model name should be a string') + assert.strictEqual(typeof model.description, 'string', 'Model description should be a string') }) // Check specific model names const claudeSonnet4 = FALLBACK_MODEL_OPTIONS.find(model => model.id === 'CLAUDE_SONNET_4_20250514_V1_0') - const claudeSonnet37 = FALLBACK_MODEL_OPTIONS.find(model => model.id === 'CLAUDE_3_7_SONNET_20250219_V1_0') assert.strictEqual(claudeSonnet4?.name, 'Claude Sonnet 4', 'claude-sonnet-4 should have correct name') - assert.strictEqual(claudeSonnet37?.name, 'Claude 3.7 Sonnet', 'claude-3.7-sonnet should have correct name') }) }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.ts index 46c5446c8c..9e9927b10c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/modelSelection.ts @@ -5,26 +5,28 @@ import { ListAvailableModelsResult } from '@aws/language-server-runtimes/protoco */ export enum BedrockModel { CLAUDE_SONNET_4_20250514_V1_0 = 'CLAUDE_SONNET_4_20250514_V1_0', - CLAUDE_3_7_SONNET_20250219_V1_0 = 'CLAUDE_3_7_SONNET_20250219_V1_0', } type ModelDetails = { label: string + description: string } export const FALLBACK_MODEL_RECORD: Record = { - [BedrockModel.CLAUDE_3_7_SONNET_20250219_V1_0]: { label: 'Claude 3.7 Sonnet' }, - [BedrockModel.CLAUDE_SONNET_4_20250514_V1_0]: { label: 'Claude Sonnet 4' }, + [BedrockModel.CLAUDE_SONNET_4_20250514_V1_0]: { + label: 'Claude Sonnet 4', + description: 'Hybrid reasoning and coding for regular use', + }, } export const BEDROCK_MODEL_TO_MODEL_ID: Record = { - [BedrockModel.CLAUDE_3_7_SONNET_20250219_V1_0]: 'claude-3.7-sonnet', [BedrockModel.CLAUDE_SONNET_4_20250514_V1_0]: 'claude-sonnet-4', } export const FALLBACK_MODEL_OPTIONS: ListAvailableModelsResult['models'] = Object.entries(FALLBACK_MODEL_RECORD).map( - ([value, { label }]) => ({ + ([value, { label, description }]) => ({ id: value, name: label, + description: description, }) ) From 4f5a9dacf3bfd68aeb40920fb800adf001ed43d5 Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Tue, 7 Oct 2025 09:44:50 -0700 Subject: [PATCH 130/158] fix: addonly EDITS should be handled as COMPLETIONS (#2133) --- .../handler/editCompletionHandler.ts | 14 +- .../inline-completion/utils/diffUtils.test.ts | 312 +++++++++++++++++- .../inline-completion/utils/diffUtils.ts | 203 ++++++++++++ .../src/shared/codeWhispererService.ts | 36 +- 4 files changed, 544 insertions(+), 21 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts index bbfd441699..42a45f1f8c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts @@ -38,6 +38,7 @@ import { AmazonQError, AmazonQServiceConnectionExpiredError } from '../../../sha import { DocumentChangedListener } from '../documentChangedListener' import { EMPTY_RESULT, EDIT_DEBOUNCE_INTERVAL_MS } from '../contants/constants' import { StreakTracker } from '../tracker/streakTracker' +import { processEditSuggestion } from '../utils/diffUtils' export class EditCompletionHandler { private readonly editsEnabled: boolean @@ -396,6 +397,13 @@ export class EditCompletionHandler { textDocument?.uri || '' ) + const processedSuggestion = processEditSuggestion( + suggestion.content, + session.startPosition, + session.document + ) + const isInlineEdit = processedSuggestion.type === SuggestionType.EDIT + if (isSimilarToRejected) { // Mark as rejected in the session session.setSuggestionState(suggestion.itemId, 'Reject') @@ -405,14 +413,14 @@ export class EditCompletionHandler { // Return empty item that will be filtered out return { insertText: '', - isInlineEdit: true, + isInlineEdit: isInlineEdit, itemId: suggestion.itemId, } } return { - insertText: suggestion.content, - isInlineEdit: true, + insertText: processedSuggestion.suggestionContent, + isInlineEdit: isInlineEdit, itemId: suggestion.itemId, } }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.test.ts index 40caa458a5..20d5890d77 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.test.ts @@ -1,5 +1,315 @@ import * as assert from 'assert' -import { getAddedAndDeletedLines, getCharacterDifferences, generateDiffContexts } from './diffUtils' +import { + categorizeUnifieddiff, + extractAdditions, + getAddedAndDeletedLines, + getCharacterDifferences, + generateDiffContexts, +} from './diffUtils' + +describe('extractAdditions', function () { + interface Case { + udiff: string + expected: string + } + + const cases: Case[] = [ + { + udiff: `--- file:///Volumes/workplace/ide/sample_projects/Calculator/src/main/hello/MathUtil.java ++++ file:///Volumes/workplace/ide/sample_projects/Calculator/src/main/hello/MathUtil.java +@@ -1,9 +1,10 @@ + public class MathUtil { + // write a function to add 2 numbers + public static int add(int a, int b) { + ++ return a + b; + } + + // write a function to subtract 2 numbers + public static int subtract(int a, int b) { + return a - b;`, + expected: ' return a + b;', + }, + { + udiff: `--- file:///Volumes/workplace/ide/sample_projects/Calculator/src/main/hello/MathUtil.java ++++ file:///Volumes/workplace/ide/sample_projects/Calculator/src/main/hello/MathUtil.java +@@ -1,9 +1,17 @@ + public class MathUtil { + // write a function to add 2 numbers + public static int add(int a, int b) { + ++ if (a > Integer.MAX_VALUE - b){ ++ throw new IllegalArgumentException("Overflow!"); ++ } ++ else if (a < Integer.MIN_VALUE - b){ ++ throw new IllegalArgumentException("Underflow"); ++ } ++ else{ ++ return a + b; ++ } + } + + // write a function to subtract 2 numbers + public static int subtract(int a, int b) { + return a - b;`, + expected: ` if (a > Integer.MAX_VALUE - b){ + throw new IllegalArgumentException("Overflow!"); + } + else if (a < Integer.MIN_VALUE - b){ + throw new IllegalArgumentException("Underflow"); + } + else{ + return a + b; + }`, + }, + { + udiff: `--- file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java ++++ file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java +@@ -6,7 +6,11 @@ + + // write a function to subtract 2 numbers + public static int subtract(int a, int b) { + return a - b; + } +- ++ ++ // write a function to multiply 2 numbers ++ public static int multiply(int a, int b) { ++ return a * b; ++ } + }`, + expected: ` + // write a function to multiply 2 numbers + public static int multiply(int a, int b) { + return a * b; + }`, + }, + { + udiff: `--- file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java ++++ file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java +@@ -3,7 +3,9 @@ + public static int add(int a, int b) { + return a + b; + } + + // write a function to subtract 2 numbers +- ++ public static int subtract(int a, int b) { ++ return a - b; ++ } + }`, + expected: ` public static int subtract(int a, int b) { + return a - b; + }`, + }, + ] + + for (let i = 0; i < cases.length; i++) { + it(`case ${i}`, function () { + const c = cases[i] + const udiff = c.udiff + const expected = c.expected + + const actual = extractAdditions(udiff) + assert.strictEqual(actual, expected) + }) + } +}) + +describe('categorizeUnifieddiffV2v2 should return correct type (addOnly, edit, deleteOnly)', function () { + interface Case { + udiff: string + } + + describe('addOnly', function () { + const addOnlyCases: Case[] = [ + { + udiff: `--- file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java ++++ file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java +@@ -6,7 +6,11 @@ + + // write a function to subtract 2 numbers + public static int subtract(int a, int b) { + return a - b; + } +- ++ ++ // write a function to multiply 2 numbers ++ public static int multiply(int a, int b) { ++ return a * b; ++ } + }`, + }, + { + udiff: `--- file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java ++++ file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java +@@ -6,7 +6,11 @@ + + // write a function to subtract 2 numbers + public static int subtract(int a, int b) { + return a - b; + } +- ++ ++ ++ // write a function to multiply 2 numbers ++ public static int multiply(int a, int b) { ++ return a * b; ++ } + }`, + }, + { + udiff: `--- file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java ++++ file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java +@@ -6,7 +6,11 @@ + + // write a function to subtract 2 numbers + public static int subtract(int a, int b) { + return a - b; + } +- ++ ++ // write a function to multiply 2 numbers ++ public static int multiply(int a, int b) { ++ return a * b; ++ } + }`, + }, + { + udiff: `--- file:///Volumes/workplace/ide/sample_projects/Calculator/src/main/hello/MathUtil.java ++++ file:///Volumes/workplace/ide/sample_projects/Calculator/src/main/hello/MathUtil.java +@@ -1,9 +1,10 @@ + public class MathUtil { + // write a function to add 2 numbers + public static int add(int a, int b) { + ++ return a + b; + } + + // write a function to subtract 2 numbers + public static int subtract(int a, int b) { + return a - b;`, + }, + { + udiff: `--- file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java ++++ file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java +@@ -3,7 +3,9 @@ + public static int add(int a, int b) { + return a + b; + } + + // write a function to subtract 2 numbers +- ++ public static int subtract(int a, int b) { ++ return a - b; ++ } + }`, + }, + { + udiff: `--- file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java ++++ file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java +@@ -4,8 +4,8 @@ + return a + b; + } + + // write a function to subtract 2 numbers + public static int subtract(int a, int b) { +- return ++ return a - b; + } + }`, + }, + { + udiff: `--- file:///Volumes/workplace/ide/sample_projects/Calculator/src/main/hello/LRUCache.java ++++ file:///Volumes/workplace/ide/sample_projects/Calculator/src/main/hello/LRUCache.java +@@ -7,7 +7,11 @@ + private Map map; + private DoubleLinkedList list; + private int capacity; + + // get +- public LruCache ++ public LruCache(int capacity) { ++ this.capacity = capacity; ++ map = new HashMap<>(); ++ list = new DoubleLinkedList(); ++ } + }`, + }, + ] + + for (let i = 0; i < addOnlyCases.length; i++) { + it(`case ${i}`, function () { + const actual = categorizeUnifieddiff(addOnlyCases[i].udiff) + assert.strictEqual(actual, 'addOnly') + }) + } + }) + + describe('edit', function () { + const cases: Case[] = [ + { + udiff: `--- a/src/main/hello/MathUtil.java ++++ b/src/main/hello/MathUtil.java +@@ -1,11 +1,11 @@ + public class MathUtil { + // write a function to add 2 numbers +- public static int add(int a, int b) { ++ public static double add(double a, double b) { + return a + b; + } + + // write a function to subtract 2 numbers + public static int subtract(int a, int b) { + public static double subtract(double a, double b) { + return a - b; + } + }`, + }, + { + udiff: `--- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts ++++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +@@ -502,11 +502,7 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { + : undefined + } + +- private withProfileArn(request: T): T { +- if (!this.profileArn) return request +- +- return { ...request, profileArn: this.profileArn } +- } ++ // ddddddddddddddddd + + async generateSuggestions(request: BaseGenerateSuggestionsRequest): Promise { + // Cast is now safe because GenerateTokenSuggestionsRequest extends GenerateCompletionsRequest`, + }, + { + udiff: `--- file:///Users/atona/workplace/NEP/language-servers/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/textDocumentUtils.ts ++++ file:///Users/atona/workplace/NEP/language-servers/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/textDocumentUtils.ts +@@ -15,11 +15,11 @@ + return '' + } + } + + export const getTextDocument = async (uri: string, workspace: any, logging: any): Promise => { +- let ++ if (!textDocument) { + if (!textDocument) { + try { + const content = await workspace.fs.readFile(URI.parse(uri).fsPath) + const languageId = getLanguageIdFromUri(uri) + textDocument = TextDocument.create(uri, languageId, 0, content)`, + }, + ] + + for (let i = 0; i < cases.length; i++) { + it(`case ${i}`, function () { + const actual = categorizeUnifieddiff(cases[i].udiff) + assert.strictEqual(actual, 'edit') + }) + } + }) +}) describe('diffUtils', () => { describe('getAddedAndDeletedLines', () => { diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.ts index 77e6c28e6c..8c67a92746 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.ts @@ -6,6 +6,9 @@ import * as diff from 'diff' import { CodeWhispererSupplementalContext, CodeWhispererSupplementalContextItem } from '../../../shared/models/model' import { trimSupplementalContexts } from '../../../shared/supplementalContextUtil/supplementalContextUtil' +import { Position, TextDocument, Range } from '@aws/language-server-runtimes/protocol' +import { SuggestionType } from '../../../shared/codeWhispererService' +import { getPrefixSuffixOverlap } from './mergeRightUtils' /** * Generates a unified diff format between old and new file contents @@ -197,3 +200,203 @@ export function getCharacterDifferences(addedLines: string[], deletedLines: stri charactersRemoved: deletedText.length - lcsLen, } } + +export function processEditSuggestion( + unifiedDiff: string, + triggerPosition: Position, + document: TextDocument +): { suggestionContent: string; type: SuggestionType } { + // Assume it's an edit if anything goes wrong, at the very least it will not be rendered incorrectly + let diffCategory: ReturnType = 'edit' + try { + diffCategory = categorizeUnifieddiff(unifiedDiff) + } catch (e) { + // We dont have logger here.... + diffCategory = 'edit' + } + + if (diffCategory === 'addOnly') { + const preprocessAdd = extractAdditions(unifiedDiff) + const leftContextAtTriggerLine = document.getText( + Range.create(Position.create(triggerPosition.line, 0), triggerPosition) + ) + /** + * SHOULD NOT remove the entire overlapping string, the way inline suggestion prefix matching work depends on where it triggers + * For example (^ note where user triggers) + * console.lo + * ^ + * if LSP returns `g('foo')` instead of `.log()` the suggestion will be discarded because prefix doesnt match + */ + const processedAdd = removeOverlapCodeFromSuggestion(leftContextAtTriggerLine, preprocessAdd) + return { + suggestionContent: processedAdd, + type: SuggestionType.COMPLETION, + } + } else { + return { + suggestionContent: unifiedDiff, + type: SuggestionType.EDIT, + } + } +} + +// TODO: MAKE it a class and abstract all the business parsing logic within the classsssss so we dont need to redo the same thing again and again +interface UnifiedDiff { + linesWithoutHeaders: string[] + firstMinusIndex: number + firstPlusIndex: number + minusIndexes: number[] + plusIndexes: number[] +} + +// TODO: refine +export function readUdiff(unifiedDiff: string): UnifiedDiff { + const lines = unifiedDiff.split('\n') + const headerEndIndex = lines.findIndex(l => l.startsWith('@@')) + if (headerEndIndex === -1) { + throw new Error('not able to parse') + } + const relevantLines = lines.slice(headerEndIndex + 1) + if (relevantLines.length === 0) { + throw new Error('not able to parse') + } + + const minusIndexes: number[] = [] + const plusIndexes: number[] = [] + for (let i = 0; i < relevantLines.length; i++) { + const l = relevantLines[i] + if (l.startsWith('-')) { + minusIndexes.push(i) + } else if (l.startsWith('+')) { + plusIndexes.push(i) + } + } + + const firstMinusIndex = relevantLines.findIndex(s => s.startsWith('-')) + const firstPlusIndex = relevantLines.findIndex(s => s.startsWith('+')) + + return { + linesWithoutHeaders: relevantLines, + firstMinusIndex: firstMinusIndex, + firstPlusIndex: firstPlusIndex, + minusIndexes: minusIndexes, + plusIndexes: plusIndexes, + } +} + +export function categorizeUnifieddiff(unifiedDiff: string): 'addOnly' | 'deleteOnly' | 'edit' { + try { + const d = readUdiff(unifiedDiff) + const firstMinusIndex = d.firstMinusIndex + const firstPlusIndex = d.firstPlusIndex + const diffWithoutHeaders = d.linesWithoutHeaders + + if (firstMinusIndex === -1 && firstPlusIndex === -1) { + return 'edit' + } + + if (firstMinusIndex === -1 && firstPlusIndex !== -1) { + return 'addOnly' + } + + if (firstMinusIndex !== -1 && firstPlusIndex === -1) { + return 'deleteOnly' + } + + const minusIndexes = d.minusIndexes + const plusIndexes = d.plusIndexes + + // If there are multiple (> 1) non empty '-' lines, it must be edit + const c = minusIndexes.reduce((acc: number, cur: number): number => { + if (diffWithoutHeaders[cur].trim().length > 0) { + return acc++ + } + + return acc + }, 0) + + if (c > 1) { + return 'edit' + } + + // If last '-' line is followed by '+' block, it could be addonly + if (plusIndexes[0] === minusIndexes[minusIndexes.length - 1] + 1) { + const minusLine = diffWithoutHeaders[minusIndexes[minusIndexes.length - 1]].substring(1) + const pluscode = extractAdditions(unifiedDiff) + + // If minusLine subtract the longest common substring of minusLine and plugcode and it's empty string, it's addonly + const commonPrefix = longestCommonPrefix(minusLine, pluscode) + if (minusLine.substring(commonPrefix.length).trim().length === 0) { + return 'addOnly' + } + } + + return 'edit' + } catch (e) { + return 'edit' + } +} + +// TODO: current implementation here assumes service only return 1 chunk of edits (consecutive lines) and hacky +export function extractAdditions(unifiedDiff: string): string { + const lines = unifiedDiff.split('\n') + let completionSuggestion = '' + let isInAdditionBlock = false + + for (const line of lines) { + // Skip diff headers (files) + if (line.startsWith('+++') || line.startsWith('---')) { + continue + } + + // Skip hunk headers (@@ lines) + if (line.startsWith('@@')) { + continue + } + + // Handle additions + if (line.startsWith('+')) { + completionSuggestion += line.substring(1) + '\n' + isInAdditionBlock = true + } else if (isInAdditionBlock && !line.startsWith('+')) { + // End of addition block + isInAdditionBlock = false + } + } + + // Remove trailing newline + return completionSuggestion.trimEnd() +} + +/** + * + * example + * code = 'return' + * suggestion = 'return a + b;' + * output = ' a + b;' + */ +export function removeOverlapCodeFromSuggestion(code: string, suggestion: string): string { + const suggestionLines = suggestion.split('\n') + const firstLineSuggestion = suggestionLines[0] + + // Find the common string in code surfix and prefix of suggestion + const s = getPrefixSuffixOverlap(code, firstLineSuggestion) + + // Remove overlap s from suggestion + return suggestion.substring(s.length) +} + +export function longestCommonPrefix(str1: string, str2: string): string { + const minLength = Math.min(str1.length, str2.length) + let prefix = '' + + for (let i = 0; i < minLength; i++) { + if (str1[i] === str2[i]) { + prefix += str1[i] + } else { + break + } + } + + return prefix +} diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index 9c229ccd86..27dac024af 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -522,20 +522,21 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { } const beforeApiCall = Date.now() - let recentEditsLogStr = '' - const recentEdits = tokenRequest.supplementalContexts?.filter(it => it.type === 'PreviousEditorState') - if (recentEdits) { - if (recentEdits.length === 0) { - recentEditsLogStr += `No recent edits` - } else { - recentEditsLogStr += '\n' - for (let i = 0; i < recentEdits.length; i++) { - const e = recentEdits[i] - recentEditsLogStr += `[recentEdits ${i}th]:\n` - recentEditsLogStr += `${e.content}\n` - } - } - } + // TODO: Should make context log as a dev option, too noisy, comment it out temporarily + // let recentEditsLogStr = '' + // const recentEdits = tokenRequest.supplementalContexts?.filter(it => it.type === 'PreviousEditorState') + // if (recentEdits) { + // if (recentEdits.length === 0) { + // recentEditsLogStr += `No recent edits` + // } else { + // recentEditsLogStr += '\n' + // for (let i = 0; i < recentEdits.length; i++) { + // const e = recentEdits[i] + // recentEditsLogStr += `[recentEdits ${i}th]:\n` + // recentEditsLogStr += `${e.content}\n` + // } + // } + // } logstr += `@@request metadata@@ "endpoint": ${this.codeWhispererEndpoint}, @@ -545,8 +546,8 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { rightContextLength: ${request.fileContext.rightFileContent.length}, "language": ${tokenRequest.fileContext.programmingLanguage.languageName}, "supplementalContextCount": ${tokenRequest.supplementalContexts?.length ?? 0}, - "request.nextToken": ${tokenRequest.nextToken}, - "recentEdits": ${recentEditsLogStr}\n` + "request.nextToken": ${tokenRequest.nextToken}` + // "recentEdits": ${recentEditsLogStr}\n` const response = await this.client.generateCompletions(this.withProfileArn(tokenRequest)).promise() @@ -566,7 +567,7 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { "sessionId": ${responseContext.codewhispererSessionId}, "response.completions.length": ${response.completions?.length ?? 0}, "response.predictions.length": ${response.predictions?.length ?? 0}, - "predictionType": ${tokenRequest.predictionTypes?.toString() ?? ''}, + "predictionType": ${tokenRequest.predictionTypes?.toString() ?? 'Not specified (COMPLETIONS)'}, "latency": ${Date.now() - beforeApiCall}, "response.nextToken": ${response.nextToken}, "firstSuggestion": ${firstSuggestionLogstr}` @@ -599,6 +600,7 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { } } + // Backward compatibility, completions will be returned if predictionType is not specified (either Completion or Edit) for (const recommendation of apiResponse?.completions ?? []) { Object.assign(recommendation, { itemId: this.generateItemId() }) } From 4ce9d8facf25ebb22b3d246c8efd0b2a257e9568 Mon Sep 17 00:00:00 2001 From: atontb <104926752+atonaamz@users.noreply.github.com> Date: Tue, 7 Oct 2025 10:58:46 -0700 Subject: [PATCH 131/158] chore(amazonq): adding test for editCompletionHandler (#2396) --- .../handler/editCompletionHandler.test.ts | 495 ++++++++++++++++++ 1 file changed, 495 insertions(+) create mode 100644 server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.test.ts diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.test.ts new file mode 100644 index 0000000000..171158b543 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.test.ts @@ -0,0 +1,495 @@ +import * as assert from 'assert' +import { EditCompletionHandler } from './editCompletionHandler' +import { InlineCompletionTriggerKind, TextDocument, CancellationToken } from '@aws/language-server-runtimes/protocol' +import { EMPTY_RESULT } from '../contants/constants' +import * as sinon from 'sinon' +import { CodeWhispererSession, SessionData, SessionManager } from '../session/sessionManager' +import { HELLO_WORLD_IN_CSHARP } from '../../../shared/testUtils' +import { CodeWhispererServiceToken } from '../../../shared/codeWhispererService' + +describe('EditCompletionHandler', () => { + let handler: EditCompletionHandler + let sessionManager: SessionManager + let logging: any + let workspace: any + let amazonQServiceManager: any + let cursorTracker: any + let recentEditsTracker: any + let rejectedEditTracker: any + let telemetry: any + let telemetryService: any + let credentialsProvider: any + let codeWhispererService: any + let documentChangedListener: any + + const requestContext = { + maxResults: 5, + fileContext: { + filename: 'SomeFile', + programmingLanguage: { languageName: 'csharp' }, + leftFileContent: 'LeftFileContent', + rightFileContent: 'RightFileContent', + }, + } + + const data: SessionData = { + document: TextDocument.create('file:///rightContext.cs', 'csharp', 1, HELLO_WORLD_IN_CSHARP), + startPreprocessTimestamp: 0, + startPosition: { line: 0, character: 0 }, + triggerType: 'OnDemand', + language: 'csharp', + requestContext: requestContext, + autoTriggerType: 'Enter', + } + + beforeEach(() => { + SessionManager.reset() + sessionManager = SessionManager.getInstance('EDITS') + logging = { info: sinon.stub(), warn: sinon.stub(), log: sinon.stub(), debug: sinon.stub() } + workspace = { getTextDocument: sinon.stub(), getWorkspaceFolder: sinon.stub() } + codeWhispererService = { + generateSuggestions: sinon.stub(), + constructSupplementalContext: sinon.stub(), + customizationArn: undefined, + } + amazonQServiceManager = { getCodewhispererService: sinon.stub().returns(codeWhispererService) } + cursorTracker = { trackPosition: sinon.stub() } + recentEditsTracker = {} + rejectedEditTracker = { isSimilarToRejected: sinon.stub().returns(false) } + telemetry = { emitMetric: sinon.stub() } + telemetryService = { emitUserTriggerDecision: sinon.stub() } + credentialsProvider = { getConnectionMetadata: sinon.stub() } + documentChangedListener = { documentChanged: sinon.stub(), timeSinceLastUserModification: 1000 } + + const clientMetadata = { + processId: 123, + rootUri: null, + capabilities: {}, + initializationOptions: { + aws: { + awsClientCapabilities: { + textDocument: { + inlineCompletionWithReferences: { + inlineEditSupport: true, + }, + }, + }, + }, + }, + } + + handler = new EditCompletionHandler( + logging, + clientMetadata, + workspace, + amazonQServiceManager, + sessionManager, + cursorTracker, + recentEditsTracker, + rejectedEditTracker, + documentChangedListener, + telemetry, + telemetryService, + credentialsProvider + ) + + // Make service a token service by default + Object.setPrototypeOf(codeWhispererService, CodeWhispererServiceToken.prototype) + }) + + afterEach(() => { + sinon.restore() + SessionManager.reset() + }) + + describe('onEditCompletion', () => { + it('should return empty result when in progress', async () => { + handler['isInProgress'] = true + const params = { + textDocument: { uri: 'test.ts' }, + position: { line: 0, character: 0 }, + context: { triggerKind: InlineCompletionTriggerKind.Automatic }, + } + + const result = await handler.onEditCompletion(params as any, {} as any) + + assert.deepEqual(result, EMPTY_RESULT) + sinon.assert.calledWith(logging.info, 'editCompletionHandler is WIP, skip the request') + }) + + it('should return empty result when text document not found', async () => { + workspace.getTextDocument.resolves(null) + const params = { + textDocument: { uri: 'test.ts' }, + position: { line: 0, character: 0 }, + context: { triggerKind: InlineCompletionTriggerKind.Automatic }, + } + + const result = await handler.onEditCompletion(params as any, {} as any) + + assert.deepEqual(result, EMPTY_RESULT) + sinon.assert.calledWith(logging.warn, 'textDocument [test.ts] not found') + }) + + it('should return empty result when service is not token service', async () => { + const textDocument = { languageId: 'typescript' } + workspace.getTextDocument.resolves(textDocument) + amazonQServiceManager.getCodewhispererService.returns({}) + + const params = { + textDocument: { uri: 'test.ts' }, + position: { line: 0, character: 0 }, + context: { triggerKind: InlineCompletionTriggerKind.Automatic }, + } + + const result = await handler.onEditCompletion(params as any, CancellationToken.None) + + assert.deepEqual(result, EMPTY_RESULT) + }) + + it('should return empty result when language not supported', async () => { + const textDocument = { languageId: 'unsupported', uri: 'test.xyz' } + workspace.getTextDocument.resolves(textDocument) + + const params = { + textDocument: { uri: 'test.xyz' }, + position: { line: 0, character: 0 }, + context: { triggerKind: InlineCompletionTriggerKind.Automatic }, + } + + const result = await handler.onEditCompletion(params as any, CancellationToken.None) + + assert.deepEqual(result, EMPTY_RESULT) + sinon.assert.calledWith(logging.log, sinon.match('not supported')) + }) + + it('should handle partial result token with existing session', async () => { + const textDocument = { languageId: 'typescript', uri: 'test.ts' } + workspace.getTextDocument.resolves(textDocument) + sessionManager.createSession(data) + const currentSession = sessionManager.getCurrentSession() + if (currentSession) { + sessionManager.activateSession(currentSession) + } + + codeWhispererService.generateSuggestions.resolves({ + suggestions: [{ itemId: 'item-1', content: 'test' }], + responseContext: { requestId: 'req-1', nextToken: null }, + }) + + const params = { + textDocument: { uri: 'test.ts' }, + position: { line: 0, character: 0 }, + context: { triggerKind: InlineCompletionTriggerKind.Automatic }, + partialResultToken: 'token123', + } + + const result = await handler.onEditCompletion(params as any, CancellationToken.None) + + assert.strictEqual(result.items.length, 1) + assert.strictEqual(currentSession?.state, 'DISCARD') + }) + + it('should handle error in partial result token request', async () => { + const textDocument = { languageId: 'typescript', uri: 'test.ts' } + workspace.getTextDocument.resolves(textDocument) + + sessionManager.createSession(data) + + codeWhispererService.generateSuggestions.rejects(new Error('API Error')) + + const params = { + textDocument: { uri: 'test.ts' }, + position: { line: 0, character: 0 }, + context: { triggerKind: InlineCompletionTriggerKind.Automatic }, + partialResultToken: 'token123', + } + + const result = await handler.onEditCompletion(params as any, CancellationToken.None) + + assert.deepEqual(result, EMPTY_RESULT) + }) + + it('should track cursor position when available', async () => { + workspace.getTextDocument.resolves(null) + + const params = { + textDocument: { uri: 'test.ts' }, + position: { line: 5, character: 10 }, + context: { triggerKind: InlineCompletionTriggerKind.Automatic }, + } + + await handler.onEditCompletion(params as any, CancellationToken.None) + + sinon.assert.calledWith(cursorTracker.trackPosition, 'test.ts', { line: 5, character: 10 }) + }) + }) + + describe('documentChanged', () => { + it('should set hasDocumentChangedSinceInvocation when waiting', () => { + handler['debounceTimeout'] = setTimeout(() => {}, 1000) as any + handler['isWaiting'] = true + + handler.documentChanged() + + assert.strictEqual(handler['hasDocumentChangedSinceInvocation'], true) + }) + + it('should refresh timeout when not waiting', () => { + const timeout = { refresh: sinon.stub() } + handler['debounceTimeout'] = timeout as any + handler['isWaiting'] = false + + handler.documentChanged() + + sinon.assert.called(timeout.refresh) + }) + + it('should do nothing when no timeout exists', () => { + handler['debounceTimeout'] = undefined + + assert.doesNotThrow(() => handler.documentChanged()) + }) + }) + + describe('processSuggestionResponse', () => { + it('should filter out similar rejected suggestions', async () => { + rejectedEditTracker.isSimilarToRejected.returns(true) + const session = new CodeWhispererSession(data) + const suggestionResponse = { + suggestions: [{ itemId: 'item-1', content: 'test content' }], + responseContext: { requestId: 'req-1', nextToken: null }, + } + + const result = await handler.processSuggestionResponse(suggestionResponse as any, session as any, true) + + assert.strictEqual(result.items.length, 0) + assert.strictEqual(session.getSuggestionState('item-1'), 'Reject') + }) + + it('should return suggestions when not rejected', async () => { + const session = new CodeWhispererSession(data) + const suggestionResponse = { + suggestions: [{ itemId: 'item-1', content: 'test content' }], + responseContext: { requestId: 'req-1', nextToken: null }, + } + + const result = await handler.processSuggestionResponse(suggestionResponse as any, session as any, true) + + assert.strictEqual(result.items.length, 1) + assert.strictEqual(result.items[0].insertText, 'test content') + assert.strictEqual(result.items[0].isInlineEdit, true) + }) + + it('should handle empty suggestions response', async () => { + telemetryService.emitUserTriggerDecision.resolves() + const session = new CodeWhispererSession(data) + const suggestionResponse = { + suggestions: [], + responseContext: { requestId: 'req-1', nextToken: null }, + } + + const result = await handler.processSuggestionResponse(suggestionResponse as any, session, true) + + assert.deepEqual(result, EMPTY_RESULT) + }) + + it('should handle session with discardInflightSessionOnNewInvocation flag', async () => { + const session = new CodeWhispererSession(data) + session.discardInflightSessionOnNewInvocation = true + + const suggestionResponse = { + suggestions: [{ itemId: 'item-1', content: 'test content' }], + responseContext: { requestId: 'req-1', nextToken: null }, + } + + await handler.processSuggestionResponse(suggestionResponse as any, session, true) + + assert.strictEqual(session.state, 'DISCARD') + assert.strictEqual(session.discardInflightSessionOnNewInvocation, false) + }) + + it('should append suggestions for non-new session', async () => { + const session = new CodeWhispererSession(data) + session.suggestions = [{ itemId: 'existing', content: 'existing' }] + + const suggestionResponse = { + suggestions: [{ itemId: 'item-1', content: 'test content' }], + responseContext: { requestId: 'req-1', nextToken: null }, + } + + await handler.processSuggestionResponse(suggestionResponse as any, session, false) + + assert.strictEqual(session.suggestions.length, 2) + assert.strictEqual(session.suggestions[1].itemId, 'item-1') + }) + }) + + describe('_invoke', () => { + const textDocument = { + languageId: 'typescript', + uri: 'test.ts', + getText: () => 'content', + positionAt: sinon.stub(), + } + const params = { + textDocument: textDocument, + position: { line: 0, character: 0 }, + context: { triggerKind: InlineCompletionTriggerKind.Automatic }, + } + it('should return empty result when shouldTriggerEdits returns false', async () => { + workspace.getWorkspaceFolder.returns(undefined) + + const shouldTriggerEditsStub = sinon + .stub(require('../utils/triggerUtils'), 'shouldTriggerEdits') + .returns(false) + + const result = await handler._invoke( + params as any, + Date.now(), + CancellationToken.None, + textDocument as any, + 'typescript', + undefined + ) + + assert.deepEqual(result, EMPTY_RESULT) + shouldTriggerEditsStub.restore() + }) + + it('should create session and call generateSuggestions when trigger is valid', async () => { + workspace.getWorkspaceFolder.returns(undefined) + + const shouldTriggerEditsStub = sinon + .stub(require('../utils/triggerUtils'), 'shouldTriggerEdits') + .returns(true) + codeWhispererService.constructSupplementalContext.resolves(null) + codeWhispererService.generateSuggestions.resolves({ + suggestions: [{ itemId: 'item-1', content: 'test content' }], + responseContext: { requestId: 'req-1', nextToken: null }, + }) + + const result = await handler._invoke( + params as any, + Date.now(), + CancellationToken.None, + textDocument as any, + 'typescript', + undefined + ) + + assert.strictEqual(result.items.length, 1) + sinon.assert.called(codeWhispererService.generateSuggestions) + shouldTriggerEditsStub.restore() + }) + + it('should handle active session and emit telemetry', async () => { + workspace.getWorkspaceFolder.returns(undefined) + + sessionManager.createSession(data) + const currentSession = sessionManager.getCurrentSession() + if (currentSession) { + sessionManager.activateSession(currentSession) + } + const shouldTriggerEditsStub = sinon + .stub(require('../utils/triggerUtils'), 'shouldTriggerEdits') + .returns(true) + codeWhispererService.constructSupplementalContext.resolves(null) + codeWhispererService.generateSuggestions.resolves({ + suggestions: [{ itemId: 'item-1', content: 'test content' }], + responseContext: { requestId: 'req-1', nextToken: null }, + }) + + await handler._invoke( + params as any, + Date.now(), + CancellationToken.None, + textDocument as any, + 'typescript', + currentSession + ) + + assert.strictEqual(currentSession?.state, 'DISCARD') + shouldTriggerEditsStub.restore() + }) + + it('should handle supplemental context when available', async () => { + workspace.getWorkspaceFolder.returns(undefined) + + const shouldTriggerEditsStub = sinon + .stub(require('../utils/triggerUtils'), 'shouldTriggerEdits') + .returns(true) + codeWhispererService.constructSupplementalContext.resolves({ + items: [{ content: 'context', filePath: 'file.ts' }], + supContextData: { isUtg: false }, + }) + codeWhispererService.generateSuggestions.resolves({ + suggestions: [{ itemId: 'item-1', content: 'test content' }], + responseContext: { requestId: 'req-1', nextToken: null }, + }) + + await handler._invoke( + params as any, + Date.now(), + CancellationToken.None, + textDocument as any, + 'typescript', + undefined + ) + + sinon.assert.calledWith(codeWhispererService.generateSuggestions, sinon.match.has('supplementalContexts')) + shouldTriggerEditsStub.restore() + }) + }) + + describe('handleSuggestionsErrors', () => { + it('should handle generic error and return empty result', () => { + const session = new CodeWhispererSession(data) + const error = new Error('Generic error') + const emitServiceInvocationFailureStub = sinon.stub( + require('../telemetry/telemetry'), + 'emitServiceInvocationFailure' + ) + + const result = handler.handleSuggestionsErrors(error, session) + + assert.deepEqual(result, EMPTY_RESULT) + assert.strictEqual(session.state, 'CLOSED') + sinon.assert.calledWith(logging.log, sinon.match('Recommendation failure')) + sinon.assert.calledWith(emitServiceInvocationFailureStub, telemetry, session, error) + emitServiceInvocationFailureStub.restore() + }) + + it('should handle connection expired error and return empty result', () => { + const session = new CodeWhispererSession(data) + const error = new Error('ExpiredTokenException') + + const result = handler.handleSuggestionsErrors(error, session) + + assert.strictEqual(session.state, 'CLOSED') + }) + + it('should handle AmazonQError and throw ResponseError with error code', () => { + const session = new CodeWhispererSession(data) + const { AmazonQError } = require('../../../shared/amazonQServiceManager/errors') + const error = new AmazonQError('Service error', '500') + + assert.throws(() => { + handler.handleSuggestionsErrors(error, session) + }) + + assert.strictEqual(session.state, 'CLOSED') + }) + + it('should handle error without message', () => { + const session = new CodeWhispererSession(data) + const error = new Error() + error.message = '' + + const result = handler.handleSuggestionsErrors(error, session) + + assert.deepEqual(result, EMPTY_RESULT) + assert.strictEqual(session.state, 'CLOSED') + }) + }) +}) From a9081954bcaf20b7d0fbe0af11e61b8f82c7e82f Mon Sep 17 00:00:00 2001 From: Nora Xia <69574282+ruotingx@users.noreply.github.com> Date: Tue, 7 Oct 2025 14:57:52 -0700 Subject: [PATCH 132/158] feat(amazonq): env var change for JupyterLab conversation history on refresh support (#2395) use SAGEMAKER_APP_TYPE_LOWERCASE env var Co-authored-by: ruotingx --- .../language-server/agenticChat/tabBarController.test.ts | 6 ++++-- .../src/language-server/agenticChat/tabBarController.ts | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.test.ts index 5aa341d232..1df34c2162 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.test.ts @@ -15,6 +15,8 @@ import { ChatHistoryActionType } from '../../shared/telemetry/types' import { TelemetryService } from '../../shared/telemetry/telemetryService' import { URI } from 'vscode-uri' +const JUPYTERLAB_APP_TYPE_VALUE = 'jupyterlab' + describe('TabBarController', () => { let testFeatures: TestFeatures let chatHistoryDb: ChatDatabase @@ -50,7 +52,7 @@ describe('TabBarController', () => { afterEach(() => { sinon.restore() clock.restore() - delete process.env.JUPYTER_LAB // Clean up JupyterLab environment variables + delete process.env.SAGEMAKER_APP_TYPE_LOWERCASE // Clean up JupyterLab environment variables testFeatures.dispose() }) @@ -563,7 +565,7 @@ describe('TabBarController', () => { it('should allow multiple loads in JupyterLab environment', async () => { // Set JupyterLab environment - process.env.JUPYTER_LAB = 'true' + process.env.SAGEMAKER_APP_TYPE_LOWERCASE = JUPYTERLAB_APP_TYPE_VALUE const mockTabs = [{ historyId: 'history1', conversations: [{ messages: [] }] }] as unknown as Tab[] ;(chatHistoryDb.getOpenTabs as sinon.SinonStub).returns(mockTabs) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.ts index 4531a9c589..6ba6da3508 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tabBarController.ts @@ -22,6 +22,7 @@ import { ChatHistoryActionType } from '../../shared/telemetry/types' import { CancellationError } from '@aws/lsp-core' const MaxRestoredHistoryMessages = 250 +const JUPYTERLAB_APP_TYPE_VALUE = 'jupyterlab' /** * Controller for managing chat history and export functionality. @@ -344,9 +345,9 @@ export class TabBarController { */ private isJupyterLabEnvironment(): boolean { try { - return process.env.JUPYTER_LAB === 'true' + return process.env.SAGEMAKER_APP_TYPE_LOWERCASE === JUPYTERLAB_APP_TYPE_VALUE } catch (error) { - this.#features.logging.error(`Failed to read JUPYTER_LAB environment variable: ${error}`) + this.#features.logging.error(`Failed to read SAGEMAKER_APP_TYPE_LOWERCASE environment variable: ${error}`) return false } } From 15d1b1f5947a1b83dab65c9d3fef901ab8a033c9 Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Wed, 8 Oct 2025 13:31:41 -0700 Subject: [PATCH 133/158] feat(amazonq): adding classification based retry strategy for chat (#2234) (#2409) --- .../agenticChat/agenticChatController.ts | 8 + .../agenticChat/agenticChatResultStream.ts | 22 + .../agenticChat/constants/constants.ts | 35 ++ .../retry/delayInterceptor.test.ts | 182 ++++++++ .../agenticChat/retry/delayInterceptor.ts | 93 ++++ .../retry/errorTransformer.test.ts | 420 ++++++++++++++++++ .../agenticChat/retry/errorTransformer.ts | 221 +++++++++ .../agenticChat/retry/index.ts | 3 + .../agenticChat/retry/qRetryStrategy.test.ts | 179 ++++++++ .../agenticChat/retry/qRetryStrategy.ts | 89 ++++ .../agenticChat/retry/retryClassifier.test.ts | 254 +++++++++++ .../agenticChat/retry/retryClassifier.ts | 166 +++++++ .../language-server/chat/chatController.ts | 12 +- .../chat/chatSessionService.ts | 180 ++------ .../src/language-server/chat/constants.ts | 2 + .../codeWhispererServer.test.ts | 2 + .../inline-completion/telemetry/telemetry.ts | 6 +- .../workspaceFolderManager.ts | 8 +- .../src/shared/streamingClientService.ts | 64 ++- .../src/shared/telemetry/telemetryService.ts | 2 +- .../src/shared/utils.test.ts | 64 ++- .../aws-lsp-codewhisperer/src/shared/utils.ts | 32 +- 22 files changed, 1832 insertions(+), 212 deletions(-) create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/delayInterceptor.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/delayInterceptor.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/errorTransformer.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/errorTransformer.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/index.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/qRetryStrategy.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/qRetryStrategy.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/retryClassifier.test.ts create mode 100644 server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/retryClassifier.ts diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 005101b715..e59513a799 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -1013,6 +1013,14 @@ export class AgenticChatController implements ChatHandlers { }) session.setConversationType('AgenticChat') + // Set up delay notification callback to show retry progress to users + session.setDelayNotificationCallback(notification => { + if (notification.thresholdExceeded) { + this.#log(`Updating progress message: ${notification.message}`) + void chatResultStream.updateProgressMessage(notification.message) + } + }) + const additionalContext = await this.#additionalContextProvider.getAdditionalContext( triggerContext, params.tabId, diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatResultStream.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatResultStream.ts index 195e1e880b..a878267ffd 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatResultStream.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatResultStream.ts @@ -194,6 +194,28 @@ export class AgenticChatResultStream { } } + async updateProgressMessage(message: string) { + for (const block of this.#state.chatResultBlocks) { + if (block.messageId?.startsWith(progressPrefix) && block.header?.status?.icon === 'progress') { + const blockId = this.getMessageBlockId(block.messageId) + if (blockId !== undefined) { + const updatedBlock = { + ...block, + header: { + ...block.header, + status: { + ...block.header.status, + text: message, + }, + }, + } + await this.overwriteResultBlock(updatedBlock, blockId) + } + break + } + } + } + hasMessage(messageId: string): boolean { return this.#state.chatResultBlocks.some(block => block.messageId === messageId) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts index f01d4a4b0a..b291367e2c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts @@ -83,6 +83,41 @@ The summary should have following main sections: ` +// Retry Strategy Constants +export const RETRY_BASE_DELAY_MS = 1000 +export const RETRY_MAX_DELAY_MS = 10000 +export const RETRY_JITTER_MIN = 0.5 +export const RETRY_JITTER_MAX = 1.0 +export const RETRY_DELAY_NOTIFICATION_THRESHOLD_MS = 2000 +export const RETRY_BACKOFF_MULTIPLIER = 2 + +// HTTP Status Codes +export const HTTP_STATUS_TOO_MANY_REQUESTS = 429 +export const HTTP_STATUS_INTERNAL_SERVER_ERROR = 500 + +// Error Messages +export const MONTHLY_LIMIT_ERROR_MARKER = 'MONTHLY_REQUEST_COUNT' +export const CONTENT_LENGTH_EXCEEDS_THRESHOLD = 'CONTENT_LENGTH_EXCEEDS_THRESHOLD' +export const HIGH_LOAD_ERROR_MESSAGE = + 'Encountered unexpectedly high load when processing the request, please try again.' +export const SERVICE_UNAVAILABLE_EXCEPTION = 'ServiceUnavailableException' +export const INSUFFICIENT_MODEL_CAPACITY = 'INSUFFICIENT_MODEL_CAPACITY' +export const INVALID_MODEL_ID = 'INVALID_MODEL_ID' +export const SERVICE_QUOTA_EXCEPTION = 'ServiceQuotaExceededException' +export const MAXIMUM_CHAT_CONTENT_MESSAGE = 'Exceeded max chat context length.' + +// Delay tracking constants +export const MINOR_DELAY_THRESHOLD_MS = 2000 // 2 seconds +export const MAJOR_DELAY_THRESHOLD_MS = 5000 // 5 seconds +export const MAX_RETRY_DELAY_MS = 10000 // 10 seconds + +// Stalled stream protection constants +export const STALLED_STREAM_GRACE_PERIOD_MS = 300000 // 5 minutes +export const STALLED_STREAM_CHECK_INTERVAL_MS = 1000 // 1 second + +// Request attempt tracking +export const MAX_REQUEST_ATTEMPTS = 3 + // FsRead limits export const FSREAD_MAX_PER_FILE = 200_000 export const FSREAD_MAX_TOTAL = 400_000 diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/delayInterceptor.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/delayInterceptor.test.ts new file mode 100644 index 0000000000..889ea59f4d --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/delayInterceptor.test.ts @@ -0,0 +1,182 @@ +import { QDelayTrackingInterceptor, DelayNotification } from './delayInterceptor' +import { expect } from 'chai' +import * as sinon from 'sinon' + +describe('QDelayTrackingInterceptor', () => { + let interceptor: QDelayTrackingInterceptor + let mockLogging: any + let mockCallback: sinon.SinonSpy + + beforeEach(() => { + mockLogging = { + log: sinon.spy(), + debug: sinon.spy(), + } + mockCallback = sinon.spy() + interceptor = new QDelayTrackingInterceptor(mockLogging) + }) + + describe('setDelayNotificationCallback', () => { + it('should set callback and log debug message', () => { + interceptor.setDelayNotificationCallback(mockCallback) + + expect(mockLogging.debug.calledWith('QDelayTrackingInterceptor: setDelayNotificationCallback called')).to.be + .true + }) + }) + + describe('beforeAttempt', () => { + it('should log first attempt without delay calculation', () => { + interceptor.beforeAttempt(1) + + expect(mockLogging.debug.calledWith('QDelayTrackingInterceptor: Attempt 1')).to.be.true + expect( + mockLogging.debug.calledWith( + 'QDelayTrackingInterceptor: First attempt or no lastAttemptTime, skipping delay calculation' + ) + ).to.be.true + }) + + it('should calculate delay for subsequent attempts', () => { + const clock = sinon.useFakeTimers() + + // First attempt + interceptor.beforeAttempt(1) + + // Wait a bit and make second attempt + clock.tick(3000) // 3 seconds + interceptor.beforeAttempt(2) + + expect(mockLogging.debug.args.some((args: any) => args[0].includes('Delay'))).to.be.true + + clock.restore() + }) + + it('should send major delay notification for long delays', () => { + interceptor.setDelayNotificationCallback(mockCallback) + + const clock = sinon.useFakeTimers(1000) + + // First attempt + interceptor.beforeAttempt(1) + + // Simulate 6 second delay (major threshold) + clock.tick(6000) + interceptor.beforeAttempt(2) + + expect(mockCallback.calledOnce).to.be.true + const call = mockCallback.getCall(0) + expect(call.args[0].message).to.include('retrying within 10s') + expect(call.args[0].attemptNumber).to.equal(2) + expect(call.args[0].delay).to.equal(6) + expect(call.args[0].thresholdExceeded).to.be.true + + clock.restore() + }) + + it('should send minor delay notification for medium delays', () => { + interceptor.setDelayNotificationCallback(mockCallback) + + const clock = sinon.useFakeTimers(1000) + + // First attempt + interceptor.beforeAttempt(1) + + // Simulate 3 second delay (minor threshold) + clock.tick(3000) + interceptor.beforeAttempt(2) + + expect(mockCallback.calledOnce).to.be.true + const call = mockCallback.getCall(0) + expect(call.args[0].message).to.include('retrying within 5s') + expect(call.args[0].attemptNumber).to.equal(2) + expect(call.args[0].delay).to.equal(3) + expect(call.args[0].thresholdExceeded).to.be.true + + clock.restore() + }) + + it('should not notify for short delays', () => { + interceptor.setDelayNotificationCallback(mockCallback) + + const clock = sinon.useFakeTimers(1000) + + // First attempt + interceptor.beforeAttempt(1) + + // Simulate 1 second delay (below threshold) + clock.tick(1000) + interceptor.beforeAttempt(2) + + expect(mockCallback.called).to.be.false + expect( + mockLogging.debug.calledWith('QDelayTrackingInterceptor: Delay 1000ms below threshold, no notification') + ).to.be.true + + clock.restore() + }) + + it('should cap delay at maximum retry delay', () => { + interceptor.setDelayNotificationCallback(mockCallback) + + const clock = sinon.useFakeTimers(1000) + + // First attempt + interceptor.beforeAttempt(1) + + // Simulate very long delay (15 seconds) + clock.tick(15000) + interceptor.beforeAttempt(2) + + expect(mockCallback.calledOnce).to.be.true + const call = mockCallback.getCall(0) + expect(call.args[0].message).to.include('retrying within 10s') + expect(call.args[0].attemptNumber).to.equal(2) + expect(call.args[0].delay).to.equal(10) // Capped at 10 seconds + expect(call.args[0].thresholdExceeded).to.be.true + + clock.restore() + }) + + it('should log when no callback is set', () => { + const clock = sinon.useFakeTimers(1000) + + // First attempt + interceptor.beforeAttempt(1) + + // Simulate delay above threshold + clock.tick(3000) + interceptor.beforeAttempt(2) + + expect(mockLogging.debug.calledWith('QDelayTrackingInterceptor: No delay notification callback set')).to.be + .true + + clock.restore() + }) + }) + + describe('reset', () => { + it('should reset lastAttemptTime', () => { + // Make an attempt to set lastAttemptTime + interceptor.beforeAttempt(1) + + // Reset + interceptor.reset() + + // Next attempt should be treated as first + interceptor.beforeAttempt(1) + + expect( + mockLogging.debug.calledWith( + 'QDelayTrackingInterceptor: First attempt or no lastAttemptTime, skipping delay calculation' + ) + ).to.be.true + }) + }) + + describe('name', () => { + it('should return correct name', () => { + expect(interceptor.name()).to.equal('Q Language Server Delay Tracking Interceptor') + }) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/delayInterceptor.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/delayInterceptor.ts new file mode 100644 index 0000000000..6c81abc42a --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/delayInterceptor.ts @@ -0,0 +1,93 @@ +import { Logging } from '@aws/language-server-runtimes/server-interface' +import { MINOR_DELAY_THRESHOLD_MS, MAJOR_DELAY_THRESHOLD_MS, MAX_RETRY_DELAY_MS } from '../constants/constants' + +export interface DelayNotification { + message: string + attemptNumber: number + delay: number + thresholdExceeded: boolean +} + +/** + * Delay tracking interceptor that matches CLI's DelayTrackingInterceptor behavior. + * Tracks retry delays and provides user notifications. + */ +export class QDelayTrackingInterceptor { + private logging?: Logging + private minorDelayThreshold: number = MINOR_DELAY_THRESHOLD_MS + private majorDelayThreshold: number = MAJOR_DELAY_THRESHOLD_MS + private maxRetryDelay: number = MAX_RETRY_DELAY_MS + private lastAttemptTime?: number + private onDelayNotification?: (notification: DelayNotification) => void + + constructor(logging?: Logging) { + this.logging = logging + } + + /** + * Sets the delay notification callback for UI integration + */ + public setDelayNotificationCallback(callback: (notification: DelayNotification) => void): void { + this.logging?.debug(`QDelayTrackingInterceptor: setDelayNotificationCallback called`) + this.onDelayNotification = callback + } + + /** + * Called before each request attempt to track delays and notify users + */ + public beforeAttempt(attemptNumber: number): void { + this.logging?.debug(`QDelayTrackingInterceptor: Attempt ${attemptNumber}`) + const now = Date.now() + + if (this.lastAttemptTime && attemptNumber > 1) { + const delay = Math.min(now - this.lastAttemptTime, this.maxRetryDelay) + this.logging?.debug( + `QDelayTrackingInterceptor: Delay ${delay}ms, thresholds: minor=${this.minorDelayThreshold}ms, major=${this.majorDelayThreshold}ms` + ) + + let message: string + if (delay >= this.majorDelayThreshold) { + message = `Retry #${attemptNumber}, retrying within ${Math.ceil(this.maxRetryDelay / 1000)}s..` + } else if (delay >= this.minorDelayThreshold) { + message = `Retry #${attemptNumber}, retrying within 5s..` + } else { + // No notification for short delays + this.logging?.debug(`QDelayTrackingInterceptor: Delay ${delay}ms below threshold, no notification`) + this.lastAttemptTime = now + return + } + + this.logging?.debug(`QDelayTrackingInterceptor: Delay message: ${message}`) + + // Notify UI about the delay + if (this.onDelayNotification) { + this.logging?.debug(`QDelayTrackingInterceptor: Sending delay notification`) + this.onDelayNotification({ + message, + attemptNumber, + delay: Math.ceil(delay / 1000), + thresholdExceeded: delay >= this.minorDelayThreshold, + }) + } else { + this.logging?.debug(`QDelayTrackingInterceptor: No delay notification callback set`) + } + } else { + this.logging?.debug( + `QDelayTrackingInterceptor: First attempt or no lastAttemptTime, skipping delay calculation` + ) + } + + this.lastAttemptTime = now + } + + /** + * Reset tracking state + */ + public reset(): void { + this.lastAttemptTime = undefined + } + + public name(): string { + return 'Q Language Server Delay Tracking Interceptor' + } +} diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/errorTransformer.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/errorTransformer.test.ts new file mode 100644 index 0000000000..05becfa162 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/errorTransformer.test.ts @@ -0,0 +1,420 @@ +import { QErrorTransformer } from './errorTransformer' +import { AgenticChatError } from '../errors' +import { expect } from 'chai' +import * as sinon from 'sinon' +import { + MONTHLY_LIMIT_ERROR_MARKER, + HIGH_LOAD_ERROR_MESSAGE, + INSUFFICIENT_MODEL_CAPACITY, + SERVICE_UNAVAILABLE_EXCEPTION, +} from '../constants/constants' + +describe('QErrorTransformer', () => { + let transformer: QErrorTransformer + let mockLogging: any + + beforeEach(() => { + mockLogging = { + log: sinon.spy(), + debug: sinon.spy(), + } + transformer = new QErrorTransformer(mockLogging, false) + }) + + describe('transformFinalError', () => { + it('should transform usage limit errors', () => { + const error = new Error('Usage limit exceeded') + ;(error as any).code = 'AmazonQUsageLimitError' + error.message = `${MONTHLY_LIMIT_ERROR_MARKER} exceeded` + + const result = transformer.transformFinalError(error) + + expect(result).to.be.instanceOf(AgenticChatError) + expect(result.message).to.include('Request failed after 3 attempts') + expect((result as AgenticChatError).code).to.equal('AmazonQUsageLimitError') + }) + + it('should transform monthly limit errors from response body', () => { + const error = new Error('Service error') + ;(error as any).cause = { + $metadata: { + body: `Error: ${MONTHLY_LIMIT_ERROR_MARKER} exceeded for user`, + }, + } + + const result = transformer.transformFinalError(error) + + expect(result).to.be.instanceOf(AgenticChatError) + expect((result as AgenticChatError).code).to.equal('AmazonQUsageLimitError') + }) + + it('should transform abort errors', () => { + const error = new Error('Request aborted') + error.name = 'AbortError' + + const result = transformer.transformFinalError(error) + + expect(result).to.be.instanceOf(AgenticChatError) + expect(result.message).to.equal('Request aborted') + expect((result as AgenticChatError).code).to.equal('RequestAborted') + }) + + it('should transform input too long errors', () => { + const error = new Error('input too long') + ;(error as any).code = 'InputTooLong' + + const result = transformer.transformFinalError(error) + + expect(result).to.be.instanceOf(AgenticChatError) + expect(result.message).to.include('Too much context loaded') + expect((result as AgenticChatError).code).to.equal('InputTooLong') + }) + + it('should transform model unavailable errors with model selection enabled', () => { + const transformerWithModelSelection = new QErrorTransformer(mockLogging, true) + const error = new Error('Model unavailable') + ;(error as any).statusCode = 429 + ;(error as any).cause = { reason: INSUFFICIENT_MODEL_CAPACITY } + + const result = transformerWithModelSelection.transformFinalError(error) + + expect(result).to.be.instanceOf(AgenticChatError) + expect(result.message).to.include('model you selected is temporarily unavailable') + expect((result as AgenticChatError).code).to.equal('QModelResponse') + }) + + it('should transform model unavailable errors without model selection', () => { + const error = new Error('High load') + ;(error as any).statusCode = 500 + error.message = HIGH_LOAD_ERROR_MESSAGE + + const result = transformer.transformFinalError(error) + + expect(result).to.be.instanceOf(AgenticChatError) + expect(result.message).to.include('experiencing high traffic') + expect((result as AgenticChatError).code).to.equal('QModelResponse') + }) + + it('should transform throttling errors', () => { + const error = new Error('Throttling') + ;(error as any).code = 'ThrottlingException' + ;(error as any).statusCode = 429 + + const result = transformer.transformFinalError(error) + + expect(result).to.be.instanceOf(AgenticChatError) + expect(result.message).to.include('Service is currently experiencing high traffic') + expect((result as AgenticChatError).code).to.equal('RequestThrottled') + }) + + it('should transform service overloaded errors', () => { + const error = new Error('Service error') + ;(error as any).statusCode = 500 + ;(error as any).cause = { + $metadata: { + body: `${SERVICE_UNAVAILABLE_EXCEPTION}: Service temporarily unavailable`, + }, + } + + const result = transformer.transformFinalError(error) + + expect(result).to.be.instanceOf(AgenticChatError) + expect(result.message).to.include('Service is currently experiencing high traffic') + expect((result as AgenticChatError).code).to.equal('RequestThrottled') + }) + + it('should handle unknown errors', () => { + const error = new Error('Unknown error') + + const result = transformer.transformFinalError(error) + + expect(result).to.be.instanceOf(AgenticChatError) + expect(result.message).to.equal('Unknown error') + expect((result as AgenticChatError).code).to.equal('QModelResponse') + }) + + it('should use custom attempt count when provided', () => { + const error = new Error('Throttling') + ;(error as any).code = 'AmazonQUsageLimitError' + + const result = transformer.transformFinalError(error, 5) + + expect(result.message).to.include('Request failed after 5 attempts') + }) + + it('should extract request ID from error', () => { + const error = new Error('Service error') + ;(error as any).cause = { + $metadata: { requestId: 'test-request-123' }, + } + + const result = transformer.transformFinalError(error) as AgenticChatError + + expect(result.requestId).to.equal('test-request-123') + }) + + it('should pass through authentication errors', () => { + // Mock the instanceof check by creating a proper error type + const authError = new Error('Auth error') + ;(authError as any).constructor = { name: 'AmazonQServicePendingSigninError' } + + // Mock the instanceof check + const originalTransform = transformer.transformFinalError + transformer.transformFinalError = function (error: any, attemptCount?: number) { + if (error.constructor?.name === 'AmazonQServicePendingSigninError') { + return error + } + return originalTransform.call(this, error, attemptCount) + } + + const result = transformer.transformFinalError(authError) + + expect(result).to.equal(authError) + }) + + it('should handle model unavailable with reason property', () => { + const error = new Error('Model unavailable') + ;(error as any).statusCode = 429 + ;(error as any).reason = INSUFFICIENT_MODEL_CAPACITY + + const result = transformer.transformFinalError(error) + + expect(result).to.be.instanceOf(AgenticChatError) + expect((result as AgenticChatError).code).to.equal('QModelResponse') + }) + + it('should handle non-Error objects', () => { + const nonError = 'string error' + + const result = transformer.transformFinalError(nonError) + + expect(result).to.be.instanceOf(AgenticChatError) + expect(result.message).to.equal('string error') + }) + }) + + describe('extractResponseBody', () => { + it('should extract body from different error formats', () => { + const transformer = new QErrorTransformer() + + // Test cause.$metadata.body + let error: any = { + cause: { $metadata: { body: 'test body 1' } }, + } + expect((transformer as any).extractResponseBody(error)).to.equal('test body 1') + + // Test $metadata.body + error = { + $metadata: { body: 'test body 2' }, + } + expect((transformer as any).extractResponseBody(error)).to.equal('test body 2') + + // Test message + error = { + message: 'test body 3', + } + expect((transformer as any).extractResponseBody(error)).to.equal('test body 3') + }) + + it('should handle extraction errors gracefully', () => { + const transformer = new QErrorTransformer() + + // Test extractTextFromBody error handling + const bodyThatThrows = { + get toString() { + throw new Error('Access denied') + }, + } + + const result = (transformer as any).extractTextFromBody(bodyThatThrows) + expect(result).to.be.null + }) + + it('should extract from response data and body', () => { + const transformer = new QErrorTransformer() + + // Test response.data + let error: any = { + response: { data: 'response data' }, + } + expect((transformer as any).extractResponseBody(error)).to.equal('response data') + + // Test response.body + error = { + response: { body: 'response body' }, + } + expect((transformer as any).extractResponseBody(error)).to.equal('response body') + }) + }) + + describe('getStatusCode', () => { + it('should extract status code from different error formats', () => { + const transformer = new QErrorTransformer() + + // Test cause.$metadata.httpStatusCode + let error: any = { + cause: { $metadata: { httpStatusCode: 429 } }, + } + expect((transformer as any).getStatusCode(error)).to.equal(429) + + // Test $metadata.httpStatusCode + error = { + $metadata: { httpStatusCode: 500 }, + } + expect((transformer as any).getStatusCode(error)).to.equal(500) + + // Test statusCode + error = { + statusCode: 404, + } + expect((transformer as any).getStatusCode(error)).to.equal(404) + + // Test status + error = { + status: 503, + } + expect((transformer as any).getStatusCode(error)).to.equal(503) + }) + + it('should handle status code extraction errors', () => { + const transformer = new QErrorTransformer() + const error: any = { + get cause() { + throw new Error('Access denied') + }, + } + + const result = (transformer as any).getStatusCode(error) + + expect(result).to.be.undefined + }) + + it('should extract status code from response patterns', () => { + const transformer = new QErrorTransformer() + + // Test response.status + let error: any = { + response: { status: 429 }, + } + expect((transformer as any).getStatusCode(error)).to.equal(429) + + // Test response.statusCode + error = { + response: { statusCode: 500 }, + } + expect((transformer as any).getStatusCode(error)).to.equal(500) + + // Test cause.statusCode + error = { + cause: { statusCode: 404 }, + } + expect((transformer as any).getStatusCode(error)).to.equal(404) + + // Test cause.status + error = { + cause: { status: 503 }, + } + expect((transformer as any).getStatusCode(error)).to.equal(503) + }) + }) + + describe('isThrottlingError', () => { + it('should identify throttling errors by status code', () => { + const transformer = new QErrorTransformer() + + const error: any = { statusCode: 429 } + expect((transformer as any).isThrottlingError(error)).to.be.true + }) + + it('should identify throttling errors by code', () => { + const transformer = new QErrorTransformer() + + const error: any = { code: 'ThrottlingException' } + expect((transformer as any).isThrottlingError(error)).to.be.true + }) + + it('should identify service overloaded errors', () => { + const transformer = new QErrorTransformer() + + const error: any = { + statusCode: 500, + cause: { + $metadata: { + body: HIGH_LOAD_ERROR_MESSAGE, + }, + }, + } + expect((transformer as any).isThrottlingError(error)).to.be.true + }) + + it('should not identify non-throttling errors', () => { + const transformer = new QErrorTransformer() + + const error: any = { statusCode: 404 } + expect((transformer as any).isThrottlingError(error)).to.be.false + }) + + it('should identify throttling by name', () => { + const transformer = new QErrorTransformer() + + const error: any = { name: 'ThrottlingException' } + expect((transformer as any).isThrottlingError(error)).to.be.true + }) + + it('should identify model capacity throttling', () => { + const transformer = new QErrorTransformer() + + const error: any = { + statusCode: 429, + cause: { reason: INSUFFICIENT_MODEL_CAPACITY }, + } + expect((transformer as any).isThrottlingError(error)).to.be.true + }) + + it('should log debug messages for service overloaded detection', () => { + const transformer = new QErrorTransformer(mockLogging) + + const error: any = { + statusCode: 500, + cause: { + $metadata: { + body: `${SERVICE_UNAVAILABLE_EXCEPTION}: Service temporarily unavailable`, + }, + }, + } + + expect((transformer as any).isThrottlingError(error)).to.be.true + expect(mockLogging.debug.called).to.be.true + }) + + it('should handle ArrayBuffer body extraction', () => { + const transformer = new QErrorTransformer() + const buffer = new TextEncoder().encode('test buffer').buffer + + const result = (transformer as any).extractTextFromBody(buffer) + expect(result).to.equal('test buffer') + }) + + it('should handle object body extraction', () => { + const transformer = new QErrorTransformer() + const obj = { message: 'test object' } + + const result = (transformer as any).extractTextFromBody(obj) + expect(result).to.equal('{"message":"test object"}') + }) + + it('should handle null body', () => { + const transformer = new QErrorTransformer() + + const result = (transformer as any).extractTextFromBody(null) + expect(result).to.be.null + }) + + it('should handle undefined body', () => { + const transformer = new QErrorTransformer() + + const result = (transformer as any).extractTextFromBody(undefined) + expect(result).to.be.null + }) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/errorTransformer.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/errorTransformer.ts new file mode 100644 index 0000000000..3f60e37ad9 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/errorTransformer.ts @@ -0,0 +1,221 @@ +import { Logging } from '@aws/language-server-runtimes/server-interface' +import { isUsageLimitError, isAwsThrottlingError, getRequestID } from '../../../shared/utils' +import { AgenticChatError, isThrottlingRelated, isRequestAbortedError, isInputTooLongError } from '../errors' +import { + AmazonQError, + AmazonQServicePendingSigninError, + AmazonQServicePendingProfileError, +} from '../../../shared/amazonQServiceManager/errors' + +import { + HTTP_STATUS_TOO_MANY_REQUESTS, + HTTP_STATUS_INTERNAL_SERVER_ERROR, + MONTHLY_LIMIT_ERROR_MARKER, + HIGH_LOAD_ERROR_MESSAGE, + SERVICE_UNAVAILABLE_EXCEPTION, + INSUFFICIENT_MODEL_CAPACITY, + MAX_REQUEST_ATTEMPTS, +} from '../constants/constants' + +/** + * Q-specific error transformation for AWS SDK native retry. + * AWS SDK handles retries, this transforms final errors into user-friendly Q messages. + */ +export class QErrorTransformer { + private logging?: Logging + private isModelSelectionEnabled: () => boolean + + constructor(logging?: Logging, isModelSelectionEnabled: (() => boolean) | boolean = false) { + this.logging = logging + this.isModelSelectionEnabled = + typeof isModelSelectionEnabled === 'function' ? isModelSelectionEnabled : () => isModelSelectionEnabled + } + + private extractResponseBody(error: any): string | null { + return ( + this.extractTextFromBody(error.cause?.$metadata?.body) || + this.extractTextFromBody(error.$metadata?.body) || + this.extractTextFromBody(error.cause?.body) || + this.extractTextFromBody(error.body) || + this.extractTextFromBody(error.response?.data) || + this.extractTextFromBody(error.response?.body) || + error.message || + null + ) + } + + private extractTextFromBody(body: any): string | null { + try { + if (typeof body === 'string') { + return body + } + if (body instanceof Uint8Array) { + return new TextDecoder('utf-8', { fatal: false }).decode(body) + } + if (body instanceof ArrayBuffer) { + return new TextDecoder('utf-8', { fatal: false }).decode(body) + } + if (typeof body === 'object' && body !== null) { + return JSON.stringify(body) + } + return null + } catch { + return null + } + } + + public transformFinalError(error: any, attemptCount?: number): Error { + // Use default attempt count if not provided + const attempts = attemptCount ?? MAX_REQUEST_ATTEMPTS + const requestId = getRequestID(error) + + // Don't transform authentication errors - let them pass through for auth follow-up handling + if (error instanceof AmazonQServicePendingSigninError || error instanceof AmazonQServicePendingProfileError) { + return error + } + + // Handle specific error types with retry context + if (isUsageLimitError(error)) { + return new AgenticChatError( + `Request failed after ${attempts} attempts`, + 'AmazonQUsageLimitError', + error instanceof Error ? error : undefined, + requestId + ) + } + + // Check response body for monthly limits + const bodyStr = this.extractResponseBody(error) + if (bodyStr && bodyStr.includes(MONTHLY_LIMIT_ERROR_MARKER)) { + return new AgenticChatError( + `Request failed after ${attempts} attempts`, + 'AmazonQUsageLimitError', + error instanceof Error ? error : undefined, + requestId + ) + } + + if ( + error?.name === 'AbortError' || + error?.code === 'RequestAborted' || + error?.name === 'RequestAborted' || + isRequestAbortedError(error) + ) { + return new AgenticChatError( + 'Request aborted', + 'RequestAborted', + error instanceof Error ? error : undefined, + requestId + ) + } + + if ( + error?.name === 'InputTooLong' || + error?.code === 'InputTooLong' || + error?.message?.includes('input too long') || + isInputTooLongError(error) + ) { + return new AgenticChatError( + 'Too much context loaded. I have cleared the conversation history. Please retry your request with smaller input.', + 'InputTooLong', + error instanceof Error ? error : undefined, + requestId + ) + } + + // Check for model unavailability first (before general throttling) + const statusCode = this.getStatusCode(error) + const isModelUnavailable = + (statusCode === HTTP_STATUS_TOO_MANY_REQUESTS && + (error.cause?.reason === INSUFFICIENT_MODEL_CAPACITY || + error.reason === INSUFFICIENT_MODEL_CAPACITY)) || + (statusCode === HTTP_STATUS_INTERNAL_SERVER_ERROR && error.message === HIGH_LOAD_ERROR_MESSAGE) + + if (isModelUnavailable) { + const message = this.isModelSelectionEnabled() + ? `The model you selected is temporarily unavailable. Please switch to a different model and try again.` + : `I am experiencing high traffic, please try again shortly.` + + return new AgenticChatError( + message, + 'QModelResponse', + error instanceof Error ? error : undefined, + requestId + ) + } + + if (isAwsThrottlingError(error) || isThrottlingRelated(error) || this.isThrottlingError(error)) { + return new AgenticChatError( + `Service is currently experiencing high traffic. Request failed after ${attempts} attempts. Please try again later.`, + 'RequestThrottled', + error instanceof Error ? error : undefined, + requestId + ) + } + + // Handle other errors - fallback to QModelResponse with request ID + return new AgenticChatError( + error instanceof Error ? error.message : String(error), + 'QModelResponse', + error instanceof Error ? error : undefined, + requestId + ) + } + + private isThrottlingError(error: any): boolean { + const statusCode = this.getStatusCode(error) + + // Check for AWS throttling patterns + if ( + statusCode === HTTP_STATUS_TOO_MANY_REQUESTS || + error?.name === 'ThrottlingException' || + error?.code === 'ThrottlingException' + ) + return true + + // Check for service overloaded errors (status 500 with specific messages) + if (statusCode === HTTP_STATUS_INTERNAL_SERVER_ERROR) { + // Check response body directly (not error message) to avoid conflict with model unavailability + const responseBody = error.cause?.$metadata?.body || error.$metadata?.body + if (responseBody) { + const isOverloaded = + responseBody.includes(HIGH_LOAD_ERROR_MESSAGE) || + responseBody.includes(SERVICE_UNAVAILABLE_EXCEPTION) + this.logging?.debug( + `QErrorTransformer: Service overloaded error detected (status 500): ${isOverloaded}` + ) + return isOverloaded + } + } + + // Model capacity issues - but these should be handled by model unavailability check first + if ( + statusCode === HTTP_STATUS_TOO_MANY_REQUESTS && + (error.cause?.reason === INSUFFICIENT_MODEL_CAPACITY || error.reason === INSUFFICIENT_MODEL_CAPACITY) + ) { + return true + } + + return false + } + + private getStatusCode(error: any): number | undefined { + try { + // AWS SDK v3 metadata patterns + if (error.cause?.$metadata?.httpStatusCode) return error.cause.$metadata.httpStatusCode + if (error.$metadata?.httpStatusCode) return error.$metadata.httpStatusCode + // Direct status properties + if (error.statusCode) return error.statusCode + if (error.status) return error.status + // Response object patterns + if (error.response?.status) return error.response.status + if (error.response?.statusCode) return error.response.statusCode + // Nested error patterns + if (error.cause?.statusCode) return error.cause.statusCode + if (error.cause?.status) return error.cause.status + return undefined + } catch { + return undefined + } + } +} diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/index.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/index.ts new file mode 100644 index 0000000000..868f69ac4a --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/index.ts @@ -0,0 +1,3 @@ +export { QRetryClassifier, RetryAction, type RetryClassifierPriority, type InterceptorContext } from './retryClassifier' +export { QDelayTrackingInterceptor, type DelayNotification } from './delayInterceptor' +export { QErrorTransformer } from './errorTransformer' diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/qRetryStrategy.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/qRetryStrategy.test.ts new file mode 100644 index 0000000000..920758a505 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/qRetryStrategy.test.ts @@ -0,0 +1,179 @@ +import { QRetryStrategy } from './qRetryStrategy' +import { QRetryClassifier, RetryAction } from './retryClassifier' +import { QDelayTrackingInterceptor } from './delayInterceptor' +import { RetryToken, RetryErrorInfo } from '@aws-sdk/types' +import { expect } from 'chai' +import * as sinon from 'sinon' + +describe('QRetryStrategy', () => { + let retryStrategy: QRetryStrategy + let mockClassifier: sinon.SinonStubbedInstance + let mockDelayInterceptor: sinon.SinonStubbedInstance + let mockLogging: any + + beforeEach(() => { + mockLogging = { + log: sinon.spy(), + debug: sinon.spy(), + } + + mockClassifier = { + classifyRetry: sinon.stub(), + } as sinon.SinonStubbedInstance + + mockDelayInterceptor = { + beforeAttempt: sinon.stub(), + reset: sinon.stub(), + } as sinon.SinonStubbedInstance + + retryStrategy = new QRetryStrategy(mockClassifier, mockDelayInterceptor, 3, mockLogging) + }) + + describe('acquireInitialRetryToken', () => { + it('should return initial token with zero counts', async () => { + const token = await retryStrategy.acquireInitialRetryToken('test-scope') + + expect(token.getRetryCount()).to.equal(0) + expect((retryStrategy as any).attemptCount).to.equal(0) + expect( + mockLogging.log.args.some((args: any) => + args[0].includes('Initial retry token acquired for scope: test-scope') + ) + ).to.be.true + }) + }) + + describe('refreshRetryTokenForRetry', () => { + let initialToken: RetryToken + + beforeEach(async () => { + initialToken = await retryStrategy.acquireInitialRetryToken('test-scope') + }) + + it('should allow retry for throttling errors', async () => { + const error = new Error('Throttling') + ;(error as any).code = 'ThrottlingException' + ;(error as any).$metadata = {} + const errorInfo: RetryErrorInfo = { error: error as any, errorType: 'THROTTLING' } + + mockClassifier.classifyRetry.returns(RetryAction.ThrottlingError) + + const newToken = await retryStrategy.refreshRetryTokenForRetry(initialToken, errorInfo) + + expect(newToken.getRetryCount()).to.equal(1) + expect(mockDelayInterceptor.beforeAttempt.calledWith(2)).to.be.true + }) + + it('should reject retry for forbidden errors', async () => { + const error = new Error('Abort') + ;(error as any).$metadata = {} + const errorInfo: RetryErrorInfo = { error: error as any, errorType: 'CLIENT_ERROR' } + mockClassifier.classifyRetry.returns(RetryAction.RetryForbidden) + + try { + await retryStrategy.refreshRetryTokenForRetry(initialToken, errorInfo) + expect.fail('Should have thrown error') + } catch (e: any) { + expect(e.message).to.equal('Abort') // Original error is thrown + } + }) + + it('should delegate to adaptive strategy for max attempts', async () => { + mockClassifier.classifyRetry.returns(RetryAction.ThrottlingError) + const error = new Error('Test error') + ;(error as any).$metadata = {} + const errorInfo: RetryErrorInfo = { error: error as any, errorType: 'THROTTLING' } + + // The adaptive strategy will handle max attempts internally + // We just verify our classifier is called + try { + await retryStrategy.refreshRetryTokenForRetry(initialToken, errorInfo) + } catch (e) { + // May throw due to adaptive strategy limits + } + + expect(mockClassifier.classifyRetry.called).to.be.true + }) + + it('should delegate delay calculation to adaptive strategy', async () => { + mockClassifier.classifyRetry.returns(RetryAction.ThrottlingError) + const error = new Error() + ;(error as any).$metadata = {} + const errorInfo: RetryErrorInfo = { error: error as any, errorType: 'THROTTLING' } + + const token = await retryStrategy.refreshRetryTokenForRetry(initialToken, errorInfo) + + // Adaptive strategy handles delay calculation + expect(token.getRetryCount()).to.equal(1) + expect(mockDelayInterceptor.beforeAttempt.calledWith(2)).to.be.true + }) + + it('should track delay interceptor calls', async () => { + mockClassifier.classifyRetry.returns(RetryAction.ThrottlingError) + const error = new Error() + ;(error as any).$metadata = {} + const errorInfo: RetryErrorInfo = { error: error as any, errorType: 'THROTTLING' } + + await retryStrategy.refreshRetryTokenForRetry(initialToken, errorInfo) + + expect(mockDelayInterceptor.beforeAttempt.calledWith(2)).to.be.true + }) + }) + + describe('recordSuccess', () => { + it('should reset state and call delay interceptor', async () => { + const token = await retryStrategy.acquireInitialRetryToken('test-scope') + + retryStrategy.recordSuccess(token) + + expect(mockDelayInterceptor.reset.called).to.be.true + expect((retryStrategy as any).attemptCount).to.equal(0) + expect( + mockLogging.log.args.some((args: any) => args[0].includes('Request succeeded after 1 total attempts')) + ).to.be.true + }) + + it('should handle reset errors gracefully', async () => { + mockDelayInterceptor.reset.throws(new Error('Reset failed')) + + const token = await retryStrategy.acquireInitialRetryToken('test-scope') + + retryStrategy.recordSuccess(token) // Should not throw + expect( + mockLogging.log.args.some((args: any) => + args[0].includes('Warning - failed to reset state after success') + ) + ).to.be.true + }) + + it('should handle parent recordSuccess errors gracefully', async () => { + const strategy = new QRetryStrategy(mockClassifier, mockDelayInterceptor, 3, mockLogging) + const token = await strategy.acquireInitialRetryToken('test-scope') + + // Mock the parent recordSuccess to throw + const originalRecordSuccess = Object.getPrototypeOf(Object.getPrototypeOf(strategy)).recordSuccess + Object.getPrototypeOf(Object.getPrototypeOf(strategy)).recordSuccess = () => { + throw new Error('Parent recordSuccess failed') + } + + strategy.recordSuccess(token) // Should not throw + + // Restore original method + Object.getPrototypeOf(Object.getPrototypeOf(strategy)).recordSuccess = originalRecordSuccess + + expect( + mockLogging.log.args.some((args: any) => + args[0].includes('Warning - failed to reset state after success') + ) + ).to.be.true + }) + }) + + describe('getAttemptCount', () => { + it('should return current attempt count', async () => { + const token = await retryStrategy.acquireInitialRetryToken('test-scope') + + expect(retryStrategy.getAttemptCount()).to.equal(0) + }) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/qRetryStrategy.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/qRetryStrategy.ts new file mode 100644 index 0000000000..af3316c158 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/qRetryStrategy.ts @@ -0,0 +1,89 @@ +import { RetryToken, RetryErrorInfo, RetryErrorType } from '@aws-sdk/types' +import { AdaptiveRetryStrategy } from '@smithy/util-retry' +import { StandardRetryToken } from '@smithy/types' +import { QRetryClassifier, RetryAction } from './retryClassifier' +import { QDelayTrackingInterceptor } from './delayInterceptor' +import { Logging } from '@aws/language-server-runtimes/server-interface' +import { sanitizeLogInput } from '../../../shared/utils' + +/** + * Custom retry strategy that extends AWS SDK v3's AdaptiveRetryStrategy with Q-specific logic + */ +export class QRetryStrategy extends AdaptiveRetryStrategy { + private retryClassifier: QRetryClassifier + private delayInterceptor: QDelayTrackingInterceptor + private maxAttempts: number + private logging?: Logging + private attemptCount: number = 0 + + constructor( + retryClassifier: QRetryClassifier, + delayInterceptor: QDelayTrackingInterceptor, + maxAttempts: number, + logging?: Logging + ) { + super(() => Promise.resolve(maxAttempts)) + this.retryClassifier = retryClassifier + this.delayInterceptor = delayInterceptor + this.maxAttempts = maxAttempts + this.logging = logging + } + + override async acquireInitialRetryToken(retryTokenScope: string): Promise { + this.attemptCount = 0 + this.logging?.log( + `QRetryStrategy: Initial retry token acquired for scope: ${retryTokenScope}, attempt count reset to 0` + ) + // AdaptiveRetryStrategy returns StandardRetryToken, but interface expects RetryToken + return super.acquireInitialRetryToken(retryTokenScope) + } + + override async refreshRetryTokenForRetry(token: RetryToken, errorInfo: RetryErrorInfo): Promise { + const currentAttempt = token.getRetryCount() + 1 + this.attemptCount = currentAttempt + + const errorCode = sanitizeLogInput( + (errorInfo.error as any)?.name || (errorInfo.error as any)?.code || 'Unknown' + ) + this.logging?.log(`QRetryStrategy: Retry attempt ${currentAttempt} for error: ${errorCode}`) + + // Apply Q-specific retry classification + const context = { error: errorInfo.error, response: (errorInfo.error as any)?.$response } + const action = this.retryClassifier.classifyRetry(context) + this.logging?.log(`QRetryStrategy: Retry classification result: ${action}`) + + // Check if we should retry based on Q classification + if (action === RetryAction.RetryForbidden) { + this.logging?.log(`QRetryStrategy: Retry forbidden, stopping retries after ${currentAttempt} attempts`) + throw errorInfo.error + } + + // Track delay for UI notifications - CALL BEFORE ATTEMPT + this.delayInterceptor.beforeAttempt(currentAttempt + 1) + + // Delegate to adaptive strategy for delay calculation and max attempts check + // AdaptiveRetryStrategy expects StandardRetryToken but we receive RetryToken + // The token from acquireInitialRetryToken is actually StandardRetryToken, so this cast is safe + return super.refreshRetryTokenForRetry(token as StandardRetryToken, errorInfo) + } + + override recordSuccess(token: RetryToken): void { + try { + this.logging?.log(`QRetryStrategy: Request succeeded after ${this.attemptCount + 1} total attempts`) + // Reset delay tracking on success + this.delayInterceptor.reset() + this.attemptCount = 0 + // Call parent to maintain adaptive strategy state + // Token is actually StandardRetryToken from AdaptiveRetryStrategy + super.recordSuccess(token as StandardRetryToken) + } catch (error) { + // Log but don't throw - success recording should not fail + this.logging?.log(`QRetryStrategy: Warning - failed to reset state after success: ${error}`) + } + } + + // Test helper method to get current attempt count + public getAttemptCount(): number { + return this.attemptCount + } +} diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/retryClassifier.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/retryClassifier.test.ts new file mode 100644 index 0000000000..4f140c3b09 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/retryClassifier.test.ts @@ -0,0 +1,254 @@ +import { QRetryClassifier, RetryAction } from './retryClassifier' +import { expect } from 'chai' +import * as sinon from 'sinon' +import { + CONTENT_LENGTH_EXCEEDS_THRESHOLD, + INVALID_MODEL_ID, + MAXIMUM_CHAT_CONTENT_MESSAGE, + MONTHLY_LIMIT_ERROR_MARKER, + HIGH_LOAD_ERROR_MESSAGE, + INSUFFICIENT_MODEL_CAPACITY, +} from '../constants/constants' + +describe('QRetryClassifier', () => { + let classifier: QRetryClassifier + let mockLogging: any + + beforeEach(() => { + mockLogging = { + log: sinon.spy(), + debug: sinon.spy(), + } + classifier = new QRetryClassifier(mockLogging) + }) + + describe('classifyRetry', () => { + it('should forbid retry for AccessDeniedException', () => { + const error = new Error('Access denied') + error.name = 'AccessDeniedException' + + const result = classifier.classifyRetry({ error }) + + expect(result).to.equal(RetryAction.RetryForbidden) + }) + + it('should forbid retry for SERVICE_QUOTA_EXCEPTION', () => { + const error = new Error('Service quota exceeded') + error.name = 'SERVICE_QUOTA_EXCEPTION' + + const result = classifier.classifyRetry({ error }) + + expect(result).to.equal(RetryAction.RetryForbidden) + }) + + it('should forbid retry for abort errors', () => { + const error = new Error('Request aborted') + error.name = 'AbortError' + + const result = classifier.classifyRetry({ error }) + + expect(result).to.equal(RetryAction.RetryForbidden) + }) + + it('should forbid retry for input too long errors', () => { + const error = new Error('input too long') + ;(error as any).reason = CONTENT_LENGTH_EXCEEDS_THRESHOLD + + const result = classifier.classifyRetry({ error }) + + expect(result).to.equal(RetryAction.RetryForbidden) + }) + + it('should forbid retry for invalid model ID errors', () => { + const error = new Error('Invalid model') + ;(error as any).reason = INVALID_MODEL_ID + + const result = classifier.classifyRetry({ error }) + + expect(result).to.equal(RetryAction.RetryForbidden) + }) + + it('should forbid retry for maximum chat content message', () => { + const error = new Error(MAXIMUM_CHAT_CONTENT_MESSAGE) + error.message = MAXIMUM_CHAT_CONTENT_MESSAGE + + const result = classifier.classifyRetry({ error }) + + expect(result).to.equal(RetryAction.RetryForbidden) + }) + + it('should forbid retry for monthly limit errors', () => { + const error = new Error('Monthly limit exceeded') + ;(error as any).reason = MONTHLY_LIMIT_ERROR_MARKER + const context = { + error, + response: { + status: 400, + body: `Error: ${MONTHLY_LIMIT_ERROR_MARKER} exceeded`, + }, + } + + const result = classifier.classifyRetry(context) + + expect(result).to.equal(RetryAction.RetryForbidden) + }) + + it('should classify throttling for service overloaded errors', () => { + const context = { + error: new Error('Service unavailable'), + response: { + status: 500, + body: HIGH_LOAD_ERROR_MESSAGE, + }, + } + + const result = classifier.classifyRetry(context) + + expect(result).to.equal(RetryAction.ThrottlingError) + }) + + it('should classify throttling for 429 status with model capacity', () => { + const error = new Error('Model unavailable') + ;(error as any).$metadata = { httpStatusCode: 429 } + ;(error as any).reason = INSUFFICIENT_MODEL_CAPACITY + + const result = classifier.classifyRetry({ error }) + + expect(result).to.equal(RetryAction.ThrottlingError) + }) + + it('should return no action for unknown errors', () => { + const error = new Error('Unknown error') + + const result = classifier.classifyRetry({ error }) + + expect(result).to.equal(RetryAction.NoActionIndicated) + }) + + it('should handle errors without response body', () => { + const error = new Error('Network error') + + const result = classifier.classifyRetry({ error }) + + expect(result).to.equal(RetryAction.NoActionIndicated) + }) + + it('should extract response body from different error formats', () => { + const classifier = new QRetryClassifier() + + // Test different body extraction paths - these should NOT trigger monthly limit errors + // since monthly limit detection now uses error.reason instead of body content + const context1 = { + error: { + cause: { $metadata: { body: MONTHLY_LIMIT_ERROR_MARKER } }, + }, + } + expect(classifier.classifyRetry(context1)).to.equal(RetryAction.NoActionIndicated) + + const context2 = { + error: { + $metadata: { body: MONTHLY_LIMIT_ERROR_MARKER }, + }, + } + expect(classifier.classifyRetry(context2)).to.equal(RetryAction.NoActionIndicated) + + const context3 = { + error: { + message: `${MONTHLY_LIMIT_ERROR_MARKER} exceeded`, + }, + } + expect(classifier.classifyRetry(context3)).to.equal(RetryAction.NoActionIndicated) + }) + }) + + describe('extractResponseBody', () => { + it('should extract body from Uint8Array', () => { + const classifier = new QRetryClassifier() + const body = new TextEncoder().encode('test body') + const context = { + error: {}, + response: { body }, + } + + const result = (classifier as any).extractResponseBody(context) + + expect(result).to.equal('test body') + }) + + it('should extract body from ArrayBuffer', () => { + const classifier = new QRetryClassifier() + const body = new TextEncoder().encode('test body').buffer + const context = { + error: { body }, + } + + const result = (classifier as any).extractResponseBody(context) + + expect(result).to.equal('test body') + }) + + it('should extract body from object', () => { + const classifier = new QRetryClassifier() + const body = { message: 'test' } + const context = { + error: { body }, + } + + const result = (classifier as any).extractResponseBody(context) + + expect(result).to.equal('{"message":"test"}') + }) + + it('should handle extraction errors gracefully', () => { + const classifier = new QRetryClassifier() + + // Test extractTextFromBody error handling + const bodyThatThrows = { + get toString() { + throw new Error('Access denied') + }, + } + + const result = (classifier as any).extractTextFromBody(bodyThatThrows) + expect(result).to.be.null + }) + }) + + describe('name and priority', () => { + it('should return correct name', () => { + expect(classifier.name()).to.equal('Q Language Server Retry Classifier') + }) + + it('should return correct priority', () => { + expect(classifier.priority().value).to.equal(100) + expect(QRetryClassifier.priority().value).to.equal(100) + }) + }) + + describe('isMonthlyLimitError', () => { + it('should log debug messages for monthly limit detection', () => { + const classifierWithLogging = new QRetryClassifier(mockLogging) + const error = { reason: MONTHLY_LIMIT_ERROR_MARKER } + + const result = (classifierWithLogging as any).isMonthlyLimitError(error) + + expect(result).to.be.true + expect(mockLogging.debug.called).to.be.true + }) + }) + + describe('isServiceOverloadedError', () => { + it('should log debug messages for service overloaded detection', () => { + const classifierWithLogging = new QRetryClassifier(mockLogging) + const context = { + error: { $metadata: { httpStatusCode: 500 } }, + response: { status: 500 }, + } + + const result = (classifierWithLogging as any).isServiceOverloadedError(context, HIGH_LOAD_ERROR_MESSAGE) + + expect(result).to.be.true + expect(mockLogging.debug.called).to.be.true + }) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/retryClassifier.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/retryClassifier.ts new file mode 100644 index 0000000000..1940113ad5 --- /dev/null +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/retry/retryClassifier.ts @@ -0,0 +1,166 @@ +import { Logging } from '@aws/language-server-runtimes/server-interface' +import { isRequestAbortedError, isInputTooLongError, isThrottlingRelated } from '../errors' +import { + MONTHLY_LIMIT_ERROR_MARKER, + HIGH_LOAD_ERROR_MESSAGE, + SERVICE_UNAVAILABLE_EXCEPTION, + HTTP_STATUS_INTERNAL_SERVER_ERROR, + INSUFFICIENT_MODEL_CAPACITY, + CONTENT_LENGTH_EXCEEDS_THRESHOLD, + INVALID_MODEL_ID, + MAXIMUM_CHAT_CONTENT_MESSAGE, +} from '../constants/constants' + +export enum RetryAction { + NoActionIndicated = 'no_action', + RetryForbidden = 'retry_forbidden', + ThrottlingError = 'throttling_error', +} + +export interface RetryClassifierPriority { + value: number +} + +export interface InterceptorContext { + error: any + response?: { + status?: number + body?: string | Uint8Array + } +} + +/** + * Retry classifier that matches CLI's QCliRetryClassifier behavior. + * Runs after AWS SDK's transient error classifier with higher priority. + */ +export class QRetryClassifier { + private logging?: Logging + + constructor(logging?: Logging) { + this.logging = logging + } + + static priority(): RetryClassifierPriority { + // Run after transient error classifier (higher priority number) + return { value: 100 } + } + + classifyRetry(context: InterceptorContext): RetryAction { + const error = context.error + + // Handle non-retryable errors first (matching original + enhanced detection) + if ( + error?.name === 'AccessDeniedException' || + error?.name === 'SERVICE_QUOTA_EXCEPTION' || + error?.name === 'AbortError' || + error?.code === 'RequestAborted' || + error?.name === 'RequestAborted' || + isRequestAbortedError(error) + ) { + return RetryAction.RetryForbidden + } + + if ( + error?.reason === CONTENT_LENGTH_EXCEEDS_THRESHOLD || + isInputTooLongError(error) || + error?.reason === INVALID_MODEL_ID + ) { + return RetryAction.RetryForbidden + } + + // Check for monthly limit error in error object + if (this.isMonthlyLimitError(error)) { + return RetryAction.RetryForbidden + } + + if (error?.message === MAXIMUM_CHAT_CONTENT_MESSAGE) { + return RetryAction.RetryForbidden + } + + const bodyStr = this.extractResponseBody(context) + if (bodyStr && this.isServiceOverloadedError(context, bodyStr)) { + return RetryAction.ThrottlingError + } + + // Check for model capacity issues + const status = context.response?.status || context.error?.$metadata?.httpStatusCode + if (status === 429 && error?.reason === INSUFFICIENT_MODEL_CAPACITY) { + return RetryAction.ThrottlingError + } + + // Check for throttling related errors (from errors.ts) + if (isThrottlingRelated(error)) { + return RetryAction.ThrottlingError + } + + return RetryAction.NoActionIndicated + } + + private extractResponseBody(context: InterceptorContext): string | null { + // Try context response first + const contextBody = this.extractTextFromBody(context.response?.body) + if (contextBody) return contextBody + + // Fallback to error-based extraction + const error = context.error + return ( + error?.message || + this.extractTextFromBody(error?.cause?.$metadata?.body) || + this.extractTextFromBody(error?.$metadata?.body) || + this.extractTextFromBody(error?.cause?.body) || + this.extractTextFromBody(error?.body) || + this.extractTextFromBody(error?.response?.data) || + this.extractTextFromBody(error?.response?.body) || + null + ) + } + + private extractTextFromBody(body: any): string | null { + try { + if (typeof body === 'string') { + return body + } + if (body instanceof Uint8Array) { + const decoded = new TextDecoder('utf-8', { fatal: false }).decode(body) + return decoded || null + } + if (body instanceof ArrayBuffer) { + return new TextDecoder('utf-8', { fatal: false }).decode(body) + } + if (typeof body === 'object' && body !== null) { + return JSON.stringify(body) + } + return null + } catch { + return null + } + } + + private isMonthlyLimitError(error: any): boolean { + const isMonthlyLimit = error?.reason === MONTHLY_LIMIT_ERROR_MARKER + this.logging?.debug(`QRetryClassifier: Monthly limit error detected: ${isMonthlyLimit}`) + return isMonthlyLimit + } + + private isServiceOverloadedError(context: InterceptorContext, bodyStr: string): boolean { + const status = context.response?.status || context.error?.status || context.error?.$metadata?.httpStatusCode + + if (status !== HTTP_STATUS_INTERNAL_SERVER_ERROR) { + return false + } + + const isOverloaded = + bodyStr.includes(HIGH_LOAD_ERROR_MESSAGE) || bodyStr.includes(SERVICE_UNAVAILABLE_EXCEPTION) + + this.logging?.debug(`QRetryClassifier: Service overloaded error detected (status 500): ${isOverloaded}`) + return isOverloaded + } + + name(): string { + return 'Q Language Server Retry Classifier' + } + + priority(): RetryClassifierPriority { + return QRetryClassifier.priority() + } +} diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/chatController.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/chatController.ts index 30235a0af9..1edba5a82c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/chatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/chatController.ts @@ -172,7 +172,7 @@ export class ChatController implements ChatHandlers { this.#log('Response for conversation id:', conversationIdentifier, JSON.stringify(response.$metadata)) } catch (err) { if (isAwsError(err) || (isObject(err) && 'statusCode' in err && typeof err.statusCode === 'number')) { - metric.setDimension('cwsprChatRepsonseCode', err.statusCode ?? 400) + metric.setDimension('cwsprChatRepsonseCode', (err as any).statusCode ?? 400) this.#telemetryController.emitMessageResponseError(params.tabId, metric.metric) } @@ -289,7 +289,7 @@ export class ChatController implements ChatHandlers { name: 'codewhisperer_inlineChatServiceInvocation', result: 'Failed', data: { - codewhispererRequestId: isAwsError(err) ? err.requestId : undefined, + codewhispererRequestId: isAwsError(err) ? (err as any).requestId : undefined, codewhispererTriggerType: this.#inlineChatTriggerType, duration: this.#inlineChatResponseLatency, codewhispererLanguage: this.#inlineChatLanguage, @@ -302,8 +302,8 @@ export class ChatController implements ChatHandlers { }, errorData: { reason: err instanceof Error ? err.name : 'UnknownError', - errorCode: isAwsError(err) ? err.code : undefined, - httpStatusCode: isAwsError(err) ? err.statusCode : undefined, + errorCode: isAwsError(err) ? (err as any).code : undefined, + httpStatusCode: isAwsError(err) ? (err as any).statusCode : undefined, }, }) @@ -370,8 +370,8 @@ export class ChatController implements ChatHandlers { }, errorData: { reason: err instanceof Error ? err.name : 'UnknownError', - errorCode: isAwsError(err) ? err.code : undefined, - httpStatusCode: isAwsError(err) ? err.statusCode : undefined, + errorCode: isAwsError(err) ? (err as any).code : undefined, + httpStatusCode: isAwsError(err) ? (err as any).statusCode : undefined, }, }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts index 0b92d13e12..bb76ceabaa 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts @@ -1,12 +1,4 @@ -import { - CodeWhispererStreamingClientConfig, - CodeWhispererStreamingServiceException, - GenerateAssistantResponseCommandInput, - GenerateAssistantResponseCommandOutput, - Origin, - SendMessageCommand, - ToolUse, -} from '@amzn/codewhisperer-streaming' +import { CodeWhispererStreamingClientConfig, Origin, ToolUse } from '@amzn/codewhisperer-streaming' import { StreamingClientServiceToken, SendMessageCommandInput, @@ -16,19 +8,15 @@ import { ChatCommandOutput, } from '../../shared/streamingClientService' import { ChatResult } from '@aws/language-server-runtimes/server-interface' -import { - AgenticChatError, - isInputTooLongError, - isRequestAbortedError, - isThrottlingRelated, - wrapErrorWithCode, -} from '../agenticChat/errors' +import { AgenticChatError } from '../agenticChat/errors' import { AmazonQBaseServiceManager } from '../../shared/amazonQServiceManager/BaseAmazonQServiceManager' -import { loggingUtils } from '@aws/lsp-core' import { Logging } from '@aws/language-server-runtimes/server-interface' import { Features } from '../types' -import { getOriginFromClientInfo, getClientName, getRequestID, isUsageLimitError } from '../../shared/utils' +import { getOriginFromClientInfo, getClientName } from '../../shared/utils' import { enabledModelSelection } from '../../shared/utils' +import { QErrorTransformer } from '../agenticChat/retry/errorTransformer' +import { DelayNotification } from '../agenticChat/retry/delayInterceptor' +import { MAX_REQUEST_ATTEMPTS } from '../agenticChat/constants/constants' export type ChatSessionServiceConfig = CodeWhispererStreamingClientConfig type FileChange = { before?: string; after?: string } @@ -59,6 +47,7 @@ export class ChatSessionService { #serviceManager?: AmazonQBaseServiceManager #logging?: Logging #origin?: Origin + #errorTransformer: QErrorTransformer public getConversationType(): string { return this.#conversationType @@ -147,6 +136,9 @@ export class ChatSessionService { this.#lsp = lsp this.#logging = logging this.#origin = getOriginFromClientInfo(getClientName(this.#lsp?.getClientInitializeParams())) + + // Initialize Q-specific error transformation + this.#errorTransformer = new QErrorTransformer(logging, () => this.isModelSelectionEnabled()) } public async sendMessage(request: SendMessageCommandInput): Promise { @@ -162,9 +154,12 @@ export class ChatSessionService { const client = this.#serviceManager.getStreamingClient() - const response = await client.sendMessage(request, this.#abortController) - - return response + // AWS SDK handles retries natively, we just transform final errors + try { + return await client.sendMessage(request, this.#abortController) + } catch (error) { + throw this.#errorTransformer.transformFinalError(error) + } } private isModelSelectionEnabled(): boolean { @@ -184,125 +179,23 @@ export class ChatSessionService { const client = this.#serviceManager.getStreamingClient() + // AWS SDK handles retries natively, we just transform final errors + try { + return await this.#performChatRequest(client, request) + } catch (error) { + throw this.#errorTransformer.transformFinalError(error) + } + } + + async #performChatRequest(client: any, request: ChatCommandInput): Promise { if (client instanceof StreamingClientServiceToken) { - try { - return await client.generateAssistantResponse(request, this.#abortController) - } catch (e) { - // Log the error using the logging property if available, otherwise fall back to console.error - if (this.#logging) { - this.#logging.error(`Error in generateAssistantResponse: ${loggingUtils.formatErr(e)}`) - } - - const requestId = getRequestID(e) - if (isUsageLimitError(e)) { - throw new AgenticChatError( - 'Request aborted', - 'AmazonQUsageLimitError', - e instanceof Error ? e : undefined, - requestId - ) - } - if (isRequestAbortedError(e)) { - throw new AgenticChatError( - 'Request aborted', - 'RequestAborted', - e instanceof Error ? e : undefined, - requestId - ) - } - if (isInputTooLongError(e)) { - throw new AgenticChatError( - 'Too much context loaded. I have cleared the conversation history. Please retry your request with smaller input.', - 'InputTooLong', - e instanceof Error ? e : undefined, - requestId - ) - } - if (isThrottlingRelated(e)) { - throw new AgenticChatError( - 'Service is currently experiencing high traffic. Please try again later.', - 'RequestThrottled', - e instanceof Error ? e : undefined, - requestId - ) - } - let error = wrapErrorWithCode(e, 'QModelResponse') - if ( - (request.conversationState?.currentMessage?.userInputMessage?.modelId !== undefined && - (error.cause as any)?.$metadata?.httpStatusCode === 500 && - error.message === - 'Encountered unexpectedly high load when processing the request, please try again.') || - (error.cause && - typeof error.cause === 'object' && - '$metadata' in error.cause && - (error.cause as any).$metadata?.httpStatusCode === 429 && - 'reason' in error.cause && - error.cause.reason === 'INSUFFICIENT_MODEL_CAPACITY') - ) { - error.message = this.isModelSelectionEnabled() - ? `The model you selected is temporarily unavailable. Please switch to a different model and try again.` - : `I am experiencing high traffic, please try again shortly.` - } - - throw error - } + return await client.generateAssistantResponse(request, this.#abortController) } else if (client instanceof StreamingClientServiceIAM) { - try { - // @ts-ignore - // SendMessageStreaming checks for origin from request source - // https://code.amazon.com/packages/AWSVectorConsolasRuntimeService/blobs/ac917609a28dbcb6757a8427bcc585a42fd15bf2/--/src/com/amazon/aws/vector/consolas/runtimeservice/activity/SendMessageStreamingActivity.java#L246 - request.source = this.#origin ? this.#origin : 'IDE' - return await client.sendMessage(request, this.#abortController) - } catch (e) { - // Log the error using the logging property if available, otherwise fall back to console.error - if (this.#logging) { - this.#logging.error(`Error in Send Message response: ${loggingUtils.formatErr(e)}`) - } - - const requestId = getRequestID(e) - if (isUsageLimitError(e)) { - throw new AgenticChatError( - 'Request aborted', - 'AmazonQUsageLimitError', - e instanceof Error ? e : undefined, - requestId - ) - } - if (isRequestAbortedError(e)) { - throw new AgenticChatError( - 'Request aborted', - 'RequestAborted', - e instanceof Error ? e : undefined, - requestId - ) - } - if (isInputTooLongError(e)) { - throw new AgenticChatError( - 'Too much context loaded. I have cleared the conversation history. Please retry your request with smaller input.', - 'InputTooLong', - e instanceof Error ? e : undefined, - requestId - ) - } - let error = wrapErrorWithCode(e, 'QModelResponse') - if ( - (request.conversationState?.currentMessage?.userInputMessage?.modelId !== undefined && - (error.cause as any)?.$metadata?.httpStatusCode === 500 && - error.message === - 'Encountered unexpectedly high load when processing the request, please try again.') || - (error.cause && - typeof error.cause === 'object' && - '$metadata' in error.cause && - (error.cause as any).$metadata?.httpStatusCode === 429 && - 'reason' in error.cause && - error.cause.reason === 'INSUFFICIENT_MODEL_CAPACITY') - ) { - error.message = this.isModelSelectionEnabled() - ? `The model you selected is temporarily unavailable. Please switch to a different model and try again.` - : `I am experiencing high traffic, please try again shortly.` - } - throw error - } + // @ts-ignore + // SendMessageStreaming checks for origin from request source + // https://code.amazon.com/packages/AWSVectorConsolasRuntimeService/blobs/ac917609a28dbcb6757a8427bcc585a42fd15bf2/--/src/com/amazon/aws/vector/consolas/runtimeservice/activity/SendMessageStreamingActivity.java#L246 + request.source = this.#origin ? this.#origin : 'IDE' + return await client.sendMessage(request, this.#abortController) } else { // error return Promise.reject( @@ -349,4 +242,15 @@ export class ChatSessionService { public setLogging(logging: Logging): void { this.#logging = logging } + + /** + * Sets the delay notification callback for UI integration + * @param callback Function to call when delay notifications occur + */ + public setDelayNotificationCallback(callback: (notification: DelayNotification) => void): void { + if (this.#serviceManager) { + const client = this.#serviceManager.getStreamingClient() + client.setDelayNotificationCallback(callback) + } + } } diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/constants.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/constants.ts index 3263cb7b42..0b96c80cc9 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/constants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/constants.ts @@ -79,6 +79,8 @@ export const DEFAULT_EXCLUDE_FILES = [ '.DS_Store', ] +export const DEFAULT_RETRY_ATTEMPTS = 3 + export const loadingMessage: ChatMessage = { body: '', // @ts-ignore diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts index 18a68d1676..ade8e8ca7a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts @@ -1833,6 +1833,8 @@ describe('CodeWhisperer Server', () => { error.statusCode = 500 error.time = new Date() error.requestId = 'failed-request-id' + // Add $metadata to make isAwsError return true + ;(error as any).$metadata = {} service.generateSuggestions.callsFake(_request => { clock.tick(1000) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry/telemetry.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry/telemetry.ts index 5272983b61..e1a6ed5ffc 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry/telemetry.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry/telemetry.ts @@ -52,7 +52,7 @@ export const emitServiceInvocationFailure = ( error: Error | AWSError ) => { const duration = new Date().getTime() - session.startTime - const codewhispererRequestId = isAwsError(error) ? error.requestId : undefined + const codewhispererRequestId = isAwsError(error) ? (error as any).requestId : undefined const data: CodeWhispererServiceInvocationEvent = { codewhispererRequestId: codewhispererRequestId, @@ -82,8 +82,8 @@ export const emitServiceInvocationFailure = ( data, errorData: { reason: error.name || 'UnknownError', - errorCode: isAwsError(error) ? error.code : undefined, - httpStatusCode: isAwsError(error) ? error.statusCode : undefined, + errorCode: isAwsError(error) ? (error as any).code : undefined, + httpStatusCode: isAwsError(error) ? (error as any).statusCode : undefined, }, }) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts index 89511d34e4..2b59be910f 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts @@ -834,7 +834,11 @@ export class WorkspaceFolderManager { this.logging.log(`User's administrator opted out server-side workspace context`) optOut = true } - if (isAwsError(e) && e.code === 'AccessDeniedException' && e.message.includes('Feature is not supported')) { + if ( + isAwsError(e) && + (e as any).code === 'AccessDeniedException' && + e.message.includes('Feature is not supported') + ) { featureDisabled = true } } @@ -857,7 +861,7 @@ export class WorkspaceFolderManager { this.logging.warn( `Error while creating workspace (${workspaceRoot}): ${e.message}. Error is ${e.retryable ? '' : 'not'} retryable}` ) - if (isAwsError(e) && e.code === 'ServiceQuotaExceededException') { + if (isAwsError(e) && (e as any).code === 'ServiceQuotaExceededException') { isServiceQuotaExceeded = true } error = { diff --git a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts index 88071f357d..aa3c1e6c44 100644 --- a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts @@ -19,12 +19,14 @@ import { IamCredentials, } from '@aws/language-server-runtimes/server-interface' import { getBearerTokenFromProvider, isUsageLimitError } from './utils' -import { ConfiguredRetryStrategy } from '@aws-sdk/util-retry' -import { CredentialProviderChain, Credentials } from 'aws-sdk' -import { CLIENT_TIMEOUT_MS } from '../language-server/agenticChat/constants/constants' +import { Credentials } from 'aws-sdk' +import { CLIENT_TIMEOUT_MS, MAX_REQUEST_ATTEMPTS } from '../language-server/agenticChat/constants/constants' import { AmazonQUsageLimitError } from './amazonQServiceManager/errors' import { NodeHttpHandler } from '@smithy/node-http-handler' import { AwsCredentialIdentity, AwsCredentialIdentityProvider } from '@aws-sdk/types' +import { QRetryClassifier } from '../language-server/agenticChat/retry/retryClassifier' +import { QDelayTrackingInterceptor, DelayNotification } from '../language-server/agenticChat/retry/delayInterceptor' +import { QRetryStrategy } from '../language-server/agenticChat/retry/qRetryStrategy' export type SendMessageCommandInput = | SendMessageCommandInputCodeWhispererStreaming @@ -39,15 +41,17 @@ export type ChatCommandOutput = SendMessageCommandOutput | GenerateAssistantResp export abstract class StreamingClientServiceBase { protected readonly region protected readonly endpoint + protected delayInterceptor: QDelayTrackingInterceptor public shareCodeWhispererContentWithAWS?: boolean inflightRequests: Set = new Set() abstract client: CodeWhispererStreaming | QDeveloperStreaming - constructor(region: string, endpoint: string) { + constructor(region: string, endpoint: string, logging?: Logging) { this.region = region this.endpoint = endpoint + this.delayInterceptor = new QDelayTrackingInterceptor(logging) } abstract sendMessage( @@ -61,11 +65,16 @@ export abstract class StreamingClientServiceBase { }) this.inflightRequests.clear() } + + public setDelayNotificationCallback(callback: (notification: DelayNotification) => void): void { + this.delayInterceptor.setDelayNotificationCallback(callback) + } } export class StreamingClientServiceToken extends StreamingClientServiceBase { client: CodeWhispererStreaming public profileArn?: string + private retryClassifier: QRetryClassifier constructor( credentialsProvider: CredentialsProvider, @@ -75,7 +84,8 @@ export class StreamingClientServiceToken extends StreamingClientServiceBase { endpoint: string, customUserAgent: string ) { - super(region, endpoint) + super(region, endpoint, logging) + this.retryClassifier = new QRetryClassifier(logging) const tokenProvider = async () => { const token = getBearerTokenFromProvider(credentialsProvider) @@ -86,11 +96,20 @@ export class StreamingClientServiceToken extends StreamingClientServiceBase { logging.log( `Passing client for class CodeWhispererStreaming to sdkInitializator (v3) for additional setup (e.g. proxy)` ) + + // Create Q-specific retry strategy with classifier and delay tracking + const retryStrategy = new QRetryStrategy( + this.retryClassifier, + this.delayInterceptor, + MAX_REQUEST_ATTEMPTS, + logging + ) + this.client = sdkInitializator(CodeWhispererStreaming, { region, endpoint, token: tokenProvider, - retryStrategy: new ConfiguredRetryStrategy(0, (attempt: number) => 500 + attempt ** 10), + retryStrategy: retryStrategy, requestHandler: new NodeHttpHandler({ requestTimeout: CLIENT_TIMEOUT_MS, }), @@ -160,7 +179,6 @@ export class StreamingClientServiceToken extends StreamingClientServiceBase { return response } catch (e) { - // TODO add a test for this if (isUsageLimitError(e)) { throw new AmazonQUsageLimitError(e) } @@ -186,6 +204,8 @@ export class StreamingClientServiceToken extends StreamingClientServiceBase { export class StreamingClientServiceIAM extends StreamingClientServiceBase { client: QDeveloperStreaming + private retryClassifier: QRetryClassifier + constructor( credentialsProvider: CredentialsProvider, sdkInitializator: SDKInitializator, @@ -193,7 +213,9 @@ export class StreamingClientServiceIAM extends StreamingClientServiceBase { region: string, endpoint: string ) { - super(region, endpoint) + super(region, endpoint, logging) + this.retryClassifier = new QRetryClassifier(logging) + logging.log( `Passing client for class QDeveloperStreaming to sdkInitializator (v3) for additional setup (e.g. proxy)` ) @@ -214,11 +236,19 @@ export class StreamingClientServiceIAM extends StreamingClientServiceBase { } } + // Create Q-specific retry strategy with classifier and delay tracking + const retryStrategy = new QRetryStrategy( + this.retryClassifier, + this.delayInterceptor, + MAX_REQUEST_ATTEMPTS, + logging + ) + this.client = sdkInitializator(QDeveloperStreaming, { region: region, endpoint: endpoint, credentials: iamCredentialProvider, - retryStrategy: new ConfiguredRetryStrategy(0, (attempt: number) => 500 + attempt ** 10), + retryStrategy: retryStrategy, }) this.client.middlewareStack.add( @@ -242,12 +272,16 @@ export class StreamingClientServiceIAM extends StreamingClientServiceBase { this.inflightRequests.add(controller) - const response = await this.client.sendMessage(request, { - abortSignal: controller.signal, - }) - - this.inflightRequests.delete(controller) + try { + const response = await this.client.sendMessage(request, { + abortSignal: controller.signal, + }) - return response + return response + } catch (e) { + throw e + } finally { + this.inflightRequests.delete(controller) + } } } diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts index 3fef1bec68..2e8c2eb638 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts @@ -151,7 +151,7 @@ export class TelemetryService { private logSendTelemetryEventFailure(error: any) { let requestId: string | undefined if (isAwsError(error)) { - requestId = error.requestId + requestId = (error as any).requestId } this.logging.log( diff --git a/server/aws-lsp-codewhisperer/src/shared/utils.test.ts b/server/aws-lsp-codewhisperer/src/shared/utils.test.ts index 7ffe837938..19f226fc38 100644 --- a/server/aws-lsp-codewhisperer/src/shared/utils.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/utils.test.ts @@ -5,7 +5,6 @@ import { } from '@amzn/codewhisperer-streaming' import { CredentialsProvider, Position, InitializeParams } from '@aws/language-server-runtimes/server-interface' import * as assert from 'assert' -import { AWSError } from 'aws-sdk' import { expect } from 'chai' import * as sinon from 'sinon' import * as os from 'os' @@ -462,29 +461,25 @@ describe('isAwsThrottlingError', function () { }) it('false for non-throttling AWS errors', function () { - const nonThrottlingError = { - name: 'AWSError', - message: 'Not a throttling error', - code: 'SomeOtherError', - time: new Date(), - } as AWSError + const nonThrottlingError = new Error('Not a throttling error') + ;(nonThrottlingError as any).name = 'SomeOtherError' + ;(nonThrottlingError as any).$metadata = {} assert.strictEqual(isAwsThrottlingError(nonThrottlingError), false) }) it('true for AWS throttling errors', function () { - const sdkV2Error = new Error() - ;(sdkV2Error as any).name = 'ThrottlingException' - ;(sdkV2Error as any).message = 'Rate exceeded' - ;(sdkV2Error as any).code = 'ThrottlingException' - ;(sdkV2Error as any).time = new Date() - assert.strictEqual(isAwsThrottlingError(sdkV2Error), true) - const sdkV3Error = new ThrottlingException({ message: 'Too many requests', $metadata: {}, }) assert.strictEqual(isAwsThrottlingError(sdkV3Error), true) + + // Test error with $metadata property + const errorWithMetadata = new Error('Rate exceeded') + ;(errorWithMetadata as any).$metadata = {} + ;(errorWithMetadata as any).name = 'ThrottlingException' + assert.strictEqual(isAwsThrottlingError(errorWithMetadata), true) }) }) @@ -503,22 +498,20 @@ describe('isMonthlyLimitError', function () { }) it('false for throttling errors without MONTHLY_REQUEST_COUNT reason', function () { - const throttlingError = new Error() - ;(throttlingError as any).name = 'ThrottlingException' - ;(throttlingError as any).message = 'Rate exceeded' - ;(throttlingError as any).code = 'ThrottlingException' - ;(throttlingError as any).time = new Date() + const throttlingError = new ThrottlingException({ + message: 'Rate exceeded', + $metadata: {}, + }) ;(throttlingError as any).reason = 'SOME_OTHER_REASON' assert.strictEqual(isUsageLimitError(throttlingError), false) }) it('true for throttling errors with MONTHLY_REQUEST_COUNT reason', function () { - const usageLimitError = new Error() - ;(usageLimitError as any).name = 'ThrottlingException' - ;(usageLimitError as any).message = 'Free tier limit reached' - ;(usageLimitError as any).code = 'ThrottlingException' - ;(usageLimitError as any).time = new Date() + const usageLimitError = new ThrottlingException({ + message: 'Free tier limit reached', + $metadata: {}, + }) ;(usageLimitError as any).reason = ThrottlingExceptionReason.MONTHLY_REQUEST_COUNT assert.strictEqual(isUsageLimitError(usageLimitError), true) @@ -554,11 +547,10 @@ describe('isQuotaExceededError', function () { }) it('true for specific messages', function () { - const reachedForThisMonth = new Error() - ;(reachedForThisMonth as any).name = 'ThrottlingException' - ;(reachedForThisMonth as any).message = 'You have reached the limit for this month' - ;(reachedForThisMonth as any).code = 'ThrottlingException' - ;(reachedForThisMonth as any).time = new Date() + const reachedForThisMonth = new ThrottlingException({ + message: 'You have reached the limit for this month', + $metadata: {}, + }) const limitForIterationsError = new ThrottlingException({ message: 'You have reached the limit for number of iterations', @@ -569,10 +561,16 @@ describe('isQuotaExceededError', function () { assert.strictEqual(isQuotaExceededError(limitForIterationsError), true) // Invalid cases - reachedForThisMonth.message = 'some other messsage' - assert.strictEqual(isQuotaExceededError(reachedForThisMonth), false) - limitForIterationsError.message = 'foo bar' - assert.strictEqual(isQuotaExceededError(limitForIterationsError), false) + const invalidError1 = new ThrottlingException({ + message: 'some other messsage', + $metadata: {}, + }) + const invalidError2 = new ThrottlingException({ + message: 'foo bar', + $metadata: {}, + }) + assert.strictEqual(isQuotaExceededError(invalidError1), false) + assert.strictEqual(isQuotaExceededError(invalidError2), false) }) }) diff --git a/server/aws-lsp-codewhisperer/src/shared/utils.ts b/server/aws-lsp-codewhisperer/src/shared/utils.ts index 3602153ad6..8968176b54 100644 --- a/server/aws-lsp-codewhisperer/src/shared/utils.ts +++ b/server/aws-lsp-codewhisperer/src/shared/utils.ts @@ -5,7 +5,8 @@ import { Position, SsoConnectionType, } from '@aws/language-server-runtimes/server-interface' -import { AWSError, Credentials } from 'aws-sdk' +import { AwsCredentialIdentity } from '@aws-sdk/types' + import { distance } from 'fastest-levenshtein' import { Suggestion } from './codeWhispererService' import { CodewhispererCompletionType } from './telemetry/types' @@ -33,13 +34,13 @@ import { InitializeParams } from '@aws/language-server-runtimes/server-interface import { QClientCapabilities } from '../language-server/configuration/qConfigurationServer' import escapeHTML = require('escape-html') -export function isAwsError(error: unknown): error is AWSError { +export function isAwsError(error: unknown): error is ServiceException { if (error === undefined) { return false } - // TODO: do SDK v3 errors have `.code` ? - return error instanceof Error && hasCode(error) && hasTime(error) + // AWS SDK v3 errors extend ServiceException + return error instanceof ServiceException || (error instanceof Error && '$metadata' in error) } export function isAwsThrottlingError(e: unknown): e is ThrottlingException { @@ -53,7 +54,7 @@ export function isAwsThrottlingError(e: unknown): e is ThrottlingException { // return true // } - if (e instanceof ThrottlingException || (isAwsError(e) && e.code === 'ThrottlingException')) { + if (e instanceof ThrottlingException || (isAwsError(e) && e.name === 'ThrottlingException')) { return true } @@ -90,7 +91,7 @@ export function isUsageLimitError(e: unknown): e is ThrottlingException { return false } -export function isQuotaExceededError(e: unknown): e is AWSError { +export function isQuotaExceededError(e: unknown): e is ServiceException { if (!e) { return false } @@ -102,7 +103,7 @@ export function isQuotaExceededError(e: unknown): e is AWSError { // https://github.com/aws/aws-toolkit-vscode/blob/db673c9b74b36591bb5642b3da7d4bc7ae2afaf4/packages/core/src/amazonqFeatureDev/client/featureDev.ts#L199 // "Backend service will throw ServiceQuota if code generation iteration limit is reached". - if (e instanceof ServiceQuotaExceededException || (isAwsError(e) && e.code == 'ServiceQuotaExceededException')) { + if (e instanceof ServiceQuotaExceededException || (isAwsError(e) && e.name == 'ServiceQuotaExceededException')) { return true } @@ -489,9 +490,6 @@ export function isStringOrNull(object: any): object is string | null { export function getHttpStatusCode(err: unknown): number | undefined { // RTS throws validation errors with a 400 status code to LSP, we convert them to 500 from the perspective of the user - if (hasResponse(err) && err?.$response?.statusCode !== undefined) { - return err?.$response?.statusCode - } if (hasMetadata(err) && err.$metadata?.httpStatusCode !== undefined) { return err.$metadata?.httpStatusCode } @@ -502,10 +500,6 @@ export function getHttpStatusCode(err: unknown): number | undefined { return undefined } -function hasResponse(error: T): error is T & Pick { - return typeof (error as { $response?: unknown })?.$response === 'object' -} - function hasMetadata(error: T): error is T & Pick { return typeof (error as { $metadata?: unknown })?.$metadata === 'object' } @@ -626,6 +620,16 @@ export function sanitizeInput(input: string, enableEscapingHTML: boolean = false ) } +/** + * Sanitizes input for logging to prevent log injection attacks + * @param input The input string to sanitize + * @returns The sanitized string with control characters replaced + */ +export function sanitizeLogInput(input: string): string { + // Remove newlines, carriage returns, and other control characters + return input.replace(/[\r\n\t\x00-\x1f\x7f-\x9f]/g, '_') +} + /** * Recursively sanitizes the entire request input to prevent Unicode ASCII smuggling * @param input The request input to sanitize From f3086d71808bd49336e0df9ba30f5be5fda837c3 Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Wed, 8 Oct 2025 20:23:10 -0700 Subject: [PATCH 134/158] fix: patch #2133 and handle more variants of FIM suggestions (#2407) * fix: patch #2133 and handle more variants of FIM suggestions * fix: only consider FIM if the first edit line matches trigger position * fix: test --------- Co-authored-by: atontb <104926752+atonaamz@users.noreply.github.com> --- .../handler/editCompletionHandler.ts | 3 +- .../inline-completion/utils/diffUtils.test.ts | 52 ++++++-- .../inline-completion/utils/diffUtils.ts | 123 ++++++++++++++++-- 3 files changed, 155 insertions(+), 23 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts index 42a45f1f8c..c9e1d25d66 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts @@ -400,7 +400,8 @@ export class EditCompletionHandler { const processedSuggestion = processEditSuggestion( suggestion.content, session.startPosition, - session.document + session.document, + session.requestContext.fileContext.rightFileContent ) const isInlineEdit = processedSuggestion.type === SuggestionType.EDIT diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.test.ts index 20d5890d77..0dbf3318a7 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.test.ts @@ -123,6 +123,27 @@ describe('categorizeUnifieddiffV2v2 should return correct type (addOnly, edit, d describe('addOnly', function () { const addOnlyCases: Case[] = [ + { + udiff: `--- a/src/main/hello/MathUtil.java ++++ b/src/main/hello/MathUtil.java +@@ -10,6 +10,6 @@ public class MathUtil { + } + + public static int multiply(int a, int b) { +- return a * b; ++ return a * b * c; + } + }`, + }, + { + udiff: `--- file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java ++++ file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java +@@ -6,2 +6,3 @@ +- return a * b; ++ return a * b * ++ c * d; + }`, + }, { udiff: `--- file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java +++ file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java @@ -141,12 +162,10 @@ describe('categorizeUnifieddiffV2v2 should return correct type (addOnly, edit, d }`, }, { - udiff: `--- file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java -+++ file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java -@@ -6,7 +6,11 @@ - - // write a function to subtract 2 numbers - public static int subtract(int a, int b) { + udiff: `--- a/src/main/hello/MathUtil.java ++++ b/src/main/hello/MathUtil.java +@@ -8,5 +8,10 @@ public class MathUtil { + public static int subtract(int a, int b) { return a - b; } - @@ -251,20 +270,14 @@ describe('categorizeUnifieddiffV2v2 should return correct type (addOnly, edit, d { udiff: `--- a/src/main/hello/MathUtil.java +++ b/src/main/hello/MathUtil.java -@@ -1,11 +1,11 @@ +@@ -1,6 +1,6 @@ public class MathUtil { // write a function to add 2 numbers - public static int add(int a, int b) { + public static double add(double a, double b) { return a + b; } - - // write a function to subtract 2 numbers - public static int subtract(int a, int b) { - public static double subtract(double a, double b) { - return a - b; - } - }`, + `, }, { udiff: `--- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -300,6 +313,17 @@ describe('categorizeUnifieddiffV2v2 should return correct type (addOnly, edit, d const languageId = getLanguageIdFromUri(uri) textDocument = TextDocument.create(uri, languageId, 0, content)`, }, + { + udiff: `--- a/src/main/hello/MathUtil.java ++++ b/src/main/hello/MathUtil.java +@@ -12,4 +12,5 @@ public class MathUtil { + + // write a function to multiply 2 numbers + public static int multiply(int a, int b) { +- return a * b; ++ return a * b * c; ++ }`, + }, ] for (let i = 0; i < cases.length; i++) { diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.ts index 8c67a92746..5d32f03589 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/diffUtils.ts @@ -3,12 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as diff from 'diff' +import { parsePatch, Hunk, createTwoFilesPatch } from 'diff' import { CodeWhispererSupplementalContext, CodeWhispererSupplementalContextItem } from '../../../shared/models/model' import { trimSupplementalContexts } from '../../../shared/supplementalContextUtil/supplementalContextUtil' import { Position, TextDocument, Range } from '@aws/language-server-runtimes/protocol' import { SuggestionType } from '../../../shared/codeWhispererService' -import { getPrefixSuffixOverlap } from './mergeRightUtils' +import { getPrefixSuffixOverlap, truncateOverlapWithRightContext } from './mergeRightUtils' /** * Generates a unified diff format between old and new file contents @@ -31,7 +31,7 @@ export function generateUnifiedDiffWithTimestamps( newTimestamp: number, contextSize: number = 3 ): string { - const patchResult = diff.createTwoFilesPatch( + const patchResult = createTwoFilesPatch( oldFilePath, newFilePath, oldContent, @@ -204,12 +204,13 @@ export function getCharacterDifferences(addedLines: string[], deletedLines: stri export function processEditSuggestion( unifiedDiff: string, triggerPosition: Position, - document: TextDocument + document: TextDocument, + rightContext: string ): { suggestionContent: string; type: SuggestionType } { // Assume it's an edit if anything goes wrong, at the very least it will not be rendered incorrectly let diffCategory: ReturnType = 'edit' try { - diffCategory = categorizeUnifieddiff(unifiedDiff) + diffCategory = categorizeUnifieddiff(unifiedDiff, triggerPosition.line) } catch (e) { // We dont have logger here.... diffCategory = 'edit' @@ -228,8 +229,9 @@ export function processEditSuggestion( * if LSP returns `g('foo')` instead of `.log()` the suggestion will be discarded because prefix doesnt match */ const processedAdd = removeOverlapCodeFromSuggestion(leftContextAtTriggerLine, preprocessAdd) + const mergedWithRightContext = truncateOverlapWithRightContext(rightContext, processedAdd) return { - suggestionContent: processedAdd, + suggestionContent: mergedWithRightContext, type: SuggestionType.COMPLETION, } } else { @@ -247,10 +249,26 @@ interface UnifiedDiff { firstPlusIndex: number minusIndexes: number[] plusIndexes: number[] + hunk: Hunk } // TODO: refine export function readUdiff(unifiedDiff: string): UnifiedDiff { + let hunk: Hunk | undefined + try { + const patches = parsePatch(unifiedDiff) + if (patches.length !== 1) { + throw new Error(`Provided unified diff from has 0 or more than 1 patches`) + } + hunk = patches[0].hunks[0] + if (!hunk) { + throw new Error(`Null hunk`) + } + } catch (e) { + throw e + } + + // TODO: Should use hunk instead of parsing manually const lines = unifiedDiff.split('\n') const headerEndIndex = lines.findIndex(l => l.startsWith('@@')) if (headerEndIndex === -1) { @@ -275,30 +293,64 @@ export function readUdiff(unifiedDiff: string): UnifiedDiff { const firstMinusIndex = relevantLines.findIndex(s => s.startsWith('-')) const firstPlusIndex = relevantLines.findIndex(s => s.startsWith('+')) + // TODO: Comment these out as they are used for a different version of addonly type determination logic in case the current implementation doesn't work. + // Could remove later if we are sure current imple works. + /** + * Concatenate all contiguous added lines (i.e., unbroken sequence of "+"s). + * Exclude all newlines when concatenating, so we get a single line representing the new text + */ + // let singleLine = '' + // let prev: number | undefined + // for (const idx of plusIndexes) { + // if (!prev || idx === prev + 1) { + // const removedPlus = relevantLines[idx].substring(1) + // const removedStartNewline = trimStartNewline(removedPlus) + // singleLine += removedStartNewline + // } else { + // break + // } + // } + return { linesWithoutHeaders: relevantLines, firstMinusIndex: firstMinusIndex, firstPlusIndex: firstPlusIndex, minusIndexes: minusIndexes, plusIndexes: plusIndexes, + hunk: hunk, } } -export function categorizeUnifieddiff(unifiedDiff: string): 'addOnly' | 'deleteOnly' | 'edit' { +// Theoretically, we should always pass userTriggerAtLine, keeping it nullable for easier testing for now +export function categorizeUnifieddiff( + unifiedDiff: string, + userTriggerAtLine?: number +): 'addOnly' | 'deleteOnly' | 'edit' { try { const d = readUdiff(unifiedDiff) + const hunk = d.hunk const firstMinusIndex = d.firstMinusIndex const firstPlusIndex = d.firstPlusIndex const diffWithoutHeaders = d.linesWithoutHeaders + // Shouldn't be the case but if there is no - nor +, assume it's an edit if (firstMinusIndex === -1 && firstPlusIndex === -1) { return 'edit' } + // If first "EDIT" line is not where users trigger, it must be EDIT + // Note hunk.start is 1 based index + const firstLineEdited = hunk.oldStart - 1 + Math.min(...d.minusIndexes, ...d.plusIndexes) + if (userTriggerAtLine !== undefined && userTriggerAtLine !== firstLineEdited) { + return 'edit' + } + + // Naive case, only + if (firstMinusIndex === -1 && firstPlusIndex !== -1) { return 'addOnly' } + // Naive case, only - if (firstMinusIndex !== -1 && firstPlusIndex === -1) { return 'deleteOnly' } @@ -321,12 +373,47 @@ export function categorizeUnifieddiff(unifiedDiff: string): 'addOnly' | 'deleteO // If last '-' line is followed by '+' block, it could be addonly if (plusIndexes[0] === minusIndexes[minusIndexes.length - 1] + 1) { + /** + ------------------------------- + - return + + return a - b; + ------------------------------- + commonPrefix = "return " + minusLinesDelta = "" + + -------------------------------- + -\t\t\t + +\treturn a - b; + -------------------------------- + commonPrefix = "\t" + minusLinesDelta = "\t\t" + + * + * + * + */ const minusLine = diffWithoutHeaders[minusIndexes[minusIndexes.length - 1]].substring(1) const pluscode = extractAdditions(unifiedDiff) // If minusLine subtract the longest common substring of minusLine and plugcode and it's empty string, it's addonly const commonPrefix = longestCommonPrefix(minusLine, pluscode) - if (minusLine.substring(commonPrefix.length).trim().length === 0) { + const minusLinesDelta = minusLine.substring(commonPrefix.length) + if (minusLinesDelta.trim().length === 0) { + return 'addOnly' + } + + /** + ------------------------------- + - return a * b; + + return a * b * c; + ------------------------------- + commonPrefix = "return a * b" + minusLinesDelta = ";" + pluscodeDelta = " * c;" + * + */ + const pluscodeDelta = pluscode.substring(commonPrefix.length) + if (pluscodeDelta.endsWith(minusLinesDelta)) { return 'addOnly' } } @@ -400,3 +487,23 @@ export function longestCommonPrefix(str1: string, str2: string): string { return prefix } + +// TODO: They are used for a different version of addonly type determination logic in case the current implementation doesn't work. +// Could remove later if we are sure current impl works. +// function trimStartNewline(str: string): string { +// return str.replace(/^[\n\r]+/, '') +// } + +// function hasOneContiguousInsert(original: string, changed: string) { +// const delta = changed.length - original.length +// if (delta <= 0) { +// // Changed string must be longer +// return false +// } + +// let p, s +// for (p = 0; original[p] === changed[p] && p < original.length; ++p); +// for (s = original.length - 1; original[s] === changed[s + delta] && s >= 0; --s); + +// return p === s + 1 +// } From 06fbeb27b824e0184385ec18318ba38caa99307a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 9 Oct 2025 09:46:02 -0700 Subject: [PATCH 135/158] chore(release): release packages from branch main (#2384) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .release-please-manifest.json | 4 ++-- chat-client/CHANGELOG.md | 7 +++++++ chat-client/package.json | 2 +- package-lock.json | 4 ++-- server/aws-lsp-codewhisperer/CHANGELOG.md | 17 +++++++++++++++++ server/aws-lsp-codewhisperer/package.json | 2 +- 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3b135d3905..62a41204e9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,8 +1,8 @@ { - "chat-client": "0.1.38", + "chat-client": "0.1.39", "core/aws-lsp-core": "0.0.16", "server/aws-lsp-antlr4": "0.1.20", - "server/aws-lsp-codewhisperer": "0.0.83", + "server/aws-lsp-codewhisperer": "0.0.84", "server/aws-lsp-json": "0.1.20", "server/aws-lsp-partiql": "0.0.18", "server/aws-lsp-yaml": "0.1.20" diff --git a/chat-client/CHANGELOG.md b/chat-client/CHANGELOG.md index 06a614f1bd..79a0f67ac4 100644 --- a/chat-client/CHANGELOG.md +++ b/chat-client/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.1.39](https://github.com/aws/language-servers/compare/chat-client/v0.1.38...chat-client/v0.1.39) (2025-10-09) + + +### Features + +* add model description to dropdown ([#2374](https://github.com/aws/language-servers/issues/2374)) ([ed8c6dd](https://github.com/aws/language-servers/commit/ed8c6dda1312f728e9ee7472f7ca447196ad9d84)) + ## [0.1.38](https://github.com/aws/language-servers/compare/chat-client/v0.1.37...chat-client/v0.1.38) (2025-10-01) diff --git a/chat-client/package.json b/chat-client/package.json index aff0948d16..7c83bc4ff4 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -1,6 +1,6 @@ { "name": "@aws/chat-client", - "version": "0.1.38", + "version": "0.1.39", "description": "AWS Chat Client", "main": "out/index.js", "repository": { diff --git a/package-lock.json b/package-lock.json index 638493ff16..6f80254f7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -251,7 +251,7 @@ }, "chat-client": { "name": "@aws/chat-client", - "version": "0.1.38", + "version": "0.1.39", "license": "Apache-2.0", "dependencies": { "@aws/chat-client-ui-types": "^0.1.57", @@ -28674,7 +28674,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.83", + "version": "0.0.84", "bundleDependencies": [ "@amzn/codewhisperer-streaming", "@amzn/amazon-q-developer-streaming-client" diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index 3f2fd79c58..e3a342833c 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## [0.0.84](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.83...lsp-codewhisperer/v0.0.84) (2025-10-09) + + +### Features + +* add model description to dropdown ([#2374](https://github.com/aws/language-servers/issues/2374)) ([ed8c6dd](https://github.com/aws/language-servers/commit/ed8c6dda1312f728e9ee7472f7ca447196ad9d84)) +* **amazonq:** adding classification based retry strategy for chat ([#2234](https://github.com/aws/language-servers/issues/2234)) ([#2409](https://github.com/aws/language-servers/issues/2409)) ([15d1b1f](https://github.com/aws/language-servers/commit/15d1b1f5947a1b83dab65c9d3fef901ab8a033c9)) +* **amazonq:** env var change for JupyterLab conversation history on refresh support ([#2395](https://github.com/aws/language-servers/issues/2395)) ([a908195](https://github.com/aws/language-servers/commit/a9081954bcaf20b7d0fbe0af11e61b8f82c7e82f)) +* **amazonq:** support JupyterLab conversation history on refresh ([#2325](https://github.com/aws/language-servers/issues/2325)) ([0980351](https://github.com/aws/language-servers/commit/09803514d1ce31ca77a532161e071e1d037e3fb1)) + + +### Bug Fixes + +* add in-loop compaction ([#2387](https://github.com/aws/language-servers/issues/2387)) ([35f0795](https://github.com/aws/language-servers/commit/35f0795fa5d09f3610e6a29cb72d49f32cc5534e)) +* addonly EDITS should be handled as COMPLETIONS ([#2133](https://github.com/aws/language-servers/issues/2133)) ([4f5a9da](https://github.com/aws/language-servers/commit/4f5a9dacf3bfd68aeb40920fb800adf001ed43d5)) +* patch [#2133](https://github.com/aws/language-servers/issues/2133) and handle more variants of FIM suggestions ([#2407](https://github.com/aws/language-servers/issues/2407)) ([f3086d7](https://github.com/aws/language-servers/commit/f3086d71808bd49336e0df9ba30f5be5fda837c3)) + ## [0.0.83](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.82...lsp-codewhisperer/v0.0.83) (2025-10-01) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index bd6432040d..baa5f2e253 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.83", + "version": "0.0.84", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { From 12e089bf37c9a5f08fcebcbc5e9205096f2b3adf Mon Sep 17 00:00:00 2001 From: chungjac Date: Thu, 9 Oct 2025 11:10:13 -0700 Subject: [PATCH 136/158] build: temporarily lock node.js version to 24.9.0 (#2413) --- .../scripts/download-node.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/scripts/download-node.sh b/app/aws-lsp-codewhisperer-runtimes/scripts/download-node.sh index db99f68d06..35322d871b 100755 --- a/app/aws-lsp-codewhisperer-runtimes/scripts/download-node.sh +++ b/app/aws-lsp-codewhisperer-runtimes/scripts/download-node.sh @@ -6,7 +6,7 @@ set -eo pipefail NODE_VERSION="24" -BASE_URL="https://nodejs.org/download/release/latest-v${NODE_VERSION}.x" +BASE_URL="https://nodejs.org/download/release/v24.9.0" SHASUMS_FILE="SHASUMS256.txt" ASSETS_DIR="build/node-assets" @@ -14,7 +14,10 @@ ASSETS_DIR="build/node-assets" curl -s "$BASE_URL/$SHASUMS_FILE" -o "$SHASUMS_FILE" # Extract exact Node.js version from any entry in SHASUMS256.txt -NODE_SEMVER=$(grep -o 'node-v[0-9]*\.[0-9]*\.[0-9]*' SHASUMS256.txt | head -1 | cut -d'v' -f2) +# NODE_SEMVER=$(grep -o 'node-v[0-9]*\.[0-9]*\.[0-9]*' SHASUMS256.txt | head -1 | cut -d'v' -f2) + +# temporarily lock node.js version to 24.9.0 due to https://github.com/nodejs/node/issues/60176 +NODE_SEMVER="24.9.0" if [ -z "$NODE_SEMVER" ]; then echo "Failed to extract Node.js version from SHASUMS256.txt" From 0e8e36d1767f6224ebd67625b8c66572843d9742 Mon Sep 17 00:00:00 2001 From: chungjac Date: Thu, 9 Oct 2025 18:24:55 -0700 Subject: [PATCH 137/158] chore: bump agentic version: 1.38.0 (#2416) Co-authored-by: aws-toolkit-automation <> --- app/aws-lsp-codewhisperer-runtimes/src/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/src/version.json b/app/aws-lsp-codewhisperer-runtimes/src/version.json index 2be2534d8f..f8ad8ef349 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/version.json +++ b/app/aws-lsp-codewhisperer-runtimes/src/version.json @@ -1,3 +1,3 @@ { - "agenticChat": "1.37.0" + "agenticChat": "1.38.0" } From 178deecdc424df7cb826fe87c59cec02c34cced3 Mon Sep 17 00:00:00 2001 From: chungjac Date: Fri, 10 Oct 2025 15:07:40 -0700 Subject: [PATCH 138/158] refactor: migrate aws-sdk v2 to v3 (#2418) * feat: migrate codewhisperer token service to aws-sdk-v3 (#2235) * feat: migrate codewhisperer token service to aws-sdk-v3 * fix captureHeaders middleware * feat: migrate codewhisperer iam service to aws-sdk-v3 (#2284) * refactor: remove aws-sdk v2 imports (#2290) * fix: compile errors from merge conflicts (#2331) * chore: bump runtimes to 0.3.0 (#2340) * chore: bump runtimes to 0.3.0 * fix antlr4ng version conflict * fix missing url polyfill * chore: remove old ignore entries (#2350) * chore: update versions * chore: fix more dependencies * fix: fallback to empty string in aws sdk v3 (#2414) * chore: update indexing bundle(#2417) This reverts commit baf20b7c4050dd4360ecb97c06d21f6b504836b0. --------- Co-authored-by: aws-toolkit-automation <43144436+aws-toolkit-automation@users.noreply.github.com> Co-authored-by: Tai Lai Co-authored-by: Tai Lai --- .eslintignore | 4 +- .gitignore | 2 + .prettierignore | 2 - app/aws-lsp-antlr4-runtimes/package.json | 8 +- app/aws-lsp-buildspec-runtimes/package.json | 2 +- .../package.json | 2 +- .../_bundle-assets/qserver-darwin-arm64.zip | 4 +- .../_bundle-assets/qserver-darwin-x64.zip | 4 +- .../_bundle-assets/qserver-linux-arm64.zip | 4 +- .../_bundle-assets/qserver-linux-x64.zip | 4 +- .../_bundle-assets/qserver-win32-x64.zip | 4 +- .../package.json | 3 +- .../webpack.config.js | 1 + app/aws-lsp-identity-runtimes/package.json | 2 +- app/aws-lsp-json-runtimes/package.json | 4 +- .../package.json | 2 +- app/aws-lsp-partiql-runtimes/package.json | 6 +- app/aws-lsp-s3-runtimes/package.json | 2 +- app/aws-lsp-yaml-json-webworker/package.json | 2 +- app/aws-lsp-yaml-runtimes/package.json | 4 +- app/hello-world-lsp-runtimes/package.json | 4 +- chat-client/package.json | 4 +- client/vscode/package.json | 2 +- core/aws-lsp-core/package.json | 2 +- .../amzn-codewhisperer-runtime-1.0.0.tgz | Bin 0 -> 110661 bytes .../amzn-codewhisperer-1.0.0.tgz | Bin 0 -> 47406 bytes .../q-agentic-chat-server/package.json | 2 +- package-lock.json | 12875 ++++++++-------- package.json | 2 +- server/aws-lsp-antlr4/package.json | 6 +- server/aws-lsp-buildspec/package.json | 2 +- server/aws-lsp-cloudformation/package.json | 2 +- server/aws-lsp-codewhisperer/.prettierignore | 1 - server/aws-lsp-codewhisperer/package.json | 10 +- .../src/client/sigv4/codewhisperer.ts | 75 +- .../sigv4/codewhisperersigv4client.d.ts | 605 - .../src/client/sigv4/service.json | 2145 --- .../client/token/bearer-token-service.json | 6690 -------- .../src/client/token/codewhisperer.ts | 95 +- .../token/codewhispererbearertokenclient.d.ts | 2191 --- .../agenticChat/agenticChatController.ts | 22 +- .../tools/qCodeAnalysis/codeReview.ts | 11 +- .../tools/qCodeAnalysis/codeReviewTypes.ts | 2 +- .../language-server/chat/chatController.ts | 19 +- .../chat/telemetry/chatTelemetryController.ts | 2 +- .../qConfigurationServer.test.ts | 18 +- .../configuration/qConfigurationServer.ts | 19 +- .../codeWhispererServer.test.ts | 37 +- .../handler/editCompletionHandler.ts | 8 +- .../handler/inlineCompletionHandler.ts | 15 +- .../handler/sessionResultsHandler.ts | 7 +- .../inline-completion/telemetry/telemetry.ts | 17 +- .../utils/mergeRightUtils.ts | 2 +- .../language-server/netTransform/converter.ts | 36 +- .../language-server/netTransform/metrics.ts | 4 +- .../language-server/netTransform/models.ts | 6 +- .../netTransform/tests/converter.test.ts | 112 +- .../tests/transformHandler.test.ts | 56 +- ...idation.getTransformationErrorCode.test.ts | 2 +- .../netTransform/transformHandler.ts | 19 +- .../netTransform/validation.ts | 2 +- .../codeWhispererSecurityScanServer.ts | 5 +- .../securityScan/securityScanHandler.test.ts | 24 +- .../securityScan/securityScanHandler.ts | 26 +- .../src/language-server/securityScan/types.ts | 4 + .../language-server/workspaceContext/util.ts | 4 +- .../workspaceFolderManager.test.ts | 32 +- .../workspaceFolderManager.ts | 38 +- .../AmazonQTokenServiceManager.test.ts | 5 - .../AmazonQTokenServiceManager.ts | 8 +- .../BaseAmazonQServiceManager.ts | 1 - .../qDeveloperProfiles.test.ts | 5 +- .../qDeveloperProfiles.ts | 19 +- .../src/shared/codeWhispererService.test.ts | 101 +- .../src/shared/codeWhispererService.ts | 373 +- .../src/shared/streamingClientService.ts | 2 +- .../src/shared/telemetry/telemetry.test.ts | 6 +- .../shared/telemetry/telemetryService.test.ts | 16 +- .../src/shared/telemetry/telemetryService.ts | 27 +- .../src/shared/telemetry/types.ts | 8 +- .../src/shared/telemetryUtils.ts | 26 +- .../src/shared/utils.test.ts | 67 +- .../aws-lsp-codewhisperer/src/shared/utils.ts | 55 +- server/aws-lsp-identity/package.json | 4 +- server/aws-lsp-json/package.json | 5 +- server/aws-lsp-notification/package.json | 4 +- server/aws-lsp-partiql/package.json | 6 +- server/aws-lsp-s3/package.json | 4 +- server/aws-lsp-yaml/package.json | 2 +- server/device-sso-auth-lsp/package.json | 2 +- server/hello-world-lsp/package.json | 3 +- 91 files changed, 7205 insertions(+), 18872 deletions(-) create mode 100644 core/codewhisperer-runtime/amzn-codewhisperer-runtime-1.0.0.tgz create mode 100644 core/codewhisperer/amzn-codewhisperer-1.0.0.tgz delete mode 100644 server/aws-lsp-codewhisperer/src/client/sigv4/codewhisperersigv4client.d.ts delete mode 100644 server/aws-lsp-codewhisperer/src/client/sigv4/service.json delete mode 100644 server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json delete mode 100644 server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts diff --git a/.eslintignore b/.eslintignore index ea62efdf1f..ff10944af7 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,2 @@ **/node_modules/** -**/out/** -server/aws-lsp-codewhisperer/src/client/sigv4/codewhisperersigv4client.d.ts -server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts \ No newline at end of file +**/out/** \ No newline at end of file diff --git a/.gitignore b/.gitignore index fbdc246265..8f3af70b45 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ build **/*.tgz !core/codewhisperer-streaming/amzn-codewhisperer-streaming-*.tgz !core/q-developer-streaming-client/amzn-amazon-q-developer-streaming-client-*.tgz +!core/codewhisperer-runtime/amzn-codewhisperer-runtime-*.tgz +!core/codewhisperer/amzn-codewhisperer-*.tgz !server/aws-lsp-codewhisperer/types/types-local-indexing-*.tgz .testresults/** diff --git a/.prettierignore b/.prettierignore index d115549b16..89ecd86fb3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,7 +4,5 @@ node_modules/ out/ **/bin/ **/obj/ -server/aws-lsp-codewhisperer/src/client/sigv4/codewhisperersigv4client.d.ts -server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts **/*.md **/antlr-generated/ \ No newline at end of file diff --git a/app/aws-lsp-antlr4-runtimes/package.json b/app/aws-lsp-antlr4-runtimes/package.json index ae9fdd3531..a82c01197b 100644 --- a/app/aws-lsp-antlr4-runtimes/package.json +++ b/app/aws-lsp-antlr4-runtimes/package.json @@ -12,10 +12,10 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-antlr4": "*", - "antlr4-c3": "^3.4.1", - "antlr4ng": "^3.0.4" + "antlr4-c3": "^3.4.2", + "antlr4ng": "^3.0.14" }, "devDependencies": { "@types/chai": "^4.3.5", @@ -26,7 +26,7 @@ "chai-as-promised": "^7.1.1", "mocha": "^11.0.1", "ts-loader": "^9.4.4", - "ts-lsp-client": "^1.0.3", + "ts-lsp-client": "1.0.3", "webpack": "^5.94.0", "webpack-cli": "^6.0.1" } diff --git a/app/aws-lsp-buildspec-runtimes/package.json b/app/aws-lsp-buildspec-runtimes/package.json index 16920a2b0a..141d9e6d6b 100644 --- a/app/aws-lsp-buildspec-runtimes/package.json +++ b/app/aws-lsp-buildspec-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-buildspec": "^0.0.1" } } diff --git a/app/aws-lsp-cloudformation-runtimes/package.json b/app/aws-lsp-cloudformation-runtimes/package.json index 48aa6e04f4..9dfcc2bf33 100644 --- a/app/aws-lsp-cloudformation-runtimes/package.json +++ b/app/aws-lsp-cloudformation-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-cloudformation": "^0.0.1" } } diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-arm64.zip b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-arm64.zip index 24fbdb712c..fdd736d602 100644 --- a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-arm64.zip +++ b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-arm64.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f651f5364b2417df24d40cbd2d34d69f8b338f3f00aca9c5afd5b4f9ea3d22d -size 96647490 +oid sha256:f4fbd67484ea48363077bbfaa576154196558a4048a862abac84d496fec6b636 +size 96644452 diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-x64.zip b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-x64.zip index 14d5e51377..4ef652e06a 100644 --- a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-x64.zip +++ b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-darwin-x64.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:03ef43ac80e2a16e8c842e92a3f3285d5424f2ea99bba167b9cbb9dabb751262 -size 98328127 +oid sha256:2bcfa7697a0ecdc4ff43f84d1a8c8b7840c144080e51b921dd7c5d3478613a82 +size 98325089 diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-arm64.zip b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-arm64.zip index af6aae68c3..dacf7cc25a 100644 --- a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-arm64.zip +++ b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-arm64.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:33bf50f87b67a330b3dc28f9a2fb1678f5c9cd6eb33beb964b6b068790b05b6c -size 102589811 +oid sha256:1f644daa198d026a091ac87a33fa54b7c1faf1e929ce8ef3ab7e25b7510335e7 +size 102586773 diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-x64.zip b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-x64.zip index 4923a60a7f..882e8901d3 100644 --- a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-x64.zip +++ b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-linux-x64.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ec71aea47b7cb08c13e94fe4ca284b3656d23266bcdd728a3525abd7939730f0 -size 114552140 +oid sha256:1f6add24d8ae6d1248e3ff8281a8c9e8b402370fd00fcc8bf65c553457715f27 +size 114549102 diff --git a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-win32-x64.zip b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-win32-x64.zip index fe962b88c0..da87d337a6 100644 --- a/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-win32-x64.zip +++ b/app/aws-lsp-codewhisperer-runtimes/_bundle-assets/qserver-win32-x64.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cd8190acad1f1c2b37a818fcf606cc3d2fa4e1929c82ef967ac360b7345864b4 -size 113890248 +oid sha256:5949d0c3d13d02c31f6bf06ea7a0339a851be1824f90c81d48e66c48c79e4930 +size 113887210 diff --git a/app/aws-lsp-codewhisperer-runtimes/package.json b/app/aws-lsp-codewhisperer-runtimes/package.json index c06633a363..ba48f15994 100644 --- a/app/aws-lsp-codewhisperer-runtimes/package.json +++ b/app/aws-lsp-codewhisperer-runtimes/package.json @@ -23,7 +23,7 @@ "local-build": "node scripts/local-build.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", @@ -35,6 +35,7 @@ "process": "^0.11.10", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", + "url": "^0.11.4", "vscode-languageserver": "^9.0.1", "wdio": "^6.0.1", "webpack-dev-server": "^5.2.0" diff --git a/app/aws-lsp-codewhisperer-runtimes/webpack.config.js b/app/aws-lsp-codewhisperer-runtimes/webpack.config.js index 2882ae8ac9..f10f3d0202 100644 --- a/app/aws-lsp-codewhisperer-runtimes/webpack.config.js +++ b/app/aws-lsp-codewhisperer-runtimes/webpack.config.js @@ -80,6 +80,7 @@ const webworkerConfig = { http: 'stream-http', crypto: 'crypto-browserify', stream: 'stream-browserify', + url: require.resolve('url/'), fs: path.resolve(__dirname, 'src/mock-fs.js'), child_process: false, vm: false, diff --git a/app/aws-lsp-identity-runtimes/package.json b/app/aws-lsp-identity-runtimes/package.json index e94f0f6c54..44a4651c2b 100644 --- a/app/aws-lsp-identity-runtimes/package.json +++ b/app/aws-lsp-identity-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-identity": "^0.0.1" } } diff --git a/app/aws-lsp-json-runtimes/package.json b/app/aws-lsp-json-runtimes/package.json index 2e4fdae3da..7cca7ccd46 100644 --- a/app/aws-lsp-json-runtimes/package.json +++ b/app/aws-lsp-json-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-json": "*" }, "devDependencies": { @@ -22,7 +22,7 @@ "chai-as-promised": "^7.1.1", "mocha": "^11.0.1", "ts-loader": "^9.4.4", - "ts-lsp-client": "^1.0.3", + "ts-lsp-client": "1.0.3", "webpack": "^5.94.0", "webpack-cli": "^6.0.1" } diff --git a/app/aws-lsp-notification-runtimes/package.json b/app/aws-lsp-notification-runtimes/package.json index b0e5d02768..b40ae649d2 100644 --- a/app/aws-lsp-notification-runtimes/package.json +++ b/app/aws-lsp-notification-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-notification": "^0.0.1" } } diff --git a/app/aws-lsp-partiql-runtimes/package.json b/app/aws-lsp-partiql-runtimes/package.json index 21f089c3d6..50ca5d9230 100644 --- a/app/aws-lsp-partiql-runtimes/package.json +++ b/app/aws-lsp-partiql-runtimes/package.json @@ -11,12 +11,12 @@ "package": "npm run compile && npm run compile:webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", - "@aws/lsp-partiql": "^0.0.5" + "@aws/language-server-runtimes": "^0.3.0", + "@aws/lsp-partiql": "^0.0.18" }, "devDependencies": { "ts-loader": "^9.4.4", - "ts-lsp-client": "^1.0.3", + "ts-lsp-client": "1.0.3", "webpack": "^5.94.0", "webpack-cli": "^6.0.1" } diff --git a/app/aws-lsp-s3-runtimes/package.json b/app/aws-lsp-s3-runtimes/package.json index c1e2621e36..28779147bb 100644 --- a/app/aws-lsp-s3-runtimes/package.json +++ b/app/aws-lsp-s3-runtimes/package.json @@ -10,7 +10,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-s3": "^0.0.1" } } diff --git a/app/aws-lsp-yaml-json-webworker/package.json b/app/aws-lsp-yaml-json-webworker/package.json index 7df12df32b..7877c221ab 100644 --- a/app/aws-lsp-yaml-json-webworker/package.json +++ b/app/aws-lsp-yaml-json-webworker/package.json @@ -11,7 +11,7 @@ "serve:webpack": "NODE_ENV=development webpack serve" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, diff --git a/app/aws-lsp-yaml-runtimes/package.json b/app/aws-lsp-yaml-runtimes/package.json index d1645de29b..e408b07bcd 100644 --- a/app/aws-lsp-yaml-runtimes/package.json +++ b/app/aws-lsp-yaml-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-yaml": "*" }, "devDependencies": { @@ -22,7 +22,7 @@ "chai-as-promised": "^7.1.1", "mocha": "^11.0.1", "ts-loader": "^9.4.4", - "ts-lsp-client": "^1.0.3", + "ts-lsp-client": "1.0.3", "umd-compat-loader": "^2.1.2", "webpack": "^5.94.0", "webpack-cli": "^6.0.1" diff --git a/app/hello-world-lsp-runtimes/package.json b/app/hello-world-lsp-runtimes/package.json index 0d372ab621..792629426d 100644 --- a/app/hello-world-lsp-runtimes/package.json +++ b/app/hello-world-lsp-runtimes/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@aws/hello-world-lsp": "^0.0.1", - "@aws/language-server-runtimes": "^0.2.128" + "@aws/language-server-runtimes": "^0.3.0" }, "devDependencies": { "@types/chai": "^4.3.5", @@ -25,7 +25,7 @@ "chai-as-promised": "^7.1.1", "mocha": "^11.0.1", "ts-loader": "^9.4.4", - "ts-lsp-client": "^1.0.3", + "ts-lsp-client": "1.0.3", "webpack": "^5.94.0", "webpack-cli": "^6.0.1" } diff --git a/chat-client/package.json b/chat-client/package.json index 7c83bc4ff4..51662618b5 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -25,8 +25,8 @@ }, "dependencies": { "@aws/chat-client-ui-types": "^0.1.57", - "@aws/language-server-runtimes": "^0.2.129", - "@aws/language-server-runtimes-types": "^0.1.50", + "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes-types": "^0.1.56", "@aws/mynah-ui": "^4.36.8" }, "devDependencies": { diff --git a/client/vscode/package.json b/client/vscode/package.json index baeeb80cfe..3c970d47bd 100644 --- a/client/vscode/package.json +++ b/client/vscode/package.json @@ -352,7 +352,7 @@ "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", "@aws/chat-client-ui-types": "^0.1.57", - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", diff --git a/core/aws-lsp-core/package.json b/core/aws-lsp-core/package.json index d1dcc51ee4..cb7dd9f94c 100644 --- a/core/aws-lsp-core/package.json +++ b/core/aws-lsp-core/package.json @@ -28,7 +28,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", diff --git a/core/codewhisperer-runtime/amzn-codewhisperer-runtime-1.0.0.tgz b/core/codewhisperer-runtime/amzn-codewhisperer-runtime-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..7c122f9a06894aac6d5a85934606b4340bbb6699 GIT binary patch literal 110661 zcmV*EKx@AriwFP!00002|LnbMcic9XD4Ngt6+G%blhU11x%99+BQJN4EXj#-{Lqo) z-YPI2M3<+d%wSTxclnR`)>c`VSjh`@UVa2eb?XZ@Ar4T@A}^@;g^yG;P3kV zIZU$O?|a3+8}jpNe#aBwkD&J+`7k2zdrQq-`L(6yQg1uirl~HX0?# zk;X~XNY%MVxH@yAo||McR4my8hcg4j>TFiO;M#kevsKb|~dG#n*fd>=vV#n^*Uf|5rM zq{%48=wGbA434fvG6IQ*h&RL_N>DUpm9ljZ1^|a3^v)RQ${^B+PLPcrdcbE;@=-*A z2f{D|6DK2>4G=-XyY}NK!ExC20EYP=Ascj;&W3(XqX1&hkH_OU${=MGy?d05I2_(# z&wCeRHjYV(CozGfT-9R3^F7+iplq?J5U+!_dDHkF;;t7U4E=--0!94)yIvA|K1d0q z^)e{Dh^+wj#vlSiNH>r6OHzN74Xo?kk06`=?IRyOV6erNxknV6V(fJg+UDCsMrcAI z4bUKY^d=Dd6m;ih|9@|@?qUqHh0g({2}wW{&^;g{fFa2tqHXUMMsR?91VS0QFwSzz z|2s~%yiSbS|KY7|ao0h_*5nQaDTReS5kE2j@Bv~U5jv0w#A8GVLwJT~{1C8hsi4|b zoMInt(c?8%F>Qk30AdUSUOHea{)KiijsrA6K47OR-(VE^Vak@`Hch-JPP`C}5$!#R zJrWO+dx~C!b?EtV0K3K6V}LR+yh1lW{{u8kF)Q~5D1-v}_;mXR^pon)LG;MKVMx-D zosR*I$KDwFBM>1U zLl{8}XccL~BK7j)=#EowLgDbUJB9%QUh+5*r~PY;zf_3AeT=`b5i>eOF|9lTD9Wc% z900y_*|f$WfF8I5CAvFh&=cJ#*+}zh7%m$p{yaTc|4iGC_oS1EezxP?Q#`PAx3u~L3hxj3qrP3 z44{4J*C3mH28pjhKJZ&W=;lT2C<7^5MIK&aXCDm~8W z)Id7^T~A%UZ1pHMXM4xMXIulrF+j!ngcE=nrqFd^(-=bx!$&Vf(HFLGwk@d5%Rlq z7j8kw@aP`Xb`cXk(kNSfkDdZ?(P6nzbe$4X9u~I#q-$kG1?>|1h$CT4-WZ^eHVzR< zNLOT8g(yTGNdm`2B;kmV6jB!AGai}M;M-3*AD31NSxa2>u0Td4ED%>I1Pvob`%%R9 zh%KxZ6DhIU`WPo3@Wiv)+o~R6MZPYkou9y3kw;uWN*~8cr``w4l*e(9}v@{S8L@dQ3_lBwDy9KYP0$9!7(evFxo-si2*CpX-bqBPZ`sQ%84I+&smj>jmXc*3sY%w5*BlqkJ zJ!6;v6m@gCSy17bb`U*QCMR@UbXX!pm!7baJ9abd?ozTCKq@zN1!01rXi^@xY;N2H zp&5@#Qf0}FQ_ma*8(a`Gfp!8hohDsQe&TRaGOk>LS0^ejTCh!tR*J^E z^OLhJFM$sUTW@;ovOcKDE%YOvE`bDSPD*8E*?tM2a@7-f7=nQ5m?hFd?Xps$1gM=? z0Fx0lMj7}-*c7@h>necJudsGq8M1-I3n3s>of56|S(Ea#PC}{#ALYXY`54Q!E>}px zDq`g@Nb7A;M1q%pp&$}LREsWBy>M{%a&4dT8N*6{x5DLmGl~Cm2WM_*} ztVhW6XW4z?8*DgDN6g=Zd4m;L)xHYhF2kinmJQ z!iCgLZOKfOrg$WoWeQD2(FCLodC8QW%oD(M)lv#1J@0cALPFT4!G}qRd_>h>22pU3 z6!wirRf-ghS%MkMXu2vTecGdH$l;>it!RC2qMBu578|C3FdPIIU4z{F$lHI66WXZo z-Z1`h8*`7EL?veQd4tw5pE`Sh976myvh#BQfxX3Mdgy_O&4mB>mUpP#Fx81VZ3o`30Mm7OEDk|2 z)Z0g{z%tF7s#ql%V7tham(mK>EjKJX`=lIdhmMsR4OA6XtWC|A(&lbcyB3JNt>Y{2 z{A$a4dwg|%l`rnE=hr`d`h4yEdVG0#{PFty?8^IeDZ1r9z4MMg{qSNjVe5=t>}%Ny`(&?4%&4Q;*&~Un-^$;VOxZ2j2Dh_4~7~_wm!mo%4_HF3&&y zc=qA!<8{~jaCUj})A7gayKwwJbd6dgK=?ud3}EJ`Tg;wck%i1 z;?va`=eFEi7*fvyhGY^)1Tn7z^UQFqP(~Lpnc#SW5f#tbga=;AY^4nUN{TDkOS!d? zkaWy+m7H87!YDh5eN?E)oTz7hR%VSA9j#SmmgC-k^t|`QlF~-+5x7MmbDp15&g;QD zio0|i97Ys-Av1O+BN*dH!PJs_vXU4lqRAkF!w?N&I#!=}J}NrxFy;t5jN{-Qg`(~7i${`pG6B>|NM(YQ4txMmm}1V2 zKsZRFQn+DEP!kD4y#N$>#r5DFL$cjvct{0w)ex7#D2(YKxI@fII>^E|2tnB*_yw`w=OeawW7azc-E1vyZ2guj<0! zSo!hA#o5Qx^Z)mVZXvT4OeW!D7QP^c?$I(fl>5S$M8oSG8+5ZU3fY>Fi`6j-A)bVk zT61l#TWazH1jB%MF!IBgaH4-py_7H^-qzQrtx`#$mWhnpJ?6;7sA{J537T}z>zu~X z4@JCya7J_B|7+W0+B#EH$tX_4fQtCVI5O=(VB3OkmYx;z7$xALaD+0Yo)4hs{R%x0 z66&DhwKF?uPQ_VWjyHrbiIuBeOw63*%s6+g-oi3ug?UKxkr3K&Yl0CoTvHmnMR|qn z`OJb}=rAE5sPM;UE0_CS3-e5A=bC&pQr7?~)UmOGw4`-1?oNQ6OklGJynBX%&z88XMn1UhnhVdQ5ksAA# z*;7i1o>b@6`~JK3x8mO{Qus| z{exGp)cF6y-Tq-4|G$ji7Nx6{wD`%^>+iV_u*ajC__{K|-ww!sO8psssf z$EEwM<|K?k@EM1eI*o^TmEINt#&!G!+Ug$T1Py?nSO!Ai&F4wLrUizO84`%L)>RTu zuBC8hLp6XC=X#JN8GhL735yg!mlm|%JM{2#d~2^`MqOG9CUmneSdcn3ei&*+!8Huw z7$*4fjG9`s)h;150XeM9MM_2v@ZKYm6zKW^CLjO_FxHfj7C~aH`3{04#qf+Cdtf-O zSyeVTbFsL-?+`PBn=2pZ(cvO~J5;~GF>}_}*ZdF%Fm$MQ!VJggUzW-LND;$+Tz-Vg zDYythvvfitfN+<8S{=M_N{UJ*3o6@fFa2poAu(2!RI^}Hf*<`sbxuLzuY zMbMB}1hu>(u=9$*$SZOx!vaD)TI1IdA`^%qzD%P8jo}sd6Q4125Q?LlUGGh9jOlFk zdN0OoyI#1orA8;-6K{0WH$ltG%NBl&pOh*L3HR#3hh*D(^EdD7_t~9Xl6be? z8?V#vW^?M%{vb)-rYH;`-d0<`7Fv!V2p}fjn+zWP{g8Rmcj%SFAC9~qGCLaGniqeN zIQoHG_@6kS+urS@v-QGfQvumjQZ|(ohnWG<3t{5j#=&FOCJr9GH{Q=zpFZ}e&KnKU z;ITuepe%PU0bgJ-17VDLN7sCezy02=jQ?Z={VyaP*A!bIyob>+85s&c1TWQ+2|roK zI8saadYteb_~FRApQf!&DY^0C)w~1>JjU z`ss4Cy7B)0ceWaw0QK$;wmaJjn$oZntl|@m`bx>CD15Axh_jN<%Tln-f*`eZD%e&h zs&5+2)z4>9c&DXtOF@FVeRHc=L5F9+bz5%x%(<eFPF8ZCcYPVhOD8UxtuvMh`|f6%-5ewc zEc00ysS*09a-3C=1-D&wt5`vnXTXWH6M69!1y5VWzDznlpx}qD*I_eY!|I`+>-|8h z{m}IWASCb^iRU$&TT`QgB^%93lqsx`l}PktDHxzFO8*R7t#&Dr_<;;UayV_|GV zbZKaCfWJX@MKAF+)qc2VU@FCF3?44otqG!zhneZC{4IhHrI;;A$&=($nv{OJDr1BJ z@^fPpX*y8z;VF8&X2Hw&M0|O$X*cx#K*(e)`{yI&w1(TlHt#JA_czso$IeN)&z`$jo`*5HRO3(}K%{bvgCV>V`WW5-~! z-6>E0Z#R?U-;ccCx*RoKZq4nMxfYlWR4&gQr4hAS9nAQ zQSPq-Q!eIEl_5T3-cyfPPW2RIH3VX<6h);mz4)3)fBzic{)pprLg~korclLGb87{^ z%oQo7Sq7oQWzDeay5ktFo6mDbY6JdRN)-e)#2c;@fu%9M_$oiM|FcGa($rAVrCNib ziw^Yj)wE2zZ7H>(iyX+hJ}5)S)uPR!&_>?%ni?|tXhWq}i8sQ4wid8)yf~IhW4RDt zOQrZ)E=FgUv|REBku&?PS1c<6aW;c!JLM_L`uR77I*80s=Y3 z=5LNVX_?NVluNUMXf&v=!nokH(N6VD*rVP6Ss4w|jA{l#lu;U8UHCA8e)2JnKBi%~ z-6@Ds*ZUtHS@b{K65$zF=uU||7Lqg8QXCF4l1W{pkh&TwI=+yK#}{kC9j#bpEjOWN z^%~QLlC*px>p{$xNwTV2SX0A<3x*qTE2CDSad2DaL%7(rHY|}#HD%T9mlRjJ=As92 zkPU5h?xh+!PMR_y|M=Y%Q6XNh+@H|6rE)t7t0 z+J+3aVgaA*PvLA1Mq$l7R_%dWu6T9Kf~v3BI{?c=K|B7~D+p+4d$?(Hkgz(7b-d@Q z59qIt+czO!BF$JJnDSB>$mUvV1~zoG6-yXxe6VbD5SplySQI|f=dZyK&U9yE6{>+{ zmo23tnwVd|+aNTdlMqd$i+;PROg_ zj%;(ibBEIqRxzDKXflDxB~2bYhv#6Hh0B^tHu^FZkJl>tejZqDn$RL~T#CZ4K1x)$ zE~IO=^x+J(%pkO~%tnzip=wu1eQ-$lI_1q!ix^(4GmZY6`o?L~o5#yIP);`oTxwPh z+v;x*%;ktl(^$_}3zxw`5}Fi_?L4)nHg0XcXrX^jEYO)@&gr@>nc-M2A(+c6XJO-Q zfTTK&<$F41yWrIX`p=6Ln=O6jatYPUPuH(3!iQ7_)m~nhQ%sI+ziq_=%2;wDYz}Qo z)k!SOMB@8#8YNZcloilSd(uCyuL{c8r1R1xv>+(j4=gn&f+vrKkghpkdU> zaiL2WMLs}zk#v4s&_8f}NIr0XNWMKw&*dz^h+1iaUmz}6hbsyTuid-XPco%-=_ka3 z)Pd{c_d&zQ@7rVYT#iX4%6jSeTZeK%qj&p*`gi+VXn)|qMC3ma7!%^)Tb6`(e=5YYhkap6YM#os0Oowy37Yb!^{UQ zj<%BY?D*=2azUfC41sG}hHn>zOMFv-`*9dTKe3=)gMGEJN|)3LL4E3kb`KZ4hk9OO zPks=%B|m6c$n#+##V$K&rsXXQN5xdU%jnpoOr=1UBzjpfK5$795Y(p#XphXZG4s=v z{QwE!LFn^0?#~gi4LBLpB|!-4k|4C`{9MrakNEbgq2r09!y$`rc!wUAMx(XZ7}&Es z1lBAMEe<~y9L@q4mxqfLlnN|KDuTKs6)hq@7evJQCVv1E!ODFpd|sfL+kj<(JwHa! zEI&qztj|aH6F2%2jsc2LG(1m=txwrKAN>^0qhx=tYl3DJDO8nG*X$G~05u4lkzriN z2?(d2#Of@nPKPjPl1wCUNhZ>s=jU>sD_4C44s@-SEtUn#QC>+~qY)B$t~5}0>ny!ENBpr#62p|eTskFL=ek_3z=+m@C7 zn2vAhO}HDnY_*Rv)#)ijh-W{K2C+*VCtaPl7=kZBd>^UHRumYY5ECnjSHCL|XrbjH zvijl9lN4zwNKli8Cuo+2r=>*C#s(p6w8Nol=24y-Vmo1H&?I+I;Fde6MfGRHbm0J` zVZ!#=HP&KNPK1iQflG>_z%@ltdj_7%8JH>_h-1Z)B$yhE4BRp<1&uN;wfOyPXgnf* z2+$bfhAIVB$VJWSN-5Ke_=~}M1F{AUa$f}va$mLB|C}6(>UJ+GR&=hYZ^zTXIloq5 z&9BuW`Zs*>rp%@xl6i(H7W2&t&xDG^fhD_G;GA8oJp<3>3=ArpE#P$(6P6&r*w8O< z%z75MW<6^W`T1Q;N08{RrmrW3wjgQXmc1=-&ED2x`!{TXDXzjV(*|R~$-phIT;P;f zuDyo3uxqHc)ejsJxdo1i+*;!FJY#CER&Zs`j&Olf=C{Bp^IJ=J7Djk%s~|y)0zP)Wh;-Ef*SWurqtUUwI=nnVBV6)~5 zw>^hg&@_iwi`UQdhGG*GU*$zUM{Et6W%ml)vU|12-(Kfi1Uj29^wlTh3fz)$wW#}S zFZHd41e>im^;x|Fr>tHr%C@G*`QfY?-2#WCVu4Fiu@+&U3&MiQ1jlz}jxqgE-^WTW zg6xrxOP-W~T#pd>5J$<#`4ZqNlt&9*2X2YY1Z;FU47?%R&fpWPC1uO&^?F&`;uGD` zBhQQxtZNHeh}rdc@652p&ew#znZfN8_^y?9hlO#mZaLQrZ0ceJ- zY2ZHGUqFZg#(1V2t{s48xS9s;!=)E|L*yq@4%XIOGt^3T_kmLUK|cJyX`BGs90pS# zKUYwi30RxDPv#PmIK@8v7$@)IG@5oIE?_j1FgA0afXYnfuq{2DMhP0jzchxenW7sE zm-%M*5#`=Q#`l(|ZLM&W*HVj&b+cifa*$l;`zlqVKb2?Zzp}e(S;4QQlBYt1e9F0e zWdH_o>K-Mdw}8N6t+qQ9{IB_LUGmM!&O=e_X1C{3ZCemJOq{J0K=fOriXl$2u~y7A zY~9p>k`0|~7y=T{J1{a6j`H>N-gptb_xNquoBqviPrK~y%7eIOLZD}_*ULvE4LC!8 z-7*HykLkPN6&&dlqu0x8Pm<(XWh^ZMEfj$&OTMwlV-`_c6j~?>85VwH5y>W4eG8~G zN7OJb<;EgMo$AoinuQ{ib@?|Isr06b7L^u?N}5IASOn4=k6Hv;C<18~ePa>G+0xPq zK#g$3ZCy7LZ3w*Kp#84$xVD86}FOEESM_#=1`Bkk+<)mQe} zO8ju-{r0=?c@T$Te4kD(a6F#4z{yaCg>y)dIJrU5@TBO8#VQf1JIFj zA4Y&h09-|AGJzGe8Ub>FV@fFA!#fzB@Rd<(8F49M54V0A&>r4~vHztq_X&=N7>vg# z8ome7Fx68rb@MUzdB2Czkomh61m=rjEKS4845$J4Ellnqj7~-=$G{w|DrE+=r}eJm zcLOguuzHBHo&brG^3$Iv-0MU%E0l5@yc4f=n9U>^H9xh-Y%ts!54Fa-eW>~hH48EE<`@9b&Yxa91afH*({ z_o)Dx<)lU>SMp8)+p# z5Y$zv+l%R_Z<4>+UAzK*(;LEsKIPrn_Fj0q{eE8}j1v3P4wO~-2=Cd_I@f%UBB-sD zMjTCGaO|{{^xXc6QIf!@egsNo-5_)rbLE3Y9mn$O*p(koU{${0z30)p%S8dxTD$`& zgh9I^<%(RwF$@rY%xEF&V(jSpQMX3pNgQcZjQ}RlPhwnMxdDGmuUdd2KTHEic$U$* z2!NSQ#6h;hX{g~NbJ(w|)X!Ai^+V!Z@)jO%Ts4xHLIaJ-p1T$ehV1%(l%Oazh$gHG zy`-hZ_Yp|0F&Yjb)*lDE(1S6IlJfF$t~`i>vtDhem6y1bufWV?e*?_oogZnW>Xw|3 zY3d28md$%FcwoCa6Yeb&Cc*}A#lF_-?B!_5GBlpDJ2!<#m`g*2M`&qMcy1pPNEBUz zecL+9yXf5l0uK+)B1#r;CsQ8gqgk9sAr*2)AXyltJJ(vZSY5pyAEo0fNS~;naq|%* zx^kY}njWiw34pbg>LH!NupZJW47HGEGIr=JbzE^hi-Pyf4L^Bnc7bY&_D!__DmI@& z9}y%mZWY%)(B!uMX?D3|o@f@JF^q^~a*{C{#z!!QRn3%^{6f!5L#;DN{bY_}h-!^( zNOsibCfZZjgRkL3qR=3zZ0kt79c*Q{bp#2+fNEJmHh>CjsdPD%?uudvHQb)YemZts zR8}s-ksl>$xHEEN)4ups8@957ni||7r7?e7ZBi5vi-Q7w@+(S4HGP_@HbxNNWYN-e zs;yT}S6ghKv})y1J5|fG&eYGfoxDR2+)4o=-`G>NQuEd1V9LAQmcEoqQ}tCCJTzSt zW#yt3pK2FOu^t$}3pM0UgaW6oD%!H4!%985+e)!h=dzAz=vl5LcPp1!`wU{=jvUnr zjS(Y={a^O%=&q|WT|c$6sZ?p)Pxf~9DZFDZI9VrVtvh4S_NiLy&d{^Huj!y8S=msa zE2SLQ75&7D07Nst&Y8?X4c-Ety5r`nJ3pqOnvIAmEGz}7v$N~Y}nj&aH`aD zM}6)x(HO|`D%oJFb%r=jCpxVO1@HtUaL6rLQqdne`z1ZlHRBPg7{`;FK|e=`J#2FV z2qY$e+R8@IOShm_;t&>Y2Gb#stl)0*)&`px4ajM#`^0f*)Od2% zFMIr1@vep9IA+mdR*QJ0hhRfA>$3}Nlqhq*=vUfFo3njbBaUD+9~xo26dO-Fb*6Wo(C2IF(Y?sVR4YnkUAz}(;Jd@t6zL@e>GeVuq? z43l3#Sl0CZ{L}mG_ieixmKjpDikNORW|d56$VZ}`*Du`aQumIq`RUxZaU4Pr36G%0 z;V;}YL!TN>qW}(21Ov^Z!e70j@{u=H4^QH|!=`bD^iDDiF6cGi(>T2i3q`&+6 z3f1)kcJ0b(+~s?}1&}a~hR&lcD%%#<1irxt`RUm%-I*(GQZX2hq6KSjk;J>EP zmngoEj`Az+kY~)zACvyA|2u6do{0;}Mj;{mLOWU2A(tNomj^ZVd9Ngxm_MoaF=W6g zBP0RIcU-53pG%2XVrrAdYimwMgQ@WA&d#>sI+?jc@CN-2GElOF{i@U$=*WSNj~ zUCmbUP2f7DPme)AUB4sPB+nCWcD0=uoECEy}0A>TM%a30wSH?Pu%bW=dk5 z33m^CCQygjRYhHWTcVtkYmW&x6*fl-A<@mMkU`$TsS%-YCCqpK;T?}gq6rh_+h3=U z-Tvw-b(;vBtiiQl(wzf|xg7ZW`}_ZS3KB>m(;HBq1_J^UMoTK4yCRP0cW9OdwX#X8 zG-C1?>8TBu7{Y668K-LVifE0hVT+CEW?$g)hHE3zGsq`*_Ao)rl&}sAuNc);L!BnA zC!*?7mQAKzNEP2NF!JehBnv?oFwWddjkcNNi~l&)`Msn!QsA9hNj0#wkX#E$;{5rYh*o%RLN()Q6o8@cpj$+ZXtlg{=Or z&_!xo&thNSWJJ{as!PZNe7{W8^Hjcq=lc};?>u#0F?!~vQp0Xve{X{M)b+j^S7N0u zuVNHabBwF>w$RTOV;8Y2fU0Gnss6;sm!dZnB+Z~R{ZpLu^|X?yx^k<;19dF3X)AAO z3;{LkEJ}j#8_>5*eE7t#i<72eN8WBG$z!#0Pk_iI1dq+!1wx~XFvTEjz_&ypQVuo{ zOH3i#@FAhH{Us#qt=x5x(XzJ&PQb)@_sS+S?OhIL1h5`?U0NF)TGpmGOT5xde@Y{i zY?uTqQ>;}IVRP7hdnoZE zyUfR0jgn+?RV1cAs^+TiX6Tbej}|pX5CjmD-?koh!1!O$PF4d2TfcjM|9efX9cwkI z7VjTEBrpnKa9J~s9Te>B<&FG-xt>4Bpg$FfNBuYqSr}Z9(I~oNEC_b|R?0YT+GPR2 zwzgp}8NsM?%d*4%t+24B$>2Zo*R@z$jABGL{_(pj?+t%>CV!kXe`1th&D$#KqO(g{ z6_K+sKp|ZygkeyYk1uF3yTWsU<2w{UEEKY~WAKpOr6^0HYg$4jvFrE?jLHIPGHQAv^(`mYZA``&l^FAw{>yN8GU1Mj>3?#owu^xtJHKuSG{ z-}PtitIvL3@$ZKG(0CH##QW;GW+Vu>nIJ=(ulp+0MNX^*wtV#B|p8WV;*V80Y>w5Ic7XNSc z-h9_{ON-R?G%2>anx)Qf>Wj-MN5JzfgXM>=M}t-_vx9w>C*ICd9?@?sBRC-Z17`|F z8LKZPp4L1^D?31Zw>F4;Y6tw{D+->riq)EQsL!(Nb=XMxTWu)ldOy%=KXknT z2npO^(TcCZMo>LvsLP>x$}@k9-;n$<%>6!{ z?d`SMU3!P(_zs{D+=lQ(6lm94l(!6f4uZW|I5(QQR;GPPEAfGaT`uvAYI=7&sM$$W z!V^2i$?SUn!`-3(vn`#%ape$}n`JqFW9{+dAS3zQN6NXcAt~bvsd#+x`+A=3%+Rno zr#c_-($DkKPpufIw#>sD8V9ju#@)rO$BE{C&XQL{G-MC5AuPp|T0?_~m0HpZPLyDp zFE}Ygbd9A=iU{l$!&(z6_7WCZc;v!*(yeNefpzC8)e$e$S6=HYT-Hv>ksN6KnSW)# z-=HvG#B=0#j@NzDDg$1lO#`DBxiMw}QXTF> zE$G_xa_di0;>pUQ7fGe_HsEc_eN>-9TWd8fRR=o{HO=>Fo{%cF%nCx91dS5TN`(Mn z=+kr=)uJr5x=ttiBP9tMWK*rk))0?Dlsz1eQ2?u4hP~YegZ$y^rP1-g{Yfr+!t%;{ zu`H5luiy9n?cb`8$$Ec#hn)YJKMtqkW#<%Iq9r+=-4!8#>DWCEy^QDV#y>4%Jy)F7l4k`;`-+RNJW9!h~B;@@v zCjSRMa-O2RO;^F0pEw54n#x1Wg1le^lIFW@sFW{DmU0CUf`(BiU-2%Tg^X%>kpl6eFAx{R%ZvUyeyk-~%OhFEE@&j*GCIsC_=@4f#!BV8WMq+SvF^>T z7Oj?M%AqsQa=J`yz*z`#7=mzG)L0g3{1M+?)tc={Ivg?|#5?q`V2WXS)~v;dWno0- zwqEc)Tb@*Fw|ZGyjq^?Tz%mu*mXb^1^P){9O`c|J5o39BsJIcAa10R5<#wJFTa)tJ z1UH6UR!KnFQHPudG0+7|sB)7Vb6A(5S*wSqR^^eK5c)cvVu0+%cRPS0XTL$T~ z$5XY4u{6X`1HMGWP|KE%7}^KsTI5&_a)=S&73`peOF$1>^j?b>%fgEQJd)2*LSM)u z&?a@T8*G|CJIAPp0?4<<*-n&FJ`0mBw+mW4Hr&NIGGOXE29=M!7(SQ<@1#18=)v%JPO zaf#{xqOfe=@fWH) zIlM^PMhZ_8DeUz2XM5yUs0Gn`z~cmwbm^XohKk! zk5Kix7b9EjSz@sIdSOKyy1M3}t9Eo*K{Tk#!;CGme3S8@E{`U*sIjt$(4`TG+GiG9 zBzX2pcKsubEfOpX3BY863|*kWTE0dj zY@iGN@P=$1gHNoM^pIz-*UQ=#pXhoXdBXa$zRa5-KJ>|ZV|pP&#Wx;(y6F;<lBbgZ1w?x-qx}2LqbkrgkW&?;6oOXv2~=>^5bz2jKRO+ zs0Z#zkIIwxBSa<;L;ROI5cHRfaD1PwMgVWLO)eqnh%-@7R5_gUD1kTv;T6Pp5KlSm zdLWvC8ydL}{d$DsBneS8oO0N90Gc6d8n_Sl7Z9R=5&9{IYX_hiuBL(eaA^d0i2P*A z!P=T@hFYoaK2VB3$cO(ojT1nd!(i&;=L$+Q0c%tD$y`Dbr`U%d8 zzDm{TPvwjGuk5Z`R`4sS5wh6X;h| zl?+q~Pb;h$7S$yTq1HHzAt3SWfd-l6k*|dJ#*5&+r(Gp?F;<+n5FgR&_3|M|qs)-& z<|crCOy6P3$W+;LF+RQMBMW*}8r^QLxVe=T+Ki1gOJeQzirZ^gr_I=88*ksFZJu=# zjq9)(+gK-OwkKBHZ0l-m#)j*4&UTx{ZPu*OW^ArrLvJ@%++58XZN}z0tD4^u`*mBC z4cK4;Z+K`1h>}Z4CUHby7J1~ou_U?5^?gH5LEw+zMU40>QEr^( zTndw2)KG8w5< z%ZLaOd&}d~fcEeBY(;?tbh|s)kE{Mky0}fD_K-}p- zR)M-ty(kUC?H(oQkY0u<8w!oH?lNTO6)WCS&G;G+CZT%o4iS`8PYE#4y(5oa@q!d& z=c~76sjt4ihASV;;n?It-0P*|3vrgFvQ@r=f-_&tWUBQa{tTR*HJL&?&rDv24^Vxhu|I}JgE+vTlj@Bv%ap_*Lsbz92i-KKwoy}CeI6VaT%Ua-6YT7J|>VTqBQ%q zb(F*H-2ws+56)Q9R@}*CuXsl3_zKd?fHVX%f<#x& z6I9R>5-<^|wo*N$QyA7mI)$MYQX_3#XZPVM*I5+2cd_1P5yrxs0RUn(q~LLU)1 zhq;O>A86_T|CC!er^S*0jbTJgNsw3%AHf(_^(0#I3&rGG9VkfsWR8qmHO9G2UTtGK z{Dlqh8a^Zn5s=EZvc=LJehdSu2n1PQ6);lia;VA`-D7IZJB|Hx?6_#GT!tgxMRx%r zw=k`{U$t8*%ciNp4H_Dgr`4uG0kPNx;3vPLWK`3qsj3YDe3S7*17BOOoSC-RK0nol zpmwU3XPv2^Ydd*|9=M_mBH!3kwUTw=c#HBTm<6m-sSa$RNo$}LW#v*7pK6yu(OnJT zg&J}vLV;6P6)n%uVWpnjZKc?$b6Hn1^ek7ByOqnVeFm{_$AfAG8x91q|I3~oUv*V# zLDr5`opn@OLD#Qww^Ce7DemrCT#LIEcXtU=pv8-OaJS;F#ogWAi+j%HeZRZDb?-k( z)|{1`$;=+x&)&cDN3|b;-IxCiXX6hKPDNkCg8SuPVQ5=}CZ#iDTWAWMPnuA4g(Ryu zgewsiyW&4p|A+Y4>-;bAY5H-E(YLZvwxTJ~DN`P+}cfHNL8o`;-g?YK&j3aL(`PyAA{9)0s3F!gUZvU@!E*mR9iAa zRBcmJJv9YO!zL2*HQ&kThjR(`R~2I_PiGQC#T=tdwMJInToMAARm+C-%}LG%3NUT%=R9Is&~7KrIXvjFJ2n!gIX|UKdaYi z-xyy#cPt!@S|_^H!=IS@IB6c-wG#SK*YQRzrC8J}^VCS)hDpu6?|p?o4nBU-3CNBu z@nnaYuAyHU`&2>r35BcbJ)b(-L%UP75P_G85yB}kH!NHJ@73^vt?Z{y?$49oyGq=! zd3B8Z^FqJai1K9c?LIS$5uPS`KI$0tr9YNaUr$20;IX)1eUcjv#HuK)V*S6crv-)7 zghc#cb^!+w2`xYM%g`c@INpnm4NAU%+B6nb(P#Ex6DxWJx%*Pw?kJP2#A-UGpXLJ9 z#_@ZyY-3keH!)j!x(X}ed3R?H5-`Zq1C*Ti5U%L245xbdN=+^N@&o*5Eafg_-LpGR zCu+K}G!$mPO5IgHbMaz#V=ctErxGKS94?#5HU9_@BB%Kpc(badL&{V%iMD!v8{h!yLMsbq$m z@aQPq`Hk<`%u}J{I*nn<{zBxa))<%l-qz%i!gnLUv+7cXeX!3$2K7SnrQOidzK=T< z(O>T{%g_+zTE*ruH_TaqU-<+ygCANBm+^~z06k#mGB$X3s3Yl)O&eKY&eCiVN8ppc z73}kIuhS$1o2N>WSNtn6KCcAg+;8%bEYZ!pQq59DB#VzJb4^y;KV;&k-5c5m1k}EM zuq3LqyW^^&Q@m8#d=VT#CV~>7&`pqH1N=XVaN+zMsE&VZJ`dvA|09AQGQaD=tx%|Tz_Orn;bdC8xa`&=pgW-@M*BLjI(;9 zmNDEaEZs?C-JCpBt3|5;be*T%;TdXgf5K$yZM7N3=p0PK5rCpI)|_6qKv8+#U`+7` zJU<%L)zt-ni$4X`e~1o;a1vmpPPytr+isXlS7@f76x0Tk*JJ!+tuAGP`47S2%)5U2 ztW-tcA31+yVX$>AB|9!gwr48joBFB9ZR~dxes{G^Xt%nw{G4}k(wb%I&H}uYaK{e+ z=|Z5hMQ??UaVHNXpYp_LW=hSA=JPG5m)gKxDxP1UI4|@Jl&56082LxBA zDF+#W?*Y7nR<&+UEc7>Ovxf(llCUu&voqz1AkvMrWHmsvy&=;&j z$4dLL^=E>fTD=WP4NaVZ6h9PwxsWnhdnQti?GhXNzHxyh4dl^t2B*LnsiSGroao*6 zp_@;sd5&c)cVUFrm%d4+2ct``A@IT}x^?%3>nJo{j|DRRq0dto2F~hX3 zcG@g9lg$3nsD=Tt+-dqIIf4Pfdpa;+r|SM+aI<2Go0dd|Fz8CHPJ()(k@y*E(r+WJ z(k>fT{af)hnpMk^&KkEZmt6d?#_!OxlJwMyjB`o6eU&)^F)UGqfK{I*=v|PcfDSs2 z-P^_6+a*_nN5y=BZae5PuA4Tn$9$aE<6BK#3ePp-fe++U2t>)vNzOHhTLkH&LBPSh60kB15PV7hMO0 z?#$leSsUbL$->WXknNtJ;+KufOR|eDpMC!(;JT)(&DU#5Lrezp3S(|gvF7n@D({P&5F9wdM2MF<)&T(N* z<){Ap3qh1DJ!cd0*+TKRZoGRPR~O%Lyxv}Mj_9*$y06}o!q6!jk@_YyFGE`nG{yLp z2&zZdJ;5|{X%B?qIul~Jd6Oau`1cm{Ub3Zyb3N$orD-UJV>eh)Q#^QY4Hz;8Kjvgy_UW zWl3dRKYn187YEl}`oy)K;5uDS^-W$?QnHrT!kq-W+92|}C?d;Po4W<7l`;ll|CaOn z+6(QZsMbPkkmt$ZWB^N8z|2#RTTm4Q|AniC3xR<%UQ~;NVAWXDHl@1+!N(8r8!Eoe8;YG#I@bj`fSw@!6OvNEj_VN;kH&-XA=d1jFd z)YTAF(KkJyt?Z~^Q~2OrR>jpQ3Eg^FT#}aI>q}LTpFdMkK6TXbHxJ-ZeJg8^HsO#n zvsQ!Y%}TG@^y(NK6I4;iP^l z?82W2%KWg!S$vu9FWk;%Qx`t1lkfyO90D_??j0jddG3m$_5-6L#_i6l&?v-WXv6pv$XLFj^p_5pj?{i+QrIvpt zJ+l_$W@A)+U1?{pJ{xo5)|K7Re%4b^K{|f~dcOzqMnTQ{$3P)HHblp{)fhWD<4Ns- zT-~`w$~Lm4xHsrB=rBBc8$b3XNsdk-@eINzc?v;r|-fm+(&_xi%9nv79%)fBT} z1Xj}{x;lKY5NttY#KMEx%6e2rz5hVG}TkwIZJ@#CwD%hi; zrcvw6*C-sk2ZW_2(EGtR5k5-j0V$dbH&k9ft!Z5_5({np; z>TY$Tfn31_(0K#Lp8{QKDvq}Jo0k-`h8B`^w`xPy;nW+-=7KfWPpP|g8RVGUDqRhZ zdo6_7+>Ko;8Me$LBam~>w6#Q2$7!gYESg$jR;>8g#JKtAal555ej(RP7cxU}uPV5G z8^>^mE*RI&gSBxjMl~L9#3ub#$6)|t&6;#XL8O2DSu`P60(ELnW)ZsLFb{#J6~&I| zVt-Gf+HG&FhmrXf<(p+iE$fRR z-C1vo+{LaPn9BzU9``2;ZQt!T=J*dw#s{rEbcovHEFSX82d6HM>R!%H)*bOM)63;6 zCK5C*<6Lg(`1nH5vPlr}6+2=JHxyNOk4xNj<{nAUFyPu)x-Awwn`RaX--9!Exhx#o zI?~g!TkMxIhGE8|#(YrL(!+??fE{`62Erv9;GF#8-l*(;v#&3}7VtNG=&JqrG%(7r zzJ>$di!{0AzHm;DS_)N8-CS3Hm*Gl}GCV3zrufNwnn6XOLLn2H#BG__TC=wq=3yRM zdrkl^hI9!X#`AvU;Cbz=#O6Z27{);EY^PJo;(I)}XFv#e!W=!<{9k>(JCklzcZdwxs$;wsW7a zsU+SZoZmB!-5WcqC55T`OGkRz@3WVdxjA;u2oBG*F^l}NOajBIM^lKLPH5OJZhbm7 zy>v$Qqc;0#3dLnE!(2&@XHk#es(k9LFM{Q-KDt9t{vE+$8G(Ns7D%MF5h}n+J+LR{ z&n#WV{jzQk|E_@0?5ojCn7;R^wDn&}@G4i}>SVWul035gkQpQ4S~m2Wn7bSH^hhoQ zCt;7~UNN-YG4Qq4A;(gMHMb@IC(2bf)D>%p)ed^UcA*RIvpnpr7Q51~f-Y^{hLRsX zsmh#R8@e8hRTz9d3(k@YK0X^uZv6QcABA;%b-9t@VkH;qQdfn&1v)N-^RO!s*pq|% zx*Ew!nrGEUd0XGHP7)B)`?cy^cmlaXE}rg{5&esD0()_Q83}oB!QV^1yEs={lvkk_ zprx`sEd0iQ2u11UvhH^1iB6B`saeCsBPkq6yg_Cq=!5$n51ymELB`mEsu=@oVBDyo z&sBxP5Kz&2k9GY^FuF$>GTrkfls9%vk@zPJKBBvP(nrmwRE~o*@is5MKN$jedDY@V+L8U1%BzdGL_!Ti@Lpyh;M&R$XIe< zw#zTc_I_QAIsrvPfLh=rCl4SeIcs-onZ{$lSB) zA5N5bt&fS+JyZwL6Z>Vi7swfC##h8Uv)n8{rWugqw#ZEr*-BkgWEHi98NQpFxy)=g zmiL4kL+&BJ+PL)BB+FSgtsJ?kN{rH72iF;5z4K$jXV7v;sgKYgx$j!z@`Tg7Bdm%kyq7LRB9#a86Evrw(Bbns~8WKB{|nj|5JDJ z9Kl6L&m=QPwhL3onTzQG;VVTPA}5fHw3V=EE61$W0m8;ap7e z?lvEwX}PLC?O%1#&Dcb-sgU3|^A%m+(7FY=hI?ZCBxH>^V_x1A?@Sp}xPCdk1lRug zJ+W{_@EVzJ3cr&5;jXf($y_^@DcK^f? zM7qpJH^j}szA8&wiT?nB1`T2Fp8_M$#~-{*$sHEB1Cxq^OlS2X$i|Xy_mqgwaCJkC z|6BtwOQ5W`LnlyIFYxm266n%@+RVb>`$*n1YG}R|+*X^M=_aIVBzZLY_uM?Cyj$CD zLu2Ad^3q1C4C)Hysb7bIUazDzj#vP48vIz@PBs}j$qZErAF~n|qSVK>C=PI}Q)cHw z7Dc>tasgkK7pAvOr?<%;{LIfr<>QKlXEp3V?aRX=RdA zAymbw=poXqmws;I;!Mta91%WPe_5t~MV1WWMi~aDVuqy=i z&piD8cpAUMPrAdmNEPF1@(kv_l;hz3<_TPy??a4$c?Wrb#}Js!Q!0nAO28}G%yZPh zPt-CciYZj4w4FxXM>w4R;y#DI9|oS0Se=m-nZsC-l&|NiKZ>AkHD++Q8+hM*x*7v_ z4*>m@$Xm+!TkLy5%x%es4>nbZL^GZVttgXUY3e!lE%OPPGgq0h3L93wqm$cD@GOb~ zYIQcu!@z?}wLf4!dnbbHPGl9(#+AP5Q2sPt@}$9iNId@(;hq`{l-O!d-*}+9SC;5r z0<+xd{Xj9stXLffC)=r8dR-NZ)m?M+3~^4FAp^!uI;>=$Ol9#LVC;mw| z7i4VsLZ}9lLt)^^RRPCytXvm1b3pv__J z#b#!ZaT{<5wNzHu(zHnD0*{{ngP2I4#SJ zS5%F6nUaGUpXX+Bb9Kr&$i(!V%Lg0YEq57I327?-1qfPQ0@X4=9h}h$gCJ`3+_Ql@efOSA3Sz|1EW_DS;y^Dh~khT zLjj8#BwU5{mr7z>sf@qtb5|Rvc~k2cfCLZ&O+D8jsCOKnAkQn|>_&#ZgZeH?3bhl_ zJ}FDSkLT=#_{VVXAj#ueuCO^q2T=r?{d&X82z)*HG4Nv|5>-@@U660Bd*WNqFuT2C z3|#NnDY}PDCUt(+dS#U=`*Kj=mzCi6;O?PZw@KaBYC0~=u#~ejxu|?P`E&b+%0k42 znUsYYEt^tI4?hAbf*AI^OyclD4*$13wE7J2(>;AG0tF9);a-nJ zLKkL>+c^i&mz zFso%aOqP2e=kjlxu2MsAetdz3;497+D%(`uloHqZ=-0}A<8IuQR>~ZURd8cwDJ9Xp zS-#Dm2X|+aS1wXi5Kj4If7N^<+py3m0uS+%Prxg+#nh_6r z4QbRFp1ymK!F=j4@oT#Nddi(h7}soZ>FGdx2C;X4IrV(>pwd$~>WzQDjMsK1m=5p2 z>9%5(Ix|u;tP)1IY4z^JBpI-tf(`0|^*v6R2U{L)Gdh(chE-OHRD{f*QKa2U3F{K4 zp9yBdpPR^eSPjPf@Fv(yTV`jn8%YkoGAN&Ii{H=cX;to)#zlp zd@Ww10RS*-BJL2d|MNoI4zTP$-wD*|16^+4TX8pAPeQB>SSwMB+p)@UWxg_|C82j6>y4E%i;_2hKqFhCk)myr9jMGMlfs zBei4P8^p5f8S-#p0%-UGt~VDz{h;;kCP=sYs#*YeTOWD5OsT$Kc>&2k?Ryr0S7ukU zLC0@kauYZhWie+R2U}~D09(6x5SaNq z|7jG#-<1W?dLeI`gYclCVlU)u^Xz0o%3n#wwD0&@JU!gbzoeuw?c&d81}0Yg#+@OX zJpjH2Xng=MIw=fT}5tc<&%ZNVK8NX{o0BhI)9@Bv%Di=?`bDL&4KSx znQ*b}b)X4H9{(Nc^Z2{%rU{Na*u2zcs_H%9bP21{q@1@LWqJ9z;R zS@fP96V3ttIcs~s_WR4C!vv4jL&`#KE~$7^*nIIHs+*2EGoRUxszai>j>2CXW{$j_ z&%v6?UfK76_aA`&WwK|Z+y)Z9{=S^2*a4me%Fz{1{3IicPtSSLO*?vNr>-?yEZMe7 zee|T-rXMwz20;60TckdZe4SaLuZstOaK!;|+-0{3EPK5vi)U%R=+T@jZ=^eFJnWXU zqGKj3OiEtvqFc;87Z@722^+vh4iuAVuODizz7*Yd@znsjZ`C${kl*|>pp_5IPnRC7 zfPaYPT@>R8VvZ|MYJ;OUnpk6&GZhzVB|W*9W|Obh zM;Ay?DOP;zAka|K*>_Zl9Zk-mlaJSOXw~1uWp$@dYitxFFDJZ+Uw#5 zJiFq7J10<6AuyT*xD%wypPnp^>&E537Ys%Nb5rvh9|=VVAya8a%g-t3gNfsTxvbSbSJ)JviVr_o`WG} zyU@t&FgE8GMq8WyVcwe2VI2KgUP!j2dQJ+=#0IfdI_p{hHaDyP0eu~sfS%8*maES! zBT)qc*hQnRapiy^yGr3frzDqQx2UdmDvZ%p7q4aDnf%M}t=Xmqu)1E}2`p_ozKLX1 z0>|Hq=bsm(PG=n^c}h=Z8KzTdju-xDRwodR=ZzoxRL^fSMk}OeY_n!W=rWyqAAxR6 zfQAQ<;f3ZaC_Mc94ZME}ig7E=T`2C$6My$k3d5pLju?Z(4V%y=_(L)ZSx!h zeV;yu5X9n_0_UCl745*7D@@}pDCACr^rW6G5OwCDKJrb`#&t%H^FX%MJ(Hj88)~Jd zKpiK$wPjeo1$}%yNBOG=`Lz)-;HjMi7@apgZEAi1ir25jwHM#-X|gUS0uHa~#O^(k zK+5>gxnNdD{{(!7n`H}Xeb~G&y9UbF7XTn?4+QP5OKMEWAK1KANhYdg%AHJ8ahQ1v z4gH-XD`#a&mL)DWr?UBOqaFhGt_Aqt96?PZ@8i7w3MgL$elRVb2C9Z079pN^9dXRT zr;L+irJ1-MEXLnFoq)i|1icSdQStBxprz9;{*w1M+haiL6r?d{9Re&!YRsLDHMMP`3XSc0GNd! zlfR_6P$A`c->PIzT4D(bNQK5EtPs`PYF$7rIt=WETZo&rl|M4oA)gWM?~9? zCsR7jLP42YI{cbh;0-bwFb`SmeBTp2lZSo5xZF}E#M_?>+>XmZz%aQ^z@4Ul&XteE zz-wE*-*{!p&wS5t$RMe!epg)jnhvL5wxKp+l%e}S++`7Js2te|JDsR~Cd%KRN%gTB zK9pv^f^RNnZMgAU3gl5Ymo^Y{BV#1-Jy#w6u)gN&5`L@rE8z1AzUlV8If$ldVi;*O zlF!NwS{!cmxfxhp)E8_GvSi{1aR3aMgt} z6vGd;^K_{Hnb%!rryqksDwJH}pXNLfX1;)oOX-x6g3BHxIO!iw;b{JkFAue(63Uor z;P=t0PzMB3TENK+m)oeMWMDI-Nv(^FQ|O|KTfjT=x5*H`^rUfcs&-At{6pmPa{S3c znT1c|j^-kuc?-b*1i9Y>Z(6>%PmbULxTfpP9Z(C*YJ^s$*ZhB8s3Ood>hL0UH;f#C z-zlCeXrf&A;1I30`ByOF`P-zWDX^`r&IZ6aLCvsE6UKnpKO7v`LnD}`iYma-)~XE0 z{^_|?mX|XErRV&U`loA~F(oHpURZl)M~SeU_G*C_u;H|3vEl?bm{7M1(&?1+NDvHny-lu+W&eZ+gT`hL?t9|Q zbr(piO6qP@JWYx;dEWqTPLrkPbVYp`(xXaA`^ORdiO*Mt^_u`d zyiz)i41gbY^U1^bpN_x3M(}X8$4v(8C`*;DRxkA(C?069q;2}J9VMq}h^K#ZMxT7P z$a4DNgYfz;z||fFN=S^ac%Z{v;T$aIRoB%~&Rx?`iESE@RFN~`vP1P+4C)Ff)=^GLOQfncJTc&T5jw8Ud9{p&0pruoL%1`2*BQMf)s`zsCWW!N|u9SpH}$@t+EPBuhxy6D@jGU+&+Wb3C@taxU-R^*=#KfermLWSO9EX&Hp zdqqLuiw2F5HxTh2MFcX@@DHJ6zdX!_d{jOXz=5YFQo=kt!;s>z+YmsC$LZr3v9ny` zNlVTnTxiQFBsYeEi3=?KWKdw{hW?c|3^~ATloR(|d3=T~v#+NkScNtGN?)vT2A=@q zQ`mGOS~x^Vpqw^mtecS_szucn!`Z`Ue0$7fH^GY?krhk>{c-3F$G79I>#5X#;sJQZ zeYxD|5qm%DwLm~w@Jwye9`{>)zwR9d6>RdKu5~zsWMGR4f2{e7yXTN&r|D1P)bTuAm;{#_X~>wtkZA zwk(exK>yYoJAkHZN*jlgw>(IPCgE`#hsya5PKVa)7dH=_p8>tSh`8cFo$dhTmjKDx zz20+Iq7h!r6|l#0Ip=L0iG|q^Iz4G)XX1%Vl+l7Yyv5JCP|b_P#bwZ*`5re6%kIU< z#l;jLYj0mEyR5IqO?-Mvmo4F6Sl0E;sCr_;&Z@A1iul9^y@T0ZQY5>xbKt(b^k^%g z+?L9B%aWe^dtA%H>a*`(w4|{Bmank+o}=G3kNRfjcznw^lk6e1itcrb zvUlAo#|R|C~v* zl5V;fjq#OlD;gQr ztrzF&87<|FdaJz-KqGy1!#rc7otD44-5(Ud=odKVum)cVwQ-Fjpj^s&Re~cvUp~=hM7^<~T9#e!P(xW9?t4>Eb2zU$3M+ zzTw@uK zpck5T`($)_uW0`px9P8WQ#bl{(-g2mduh)dg#8S1)6W5_F=Bacfu|9W83uG89KDRM z&x$J6n?kWaU8_skH&MNyyWvwhOfthtwPvhV-Z*kS>o$QR=CWgshYJ3Di@Hij=`GaG z#P50mX-`Hu?>c$%O+3kg__=@){u4_BfIk5uAqP9`077g)buqahhvO}VSu?#Hk_Hls zR-^>E`|t43xB?Fe?cVk}BKxy8bQY7!r@ATG~T*c_ar;I65rx)-%dzxLyw=pKDPC1DCG|R#4r%`XV5Tm*9i4DaRAc@|GaDP z8%=#Kz#{smeNDYJq_kz0nB(QeOj< zF?gQA)#X4+Si2Q8EmZp#;y?#Xe-q8X>OXwCj$!jWUFduu!8Z^^Nz5Ddw<3UL4e&#Q z?Y27tMrVLo%9-J`XP8=#u!8bF-}%8Mojkp3-6 zL77*BHj|-p<&zh^XfLI7)~R#EZ5;_%6PX(@tnjSp#-y+x9c}>zdtmXM4*LfdA(eL6Jp$DRGL(^b8FEDiMrS)A9*S@{dUxT+Dni}5wH8%GB8(P)e&%hxQ zKv)zLeJfp^ONSJ&7o7K+_ZZ#Y9Ncb2RCuYXtL`qdpEc!1Wnn@-X4&eoek;Zwn~$Ua zV-~HESFVq-9r4^tmD!kRMU~z#Ib|L>~ z1eDE^iA^LlnJdXK&`>K>arU-DmCjhS`4h75&tB#;*k@~Sj}~$d9-aW^?Vrb8KGNO* zK5G8}e&K+I7U04B5mZV&rPdrsm|VP!Iws?$=?XV{+n@gwO!$(c*}6@%M#vptycrHG z@(+PZ0j+Jw;qGqVZ1mfq_X}vb_Ijb-GuqIYi2q%-;EW1Oxeh|U>E33y#-j&RYlXgm zm6f?)H#rsoR5i=|E5L#iveWFB!XK~(pVaU{d@||eitUy@-8Z*W)u01Kw>T?h(SpLh zZ_V-cT^1f9|JG$(L1PU_d-mGj12hXj%5+5p5y<43m9#7I8K(aEgz3)w=!)F3x}sSu zokwC6-RbLT$~3TRXux~{E`%J8AOBVWHroUIo8JeG_WkgDlgLU7F^eX z(CHSafJT`>ROB}oPmta*DDn^#i^1~(+$;b##S;f-mz35XcR~;Y8}G<<6`hFr`=jea z{{~ul+;(#+_YuQcan1wB#O}>Di06B6mO>sL-6_uYuYdL7Hr6IS)cJj{y*cl@B-vj z_XiMU0=gUk7KY@FnAfUl1_jB8a{iwkwAeQ9L@YKz`FM>ygdy%J2>cYA3y3gp00Cal z7Op_wdjp>qDZ#%1D!(9r)%(mN3sjTlU8({`N6{nCs0N^e=SaWr<%=@puU)8d^tcZD zk|`qA6}Dcb(>Vn>6IRAK=tXDIM^}HJfjc|E{24sE81Vv*vvQTQ)Z^m2O18MU1I-3>5tkF_N)B1s-=Q~owlkTpx{Dx`?;LaE?cU@FEvZ6}6b zhTypSuw;krB0k*XMR8CNJBWWm`Bz%|VB)ce*z^f{nxLTLhw$~seX=i3wEJQ1hdK~4=lb}r8y3BalKxV9`&1iQC{?k z4{d@p#|eTlYbCJ;_P^||fWy2tO2RaL>k%w%8(>>5b4F3qqeZO2An$S>(9vg(6C{J7 z2qRiBIUCpg>q5lT+h#D>PcIj*XiSoz%$}^Dao%&d2N>-)954!__=x$qOD^g#1$oij ztC)ydpQdj@aZ%pmig5p4)#HfzkdF26wxeI|F*8N!{y=QN!5j5UHV#cow)~K%GZ9@D z`A+~snyNIqC5^QBxT|*({~j;N@5sW;xN%~> zDp07JQhoY@e}Ex+gM{+0FlXLzH?iP1ZQb%Y{E&ES94k5{lsER0w_D;P6B?4*rUl-v zGfa=GkO<#&J^B%3KndzyS;=b7z} zpQd^!K1aX!ZQJToE0{853RVaHhFj*I^T${K21eX;pNO=VC(dyTc@I*I)0W5IOqTv-1EsT=@w>q*+NP5+w&8@(SQe5XSbUV@KJg3Pxl=5%c79{yr7VU%{rhT(Oo>i7 zj~&OJjIdHhTUnf3$ouD-<#Q%gzHYqfRFGoYd<cmDML^iA_6gogm#$D#Pw2<@zFno6-SQRn%+9BJ);}25tr&BS@lQR>H)+T`| zXfNgU$p*gA-I`C~+dq_Sv~{9^Ymw#~3jXmMTfT4HWz`ftv?8x5EkwI|0QUVqv^sXGfjQfKCCgiL}PA!W60G+z7T3IojjDZ zy6o^Zyu2F{?=3z#i{=)%8Xq(`90c*2#rN{L-#Et#_ni^x(g0WF6PIQuBZH#|4wh3y zja3GYtY=O9DP9g|5i-GRp-{U!*vS%vQXgbW(0(~x)8WQl3uECvPv9kft>S3fo^X7e zCQvB;6nIm!VcmSroqvTN@RNi2q*BnmhQL%9GPX<>MTEZC-_}d6nw5Essl|2Ff{r;c z&S5E#72d31{AzW+M6Ii;Y31&Q`>*ZTVH0fD z-OUvboZ@&W6NTgxCtnafb;)Cx!PVf(J+gr*rvSY5td9qZ;(GZ7u1{Mdb+{68$Moyf zyQH%NM{&(w$*HX`3Wk`TugTt%30DiJ)eWz0NRKVdgGwF7u;k|3;SecWhm_|WVK(1t zg!&A6<%F@D^R!L<+Qd|!Td~UJJaOeVVsp)HOTnu~6Ng`UiAvf;0&|k@(C*|n$;yKk zx_CwhDmB5qDSoo!1{F>X0q}QCh7*IN_|msPoYE&wo)-KM+)#3IS-FcI0x5k>*)JSx z3y2&4>^Di<&l@vR<+*}u;GGN{o6^Z9=X@%u(_cqOO4pRNU@vQpq!T*h29&*$q~~{) zy(BARnHx(_{33?SOFZX?%RNHW3fNon*7_$jvqh^^TfPMurr^LH{M~Hn`->xNE?KbT zLSfu7urbS!i(7z4=d9CH=;t&d%4?QKhY-8}R5DNIb9v%lvL6(lQs)^EuPO^?8$+~C zZFc>qi&K9l4@t%8o{V9#ejpwbJ!~$y)`hwKjXhszsf?!A7i->MardaE->c<4RG(6kL|^?+HHmY{OSm|5@i`Y(_$s67F%^_5gxE2Ne6r|wgXxG2wJak$n+e?P#!h_hwR9Ld z20c?k6Cnxz$wa|#0^KygLwI4K-FvH5!QWJ)W6Ra(FMh*-bR@uekFK|)+tt1?iEg(H zxKJkleu}3E0Fb6SQ(mPUndi6I_4VFYo-9pcc_>WWGhSYkN`zm2SC=tR_I$;B*0j}g zHWke_@Q)nQK@wW{q#-kM0o%DCzSp}&jzbaYEHMB2Llz*hTcn*_gu#NCw`=Jy*dG?f z6i-(q6lvD_<-=&Nog5N@kA5!O?WMpaov1F?#G=*SvO#mo%p8fj7Y-I>~j zLce4<<%U>K?tfn&&^&}J+M(yPz?a6md8=c@-=uvWdfU2dJ=fd~L6QFuL9d|~QvO_X zwP3HRU82JD<$9%Xhhl7SkqP(2&uv`w&p`1M1FnsMMtK20o1V;QanCyH=W<#Tkc z14~#3H>cn{#8#18gObu72jm)ENLIMDJF~S%x$E$O=jy&Z>ZKqWvm$w^t!_2l98>!Z zYcr=m&aDiU3A&wEA6@e}0ojOv%rE)t2wC11hMi=!6bXz$-owY^Rg@tq+0W^UPmFRX?IYgf{EHhtOYgf)qab(&=sD5Sk=yske# zxK_zL-EJ#5fgYYO+{*=syd3Jd&h9&Uuucbj`^hNa^0xAP4(vvYpS&YXhy(k>T)N$7 zZtB|n=DVAyw6=&O=LpXOenfVfAV+m39dkuxnZir^u3_O07A2_hE^#byoVm-Mm{~(Y=e+;z4abql$CzJ!3oJWa`-z@*no-a`IitggjH8Z-`AOi7pKUA*mzqo)&x?1 zo1NIbFZKrZmrEb!H3^Z4o*xCbQ&s%2M=!n)?VbmAAOs%Q7@hH5nqN^i*%PUAf~D-{ z9o|EtxG`8gH|C3@=gwmJa7xNZ)Kr~UDF14=)QQ%c{(MX|BoNzfh#~{4PV3*B4EW`G z-m>9VSixMlD_~9C%*=H!;i+-c{GB1N_%ZG9dmZ(933F0ET_fzv+ouwvR<(&DDp7)>y4`1#7)^Ry zGsQ1D^Y6q`J+rREY~Q$KxYZ*ZLg)g{h?KIRo+=URr0OX8@2HYtDv;5_^-eL^Wsu~# zaZi`wO@c!-MuyNE>mg$GGT%KMBHPtvPl3t%ICvm@QzhyO?wHQ1*|^+FQ_g<;T^kwy zc%-hd_u$k`-g}XoV$SrcX=DlA4~At#6}6t#@kDO!Cr1J&X9w>`(}hk;tQB;Ai}uKR zB5`(1L=p{#lZARcEY`60!p~5WGlon5M^;6q#QIw;g$iMmzW~Xir*@JPc50*c-JmRU zFiL}bbfUw}ZSA@v$gK!9hU8`?%c$s?uc=p{?TK0#j92~b($!m7%5cAF{P-$3O|^d7 z7X2J&#e0mpIxoO1h@y815)}~eon^Yi<>EBcI`y#>-rAdXre!t%xG`}26b z20EutA9eJ4SzBmqcV<}4pwP2{nv%QUr8qs~R%nwrXfos-F{-^ZUOgN`zie*RG$4E; zHGZ%_QSxII8}EKqtPUQ{hRskQ5c)kZr>8%``b$jR^Lo?-y4^Qa%hAQIUhg`{AOU$l}PT$NtcwVZ`4tP^^+lmrOIg*G~5 z52TX}Gf}3?d36-PhSGqa7{nV>>H$nG6n#uyTAW<*T-?DJCC2HHw?SHOyZ3kDLJ7=b z#L~(9SB8t{n2LSO)m&t4Ya>)nGzT-FDfxodid#1ObM!C3cl_vJvG*RbSRX;;#oP5t z8O&e&Hk+=@8eN9__fcbq>3$_KDM;oB82?h#hOUB6HvoOa}ND~9u z;)Rw_RJ(enr8$@OAYqu9qd15>0?iFE6Dm>;i<&bx_lR>FQ1>p(z&PyTG;-7*Gf;T| zC%5WDm8hp~G>>Lco^MymOr*B0vXrWf{W(6yWLx*r%v=-8YZ;C<1zTWcvr!$b$e`;h ztAuIw84(XEZnerfddm4~)P|vh^!0#n{Ho@g#0)oJ-^>Cos~-GI2nAvBob;?a zH@IhZUplCD(=0kFV^k%nC05^NVV{`DZBgZX}py6BAItd>q!F|wvk zV!Bkz!}G!bVWn9r7{ujW#x~eyzlqRM47*rBD6;Itdhv`C$LqI**f~lDn7h%5=~#MB z-)5!3HMn;%^O^iZd!OwTroIDyn2#GRGc>c;=u=N32f1CGkUa zdx42}v$u9psMr1^>M;*6^^L%?A88K8WS-%)tpXEJJ=|g8nqD<^*wZ0!hiJHy&jlht zuLVb_h}Lcu9N5viNYLS379VmOuxeVm_!f+KN_R#y ziIt3wn@-!_^6r}UP0)iuKGhzXf3|cU8Kn9exF$=3*VIyr4cU9^5Wk%+9{)*2S@Q|b zERQYvS=@D`&t_T?AC6C*nATRS&s;?y5q}fUyy-7xS7}ghSRY6xiSociaAW#Csp{y(ahTV4g8jEc@%j#muf`DlxOuN|IgXY+|Qid^ivGuCDrDNh^p6#sovuV=M$RI*$lKitx z`W?oa(SWhavNlK9p2khPD9f>=q~Gyl7=}fL35bDR($SHFv!{^(3;1cHJ+KzEQ}4CD zP~HoqilpnTeB$!1Jz-%}=8vsa#HAHFE(zAyd5W`(8dDRj7G89bcysX{VvEjJJC)jf za?QvbgN_)5!Fj(mgdw@$6QGi6pe)3)Jnokswnx#f@alF!x(*VoW^FD>M)%Qi{$s;l zIT1@zWO;$xIvG!>i0`XhIn9(k_+PI}uP}%RC5m~}KHKilbD$~^KA0lBADEZ@uBOoo6V)#jl2VoXoc0LUA^5l zA{Xo5c8k3k;|psRc0OK~LY7txl1o1N*y819%A;6f!zC z>RrGLu7#0pkYnnvjUw=s+~7X(e&}N5kO7pm-AF4fud7)mAB}xmfb*%>^wR}^u8tC!#p&y(^f#rJM)Xb@N`t5P4-1^)Z z{I3s`b}RdyMg|5a67U5CS-3punkKR{YmX0Qp~pGkt;ObIsVoU+5_Q!Bssqs%5PYB( zId3c%jnjv2(G7&ONUCWV$o3Uwa)diu(}K!f9f~475+CLEEtH!u)g^}VDoG}RE!GHh z%Sf}EWCq^FkRgmn_9Z2~FoMZkj(^TgPwOHiFr}SeUUNbZQxQPAb6ylE@GI$xB zYH_kRx_xqqGl|(wkNP1?5&}MR!^RvKX=*1AD=fWv%br=HXne)FR<#vy#d$5{mi=s) z2s}Qz-q`i*-ZE0_(wQJ)jn56wyOsbTiMCwVjpUI#I}Dm4R!bc{<_3!J*%~0V&Y&zC zw%?SjWMCdOK^1sqh#e$WW2TXLtFzHcTO$sbe)gfk5E>3G!r-Y_JxRivH{@Wcxdd6R&xwe1s(R*?0OF+pjRk<)5uo#e8O#5QdKUS z6M>{Zt1t|zjZ8)la;8|8*}bnuJ>gAxFCgo@DWBpih|F&2jN<0UflLD2KT^)>m7!LZ zkFvv7LL!$+;mfJ+N~`Hmko_FvoO{H8Jm;?XUeprW03nyr3c(=F+O%cUJSi9o>6Htk zIyr{=U}n5e&ZgQ8HD@5BfdH-wBaj1$bFJTa2QL&>0@=ZxQ}3d%@_i1Mvzx?}71Rd>)_MEd)JdN+`VorC0Mu7m2O|E*lvrOS0c2BRIgtC|oEem43@CIT(0#~4 zPy_+?^vrgX;Z319VNjNwdh$8$PbGP03?&jUHD|d7V(jvE7ZNq4kG8waS*tGziatH zKu-5;Fw)~JNKzltLdXjmA4TXC)ehC~W!xYWOo>l)qHz;-xu$V}j_xJA_KynnlC8f^ zMU7!dvcHk)A&=e#&>`d9#qrvt4>qk3==^95Ys(ZI1$>M>;M@Wo5$5Z1AW|J|4>Z); z8a)4ka2#pyyOH0*k}KY=cR9VKsMc&kAM`{;_D*Jyy0I`#R4jZ5f8)sQY!?))Qa~h9 z>hf{kxj4t?s$fU|+e40v9uRp!?pT!C~-3 zEu@Ba+_I+suGBhe74;5vMgIYH4$-YnF}FB`#6|J19fpOtp`W9_q<~i>Aq0vs;(xEu z+sMMA{i)=CnU%8`93Y6Qd#Dms^yty_cs@m`VH1uRBQC#I9HUO2pp9?pS{k>BjlC|T z6!>UCZ>7w6iOHM9-s`)#Bt^0KEOUmA1kJP!21%IFPOsg<$IY@=S0=mK9&g!I(JV<@ zHe@cqq3+oS3z@XS-etajXf9q?i&;^9cfOxg&V>H`=hAn>m$VXEyPirCEz4#fDr%YY z+v@Lb<;14pN~(jEL|Gz1$XaS6mAHlFk%goX70MX&P*wG43vMx!s~iN)^{BQXf7C@H z-cys}D=X>}q{v(}^3bcb(oA2sl$9i&)uFQdsbpy@27iRms8V5~onzdO;r=9PN4Gj2 z3s-Z-F@4mIq7PkzqZs5wub2ISqMg9;f}f`<$0bdDn8e$PKH@GwG7-4z{;q1p;D57-30oHl$30YDF-5IL zQf)Qh80^;iwic%pAmf*erA6$l6RJM$I#?R z@l<vc6vACOIw zqOIMLwYv^HXTSb*h9H~bY$rp9S4jJTq_5ZU@me%~2fLUK8lL5PR#ImCt_tllDuiB$ zSh#b2-RFXc8Xte2AuSDcL9l4kBh`{OZs+IH9P?A6e+hqLf21oq5j z<@m=0uBe7E?vt%66L-UQ^Q*75%s%IppKaPAR3w#+Lr()lI{qt@#*JL?FVSu$es}Qi zlNB5dU@mz?rT({85DzT)Lzg-haI`$+dth`D0sW%&rkmwU(*RGUq&>zSQylXXJ~>kbH)$keurevPBn9Q!v~t?} z%Y-|)HbOpRqJWUd5-85<+U8022UMx6mqZCeyNv9su;3t=cOV1}oNblVWIq7tt>>JO3Mx%t+M&EJ|3i&_B0mIY08% zqJ9^9`L<|W?~@)VjgW+%G&od4CFRG_n=`kQ;+#ahh9RC0SpMOwdtiLT8&vS&sm>G_ ztE*F_xssovQfhA1m{0vDx8Dgi{oa1O$%(ssZk`rY0!ZDM!S`WOjeoET_h?NQydj!Di|Y=Y#0xU>5SsDL_xS2@f~yCQJ19YTW{ zKhdt>E=Ih(AM2^8oBZe)C?mM&_TLbm_z&n|{FcTFw37hBs7*Fa2%51Ew1_>8DFaW2 zAgEW&AL0btK0?_C1yA>(ttUDfkFrv}vx0i*TzplOqzsL2!CIMoxg9zvLq*Vr$z-^> ziVg=sXxyGn&jrm4)nHQy5J5@d%Ja4lf)DXU;8zR<0!v||5$rPBfX$!>=#P87siu8c z6Tcnv&%3a$dU_apOdP-Oor#*if^SN4`NQ75;Oij~jujZE6U_tgQ_ zjeo{@TG*fKTFcv`Y~)=EW&mqlGf$x4t4&m7znDrPrtNKwej^uJpBKkhdyz!6=Q&ER z#ncp%$u@V>8mPl$3%YvuM@xkI)_wYcTz8WHHMxp$Jp53f7MJ7piJ!hdN)4U7&(WU; zxUFvz!iPjOR$kgc8!4H`w=bk^iEl4riMJiy0j|8!hu0GIg7UUG60hB5WxWA^Eq;mx z5a9&*r2Q1XZbZ7rBEfn@@=bI)X@R?* z<1jset#Yh}!$;Vu7Q|&A^e9TRNYqSQoHW6cB&-*cN(QLPFpzavJ*=&$VRTi1HU3OY zhO0VR?Y}5=f`CsSlI+g4r1;IWV5YHO=i#Qq3G=LApurNm{-lcGu>Z3&+*9{)oVNFP z@d0#+g|R5#@*z(h>bxVJp?UOC7h4nMW^(w!1;usa?a*vD>!5@f5=9$MWF}plXcSknCt+pSjzZ9qJ0evnG&+D32sR}Ne1L6TO`G78_6n&~cA*{#uxVEHhbD3; zih_dO{$3e%)@Igl9>r5LLNjEMpO+?HD%Oh?qPH6Yi}w}7X_dLwqe|=LDo4>y_b~6V zR_sY!vg>Un`n@6QGmW+0(N7 zlKzsD0P*yf(Humi<(uEYixA)ZDZ7z3V=v$Bnv%Hu&OEl-a-5|7xmu+8oSUtoIkB6+ zx(2NhrTYo{AGcE@@prm?o6CNB1wLV*f6&Wk5W_y|zhT+=a-DVPm+(G773kN<;{QrK zoe*>QU$AAybZmq{Drw4x|GZ##-LCsl@P;sV_U8(~>H|ptVa6SLQ>lAbqzeA;L?g7i zA=5_X@ob!uh9cB-gDaw$NFx8Z2cjofxKD8XMFH<~g|#nGF=*XeA%2+n86dl(5!F8g zRfq93U|su!h3(=-u}7Kjc1wvFd5o?qW}2b5l3Nh@r+Ly6IOQ>8T|5w_4&CGMAPuNv z%_a(ehiPwKv18Czmu`SW3T$+cJ`_TDBHUOwz9(&b+TyQy^4fzRZY29AveAOzL$qr3 z3x)mVb`Z=$pqeDH6C;v2Qiyb8slNm}{$K*@G9D(p-eCe!WlR9)Mr_Lk_NVHo1Yq7_ zy-fi|V1dayy_OpMS$0)g;dC^J~ru_b-Oy~lu1QK_I9T}Wg^o7TT{zg@mr}71K1e8T?*S!l;eX*n`4%-(=l)%R({=w|xs!igPgvallvU~Iyzh=c+ z{-!@B?_n2`CZ&l%6+}g;gAbAn!J*L>;sUjY3B~LYqvwsX{(2-+eI{#U!qF&cwWVFT z3ZMCpWcr>hOm|jK1X=yXsghK)NU!BSF1@#T<{tC5$1u+@hrY(mslyuvZf4$_U-oZT zJGL$IKOS&}S1!b28L}Nfu(>-eoC=);^$d6_i<(`D3-q~>~Twl%L!HAjj7O*_C5u}YAPy=vxA}0 zQmF5Vs(ru9j?=!(d#c_F>$`j*%{04y583LLg)nn^xeDN}p-b)mCD;WH;7Z)(%|EnmN#+QpnZ7cG$NC-~{Fr^kp!^upSxCQ0hTLSTbN~f#^=pYc7|z*1(r@4h zc$FcaJiDVVp*d#LTKIn$3O()rF%*t8sNf% z;seQS(Nt(Zz!w3n0avzISPL%*^`kNpsa#8=!=ZOt)bcznqHH67z|4uF_gCS?K{sw#)D&I>>U$lX#GJP%SVV z`(H|7WORZjrYZL#Ls~#hjGRfxcehP|Ak_%wK?_s1=QW5_%;IU1LX4e7^+SM!g1tn&+e{ro2+j+FaQ;`DsO4#Povv(Eq@7Zlr)(_d{RSfM9}?ZDd-7Zx-C<<=5l z|Bp)HhnNB_!E+Xo{Lc&~G(l~-5Aq2@a?`im#a=&?2bQ>&(4eZ_0G$)1!$6kcJ%+nU zLoOzr_^`~77WP-w=}_;UVeZr!QA7)sRLO@AfH$J3kuTKud(tRK>z+uz-+-}s9P1=1 zHA=bfNH=_K{4gRnKC6#+)GsN(w8>i|0Rb^L5_al&QBE&3_oiGpPNDis#K2u3W_a8h zz&x*zOzKr#kJus21>?NCj?Hys>+7*afU41X&&WHv@QY*_7l)4P&`Nj@1FeMalLmdJ>%29w z0?l(y$u8_I_HMqyRSG1-(T&C&oCtYA zNY-rbbu+G>;76iP;;Bv&#qVuCK9DEkU8MZB4*_l5lN^`Hb<8`j0Dl`V)?kwK?28yX z*hhf~F6nI5KEA)a-#3Hau^)sFSX$$k*>Er0$1sTk%&y?tAD}lVb}+w#38-22?ijkE zDNvAk7U)eE^rd^4lThy`#=hZYG_HIX@`16K~^1T%jnEXs)WcZZ70f!WFD0SyYKhMfaNe{a;Lei z%-kq*IE`k!)83&DiT_d6>eT-8xvY6aZYfvyU|_GfYKqc6kofdqRCQ)lg?5}f&1p@e zy-OwZ9|b{7V!x@TOMdW=g1{JSEfz_O_Ew8DX%;(lKdmmH-S5|PFQj!dlRt!awZ6`8 zAne^}6Jc~T>+db2TlW>AL1&yAB9)FXlGn`A<!ZAAJ?X8>gs}-guU$~>&TOSSW0Xo&ph+Q+HYRJ;c@|fPvzgm98Y$GD{(?up?uZT z;Y)V5;_6cd7M;BI?BkAcobN#zP&~ofs#z6gZlNqjEZCHnCXHD4;Rj3tS!(h8&_r+2 z%Ga6pEJ0A`u(_M&Zp5E}P`{RD*$=f(gxBAwGx~aB z8jF#VWgo&-kIO5kTtm`+qzD$0AZ)2mfW8gVY@{)PD*h%r+#V#`aF6+05V5qTa6EZZ zhuvV^zE_TZcVY?hGC!mE!wMY{PydBz3nj230cmcKoeYn8ZZIl^oLYD#>)Y5yQAkQ; zKCFiFD6+2{-K{oqCSBWB2Wnzg2sW8~a)P9Czj~5zB{`z^cN>-OY>CJtgog!M8Fz?@ z8xE!VczQM?KhkEn@K3=Y!xYQXvHLi9!JN4viPSS_6x&aQ#Ha=KfBHb1jfY)G^vBhh z%EsIxCNf}8^rq^`bh+U5z4LNC*=0JYe-^PKa+EwJ){&r#wF@P9g6U>$jQJXb{{5FV zsCrIJU8$9_GO6~|yYWnx)@MU$bgslN9wX^l_$WH>lOAn#%R4lvhknN zH&6+Ih8E8ctVmQYADDE~!i|Eh|HPvjEj$~+KJO)HBY}A-!%N6D)Gl8hSsYwc9_WUE z1Gay!aZI+(E4EOEw`IAX$VN;*Q+)FLMo=$RvTwd|{;YN4_UBqXVg+Vj<@ZuJ?Gs;C z*~We0m`&{aA%-SmTPajQ!tgCe7$lu)ji{1xznAN?=d>|_z*F_o?lFj(Ci%LOkxj7f z&V&&So%LM3q?%+rhrGs3Wgm>PF`Qe@mN?svjdOk!3lSptE6)A(g0RCg=F454zgyO3 z=(;;E!g7IAOJd)~2X28tERr~pI?I#=ERQKFW(7#kc{O|;yuPtSj=vPv3P|3@F zpEx6Xq(CHSp8;=`%rw6Wo}lOPCME3GE!tn@LlubDC`LZK;}|da*rIO^V6=p?Enz=W z+`Nfe(d}mf-DMG_5q(Vs>aKa0^<1U`1(aJvup_pO(ZId1BWXN!Sy}`i6m2FxK@eIp z2YxX8PQM9WD-$UAK#HSIAkn%s5)u3+L@ZaI=;-7GwSRa3@3_w~t$FWwq~%j%7t0!@ zJ&UeY!7kkf@=Ka4EkMjg!)EcnJmL7qX;c$1ISuIyxecB({|>?qe=d#BH*@$nlQl|ph-3#76kM=oD6JRlI8kGZ-^6Axxv)Xd7Y-lPhPNFO zb-8&%IaBWi?_R%GTSrX2!5#$`7>SkG2MhYjBOm&o5+l_tT+<40CZhHW<3lUBtq>0B zTEC=IJw5!2G;yNEh4kTwFtgru%XiQCTdbxQ9tICG#&XID5$eyI(7TV)Md7+Y#TJO% zIL>JtflFJxn(~4+KTfxXJO$N9q#?frXg1`KXFiU6Mab<4;exGO?cm;#M+fYRsHN$F z9Fe3!@ru2AltqSQkk1q{QtfO9%CIh+1Ls`+1%Nk)Qg#_dm%S5#98BD9pT4I_i;o*dm zzrXd;{VMLl*URd+CH$yhX|R~DNRznss5l|8M+T^@h{W`TS;~_8L27iWQ~_y1P-pm{ zi3f`Pbhd)AprXXMb)yoqDmHr!4EWgoj2i-a2pH5fT&+wf!HGoR1#b){Y{n9VGcqJG zZkUj`=z&UpD^5kZN?C=<>`U3et@Iq?wGG@OLj*4`3c_mrSfBBV*q;wDK!TvyR~9l{3M2>~@eRAe5eo%8 z+(=GO{}6<@5bxPnEffR|xuU+g(#^l&g*v4QInu5HFN5UzHG0?aq9x@f+9ItUg$`)a zekQ3QO&HyxX?Br|Bqe1lmOe_~al4dQ^&XowNfGsc0>Q%tBU3eMRd`?ho2Es6)upUv z!O9*5BVR^nGc_Z9(+RozLHV+ZvYgNOWt=6I2k|zTpgSJcJS{<4^zh1JCj!&W=;j(v zzxwv$^E|Q>s!DsNsI5I(PKP;DB+P2`Fb@Vtbn?#Qrq?~}Vq*8`Y(7qOBI&POBgMXs zcIg?A1z@EYLYq{iCSGiibuV=BWgrAN4gotXyBB&7laJy5hyyTTeQdM2pDMD>6REg0 zv@S(bf5I;jZ|csJe%D~0XrqT@{6h@T?OdVyKfetM5HTyYiU$dZaHO(Nr?XFSDJ}Oh zcY`kWH+7^SOY>$IhK{h42a&?&GL7W;Kw${JG@kWZ?s-ItK52YY6dfM{?v;Q|94jojH)hp-`pH4Dc#k{rh1_K1rJkt6vPb)@k8pePk_h8d(uPGWeof8C>7 z;crTGEaE9@ey6VDu;?yJVSHjhX!?!&F4^;n^F6UVJLz6jUJSc9~WpV5dv zXD*t&F09W^)Zu+6onU|0XvH$#Gzk#vM@Xu4J%k{TDHN}Z135thc0+`!bdfk5Mr|p0 zFO(q$0|vygOm$N3kzVKs%~N^Ap3HqkY5Ev%l8Tz*3|m2#OkYLPUwOSr+E5{L+#fN9 zo?f9r39VJs%9E=g#SdVl$pI;>Da4gO=V$P21wGGK%Ld;W)nG)}zo!jtEAFE{)Oh?v zH|dP=KlGC<$%c5t%27TQIsg_A{)Y|7EH8cUU)N!rlJoF>Goi8z5g4*VpnGx{dxYDp zzDsOK@T1FRF6GvqWse4F)KEu`$f)X7gYzVer?OVknxp32v_=P<@*sJJgA-r|```7| zV1NFZHUt%V85qMe?}^$>DkQGXgkAO$4ZhnB4-STQl1Jm~>@ za4p-f#p)j#@Tl!+7zd;Q?G(qV%5l%55V<1<%-V~~Ff*BkTA`vnC92_W0-6(M0kJ4^omWe(ZGNm9`|x+)Jj|{{_@s7$Eg=DskU44V%K;S<~_}L^tjP z=lo$y+!d<9)Uhk^p>5}2*dT+L`{mGnVYyxaH&^*Nu>8nB2yuP{4^@yxl#sH4`L5)_ zOEy1CqXV*DhrTm!z1zz5%$8{x#&g9p-6x5G*?da{T}Yylvr8!9v5KRTHHd#Nv@}dh zAl}#`?MGk-%)bbr!}8#F_~t5~cK~cfg}&c7yA<(ohwtHErZVj^r10^oWVo?)GB-{p zxzYza;cu?!+5kL!`8{-boVFOcSF-l}f`-2!RzdX#ppT6nXZj;X$Je0?MX{x2L#=yC z92k)axQ(AGG1vwmYE1;8z@5fex*=Q5UI2lfK`|EWp?qu8Hd0na%8Q%&kI->VJZEQv zW^I%}l#V)*6)N9Vbq8Q@AM=RivzB5Z4l1cdKq=X`G3%dpgpPt;mw_A9!YPOwOo2yA z!fd3$34z+?uuOb|`2R@%%NYKf{{Jnn;WG>klCi`Hb z@%CuKm{r{$CD_G?!2z$q&Uz@#5z5fDHddoWT?s9~603CHUlHj#gwTrwXN+VQSph8) z474eADNhQ7TJlXN@IoUI@IpR4@G(;)bxXuCyI}I`wVH+$?mGp#WRh*Q3Fbu|wIyWS zTsj|hmUwYXYd85EX6?vtz|4P>t6T&=<+pfic*|?wfVN@449BQ4lwno;j^m)Rk*6Mp z36l6^PIdPgAH!<(^1v-B~%Cj9Pfbn$xFhJP8-93biPVEXn>TfD8&4_DdV82_DKN z%7>qW6#JOaQ>+H^Pi>ro}T~uCV&l{Q~!KhLnh&X^tTlPu!|EKSA(t)~hO( zW}JbI`_19oE@&5~ZfxIzm)*a(gGi=vH&I{-3gk+rfDJ;4^vz{}|B~sTV&^*x3M%(l zygRZ``NXb#*Bc7L*|FXrkPV-+tDJi)L-W^6EuTiPhvSzlJPx7>XbUCJI0&G8A!z@N z^;I*Y1aGk(lp@Dg zVisLMFIg$N zy-9yKac)hc^_Bd;p*>hKU+>)MiLnnEm*C;`-)~MORCmgg<}wd%38)dv?WxpW)fxEn zv^?A#`<39VPS@FZn+-U#j$vCcks6ZOBdz@{D#?Ddh24gy_8|{Mny*MAuiKih+aV9V z{}vC)U#EiJNSEVK`YZse*fo6SI?m~?PrhX%h$21AVEcHAs%$%y4Ws`}4f_Zr|5RLq zUp0+}>!BIkV6POA!%UABO4Tr}*$V4DUnAlpEFoPy5%@)lzhm+~Q1WNQ&j>k0fBSOr zt@WEHx|0;iEB$k1f%3!eLwE@da&Ug7;by}uuJqqj$y-H;_RkRt!%6d!+&18}gMiT& zauA3oZJrxj!F2lP)S#Fv&z2adr%u_L4115@mPY~D%*dP*{0f8RQT9QFe=Wi<1wpf$ zVX${3_7~{%wSY^HWs3%qM{Nr(fcmMqbQlp6ux@`+!9Bkq4mi=&X=c{rK&f(n45?s! zAP02t6;R&7gZ06~!#JG{R{|mC!;L%3Bnv*k*U0{oXOA-jRR; zkBKZ(0pPFz#`sIQrY8939Hy4P!10<~(h@u?xVWWERB;6Zwpa+LezoN@6lC*g-;A-r zNQO%ofeNc1ih1YNVxE&BW;U~-@0W(D=`e)$8S(7^V|wtW$Ut}WGWIc1fHQZH(POFm zYE8jUWT%9|C8Q$^&5N44(F&gdSDmsKWj#$6$wEVn_pY=Nsa311%3jf%%|D6!2n{)UeWtFdl;eKk;DQU@2NHjwTPV5H!Y~gS_iw1T(iR_R|0jx%*ZccFQG6(Yfwv0fdqlay^ZoGtCV%Un z3(8?E%PHJriqflu$x0wx>p2zh$|<18!l&dOG8x zJSm~%XRN&xFk-Xswx)%SwXKG*yI`S}-9$a-vf(tL-o}-3-HXmBRNzF3CACfuU^pKo z%PuvWZY|KF-$*u9I@SYA7jOziT#Maj-5DTb% zVk;4cConQv4D5JGzA``eu#eMc2_)xUKI>w?=4gK~UON7jQ!H>_%Xo>3kMfEXkl}8` z3UOadjwJ1fb3Pog0C@tQzLrJ5Bu2pAC21wgEwvm&*M%Oi;Z1hp?%PE~NPXsG*!E9! zk`bX6TfT!DrWbSJS2iQ3#p2h$br-%p(&A0(FJM1`s^imBByqedBKP;%H4KKkPKO2x z?hu(SYacU4j=EKog6Lh?tlu1e%5xz!_|z#icob|^{k`-abh!fAEA-WTAvz`^M#)`{x|GU- z&uvmumWh1Vc%LsS$W$}WLuLh=(&0LE;ERY$B=yeMiFmH>^~)K zCZL5=&EEFoPJ7|cNKSIxRo_ypb%%F%cTdlkV`)EbZf*`vPGas$G^k3#Bqd8q!fLVv z2?zmxk7qM4^Sdf8J*1QG2MS?f*3TpTqAM16U%2`1SF19C;}N&haKl zydDI_-c!xTfk3~4sZt9#evjoq{UhDjM|l0@hwITc3@?~@vkb&0D72wU$!XUz&- z-3$(s?)dh(&28W`3 ze?%_iI_XqkP@g8aPNu1zA?Nc=Z$l=j9l{i;6*KiGtI^-$Lu5}XFnt9|qI}65bZdlB z4MV0zM-pbWJ^17`b#C!xLHnVw$6Lt4$X)9LM7TfT$ zmh<3$jA#0NMQ$DP@~w#P}=+e1&;%P(}@n=|1ArplLs_PIPim#q)OO zQeTLs^!(1s^^=zTAK-pY%~=-cFTRH3HWICgV3uQc_Ge# zIKZh9sze7bItmYJ4%mq$@+VyU6G$z3-_biP((j$-BHs1Kv@a$Pa}kiO?a)(va)*79 zu-lfW%u6E;o8!-_CJS>NYN=Qlj_@`ewM<0(UWbn0<1@mvhDJT&)!)Uy1ywdC0S#t= zNLg+tdiyo#4^%Uf?@U~_glluAFJCAl{x~0ke$JY?Uy@cH*6fhpo2HRccLryj|5~=+8hQ9SIe2)?_~#qk zZHI{e8JI66-ZedC??e%&OH70_G|~4Wn&%P;D3qGKzxgo(aniaLON_fG!l7y5{T=J% z>Kzzr#!Z+?=idvKyzL(tW)DJR+vW5e+G?5XE(DiA^ZSE^Qt{`rKf8eBJ&`;J1Tp6K zKM-6+-9B^${JQvwZIJ_ZSY$8E*>!(aZ*#TzqQtyNBINLf{LekO`cAfTeg$F$0E?JB zr1WBfdoGV1luI@SdV{}1&XRY`Kfv~e@IZ=O8(YXzQ7PV=_XOPCvw~IK&G8C?2Kt~& z6q;k35eyqCdV}-9s33WDXgz?0Zin3r3Mf|M^&vQ*>@rgiLi9rk*Y@)pM_HMWa zBGN`(e*(e@L>)-JyD9QMx4XMpuM&j2nLPHf{{`3O1B9a~Gtd(+1ouK)C{~lONRPIZ zN;V5=77ooz{ngpXTQtJ(7U48&zH@NL{zz+(m!z8B@8(qqZD^07blpdc7VO0yz&`a~ zgw>kz|41?1T^Raw=}dja;WCGWYbp@3j<20D9Icoa?$KU_P@1hMNh1Z}^Z&)zx#(hhjsnyPJDk z0|7H7-i*)^%MAXm-c*h z3v8}@Ibzr)&PR*0;*!xmxqaBVk;SLX!?kNeZLtE~LU+T*M(8H)9ERvM;K zCKePgXB^-P=YFX}q3D<*S-eXs;t~2KG7ekOEj!sDi?}uJe6_Yz8OCG~h@=s>$ac_5 z^t*~vrD^fSOe#LbEIH*cj>1XxHyozre#^ua-Vh*k-bqd-xsj>0VPFOsD5crU&~LUuBL$BffW`=*oR6 zc3{F%3z+disOsBDkh9Vkf3SYGP`|h-fuMHl+YCE~x@k(wDXP$^DSA4&5;S<0-MC4s0JarP42`L4+Ql$ImbIA8Td-TpQ2!|Y!|!>u5V zdh#(~okTF(=;NY-kcO>bQ z-<$O(-#Z(3EiS%e)LO2WZ(u)nw>yAIGmcS^K4&$d6bpKK+9y6UYrHI->K=36WY#hi4c+!SNBeQw`#7$_g) zFS^}3HEGL}OZsC!V8EK?FGYagG;;EGT!|9oYfg-K=(zjxhj>(o_&k0%c$60Ya`td(oc;2t z_`8kD4Z8O7K25V%V5!{O8KsJX|05f)Mi(^BgH>G^0hOwC1aPWgL!~0 zV1RLe8;_=C{p`k<~`#28`UHgdsW zy3JIcuFf$t{-JZw)@9Dtxxs5nUZ$KYO}D5j9i!H$IK2)jMEba$m2g7gh2;aSO_;q~ zS~=wj&mY?wby=yxT_9qs+*Ya4d$)i{GPitZ@DL80u;@x^y%b!jb)1(js!%#QqxQA( z3Zn){!a$r}{vx|G6kCx5&I9D(qsjjA`8abS0}h`1LUNKiFxK|MzBevs%b-(OUtEC3 zPUbO^98+%AwKScKYom8$moM*0h>#Buocep)w^8jt3hmbHfNfp?zxgin&}~ifMe*=; z^KhdU`1wyiNB)4*ff*2eZ;v2EM7ZQHh;Y&N!y zjj^$9Z+QK4Ki}Y~IxnVX=A53In(8ytJ^gEF5!_6@q$dVN@c<&$mc8e@y}P@w`T4JT zREZ16scew#=zWfoF9W# zI!E-b)0+k5xllMG@4*JsG#B^mr4Ju!6?6==p3AS}u;NW{*0Kkx2qRDGTE}5l_6)vf z@wD#?at9Nk#MmG4yy5*P!k$a=n|W=h!}3BSaLdOdPK?Jwn*?6PL+eZ+&c5Ika}~AV za>1vmdu#2WTI7pFWK6m8F_cAVL-Q4Q-Z&I0zdYUFMT|&YqHOPs21Bs!sK1G7!-|^y zy2Y`iF%S3nL615qz?H$Tv=N~HL-jb2&|xNkui-<(Yj&@c8@*&SDpvb#tZ1^MRZUOB z8P5JDMUcjL9+LEA1K=1R;e>-->~z(CnWKs`&mS=-=q5Bg#PEYefQ+gQ?&jIHqXki= zRX(OY3ttEO{bOJj@yk#hJ?2k=*XpRMvD+!J&5dZdgge{stO!0GdD3rQweWLiIR z%{VEL@JaCoZ<=(UecvT^F_1T19#Sp@4s!xs=rJvg{<>B22v;!Cxyev!xJ+br8Dg(m z^@p_t0)}8l*&!7BJ&?N%*!aDltQi{o&Jo9K*8~(O`Y@1AeI{5u+*+&xXMb*WRP77arw>k_uxG5kXCCJC)a3 zi+?qr8t>1c`X&XGyE%8Ko3^H6pWdN8a4j#6)u(U6urC*Ay zd|3Ms846~j-GpYu^}b2doOIG6r;>l;soa0YSl9gArqfoJcB`qhlCpW=e15gC00x9! z^<93OHde1aBlfgX(3f6OB#o?P4{&|+KNbes^=zbq{E-jx6 z_5ro+#QqBR#Bf|7pNxWF#VnrmZ@}ZnQc0kJ!(-p9)|ZL`A^x4ik7+fmWA?mH!bxXk z1=Y=jrB6$z`W9tY6%#tt>DaI(=PdWCvqp%j>3(2+%*TIN=f%NKWCwW#&bPjbXW+8D zz+lY8|QI>gNX4Q;_M3*%Q&BsoypRpiId5pouG3OzvPJ%#E<+5?m9GB5tS~j zL1t`aX`Hu_+Nt%we)@r*7Ixpz=FbyRQlQ;FkhkS?ET2)W0cdHCibd0sHLF)jzhP() zDETVNbK<;Fw*0JV$MfNT)b}0o+x5@f>)wDCD3tw;g8z@lP6~uovH0=nr?XH10PNIX zM!Xw!e9D}Pw9FR3bXE@)G#c|HDX0xo-%iwM$iTi-9LYSfe?EJ*vG}cl?wz) z-y6{6RWp9Tsz_pdmeyvF{i}Le!6tv^8!Yb_l(%YNQ(uGq`7F>0itzcU!Y4O`@w7n^ z3BpgOVZ}q8^sR@9rk?u_G^oA-%>^AF8mw-#k|7cl3%m2;c)D_U^!U{`Dx6DC(ob^r zr2+8H2dHWIZjh^_V(IMFy5-Fxg=x%FXCa7x#ov5oUmY0!4^8gnOZ7N{hM!!`^z4nh3N#Q>HLhT{f-Eb<4G^obg8mD{_+Y zr!n3=xNb=RB&ppOdSTaf+W5OX_YEg3Yyh(Oia$I&HDiHy-Y#G7Yf}N$RZUSK_m&H} zja_{zR`RDY6z(``28_7SqA|0=ORN}+G1}Q?6|+W4;uRKPluccyQcW;r#mhkN@U zkhku`f}A_|w(MK-V1^U4AI;#Z#yTED+hDcMPI#a|@dx&7LFiYXmrHRW5dU+>B^}8A zy)eG`qW@J~T-_+XrF0eVBUPMDn3)M6cB0MC>Pj=bo?+*5B2V~1eFf+p_T>VZMgs)A zd$@p4nEwL)B%(hXz!>6=q3{XH^A?h?c_`5?Bv1Xs}IkpnJjb}W+&V%0OPCRW0k+$srj0F`VsheE7}Sq zBFxLRodNPrATO3*jTZ!6v01$LeXjKthd2=g&ZZJwrtl24v23j&33AI1aw(H$$^b&) zQi5Mdq@;?zFDG3kmYcYqJ>z<)y>e>bqqq`C9Ec?cQs?jkfVh7wET}JRKUh8$z6c}h z*M1yF{`^ zPS1_Rrd1*BY!D-SM5bpo>o!Cio^ZZPeNq6K51oqewaz~7Z{8@9)SC^1j8d7AEB=4f zL-5|vESGVUEGiIX@JOoc*<4dpE*O?!Vf5SE-S>qF=9v$aWxXjkSR;%;rj`U6LaP-n z2&e$4a5!t+kQ^gaHfRVjT`L@r|4`ZU(;ZJ0G=}J|NW~zc2Pl#$v@#WYh@$U(V=as8 zEWml-Re=1<*u)TT4DtdG@ZX^;kTOc3f+Xmcs^wta2o{j9X+8dJOJI&if0U}XcF-rZ zG6YT5^6WylL#CIN-CkC9=w32Aw19HR;;Y$U$M_)4s-u5q4MxnqAWv>6wwmuHu=f|C zbeu)Mr}xKA&3Y2vK9=c0*Jl@f&dtuZ!GZ!u!4>D`<1wB?#lQ(?>pRHguf;c|8(|g^ z2#9C>i>-np*T{2W4BKsyBGgA4G-@2kaLxXsR0bKbD^y;TyM!b0PXkjv|+!oZmglxHP$YzQ>#@P~1gqI72H8yRT( z6ZRtgRzySyoLWyKJ(X%XQ|c^kOfQ;6Ezvjm?yK-sv3r#Pi*(=m>&1bUh(_YCHn`)? zlD#!hP78ruEul1A%iq)L;CFD1^XJ?1VYOY4cyWNO`mYCZsx9%ez<@m){H~J zYH>tMSc-#vIJFYL-p(yda-guc2iFO3f<3^e0pIO=ypC4P2YxIWCI4qbOF%XQCVc1q z(8zf=$Ul4u0M35(vJFt73+)P`wVpsUppRsM2Q#|_GlQB?``p|BO>8b^;{9FpTTahQS7lj@x z!>g^utd12bjM&%kM&%=S5_^|O7rkethSq%Fb_K1k{|W65!-BK>O^_j$L_MG|p`EOJ z)Bc&kF)G*|eguFeH`V!_{G>+K*?mVGQXh|rV)HA2=6rVl|B<6k5RvQ32({0;xC7YH+voUkfZPLfj`_08ARK!wRG_q#{lGPS9a(1-gpAF@Q^;AxbpQcDGASI8ea)r$wp|Ac zBZ-b0&YaD}YH>~Vg-_5$*S`w`c)in)Cy@1Q$+&4+_!|1@6v9}Wp9OFM?&oJB?EJR^??$aHPecINK*`cXMxdM-;(h!gv)sEFfL3{HJ!VERtZe03HFv9e~dh*&fN6%y+KBUSg#R&*05^3)tSsXGCaGWR`wPPu7a-6rK`5K--}(yi%-`8jj~OJ%WWWGtYX~@W z&t4U#I690wzWA5xn;_`8jok(E=5l4mi_?)&G-lqo=T9V+-zT9;t%4Q67lPdiWVo;?GW>fMU(k+)r zqC7hBP2kX$tFL#&-x1jegh{HW<9C7gw?bJVjBx8ez1lWGmO=u5MebNz$_p-lMx3>W84L1F*3eD9+OyZ)OHHCIj^dOj-`i~UqoC^hi61*?!@ z(?kcT3GqzUzm?apa&8Yp?h%*c%iX~8!Qpj4KH=rH-4^{^>sKJPduQelA~KUx`y+?S z-fm#QNOV*~1eEtIDtF3-bfV#NJiX0c(@nx1>*Qb#&7-nUCfM|fBRTOOh$TRyMtLa@ zMwpF`!@=w>kv%u*WgmuhTrRV-?+ImSw9AP(=uZkNL?EPM&2FzNcrHoQi3^J09E|To zZWfS5p1^pnnoGk8EEmMoA0T#W7_cRK5XF|TXiFELYk=}_M3ovLs%U)-Fj)CIX+HkZ z#g9iC$^2*a4OFN@LFqbTo?l7*W@mKbO9Hq(R{L*&@yHqm`$40f!0?H4I?8zJ+XuX) zx>4>vRND(KyM~o@6GvwYUJ08TywqN1PLoW*_%&4~C>kRQ z0Y<=1oz?KM7JncZVlhEybDw)5P??y;TWKj*sfV&N|EiK5r4xs84=f|4QA>S+C0k$ zH`*Zzq#EGuzp!As9R*q4e3KBrjcE>}2GJ2>_pe+ka1<(p}OwU3qEjJQQ!^g zNZL=AY6?cOramnqphe;nd3*;W$U7LfXpN3C-8x5~uI{w`HqrGOb|3;!h@ouY=@d3& zIyPw(>w&OmO%UQAb^us5X1A~Q!zy;8WS4Kwb=~!t24m^|IvL4gZkua8>p}h;e)UX@ z%SX}&PfJ&vhp|_K(w!0X?$JQ#&oSwa?F1d5&JM1VVnv*@L>ZYGQ?I``oU-wvszVMj zz9c62i0_2igy<)K@;q?AbGHQ(*N_*bJTvwVlHZRXBiS1B`(Vof`w9-QR-lOD*=9Vq zGvOTnP=&daLy1GhW$-*|M^YE*B>Vsf^0zJ8pcp{S%gxickBFU_Y&xjJ+oNa8NMBhKNpU@P`gv^(P2ZVUMu=aE+5A;&?~>3CfZf6n>^f zUhK)npju9l1Wk-OTt^rtb!jj?QOcUTONg!&ZA5DXEA4tB6>1)Zs=vTp=NLpn4O}4Z zFa->&OhY;*Mr{sDDv0)ZhJ}#|A+Sye{w7FyC}JC92_+J55Xa3641~!X7UQ0aUqGgD z=Qm$E_SD3SDXp3(hcd(;>9MVNYHfm2NwBAE`w;*k45OS>7D(XSjzY#~LF5hM&=BzU zH@l+*cD&jaP~|Y?)!mZ9wBulJ->R#NFB4(blO$FgCd}4Ea1MySp@TfE zLQH02&~-(9+SKp*NUhsits@ zR1_9YIA_wuPi#A7w>WCKR;0JAl-NtlRXYG!Vmetu3kQrk_^pj42jlf4~_q~Oc zX5j`=^g=}A=wLWxF$GDa{%Ta3p1d)<<8&V~-RfjqZ1h)isnqH!=VH$qfoR?z?sJux zSfh{By`e|Cj6^aVZ={eH6wRbS1t+_ojx}cP8&4=jRuZP+i47*5!YV;QHIGt?9A{&T zE`qPuMj$;ubj@FQn)Yif*N(0Vpcg0t z2~UJXOSOz(;P!2q;US|a#lZ}XGprOL){IbilWUp5iHs;GD}Ir-3B7jv%&*q^5=p63 z7f5K@9le09@`DSCYFR>1G+wfWqB%j0Dt4wWfzcV(OX}6XX?feu@yMi23?!_yTtJ@& zyT2oW!AUk9kVNJJ=#WCkrE1N{$C9AIx?)2TO|z5~Mc2#_Fsxc)`^!aw5R}q!gX6{^ z#D6kk3kv``hh8hSfCb?X-oGW!@vj{CFM;^0q zpeEiNLTD5-(CV~aF&NYc zVh<)f`G^R@#Nh2zzWH>~C!C0Qev)Du^!yrXMMu1KY^Ng2B9aI>iJjQ&e*_Q1rrt}~ zFoNk!uiUM7H{#nEn`&>PTAT`yK^S}<7bPV76FX9UDvBi4iW8oO8g0BV9ot`>M;1Y@ z6Wc%OSDeZ2_aoB0bxkmh3}04IFa;8eq;Q%(qezT28bPS_kiD5%QAsrO*F8^xg;Fj_ zGmWJ7o#nnkJt4*Jw{&n6^cHt?loWGsh`d_5EffyUm^rBv^@x0xZ@T6_0jh0}JSQ|Y&H9KcwiREPk zG-~JOHr^ujylIlsZ`CyuBzn8f@Y_*2@f7etFny-}4M6tnN^jeLgJAn_5OgRh>QgX@ zGEWFD!k$HgN6I&_nZF?e=WVM55J{qt zwm4<&UbQ?_&?!L;oGaIfvn;OdSd9Eu5I^ypqS&T*?PqDf$H>qzcBL}{f6A)T?YFA( z*OMl!M?;C;4>XLU<{gf!wQ{?2nXiDJt!$&AlWEa7rt?aB%f*sarP(Zomr?1vc|j~c z7GP&`TVzvYqc4~a2}Md_`$VFT*))6!e z2O>Z<9G@dm8+=^@flG&t3k8eZD*gvj3X3L}bdqS9trT~QB{lp(%V|VWI)>sW!u--- zrvVhXl&s=9At&1Zw93UTKED=}bQ@F$&7yHwXWfu3fE|~*^CF1(E+vcsb{jyhRpbt; z#A#_Dm_32%tS;!zMe43gVu7itK{0+S&LU%v+;m*dJY^4Al}6SY>~8?N@sFNbilCg0DI{q1DYPl{mM ziMiQiQz>izbY}D;;&w-8)Q$#^*lS!uts)?;oO@Hu?m9{FR6IO^=+ZJPOc%lcC-`rbJ2wpbvAwZiG#(7Q)gp;-GIYoc-dpv`4%r04 z$zw&+uy6H}MV(*Br!IGinS7}zP(V#bAE=PsfvQ>RTa#*E)ObPNf#zos)>^~9_B{t` z>Zb;RIZ>ntTP(cIR9Bc0QB1wt@;P44 zv|Ja1Kp>HJu@CW9QNC1UmW#!tEtg{LZkfy{F%KuP zvH#V`l&B?|xu?gjsvD=Ku?lP1bnK3Y>(;8P@}tBFSA-^c*Oh-3>}T^C?GKJ3_w2-2 zRk|xF@!!9k5Vsl_D)pmMpYUO1rq|^HDWu*9OPCuZ{$Q|R>ADV+T6|^@I7PB{ZB6D+ ztE+k2c5F=cPOF1;PGdMMx(AnyV;ya@7ojMdn}fLLX3~DI?u9GvpCd&Rvh!)nhU?*k zUdT%r>&6&(?Ape(c&XO-D9vV>fzPq1bFH9Y!JW`_PN4;2C*?HWwE(BFlJW2mciv7} zCPvYhQsU8h_BtfHj?UlG8GISoaMVr5Z^EE{acpPMZj_%24?EhxoU+L$-%MM|7~H^( zCV+IY5=Q^k3Ld$rsXs z5z*EGMxWNFPM!KiV&UnWTEC<;6fJI@UQ1bQJenF-i7q%5ojMq(yjCNNI+E`aT1R>KaOIsVOLR)3tWQNH4E z7xBa$Q4y-|UX9lGQY-CAw=czhn%32>U-hZd4hv>$9st}|_z&XYzsqk^>GW>mM(a4} zb@}h=Llp8wNU=Ww-MJ2uI}1Y*+{{Sj{@W_xGN^*;;Z;fx_AcHDuK1Ki+5^+9h2bV+ zxN&j2ojaRv&(&dR6CNY{Pha;kMdC|SgK?z((9!^OGZwj?bms}xTGt0i9aFpzxL56& zvHf5NS)=2_o~lLX=&%bcLW;@Y&_tK3F%D~Rh!DC+8Hx)9RqJGh9FV9)Py%Tr_aV_) zdrAG7&U7>@Hd&ni$_Cl)C#5F3GFGWw6M@RI_J-Y1=)qsi5t>Y$j^NH{US$Ba*BScY zmg%AvFd3x9>dkuKzJE|h405kbZr&J-3R13xE7kH9mC;xsX@oRPS{qUD)K!XgHw&3k zcM+6~g_k<7SrqfK+bz32%@#s=&SS$G^twAy`ZArEYBVozj8f)j^BiMgGp}A}1LAL3 zGsP&u_ZN>+D`$OsOA3@R1kzigb3A;Z!$fe2QvD~*_~%kBgb368o_CASOno1RANztR z@AkVuMCw5G_=eBJkH$~*f3fc`{nU;oyRpS6lt>UK_toz+BE%EE2FTFF2GiIIg9@ZO<|_?;mm|aNe7|C=px!XK_PI_( z{Jv}`ZtJ7$=zW9`DP&56zHbfrLwe~QDRa*b3?ufoIyEctQuR6-)LNlPgkLR)G{0@H z1Af7ZTudmu-%TjuHk8r?R6W|Ca8o9q7u!?Ja3}3#qG=YR-yx}ok#$iIysA+U7$PD^hP&W|k>#5GYdlQHo6r(#3Q>dPW*&z^c zlpEQ7tt>8@2FH)F2P*S>FKC(jFCQYbPiP6&GaV?Tx9w@}zy#Iu)^wcFK+=}g_LVnol&8Oapn|mY1P4^3ip;qf6`%O9HYV8wt~XGmq9-ER}vuy zwoJzkpWe$m>xUKb?1EWqI1R1u?Nn1+E=@M~K3~)ie=q&>Y-2))?uy${rlGiV-E1TY z^LIgo{bYl9bSKFMPVDRrL50%{15oH(5Hp51x4Z|U9j-p|qi%37ZBu;DQ@)}If2n;) zs?X-r`kvQk_N_;m`*KXTUt?8k+Z!ow=NU)R1YN(zV%FT3Q@AfPj>HI(^h2;2>U%04 z*XvWMj>*fg3@A4o6)rmslF^lxdb7jKK3?+6f&RG1uCxAl&ednbFBtM4X-=bDQr6>1 ztyDWI-uD`#m@lE#qz2~Kz6!H>eXK|$5e83xYmXLRTz%iB8Y_7fYsL!8O?D1=o-@pX zU6?fzF7dYg6t1=m(g{cA4fs~3^*-_!M*8SY?jMG|eY4(Q`N|3cw0aLKQkQ*~9iM%i zEr6^9G)Vk4YgI>gFRDa9GficpN_951p{tvTt*0z>#H796BF%6?^MQ*x%SZIynj(DN3yiw25DA z-xIJn{)-}}mP5+aZi2Kc9i!1^lB6pfqVXkD;F)M)Y+K=3lP-De7njGSw({674wp+j zw6XQ1pDV%54K_1)HcAVcInJZo4wHY~%wqKd2LHC4#ORrH{&h2t(KBfL`*awsCsX~` zXBNXosaTWle)t!Q+~s=X@GmNh@B>WT)-~64{d)?Ft4#?Ke%T9L2uVdfW z2`2(*@YB;igWLcSkX$Ap(#NfIP@$h(jqO2z#784C@l{SfSxU?Cs7YlOIVah@SI;cw z#`-v(-X#yR5Wx+PefwX>IgB@N1NfR@|Imx^7ow|!0CfhM-a>VShNZuvo>a4cGaG9g zXpo;KwCQ3LLGSVKHvEz(RPu76vKs1ymEB_NkVceEQU3dz$ig@5oZ)l`R zzJb`whR{nkS3E9ZQTzQ7c?t)U45z-(rFthLU6GE8vq;MkR&5h)0pW!kEff?nt#~*1 z(9F@55f#6aAv@p(s4r1PpM*GHa%@`Yd?LqG{!WiRysrI|>$caK_LX*yGO9kIE3qUC zkzpcmsnE3?E->vc-+-r&<+_nX{Yn4An1IDcEe%eBhL7(#H@j z2X{JL^kR%^Q26GGaz3Y=@$&q?CgHf{-4#s-arP*+3ddl!XpA%_oaKj|9BQo> zg3V|tjA;EBq9UhS&EV1SCWt3Aw*4@c-=iXFv@G;dwaly-XGMb)ktpygnzn3CXD$-4LXl6w$mw9%0Aj<}wfSqgR&ReAy2k zlJQ*960^mVvlX1J5dx}^-%C(OgoM$66EQ^8x>`L7q$R<~QfKZ>^3X;#gQ(YAgGq?Z zM>pP^@St?2R5CU>^?>CM53S0q?myVabaF9~-?{!A(?#i`>56@vY24QJxsb`!{B$$~ z5u&hQBMeTWqXLhrv$5BSB#0bNKC8?X>kC?gr3jYGEVSEIj8SGvBVorBe`YEzQ+`NK z?6rEYxCcC1QLDhHiZN6zH^x1hNLp-?X^QT?hSn^VzFH_j3Qk;VKT|s9lmL|QiN?M}O4)ol1R%U(xyS!MXmpmgaEUVWhiCVFhd=0Gb zI#Y$&OgRr)Sm%g)?RQ3bIFp*$s&B_HVMg=wda25OkWelr%O{a?&B;<)#E91OWv`)( z;t(bou?k-)Mml&lw^cHwN?ZTxr0QREWkkx>%BG?xZHcgw**qit>eulwNm!%}5EWYPCuH zo;_+NqPh#O7S+joGP#1*@-*ybdLamd@Oz?HGF^E%b8gPE8yk1x**=Shn0{iX`ZZWx zm{(lbffI;OqEtQX{gQ`fl|u|n3XYGr&#jV&yd9v3s?Gxz$=RoXk3xaKM%^~>;bS6Y z>-ej{rw0ff2dML6#f_yjgu9JgiXW5-=vMMthGvHQ6(q5pu3XvqVA{x6H2J)Ly8a@# zxrwy&|9>90Hjz?=%LzkMMFik}W>O^%%gKW05{LK|*Ud!FpPAw#f)G9dNfZWrcAUJ2#{_| z7=3FX4pY^-mlT!s?plBm*p8K|%FH)R_EfTBiNcPCl8GIuY~RJACa2!ybU{|VD_?)4 zk59J5fXsnmE$gS=7aw3q>O*~VI-3cBC=O%uQt@xxLvYLqjpD)um1LQTsb&AeU4hjn zn1*~mdmPyT#Sb0;@1`$4()2T_4FI+W$ZFm)WJlg4kCr;={)sQ|^X;}9#y*A;rLUTa zEEKI@%y#6rlOUDdf2F>Od;pX3#_%GU35^XPkzwGI3$O*;=mLzi>v%Vr+Zk+!xS~f7 zYVq%1#2F>-n-h0QqJntrB!obsx9O07<~9LNJ6NWxPXuHPJl-gQRqaieGWHoWtJr7` zWYxzAg1%P?kpf1M>rVd5cOZZ^ZV*3xX~eQ)v7;@ix!G<6>_S)j7NxE3%5FATyz|ZK zei>ci_HnxH#u}FU_>lc1Y~O!z-HTcdWfWoXg^xXsb^SgDVG)wJ1GP7s=faH3$@FN- z30YYH(9Ja>;_zVLZi$=6PctP6IPE;WB?xZ5Tf^1cfmdtk|kXx>a4 zQ>i;HhiGUMq3Gj+Z_)jTW7%Qf4EIlo*To_O=xpybDOItp&p$4Wft zUV66h+Q;nOd^OsfnHKBTf4I`UY;R6}FtiE(oT!`ba;murX;<@twO5P$szbW>r-Phu zcuKm|;aKpk34z|R9%^aJRy?mmdG1~Yqj7L^9M&PMy-|mq*s>P1Xp@e-P!AK|s!lA? z;hJ%=2_D|8c1qUa$akuNAhO5A39^-C+`5X%yb>7<3|~%wjPLP#9#E2i}#2(xa>vPcRMm3XJn9U zPl6jbAs6A#1x=&Be0R_E*v`LC-}>m;rMYk>iocb|Q}H{14sroaoa8O-M9m*eP8BUp zASZi+#MLe)amly4V=j9QPbk65PENw-E^!@0{EY(M4NpZTgV^5@*&P-f7-I~cFr11u zxUo`WMYa$qYSEvE=G9(wFxt>1SgJ>lR)_{$>M@d;KPm48tJX0S20ze5l>-6}u5Yd% zsVGZCs!qYNDIN_lgj?*(D5P((XSXR`x`kOLqle^UHagppiMq7){8xVj!KuIqbQ{~} z#wW7>nqo=DDwftzcfwL7)PHxvC>~Ip_trjm@|Q+fybMB~M;p7tD&l#Put%ZKogYRV zTcgg2BRgFb>Vvh9NW0|H6zmrwVaY!JoP7ns@8bWpA1==>bE4xNek(b9bKhD2k{3e_ z7l_ZQnjiKRaMB-SI<)_fC>x5=?+GTiSSnu=Bo9RiG|&F#ZOy&S<8%1#*d7Gk!!_+e z9-Tj8mxL~vbOG|pQ*&0ZE#quRW6&PCs|Pgy+Z!$6Z3uPMJu4CbW#bW1Tk&MHJB*_x zHtNlGCxK3t^^aMFrqwysj|9KV$V^;9%|&Q|FvY^Q4?J=Ab^Q-_RuW{}fe7@Qih$$Y z8~E|a92m~7mq6CxqT9vLZuhDH-zAaTWb2J?S3|;ZyV^O`1&Gk1RfQIt|7oGaRMep1 zUVBD{VQS(8@!K9?Ty6u|Xg~bN@4e}v{ywmyYqmO5IseQ+6s5i(4bgTZQJ*Nu(@j}H zgt>@73})K;wMKR3f!!u#^!7d7H}m0mOxxSQjGrNjn$xogv2!PT zM+@zDDNzOS=BGkmTZJ5^y9vK;k^cM^N+Mv2IZt-#2lNTI*r0nh_@K^xd&KB=Em z#MJa7EUmGSzB0U6w%_(RoXG_n;iklkS0aQ~5ah^>Elbz|pXkTF0>j2b z;!o7*x+^e5e@=`*NVFL}zbLlL=P2P&SW3@wH*3G>ht`_RSpV2$k43Um5(SJea6?(5 z9_=NuyH*$u1$_ZTb4v^?_p(0a`wUAJEiMg0nEi^gVQ@0wW}cM&#t8w=;uiA=bwen) zL~FT)LHU;B$PWytZ^cY=mT}N&ru*Lrkk_wG$FGm>GkG8**VmV8WQfv?(7MUBJM~=> zvIs>z1P@lvY(%=0>w)Z+<6dD0YC2ZUS_Ow&(gwX#IqEPJv-3RE8Crldytiq7XMv6s zSa}l!p#=QNB0S2X$q%nlT>Qm)jB*ne`%R}1mN#e0MOTAXF~VOWy#nohJy&8s+K;yT z89dIv2*Y$rEIYTp0S|wA+@W!*aR@$o{d(HsYT+n1dLEZ%%+GyusQd*9QaAD(`M0h; z!aoIO5)_cRL+tV~4~k*rSqQ$^pmWes1TfL~-%>Q^Mtr;Drp@0+QQ3!krPbrf+miKLQM~yMJAT(1)%V zyZ z)d*(JEC>st6mSXomI)p5K_4Ias)b=ah=cyAZLaWo(i3WA$0gF7e`hq0*O-s;r#lGv z^ER5pkUN?t?l_%Q9n{VsPOg!Rv&G6;_IxTiB0*)s%+EpzhUv8kL-ue0YD}oL=uZ%c z7p7*=QD;Ru*sq8euF`+Kt%BpaI_I~0D=RA!)r$)6jpMl)wEp^h#(Rh$DFAK2!yLHN zZxVP*oIeMs3l!U11D39kXzfR?^P@&cCph4+CBv`-FoKaNMC>&Zp77~RW7}dsckzaC zzj~gqHywSK1|hX2DU-mzogx8;R0D%SDPH@Y^Kz07%D4O2cE}=Q3W>%;YJuyMEYFVA2_0|@IG!N?4CVBR|n{7~F(OPvcSV@YOU6AZkNrGS1; zJIys;-7n_f?L_JFz?#_rg@&9s9|YddK<)ww5IWTx!S=_GmzkM|3ZJxxodjZmfVWyM zpkMt-Urn{#&;+f*&rD}k$(++NTJzuC(ywGT5pcpLl3%o$^*e=EMB_0@xKQuK%);V= z;~#wF!_F=mrD1K;l#JnX#&9P3EKLXjFS?u7*#sar z;61wy|Fhg7Eq_up^iF7P++WnXbvBDq=2ZW5s^}*%CuVqSfZ@O5Ar|0jn~^~56!3E> z#t9)8!SS}glt(rFD`#z!eGV5BohNv6U>_w22*a|XV$@JNmM`_Hrq_!fCV<>VPW4aNq-R-%ir!u z;Y1#c`M}Vhyl1=3k;k4UA?^|?FVX*oz4b6e(RRgw9}lyAn>HB`8%5A~O>xo*WkV8+ zeM5GK2b~jm>#|!1$ohbd4S9=Q0*P$`t~SZO$l$B1M>d1xaD#?~frJ4O8qx%2ib`#a zFHY)tp-4%{ce=0C;YVKbF6(B(8SCT$pvDQjeE|=>Nhutrf?y_rkHSkHbcj)(&;9d< z-^FR|gJB45q8R&Gns94^bgxaGfd5;qa-`_%B@fkKrTbgZ^$=6~^=-m~P*>UtA1@EL@Yl``_Z8{Q=bDs2cI}kW!=(wPwm2L zTrL)EY_d#5yQt8R!F-tcY8HY{vlw9@E({+^yf27K-Cn}!pG{<53|M?}T6OU<9Ce}} zcJuFz)O^f19eYtckm11uNg!HEW6K(@1>Y_+JiToU(3^HS{T*UcGdQyQ^5&LEzoRdX z(+Y;MIkv0_tPXI9 z^-mk`PZKUj9!zNpvX*1|Nibjo?eo0-C$)TxES(PZ^NGC>`qIYW?x2Cw28-me6U@_jk{Lyn=45xxBCh^(?;nJyo=3e%S@j6_g5X zHG{c0rLF3!n`@3Yo+R?Vb)|}O;}XR+M^<6wQ|*C0Tmm99QT`7DgS-eD;dsKt1m(Uw zWEsK21m*{vy?;2(9wHV*!Lw}4!bLm)|A8p+5-$Sq*}G#WtakR8ABU3tsE1{9mY{w^ zQUnxIyAcPhc4w0cIjy|KBVqB-!o(^NbCWziDTkjhFkUxMy%81LW-wB4hXYUGktLs- z!x0%Vt`32%bd2}S>4PhbSRGSjVhUW3E#i{Z(3u@(G@=8N@z|h|gaUwM#2F^0Pt>*X z-F%cYHk1-b*r-t#2`g2)1a3lI?0`-ti+c5hpM9J8J(FW}X&0)!9z`r@G&4$p^N?_I zw>5J;&tt<40MG#hLMn;i=OKDwuNn;Ij6`HOO8fnU+y|G~Br_bix7obcqk>ZbIJK&4 zTYW__*#2gw?4{^IgBXD#4~i=#?)AyejD%_g1_OgyuJ7d7Kt%Ba4O0@$5f&oq|d+%g?n^e6_MFYaV2JF-2e|hX-1+aIOEI;`o zDvW;r^+@(aLgDm2gF?aZ#6;r6R%7yD0=rQwOqblR0dENn@j-$r8{^su`P=s>0TFX- zsNwZ0O0Dvd9jONWrW~Yj&*h=wkgxh(xKjY(pWvwh<)^8%?5}|G?KHTh;rZD??{-bi z!;&E+Q({Tvi9^`YuRU?ney+pMms~COl3z-FXK}(dHn6qp;N~+;2sOM{VXcX(oJK zc=yWV-NhHWEDpgam`4$-M&=8^>6{bGgX(Z$p3|_h+!oc}O0r?$VI}U!dh&5O+SKKs z;QKw^hx=t$O+rAz$z99L zUQT}BPi~LC#)s!WT<@cw^X&q?CzhA~+IQsANF`qFsZU-YSEG!LpN7(?y*?x!N4xmp zc+d-cfJ6)_jO;^L>)*098>2@iMZgFjlh!C~$!p-+me1h70QZ7xj#pxTSs=2V9lNS* zpNt<^9I@ms^uB)^TpN5F(kj*Pyb536+~oM-d!#3)$v)M-d)Yl!)QIM65ShJ$hzPmI zxd6Ao4%g1>0FHqVOlyvwQ*_3$%5*O{3ef#6vYoqALm?>=4F6LswiZ;2V~i9JW|K6D$#>B~#9Y>dbIfiR8~vQYh5$Kc?O(JnpdF9*%9>wrw_c(zI#P z*qGQ8voRanwrx9&ZQGeI@4NT@U*E|+bIr+|tRJ3rFA!q2e+{8$+1|jHak-PFd3l@E z`h`S@#tv$2;XmJn`0>$Zwg=r}K*_rbmsFoX^O#9cd;L>EE9fqC0O(|0J^)I|D&GaU z0d3ZsUpvQg7pyEvmVPeEF=x2(*R}j(F~)>xv1^2c&Kt+pVE&e{HW!k3@z!tOt-!O4 zb9dDuy-*l6aPH*`vgJ|Cz;WcxqmvjZ*FCjr$kkxgD z{}f4$UyYZn<8hBJBY@4)Lm!E3J%ucza4w+6h_fYD^vrI|ToGGpgj5T9o2>hWpe840 z83xS;toLigBk|4{LJOE^^9Ben0*$Yd!w(EnCK$qWsgqvVD<@|rKIjLWPfS5^}2#;&wlEK&fcD45gA znHh@MCD;yb@`R^7m$mt=hlbFyf^~bLzXHg~59H=@5mhbvB3gFR2q4|Eln0oIrEL>6 zBqPfGgj|N+1?4a*gj?+hCW4JJRK19d#UwB6qR^y#JPG(}ThS`uH?7fH4$$~A<#f$S zf8+8Lv)kXHb7opjqczTF(oVozU3YNr0NuPly^dbyX;oJ4wv^ttV!}Z;(?F*!?xXHP zi|mzND_vreuI7Ndt#X1k@`FRTpcX_%U3h?Ey&&A+QZjkfC1n|xV;*|NH>gxP9y@>T%w zX|+~0LeI{LX1pF)GpCL{Bb9lQfe!uXxj&tTk3`+Ft}Y!efvaAd+oGZrpZ!@NlPumN z(ZZIPOK}C?FTmCBzf5bz4i37WW`g$Ja>Sgq0c`4X|BJP*FRb}35t*<>y}z3;*JD)a zPVcA~ZsAC9Mf7Jsp<^|k=4Uem$pB2$)V~FcS&--^a_d8eTShbS;3+zdKe>f^!Kp0C zX?r*QCibK~v)Uzs2|YG}G{JPfGadk$AnIF0-!Jq6U0t(vZn8IM+mDs6VL+|2@5QJ? zbUDHue>?%s7ha||{hj{lGwox&QKw{oQqoC!?y%RUM2atPCtD1!o??oW!X#N{e>jsQ zB#1n~LcTn8x7XL}e0*jLZ`n?PHm{yQUm~0@cK^ho(IBVttA*;XjY>h`IG)uRO#HOL zEF0&DYGS98B&(Pgu?Hc&XP~ypEFA(5`d_Z0Kf`pBW@X>)n#8cEs`e_(povWpHK@%A z9V2)(=QdPJ9~9~XtcQScpetrL@pBprT)*4VoT#77q&d#-z>YT)`!78Bb}UzbeAz&x z!>f*@WKX{mF2uKCv4G7K#px|D7pPcgBQvxu@)(R=;^CDRFR+8e@IFBZH~0cGSe3SP z(g4!WKGL8A?q?KE?RqXdJl4t1P~$p#r*=#I%pYn0xYJX)~D+ z7k%cntS#0^`KNpTGL>gtH0}7Z+V_}tY+`&8v>Y?Yd>r!>hL;ve&d zyK>s2kurDmIEXClP}vEA_iEzuND#a?)!-P$(@Hcy_QUX4HIaxrzW}$JhC=obzULrDBgQ>9v#T=&`3J=kpinNjCH(^J5(}p?4@~!3~n*D z>Xw%ExJy*H-U_bzFV#F34XS~j>x5=6eW-KAq{?sIsGgNPi>|YFvxh_hBGx2wLa-&7 z3cP+~tm&Z;#4`S{U-kl#nHWn(47S%&4soT8X&@v%TmF#hb-kY+5+E3Yhn8+Jp|0vGLEt zXQQ{a(CD{o;Tcye*+ z=~O@gR^pk7K;d=x)o8tDv{q>wP@ZNA9FOdyyhEnt>GE_7^5MCunc^qKm`IbCsKXYo+ z*i;>WSfwy1?_g{NEcCAtYS4mVlB^teo{E_MwnekLG}oA0S(lGe2rmxxk zyZEk8d`r!RKm*yM!p&F8f0K3yEdf@3h3nJgD2(B|&Z*>Mek?Bd5~Y3qcTpHcbP(wM zrrzp(dGD)J`7CR%I~k>y4%Wyr2yL!c_x#`Lc%>><*!rYVV2Q=fx`=g<$*jMaE)#TU zs1NPK`c?W&S1x~;E#J?dKiU08yY@mNW3oy3ySo^kJxkRG7!&%jZ=a{30Lus)zrlUn zbzTgzL^ciYy3e_`K&ZGNIo+T1kM*}5;cr+&KDS*u05R%nXYS2}V$8ko(+8tQMnbJT zx%gY7XJQy@^jHai*!-G8Wcsxy%;}eny4Ga8DX85jyTeB6Z%_!-&g+S8N7cth<832~ zS)P}S3>q`drs#h=(Bt^HK@lvMJa>o&Qsp;3j<5?v`O;*)M5np$cz*?9(Bj3Yja7Ao zm~F?3vG7wFNnH8Fs#*Y&XgYJ&klQ?9b_qAl;0Y79@SFFb8D4Ed<$my-J3(EKnKKJjvkJrb2>NyaqhFSYej^u4fGVe9%y+ zKfItF%7oY8wp1b4J_2|X-L>I1W+;tOhTgG%AwB<7^1qlEHU`7oCVtJno2MSkR}Ukd zTlWWg&?90}3HIw!2*||Z%tuM54CN9^g`N(FSV@H}MF=iOqG%0=_$Em`CPT1xTS?kx zxbzg+;OO+(WW*Uj)d2{qAZu?tZNQpfep~-%B!JsEYDVdgI=E42Q&=sW${^UxMuvD= z5C{fYJFf&8_!2%F#8kMZfPoU9w=U<4r}5wI?d^+uLB4$Ntc^_^&nco-v7+p^vcN)& z#3+`L-@Xm+li=NH&NZqA(r0aaq#G4T`+IPGL|}Vdb>zF3Sv8$kA=M91wmS!QZKU8N zlRrY) zLyn%yvvguOR>YhPLSv0?1~SJWKVb3~lWG7yk#OvD{-12#dktm+9fg#mzESD@A^oI= zueFnvAWHtg*U8$Bf4oQTMfc%LoJH0M3B%h-HLa9rJr#9|^{E7~SLYv}2_4&89OG(( zsTG9j*#B9ap_4QPLtT^XuK+NxM6^9^*|&i>6^5k z!`eK2T>QO;+_dqZ(dm3`Vfry;*INnMasu6nW>v+MKbiZL8Blq8{u8PZ``Mn9sus0s z18mdq{Yc~S{c1|z3A7v&3c^{^4)GgTA;kLr2ZD2}49d@RjN?07KB5z!JAJ@+)zn7F zUwWyQdN9a$(#Fwww`(i0Y+fpOH&4Uc1UTjexIzs7 zDZ4}#JbbVr^q%+=kmgak(lQI0^4FHJ>>n2%SlN!sv5~=Ll&D`}7nHT#JzuO998Va; zje(+@2~5%X4Q?Pjk}p&LSg&}wI5K&4Z(u;yZv!rIZlwsKyAC_p}6F!PP0lwm(!(70YO?Exs+r2=gsT+o zv>CUuID-UeN>H>k=%@V1N0QlwyM2tqgX&}}h{LT!OcTFKR98C5)2#%)R1Dbpt`VLx zJKSO9zPT>izEX`YN5f~>Mh55wrD;_1xD5E=jFlR89Fb!R_5sEQHxdr*6#!(r)iKiqan%Xs9}irwdr7i}^*p zdV~`XzU(?Cr2eAv$%WB9Nv2p%Sd);bfljz&?WCw`&@z`q0rxek5#z6DQcya z99=q<;t@cqg71y@^Z#srgi11L>{vRky~{Va}3%cXrro!zA2}eMM@k@N&4%vK{*)kox4q*d&Vt6`A9(*S)F9E={2sCrZF6E2p}c#N?>Sm=IVdo z{OX9xe^KNdNGSDw5@S%=Ee}v>rF21AWuGWIKB{@`fcmk79$Qk@WrVl>u>Z9`_F20^ zf}vknJtc8LQE#}vZ*g0|cSRYvP|V}A48DdLsI!<>LxRgVp~Q&mLRp6r@@6|Haf9h! z0>ogx{4Dt0Q{%9uPNQdBOr!ST6?XuynAG z@g0+SN=DF>Fz+>IOH28qgKg!-{scK)aBg`{E-lB|NU6dUgzI)O+d-iO;nq!BW}`NXyR*Xb`_vVE}}LgJ_sJbfC)1pRWXVe)%R z_20&Sv!nWYl##U_JjQ_)Lkgz6JmZcP*%#kq-6db2F|Q26y!bn%Fh|+Hwq~$Nzc?#_ zKTNkfO|}|KSJ_85WOlW{OfgP>#k6fK^ni54iC{rTtD!uf(`QlpB>N^cm3HQ2%zX9 z0m!6?;AsPQUu_lT^~-TPTL=* zfJlma7O)%cC7v^Z3t=f&%Jn|M_{-alZ$6E%Fg@Up{@} zuq`cTZ@Cx_Z}!k z)QwV7vVlj*r~U1F$x|AE)2xgS*+2p#-AcY2)(tg^`mTxz@w5)Xh^PgH3BoNe<};ff zEXLQp?drcT<|F(Y|I{9nBX2jiU@3!QN?GAMIpdBaMAE!K4)>xY;5eYg{oB3?t>EQ# zSLDnh1dy8Sh!+XC(qbR+3YM`JC)r00f>p;uO%So9|h}ok5^s zc{b?yL9i3&$3imjkTvE9E$yJ-J);-*d9yN1Xz|D1yUQmPV_ys>xl-e6zunhKCgyG| zviG`Sc|3ifJ3_!bFd(-V|1`9#RRMmvfk#~vd(LSu!PdJ@DWG9Uw4(!0+j zcJR?J^J##^pwkaq!3TOUsrCe&?QImRWbuA(k*NTZ%e(tE7zl!XZ(WSU#YOk%$ppE@_AKc>Hi@Itlx@sxN<$j5= zL^yvWPl3@9d>^6S*$8KC6_P=GAKhPo*`mgcARdBGy&+b8j$*3>;ra$6Bp-Xx;6ew% zgidJc+{l;R02C-QVqv+G)%tp`e(8Oak#T)Kw>fN;yM#KQRe?T=DHEAe$KDi2m24eD zz0uky#}Gf0EEkmeXpCv2bIn;C0zj_rvbR|O6|l??Pfng%!&|z}OJ@tyV|7Zs?#>Fd zqQ9}E^N{X6$!5T|1cSv_8P_m9RgD-rF|efLPTLeF6S~o~?K(TjOqvt+DG-n~sZzw0 zX7P}h>!SR(pgT-Rw)f>hjEd$YW)6+5$Ks;%2#n|b8x%5y2tSyw8A2Aro|6xT-yh}f!~1Q8W*N#4>Kv^y@k`M-+S6y-{)X1Kht`XlJ1z|S~mm*LFHI`9d=_^{U zsBVaI98>JT{0aV$e%OF6su9mA}X}SytCT<%nbu9dRmaLe+$W|Z@hogvvg zgzyCR+J;w4c=?sv{xw)c6y@t4kpz>UAJ4gMA=)&mLCTsQsy!o@bYOk&QHdok{);-b zR;hnBsaDo`ZumsyRgv0VN~5yn_DWX@v1szBx?!RVGi-Mpee>bie{XUfxT)LyQN{f& zUDz(OVe_<+`#wQTLzDWz1Zh`zH-pMlq0w>7V=#gSBsB3V9bFd>olz)S>Ova!aHp4F zeg`4RP+$m7aqpmk@F52YE;WP33L&=8PEw9HD^qQjz6wu7oAsEwXMBUFPXN;}P^Ztl?ePPcuomWDC#{2#qjUUI|oiPp$ z8%k&^K60;DJ!URcwpAa;=7n4BO4obV7=9KVIZ}zO*ksP4g2V?IF-# z*vJ1exieC})H(C_YH7wF_?UKd zGr}>M&OWg7+0N2XBvZNgle*^BlPSy8MXDL>`nLI>05+<4a*X>CB{3M-e&z@?y`9F- z*N$Xyt;13Ko+6`dPd7)3wQ10k-#ba=x8#xe z&2v1Nvb=VSe-3)gIu|Lw1Z7xO26b(rCNoO|uvk&V79Thdh(sbEB;@%>*q z3*9&{Y?qPGNiD>|a1;{FkDwsI>J=*PRshNrpJf$YKsA84Y;MjSdGo*IQdIo^Se`vv zN%&#OSr`5%Dn-@#2TmnyYB`#8qx&*V#MrI6g;f$WF#%4Z`A2?70G&yr%f+j|7rNgg z5zXuZXie)Ry3FN|ir{IoGIznRu6OowhNO#=8B}3WqVh85D)ADmng3@yUXDlpaCwop zyQ^jt6riKuO79;GWoDIRbRaLX5jWjB5HpP;;sal zq;_ea{AiF-torJIhCxKis3w^RXjQ&vlp0H2ot}4)6 zjY+9P!7=$WN8{`=gl6g~d#b{DvG|B*6h5w>|DV$qX#<^IVU z(uo}fKK7FR@|i8-u|5Ghd--ht>jr6+hb(NwqGr=FzgR8%*!Fr*zfn~OV}DjwA;nWY zW;9`^sT;TwlWbja^v3$f@UQsSzleJDRe-WDgn{ecpyUBis_gr{BjPUW%)`9t=pK>O zhlxK*-qQfLf>3op}RvO9rVJ*?Mq@ zS^lNr%pv2*#M7E9F zaI%w7dKLAlHqw18M?v|BVhQ`$(O)*1g)^=ftY5ORc6*2#@$%4nLohneL8s0dZMehR!Ljd- zm;f1x+PT733Fj2F^jD28zR0jk)yV>^*^33b?l2y1rMftpm2U|)16?MR0Z5bt3Ee|Q zeO2p}rw8Dov|&TuR;fu+PINpp#iKe#(V(*y`vtrlBGA^xO6gZd@TS*eK`-bE7xeSR zwFPMaUu=x)TXD<_@W6|$TqL{%g-aGv=;R5Us)H^%8NvM@8xaI=MrCCsUQS1gUCZ-x zI1$g}vv+BEiH;JNEG8)T9;6C>#5e(JXm5WCx&fVEidas8-bX%3jcmQURUWHuo{pcr zO0KlWbtM*KpWWz)nfI1;YBVn;MY|=`I&UoqW5Ty6*aG z)}QsEL{Q~nt*=`(-T&fFlydEGfz zS@ff}!Nvh_+}YbEm>w-nkE7um{*@&UVKC3 zSD00Lz)+tT9nqB;`3T5RK7E7q=;Zb78AAQ{4Bo9IO4do1WFy1;_@<_yg$zsB$@6n) zdKjg0b%WQp)9V(b6>WH8+!JvpI!(&?1!uu1(AS06Er9lCbxUVb_m27XC3@cH==9x7 zNcZgRfiHsX_Q>)L$Uq;YC?w_xnx5Y%j=}%>$Q%OQQN95=toOY9BATO6zYW7`zPL8( zF(nCLh^k8KjJpSDi-!U$cT{+#{f} z(jst{wi%7+YnFd%;w$Rxz|1-CX%;j%$|}2DPxkIE$R&9Y%sG}+P2?xwlmn}1#tVGG zFrdl`MN(Nl7Wfg_mtruzWXT<>z~nno$l%JmP~q}fnn!!L8*cN|F~up^0R8C8YP2R` zdlX%~6xwFHWAdXHfwglAgDqi1LX8wT5!1Gzpk!10KK`)jU9m-Aa*4RF9lfd5zDoVh zd~EgD^a5Qg3VE(xqYu#Iamw&Kx=L)K-Jp$?QDcW1=J*Yg+&_)HEk&q0nkC!U$$9lN z^V#diS8p6Cm5}DX19xzDVDN~)p0~#r6AKf1hc>Nlw@vH&Dc+pwhM0AxI_J4)Khmv{ z&JZXJ-)cJM0-o<71kp)%EgPx#d=R>bx_yiB2g9d+JAEnE%|%d)Esc7EO(`(lN5A;M z9J|fzpPU<3)UYq#=5*-jF8*8RdFEi(N=uy79so@7lnruZ5Q18^FFXYUm2)sM@YUUOJ6@v9ik8bgFVUo3uKjp}fEpwTE%hy?{4>?@iOk zL4%4r3sF7)Y;YE7;J`ooDVp;hh>m0C0h4RpwM36@+0jQKe7i*7 z_RA60(}&rot$S}pZ^B#ywsaP$b^CJUKpb~H`ZV;{HN6D{Yg$hv&GqgYQb$Rip!)vu z?sg=?Z9Y0kRa!F{zGoY`9)^lb9B&Kw4x6B@vkY4i0doIR3XzJgSl)_Ov47@QIY|>k z_H9btGt2njJC1m|0LZ-mp2-F{VCVgTo{a`=|AH^%2cx^~76E<+eLZsW%qO2f{X;<2 zr6E*^QY=dfac2r~cY|8(MCj@~Dw?3;Zc_+JZTV&_OAv0JbkAePE;ZiE3H4>L6E`zuoUlw{2lw1(-zmUQNk(IR{#1pGjOxw1 zC_>{o@Qc#PYYM2mQ-LvnEKiBOVf7qI^okvd8WxU50M~pGA$Z-}!K6^%&*8(We@TaZ zla>J$+U05Utw4uH`0yd<0VAaRbOlF9HCr$n-$!TeDD?Ght*S%0eAsqh6feWj-E_AI zDRT<}qg*V1hp6vt+e}&zsUBR%S&k-BstG<(FK^B8MgKS?a#PF9Q|9-9sG8fYNx?O? zfnHwcA1duC|CP~&f^I6JBtXy51m`LNA97v4@dIc|hjx82Iv2%0v{l$)ZxVFlc{XWJ z)FU2CgMLCTt8=&J(&oR75kK$A{YEY!*~Q&`I5r)l$4}QYKO71dO@n1wHTHn3pu_-t zMzAz71%XljXcq-jRSt47AEOH7;OBYNan41TE1%-v+jZu`Q|eh*wD2x{%cCOD#g3;> zr@e=Cc#)Xv1wR0bcTC<~$oPJ+9p^Z+FCja2`NyA@HZ35q~B3x(s=zhyh+B2fHO#Yf+B}S}B z?&cu+UYa2I5mXPbopy)2@n5oXyD8D5Wy^S9!Kza*!pdhNaI zm2q$4#GuaccF^9-9t`LM{KjBum5wR(sjWAdx~1m&EXlCGPo7DiX+a11+`X~Eka@ultehFV2(>VKc#u zYGsNzwBY5N0!OPTLvSD+kxoROtc`do*#IwdS?1YpIiL%EaL!J{TA0R-hVD?m%2<3h zsWw4eT5`|9f(Rw5f9IzQU)Zwo?M9YQG~AAn(m5@f$^|zO)-7N;D2xUV^mP#wUmG+C z|KGvt@oM|?Xk)|t>pn59lFj{m^|cM;Ski`YNp-8BEED&=qpmq_Px3F#6JWX=U)DgL zaZ56BBs1`zwAky+t157)*8Ibbref(uNI;=0d8to7ncYQ8UIBhDJ!AD%#MNhdZT35& zMY&p`9;q9f{@`=_Cp`30Zu2`pi%NxkZW)HaUzp+&ijny8lsg+K6oa@6zy= z**K)-uNUz_RC#tHuS|^5HcgK;^$_@KH0Q9J+ETfKX0pMo$Bg9@=oq=ZnD!{N@^V(U zTe3>ZcT3=uBo(4k0oGw$=V!V=ITb$!V>W85SVae=F_E^oIAlK$n@vJ_p?^?HXi%`V z(23cMh*)a(CnjWVfT;#D-FJaoLbMsM-me^BT$#ZqN02cls5|5tR49(KQwpZmXn*Dh z)<1|ag+OOgCB#FfGcxxi>igeAtt{DEY1KNY{?6nG{tUG8RY?OB1ECt*YCek|RWiH+ zpJX4w!@GX{b&}Q$eE<)4*6K%WkeA@sC(GTic=MOal=~1&ECIU{TO#T3;7{_ny31)%s@xs{P^`rSHA=fB#Ez#&6vP046(9luF1%N+XHz!+VoDwZLv6ph^PBLLQghuv$4xg1f zv9ZxDU+)(v;nX)knY^a}(A6dP^H%2`NWs1;__@1ewK*8XsaF98(izbU2aRK^!-A@% zW|tLTt6shipIu+x{kyMJ8|WATnpuB3Mg^p-UUe0@a>6?+s6oUiw7ciOaS77Xm|x)bZJX-G#c{@8-;)c*QaL>S-olT&E= zdH<<^0hIH{BO-$i!-cPVmtwZCVrH1JCX9s}!FNoq^)55kv%R;FbIV*)bTL9Jss_0#bL`M7U*yS6U{~X>}gOo@bfFTd3z4k zf7m(8KEA|k)YV-?KJVF(OVW?V&B9~!!X=-fQzu6M`u#_l;jROTkx!d{Hj{GA0Hf82 zowaxwpC$1J`!Pqhj@K^D1;1imDab9EApeUFEf7^N(hhR?4rGhPq?t|Q9cm_TrM`+an_;3h68Qw9=k{-X-2OqZ zHHxtztUxYU_;6zB-`ZeAep8UYRmbnV=V0o{6I0EzKIG<-9Y$EZ^D8@C(-(SA%?S>?YEgc^WElMubB?p5R3bR&_$ z1zsSI?b-SfvYdW3J{RJA!bQ>X?N}UomLSR7@)G%zfx&&)H!H7Z=2N-?0LQNdPy$N5 zT_h8-lwd-7Mh;7MZUQF$dF+3k!kH%b)}NB-GkzXw{EExniPXbVja$fBw#?4IvDxzQ z6I&h#*3pvdxavCjf@;+VV$L*h$vF7poIP~yT#J|n`dim;aW8Mr8GZrQYO!hMA6H)z z_oZ~ofztcVWVnKREQ&asd}%7?vi7o{{^=5(Wtgf~EmfEe6nZP@F-otmr0m~zgT2tn z0znKvFW}o|e_V|wdAl)+hoGKX9#)0$#pHbX?`A=go8Cjb>YU!1o8E`MrtZKwTi3OIw{=pf>~e1)`` zNkSZ(S=Ipe2ESL|b#y>{>G1>x>{{o|gYgw5$>_dlzBV5hntwG3cBB*0HAH_+z{cV9 zFVjZT&iRbzPbBai&A>_aFXNlE^hq!}*x2A5J<)hd-|vO0*WHeBaO%XPzE=A3sO8d< zIm_**SeRenGy^xYLp2TaRP~<|wFVSunzSu`sM6MU-wg$RwIFP{Lb+-=;*5K9|xx;-z*(d9P#0 z(|$IgtPc=xKcGLfkZv@5Td*%xM~nKHO(xZs)ya7&CT7wLDR7MpzvKOSy6w&A3Eu?=4vTeNcz-jRfBfgpf zgZi!c!&fuy>b=-);WTU8{>b~wE735o|ICV&N&G_Yu*r1Yeft^RMw@xZ3)}`ObS9D3 z`*cnYETZJKx}|!UWss*%LGYqG|BWd7dKd@@3yys7;7JKtA*(%=QDCS~Nr(bMz-Uxw z-~OKq(=l{VqbcUn8Ao;*EHZh^{i)?kypkQ`eUNSA1j*G+B+EWx{@ph}(5;wsN)Tj8 zUQLph^g3zjDngPUQ-i%-3ax}0b_+&^n#I`E(YvzNd~9t^j4b$pNfpU*3hwdDp`e33 zOF$4=TY!fXX?`F3U5GWLzn=~+Fa2fWWN_9wxuA+^8!aWDkVg51Da`qLB2E4)!TeEu zTCM4}XFQPJZ-zL(GLh3|j}i5vI?O=5jZ7|m?ngM;RA$wjCHFM+y=OPm%IY}s531b* zm|x0u>)T4@sC>dxy4+H}iF$klq1=)Po=@tlv8Y?+jS0;dt zbj7k6($IfToe-jAgB9PiG}&b`M$qCC7+E+|bqdlTk2vsu0&i! z1iCq5n&>cMzy;V3*KZ>{SZ@CobPqy<066-=U-oeM;{i(?Le`K?)>70IYh!w3=qlWl zE$tvso@T`EKKGb{TNK?S!n?6DU(S~IK|k7`u~^#x2P{@Itu?9kFzYSI+I53p*JBAS zem|2V5z^lZ)2E_zlQ8A2J9vVPq|XION1xjKMY2^)DG(Vp-)3al8~b&PBHdHZrJ zob24Bt-N*7=Mdp#3e`QJaJmL?3durDx85Yc(;!HOoZKqg7T@VMRYc>G_6(w1#k0rO zf2uXPcYxz!BQ#;%E(Q*N(JkC>-&B7o^~3dW|IptH#zy*BK`OXrIMrFv_+bpKz>u{* zNQqs|#rcDL-0=fVz&8~ZuZS+^j7kklQ%6^1q9Y?L3DHmaz;?&wM;AiiNdQ)6E$hA% zK_o&+?_^9*x$KZ37PPr4n1UPXtv#Zfx>Vk`1r>rs4={H;Kx=kok`yvdsjX^agF;?m zW7{{Cf0}t9YeF3cqgvrYXgo}TDc67l=DZ(;FHPKQjU>hC3a(`EA72v4eklNixm45- zBeg>5woPl>%nHl5H*h^H%pfiiEJqRhXU{Eq>4Tia1`ISVn}Z3X!lIaqz%N>f0%-7&c=iQmXWvZ5G)LdF`jvz~bnngwiea~y#* zie@)U{?goK%q-lS%JDvIQKT?{AgXx>jCB4$0?C1#mauk%ZYt$sDwwqGMuL`yud2e; zpdN9XT1Y4WU2OLZec^lGS>RWr!6%(sh}E_eT&760|8wWv@Qb*cpM)^rPslN`6H@LE zHq?sacfh8g@M#lhn|nCfXt%O0aBr#Rqsl2(OQQFyIz|{5#ejm^0Hs@Ou(Y4m1fxbg z8a_z{H7d_zdq=DvF{2Hh_*3i==|2iWn-y^gOrLK}`uT}y_enWI;A#FuNFO1FM2a7# z0eq=L4HA4(5gqMdC`H3s!J3&<@ph?MGjkv^lI)N+G8`%=TmO}0_csZV5eAt3IRAJuj=$&w zCIq1WMH(I7nH{wgEOyx;@@kJkNjs@kP6`aJ^pmxR0ztUVc#cy4A?E@A+CjS$k(9Vh zT+-ErQv0DN%Y>>Bc;b_5N}nt;b-Op_rt4eyB3I<%-b65KRd7;jSZSi>^+h|6kST0^ z`uMzhcm^}U9kXLI!6|foq1`8@~N6EI(|ln=GuBUqIl)FVAwO8&%&T&Iw&A zpOKm$Z?p|;ga_Hu^NX362|c>*{*j+i)Dd~3QV$`_VWs_AaJHd5j%w`Y92}F#5lGwE zkrYW709C#6m&^CH#v?f2$F`OQ)EcYwjTPa2HqXfeUIyNaAuZH7^H^>PsTW*8HB%L}K zY-c3ftTa5yp>si;gAW^xfa2K*s(}0;?kZ}Pz7fO7Z~@ksV>4Y{ekxm=?!EEVM1kyH zs4n-1FBs)U-uQr6m{hugft1Y7Lx^IWPxKtZ6Zf`49}|a!X+ z-`&=t+&Qq`hQ7t(BxNa4n<77TR37yNzT!Slna%shuNHp$Uo>Q{+eEZ;tr@WUeJb8; zw92g4>kjKoZY>Epf0#vd|53#S_O)!evAy%*+Rn=1H<0uI9r7ID84#*8niC_Z>&R^= zg_Ev|nqviysbtbZs>#ADoB>3^qB7PxyoIoh(shp62~4;U5TzU*G*?axoG_HN8Aaz7 zOpl~7en4cQ@E(V?jf7^$IMYH7Bh`p&0i!#xzBubJWLg@XuqcN5Y#L6TNan&(MH}5b z=hlC9>TiV;r`!WLMXm;tcIKUsg{^9)suGR2_POhhc@t2fggOW;j7e&eP{qRWTI`Ic z>~36~eHC*8C;tw{v{OYmx3rfv6_Yd_Zu6}RGo<59U76PCj8OA!C`Y;6{qrqJu*A^!$i>FyB5lUn(L@WCacAzwScFH10=grlMEmgBa;(n(J zv#NikCM5cd_0P1HV5A3qyM z7=482EdxMS%W&w$e!z|8PHjx_MHYY6u<7z7Y?l-*=_vqjQM@g#Ba8V*s&X$+aWJ+Q zstVugR>H-R7OCqwR?o2GQ}ypGyPuAVi9bjUi$lb z-=)2saxx(Kf+r6H?9x;O4R&^hw9$%`2yir%H(7D(L$KDe{ARH;R9@r=w;HENMSVhI zCU?7?jl0X3H2?;SDT)(1jbfDpP?*m8yL1HIQ5y~VF~IKKZjk4?#OO z+W!3M4D9L-*yHD<&6LZKT`L%FSBj>XjaJuHfB2TRGCx}+_uWh>PJrs*-{cgqyB;hS zDvXwX1)zSQU}Cfr)mT%L)x6(|H0{06xw3VXo5skQ!6g|O z60>gT^xO0ZXjY~?|He@zqJl2S7iLz*Qp zdWX?zRECy=#A3ZeWG1qlh5ObOGi6AsA9&zzXNRlLqnscbmyJqB&kpHr)0?nPH@Oc+ zo*d5K6W&l7;ob}zDDj5vKP3bNyL7q^LJoia-Lft!7pK6b-@`}RHcl01j#dY6*1a>k zx|FHYW%W^BYvu`Lcq%xb{>sDB$K|_agr|FcUTD9hX2f`k*e23P(YlLdQAPp-H6KGg zDy<2u@ZL(+_Ko7xf#GxixyzXsz9_+QzHd`;!tX(qOLteum?aq0*f0E)HdSS|2XMKD zYBY16bm`s;%=1>u?jJC}*~lP0vUP>%wbBim@c@d3&}@wB+?9fS7fHuTliF{${&M#I ztQ5JNp9*j1yLgX?(k&A;DRVl_lGErH|0MYqejwx*PYpl!h=vjCZW-2N&iRDeElAZg zO5O^voRHo{!lk{JcVLOd%~{Az;Z%+&f2d7uOK|(BYClE=Y}bMR>3EcL(-idalt(Uh z@@zZ4$DLp4SSJ1d0C+%$ztMAA|8yXG$`d>wM=OkP={}eb`^SB^w;(4Fr)Fb6Nc>>9 zwGK&UgAA$Gcs~4fIC?+C4dY*Sek`Pu%7F#{UGrSQ-rHbB3?0Lmh$0NY z)6JQ01rG^rH1TPg@QCapskuZJY70KG7kbM$$@0*j!XpSv18eVOcQV18ApXDp?tRn8 z(cR%cF$#Pcd=lU75=S<%If);B~GwW|&)U>$dId~c0^dR$63kTiQSO^F17at|$N zW`Niz?vfXsGoSRK&t#2a;smpT(5Ru5)>n&7hM`^Pixi#jf}(L#&=EBba0|LNy;+?l zks>N}chDHo)X`C5TPgF6}iw^R3)y)qi!@>@-*TYk4xQc*kyLnZ=!0ZV(? zNthwpFP`Wlb`_n+WT~`~Qt(bN>toRq&ARP8E~p(~&+#UTZhqT%5#ju>+|f+*OxH3S z^vuDbRm&B8j7^2i;ib@ZUe*!z2AWuV*gGvEVTEakrZh=P!B^?`sdrB!4ICSF_cbDm z_5J}J;eThPJsYD4JG>=TPCZLNEhbViDDC-CXO^sAT^yQZ&e}^Msw?JPJ^Ky=z8TO5 z@hz*35^W-7F{ecnE{lN@XkisdsJltCBz4w6)Ds#lk~_m@o3?})GRs0V#t?~!7UQOi zl{wUhY>bgwCB+_yLaXN_*ksOu%L-TLdvhNAh0^5FnU|s9JFP~zXwYDMSFIn3t@xM( zMQpKpq`ow+Tna`1osn3aAvwIwFJF1kQ*VAlbP16A{KdKe{C5){T+7$7Ef z-$QU`xqwJf<(5$hjAvk9WM*(Gj%rYJM0JC@00z>KTE?B!&{e2EvIP^;2`eU$9_+F+Ovtf^1Q{K}UNZcro>tJd zWJ_W^{>5tSU>rMpRp^$}<~)eCcJjiXc}od1Jf67S&W!pM6@Lh<@NnpM-RZP5`GAE~ zN9UCd!^63rRsq`^Onuu<{UHDV;;v1m^j@dUBfOiF^2I=tY`H!FK#*h&bOoe z4#Yz*MRFx|00}2#Jzh5OTwqK#KRPi6JlJ0 zWd@vD{oV1rFfSlK zlwO)(IZ*s=;-e<@O;h@$@v1sLO%B*Lr6^BBbcK@((R44ZG)YCWn7u~n@2*jjtvMXo zals z)BR1FqBxIk92DRX+2)~Cw5SL6{bmy*YwIuLlD`TF{P^X zj@FT@elF1s#X)&L>Lt5GH}=_+FvHTaBV2a}(j&>5Xf{OzmY9fI-}6f~{OGe&6)jjRTlOK!3ptpLe3nRfNcDpOpeLBcCSL@{b$^+1>+A7?|PgW;yA zrFziLd(up=XvKaYvh#w&K^NlmVx*P>LgLn9e3xyxfgplnGs6DHe3u{8d1 z86NHNNtB#<(PDH4{=wPfo|mJ?OO(&(_(&KdeG)_#(v(ot4(CkNk3!gC*GZT=@1|WN zN}Ytc2BkZ$YS?B50}4-yV;TM|_aTfJNb zgzTos!WgnK5G?@3jqCzNk#iAdfOF>PG64OC0K2#u>H3jIi*+k=IHwy!bO#LIK&4g? z9Cnv*N7x`l%h0tTGuL5GY%gl(!o!gyLtwPxFuOp3mbhGpd6($yEbOK5V&(y;#>%{y zv|IgogDUn@%kluFY11xHn(iV;Y5hoPBKXun?Vk|jNZOrm%e%I?RcOnar2>Fqll-0( z9n0unJVIqv2$M!bpeu({J_;+j4HsLjnqluu{wuuP268M;aBvFxVkQ3HzbFb0-)4*e zSpmZ&xmUt$BUM(6S>pIXGtc6jw}md2X8pERq)AmW#UZO?iGOA?L8zqwRzA?T)6uYS z$Y9M>IpD`rzMYKDoaLr9jr zVo|tU=B*MU3G1sFir7chKbuPZ&e+Q)1H2WEQ`{_;?GtfjCSSVJ%%J>sd%WmQIZr*U z5G9QyvtY*gSg*Y-Bk?f-nSOIVhQShj4G=- z>opDQGw)NAcoYXD7m|&$gjdwB!jYCun#aT#C^w#ez*?O$4H;h-*ZIba6hReOg_Ax; zj_Em426cJG$9T~nc?mfp?h4>jLNxH@ST4M*NX_l|Kw2J=7(7mAOycnAorX3HxuW5R z%kH&`FREnsD&pi<%Ss<&SQ8OK;$DW$3S&Ro1T3+#I$>o$)e(Ep;XlT?T+~@df%4r{ z30mnB76rI;o*7)N@~Vkf+-uXO?@Y#Z>ia5t*-DJ7p!4d>Qc*!4Dy4Gd^9VYVmr{Y$ z7@wfw!^ZcLocZ;6SpiEy?1Tk2@`yI~?x8v8x3ILYl#6Z~Y5Z^}p~l6wVGl|8F>MdT zl>*XCk#J_lkgeHv>xje4V)S4Fts0O}9Ws8E1SrBNNz|u6=q*Fn_HEpf5g2=H!@-Zgnx;E6lnwepP)iV@FtD4u5vXi?KL9`$HZO9|Uvr@)Vmm%=X zW`&CuR4aW;4i^V^k*M%NLun!0QoSSb$%}!WdE##&OVH*o~u9X z(mB+ZiAm~EFRG<>s24YncELPiG111aya?MF_Is{5kba;INV%&x6R++?pov$v8)@QI z^H3Aip~HS6p@@>=@oS%b>!|2`rTg_uSdNPi$Q<*D@iB7evwx=9t{Sg_lxC3MmU{e@l%M*J9_6%79|CRAiew-F<$S~oy-=U*`hn2 zOfeO#e-gq1jp-oB58Je8iXGR~nSej<-jhB`7^*YC- z=6ShpF;kpGPzx?nTySfxtQ7^^l|Te6+$CXhjA-6%idM;0^NyRc+A0E}=ee;oXC>+ZoQ z9|w-aL=0V3$GLr?7~>#7Y6xZee*Hf z$6t3$fq2I;g$*t?!1vQ6C>8hj_sq{$=bIGdUBcuw6LH3r!#CYp=XN^}2 zk4e5rxJbP=xOnR&k=s^xN2lX~OCEIHWVMb^jsjs_I{g8LIQGIwEFQb~gu&VnTZHCo zQ!~OA%QUM~GsHF~bto#%*HPjHN)s9YbqYjrGEf48RMHfSaq4@q+QaCx^(ec^6-sMQ zqILxQmIG(0(MP-~Z7SJ3 zWq{#%pN4sk;zs?{>RG*-;LTvwf&F3ah3Ds|g?RK+6_+$TKZnRRueL>oDY>N6X|nP1t`bPr&=I-N!qH6?+F6~?0rU3RTpPob1EQuza4a=T{}TBN(Cl( zziT$TM%T`E+f3jsSx4S&E_Y`=$UAw@?AtmRFWGr{kI# zrnw={tU-+}7E-_f6_n*tHp7gn2|AQdjMLqbe$*0S1-7H22UmA=78bHA`Ud6%w8M!D$z-khl6<*2pva^(QEeEzdt_cd`2C zUKrUgK0&Dc78tgm8R>)3PS6SkA;z!_FRwDB=(O7zF8b5y++B3Wi)r zDqJ}@tREGtNFH7{Y$D`nAHAwR`X2*Xu0Z#6-!3H7^pS3DqNk)`b47Pxxeh z`WkGj@c;I4z{SpMF~LOuNqle-$Y{vP#p|j(EPWcYrPQU`QlBqz(M4# z>{Y$nC~(1sBe#rHUIN*6`6h`1Vg^vePlM3ejJjBFw|Y^9M`Nw24TdaLr!^lO=M2Gs z*J%Pb6bj%H3&Lz2c{c`+KH5-e%Fa4@XpKvW-GDQ}S2td7sA@=`%G;RKtrl)wo$oC% za(LOLgRYUkF_|4;c)-Ch-ZVOph3Re8p|P8pmt9hBufzVm%~euEUEPgR1GRBpVnTL! z*(LFP7)M?lhw;)NKfF`JkQVR7S?a}E>F-P?(@FF2-18Mr#zEg5&K9rd{XuUrai{YE zmLOt3wAY(33W!UtU~KDxX4xHf`z~BRJ+ww~fMP#HmO;J@<79$<86ayxzzooq&pKH% z>N6qYD_`Gvo1E#+f@sO|CVS%p0w+v zCRN&M);^c~ru@SHeWqyu0*S3fz6u+G%Y;fd` z)I+>C3#g!ZUwrNCPTG-l4!68)Hgx$bS-*w{&2V+!SwOsRXi0A+UZ3geEd%B00qZ{R z+KZ)ZQw=1<22>Ny(m`GYB5O;e4s0{^(s~PqlV3DtW?pw5C4lQ{`sI!1DJ$0dCazIaL1Pyt2v(EI_MQ1wgLllTXXE-Dl`LfTdE;#a{ z=w;FwPLD^E(_-oP4+k=FBc$VmggJ(-nGgH3#mt?~ru^nezl$A}#G_CP$a^XCl`guY z;mrMg#^x|BzFA3^SgflgN$gi%YQ&bGcG|T`&C(WfZ`>#^;TM*GqNKPjhm{0=E3UQ9GM?u~9U zo*ty0-J~%U9`Tz6Q5`MDsuP*7(*zPmszv*aZe;>QIn8! zosK4qPb4kpExqaIeU^HP|dtq1kTr!WA@Kng#%O zrC9~LT#wdFOfT_CLQm{IDdqqf&iWH~!KR+Be-f?AUqjT89=0v3{;(qM{Aeoj&VT0# zJYUvEC*MnaQ!o~{*PksWZl`yOm!SGfP|B0L(yf4NU&NRqJr11v+jh~EkwwHZVeu>? ziC8QkIA8aWA7(h1dfk`-N2vk!68{hl+<_m%@vp31JZoKYGiD2f>9U2@TzjDM126jE z2q)|9CH}i-b>Anf0ZKg|C;RluLI+ad;R4DkHRDwZgY80KFjBq{^l802_Pj6RkrM;|(y zb$~xZ;Dj*4NoA85;dJ8=s@*CJx)}3Cg09l364hg_%gQrp zF&M#PtolQwJe2A-Be#6#9PQzY1nR>VTfRrQdW5g$by^vN=7XHkD~JD#+ggnMgnVZXHp#-tfbnrJ z&vx;;ve_K*rnpzsnz$WjRy3GIfUq)@s| zvQSP)-Ag{kw$_LJ;dC~ccR_kQEv*mxafWTg;XtTf&^@gBfCqGmhe;s#`wm7Y(Ci>t zwlPkWO+;m$D1+4*D9Ye18NOrWf%$w7T~&c0?h|t%iE*Kim4IWOSl75;j&+|~Y}x(0 z)MNoJ?Dx!~%GbSV_hFkpn`jpu?mLhGJHK#$9==YJ2>&Y0D7oTZvN?;824IlHOHJ_< zk5>b*jhQAluez0HePWeS$XQWR`c_tE3PCkr(HB{R%?gWC*}-_l!??o{Ygf2H+`F<1yWQE`hNTvRl!dVmMb5e<5qIDVSaMqG zpv-a719DqcfRc~5W5~pkE=xNmiwntx*4fnB=j6LiE0~5fk*!v7$d7nyLF{Oqk2d+Z ze9j1ufYCbd$B+PJJnIjI>?pW4DILx2^gi_-D{j4B!t>_!(l%ZHKJXB48G@T&ir?N#(dcy?ULbiy&Nr*^hWl&BY7W$$@x*Z&cGAf?GF0m zsi5$Di}Kg07lMfF;H^7*J?ZqtC3?GA-{dGgg-A|s=i?7Ecd|I`DWImO4Ak_r4)tyd z+~$#U@NNn(N})K+HeN(hu>w$kI`0e?)7iY&AK50uDVB*#gHwDI65tdCZT4ie#t(~l zIlakpv=a7Z5XPHp;s!q#0>GSlJ`Uk6MBsfN#zFECcI173*c-i{TH+!%78Vt`f;uL0 zg_ciZ5FOVXdDzp*?twu0lKPs}2QD)K3O2q*fI|}eY0Zej0KG#gRaPo(jiSvmjLmRS zw$=mL-7m#Eu8L!j@z!l%_*5DQA6I{9-+Pnlag=k}lVh61dPhmGSKf7%Q&#m3U2|j) z%hz~HDD`KLA)rBWiS+hI^zOh?SbQAM!{sI|6t5Fqx!4@Mha()tuT0sCM>`e2ONZRR z4?U?}evo~%eveAEH+<4nc~33Fn=6Y zO_tAarWCM8_I;bjIWv+^g11#|FrOIbg`$X!3{!F6fc0&kf6Odp9g59DXN0ue)w|6! zn%j7Ju}fZgiEu%AX7x2G;7aYl&L2qC@!6T1N7bYn1uK|l#+Xvn<;-WR`=xfb$cc2- z4i2kQ?MK^N=&K-*Cc{}xrKbCpvkp}}Gh>Lo(7?{S(Ga-f!bV}OrCksPgdq1~m1TDO zoskYqw=2>Lt#*V&dHxdnG2JYeD8p*?>snBJZESPMxVg^5#EJ#nq287quX=A-sI4}H zJDqQMD5Uh8A&F(uf6)nyRIOE?z?hbLO4DzPK)S_5icA-PW6HYi}M%jw(x2*NC6A zc}@A6?0%Y@d$+~As^`tIZEa_^{hPuxK=o-b)ogx11Z8RMcrXIYZRMArw;B|;cjp4Y zk@G;PrFl{4MsSMqH1vB_IJ`ooh2wQlcpX}A=5ftW^xN&8y-R;RGSKMX0Xs=tK% zu$}o7w?lpie)_-m$77QFjr?k1KQCJ|mHoU7R%bsigKrh$mv4xPvYG5$!Xn2$&zxz zxZ(OUEt!NxAvLs&DgiN@5M>uAicIC^W`fG#MfX;iC6)YB0~%(P3Xn;FtCWEHQ8-JI zNY4UVz93MRx5|^t`eOnStUO+!rn5|w&DxlQ6hrCXW#)ugj0xN;gALsMOIB7qVIWi; ztYg>9P-c^SS6a~`*K)%gzpWEFH%uVBlf2L6y{~d)y5&3u-}qT&&H{;tVY#yjb~#Og@I3Sd!j_>dGx!NwX!q`2qPP_^-7!ji5U?*bvaAM{lSZ+ZN3pkC zcuaPa4e+qam>4k`EebjfYkEZ_j|%veRX^7CS}?}dC68@(#rHCvq*`wtX1?nn8J~(wJCxTi31V?pgrg5*$rs8311w6}ID{N!cUo|0r zO;l!52G5cp%(F(GC4A4a8H+qRU)I2YpXSvnG}XH&P3>}X-IsKieD1?qenOQsPKA2) z(<@m(KUu9%9N^`ly8Y8Iioy)}NgQNbi2rk%GA$_{+LGoq-*cT_=q=+U%R@iYCTIh?-Uq|B5*(-dWWShl z_qFI25*S{!>$uqs79hxQYY&gJI9?i!iZYIPy*jE>z}9ki6@k+PqF2Uio@+3x+fJspv2xMCdBM@N)lyShhNS3xqq9(hg%@{2|wp?3BV)J`c-lOs!m2U-= zb-cw+(An}jK9Y}QkJ5XT-lKFwmxnR1?%72VhS_tnA}Lztdocv{h12MyIO80#Gs^7T zC1fw-yQC6^oBoI&;GR0{sl%Q+Y)2ia&H-yXd>>`m`6h~Pno$d>80#L94O?#FNHL>5 z{n*owJ^hf=k8>}K8ZsB6MExtI6;`~(k!;R;La`?l--?h>r}g?)k-EW!f23ZdJ!@NU@T8q~0U-mqKc}^~N5lcg}PlDOP-s)O)1f8Bz-tPJ2YY)7SG6 zvjcnN-6L^ z+NpSt)O)19BcA(6e<1fLzBP*P)zy0x|C%IbNBZ--M{!A7u{~1nk^1YFl^xZO^xs2h zCW~&f$KpK}f1?ubquPo8HvGMMXq_S-!YCdAmN~K@VkBgA>iL%tA=4`h9WM?XStK#O zLKPp~&QnYo@oZ0A_Qd6HtWGZ|>X*oIV4vKHt1ld1GtsJEpzcrKdL89vur6bvYf zMrwwX>UvTWEU^^{n7&QrvC$fH)Y}x4!bK}J<*=~QH7!%Qw%qr6Etz<@s40qxCAB4z zAEv%gDs4fzaI*KDc)}z+VRf*C!g~G1k@JAf;{MQ~b-nn8h5bykt3i&YE4WgQoS$be ztB%+tCl3ikk{&U)PtjPDWKevw>J(5soK51V>VBL;hWM@1vgce2^%05i$vPix@^Mr+aO3UTTgJiN&*z=9ts$s zZ_XlZ-frbqsCQmjW&1<0O{V)PO0Pm6{kBPR&%LHh#5Eu?&duj#Ni0crKYZs-rX+{_ zpnuw*E!^L`uG^#8?UkiMLeJ4~_Ga*5F>!yJyVKdCJDLw?kl<7Hy9|=IkQO98{D#A;`JYu5%OznX_2D_A*p`ubmu1 zzYnx+)%W?o&b>_piCqbOI}j)W-3K58+J^O64xtUm4rsCCI`YI252ksHYw5<%lk`Ed zhLo*~McL|TT_hv?S=;-=`s%*?&NfN(6tV(fo+kF9n=H)uo5M@<@Z9rZTx0m{ML$FK z%ryA9LrY+E4=LGv`SNSXu4;7|W`2TmLb6LUg>Tv!0<_~%a1tjO4z_M0#S?1it&nCs z0M-l7&rebA1w^FMt$q5UH)urH`&4_A*7|ef%?c<{3Z_RHFd5KSl7`DLcD(gEqVE#G zk}H&E(B8)|zi_5ufG$J-@=&|7WTQ!L&k<>~MH+PphLqPTbn|C&rb|Se@$+!GArGxrN6ti7-h$Y) zI=b8evN*RK{FaASMDtfBJbzV6nBFF5GBmfNIWsR^B0LrmXJ!|02qNUHz5K#SQRKl| z02u}1nI;L&;|#w)Cg~+k;Q7$;lT8#jX9&Xhhw(C^O(dz~Ip;|fp!87B1d(3IxW-<7 zp?OAP7)Zs9Q4tbLLsDq`hmZ`q(M!5q6wNETgwgE1>E$!?vdd1Eg;_q1ym*?Ubq5Qx zj&uYJ7Cg(*8uQu+CA^*V4r8%v^XF;U6OZs%)KP#MZaoa|bSNo&0Ff z`U*sXH~Q93N4@^>2mB&~AGWP~u|oy_PO>hn0qN1z^fn*Ga4sVE(d0X!%GPe3k>$&{+;tVe_PTj%0wpz_?bn z$G``eF}U6XUCO-vUB^GNM@AfjvrLoC+Q#*t1Vl0zFIHT$mAUCU(m)_`s0Hrh#YtO&*mZ%?} zCj~z5U5^#U$&K5r|o*X#`^j96R z;q&tn;JF;&MG5di4)9Y6@RJknATrGNWA^hT3T1YD7m1 z`^VNh_}07fH2e4V-Ra`#(1Qoo?41lk2efSzj5eE0b{lz49H<^iCajCbNELF!-=wyOVqsE6%4B7JdlD zgU)bB%E>P&K!12rK=g+v0?5Q2cP69}`cn=DA(;>0ki$?jmVQcUQTba9IcMMRT$j}TRG?t z=f5902l)T`a=h;kd!zTj+|yqz7DYM?)e1?0b;~8K@Q0m%G;*v=2q-By!xZ}KH zWR0Ls+3Uk3qBy7CC@9QA2W@Yq8&R2L9dZ9vrm%drfV}+@U+c2CkrZ6~ES>OM}kvWDcgN^YO`~(*riV z{;35wj#W$w_8ZD{{5F)gdJRq2$S?F9LW{z7;US8e1dNKRy(Q;XVQ|o((q}=@1Lj6t zW#_GpnuljoN;MCw1s6@}WF4vLsmbgl7xq9{2)r?Bdlji5Nn$Ky(6q4XomVRT4pz;& z*T~-(K~Wr-0Y7gq+C}Sa)SdTLc02vGUx+fvFB@5BbD?9gcxu680ihQ@7EtX7Ph}wy zYV@hGR_SSFsZeT0Rm-4MXwKIG*useX^q2#Xa@81VOt{hnMQj9Hv6PgJ|wn0$2;-KkCua8A_-s^C>Q(uQ|Bfg!3rSJe;HCVQUxqmuKxPSc83xqg# z5cgKOsa5C19nSjQ!Z!w#Tl^Q%)a%#&WMtEFf8qA}v(W_FEPl%j$FMa{iu`1?LUBM` zhMkN!Kv?wC9rfITaP~*TDLx+jC$ZOZZyIz|>TFp3jn(Pm_pLfj{CEEJ@MV^ivZ@4j z3k6Q&vr-#_c%g676va6PQ=4MsNe)iGMN?|PHA;Ql910Yc9iO*3|Ac;0yI-DQ)NE(5 zXOpwR@SJy)w_c~o6$%umcRZeq-Vtpt{V6#`s`kUoS)&+xS*7SIL?7jyjNM_cKRj7X z+;@HVJ>2fxhXx(Ogh<#k)r8toM(vu*j5f^!E8!7z(;B3V@6YLflnQh z^K=ta|D(*mKr56vXI_Q^uzuZS$oDdX69#T(R<<(5jbIM}X-ONt4X8Ty^{x5sQHLqq zx^6pG-t`1!n<&pT=5{d*R^u;cH&o(9PKJl0H|oY!89QpR7@7gjH_N@%TFD(>Q8zF{ zL$9Oc?8upiasE>$O}(4;WWnI--@?P6-Dl1%#df3d41skgoy*=C_Sg8!oJ$pZ)07o)0R-@r(d9vOP z>*0b~p?it=o0`B$ko^l%uHByx%>vt=4fzUdj>c3WwbeN1Dn`H6$-usCmIq@Ok3;pT z`N+KskLvG43muc4ifQZ9vfV+EF1YHRxjR(6eHt{)ll8aBdhCFF$QEa}#KT^EiG!t# z)8r})P%05u_7IM6M40UimJc9txQfoo`zwi^-<$wlp$LqQRbJr7o%vvf-N5lLD;Xa* zuu7)Kedc9&T+tsb9&WgSOnFdeRbZGxJ_84qx;`gP1mbP4XpF9y?%52uqBx4YFlk5+24lg?0AA!df|d+2x<;Xh%EOnOJDtA8ey-R9`0A*3gtx`i ze!SkObZq^Vw?vPKXfOmgn5>VotXh&9Qua?fCt&J>|Cb2$(RJRay_x$vU^x6|h2G_C zD%37N@n~Isw$;qT(ZZtqOk5}tkI3|LsFYQ52M6M2(K#ECh>Q={w?iax49OViF3OtG?r@7 z%7>IRIWsGZdJ^ups_bf>wo#;CTa89G zbHH2*v88HCt8XD8{vhZ*S|#a?8|Uc_rmV%{RG+7~mwOP!vcWrLTq1GBAb7F2gbsfz zO1Eax&GA#4C<@hkqE;BH>ueDag*2rwHSD?F$%iqHTMc%+^9hNoR{vNxK77|1^ufLc z|8Mv3W=6rhyP2=GXE#$)vFK$)SQ3JazDvpJb`Y$VnH8;8wruUwy*>GzJWs>34MdxR zAal;jTf?<_iEbWYmm6p8g{k&>^~x4-jZe-=3QMwMTE2(be|Yq=$EP(;O7>ojj1pi03mF*4Pf{Wv39$U6Je}Nx?GLBK z}Fcs6gGIN+iOx=y5>9CZL3{wW}G3V)#Sk}5fC&zCnm(eO>v{& z@l8c$((tMxm71+%4@dme@GhaP(cNwH2%p=}r#u(-3?|<~h%%0!Yba&C8wP53+_f-y z6=D@n>I!*6l-Z$Ah?#R1|L?+fOffUP5t*V=GekQ<`GmaGy}CMrvqI|VUbg?YK|ps@ z#f6otJ`Q7bdbg1&mXo2A$owSL#a5(Qu{CA{X{b5eaQq=Itv2rXI>Fw|H`|Ib*p1?z zm1$9M>a9g~uB;|rV+;{F^GT4s1S{zSYbsMQzG-W$a@ zl$KNwO|RcV{U^l1f9K*jlJG+enp^@DKO1j%U8EqEskgk5 zBaU*@IRcGhu;K{bp|ngsIZq>!4yjEprW!WU&WUTkuw9b-0T26#8^1x}q(fkl z@1O4ALTN~kIJ%nEMhkDZ`V6FGAqX=+^1>A+F)I3DWBpx^m*2=Po(piUwgtP>aQKaa z_V2`iUR=T^cJsA0G&)u&lN>Zy##fTy^z8)z%2}wN|H>-D<6p7vt&c6SGPXOoca(W7 zFOwhv-GFc%RaPW}WdxX6QVBpQFTxfrT1^f1wg#v#md#=-eWkVJZigAu8Ye@O9x+2g zG-(}MjM#(5Bws$O4|Lyg@oNTJ4V zSI}zrUjqvd|5@>%?6@mFl>N%{qHM_@)M67In4U2^Cjf_;3sE$R1#4g-XgcYmE0lUm)b-ZhSr~=+jl}92n^The zDRZ!uAT>-+Naaj!DqW=h?smqV*8`VH22Q_-=Ga_Magw*_tv?j|E5BJGk+38cCJ9A6 zItj(wigr&yC59j?E8#07n}eML3e6e14l^8BgngVS7VNY$B&PA?hqxKgvVVd6%Vd+2 z$Y>-)3EQ?Jw$6OgebbpjK z^{$s1)ICr#viMv-blqVa^v?<5_=roXHKtCGtb1xhUMG<9dr74CBE2(My{8EB&_R}4 zxF+#2JOf{>AWU%(EKE7L5w1$))7!%9D4&)%=tg|8S$VN@o`xt6qMOGAiqI?#y{Mh0!u@^RC)u9pFDuloby^{At$;_{TA?Mm&(MGyrA_dwR+NgRV)}iAR`C(RFctrv0>4~%VkXfVU7 zL!0@1wvPw-Iz`@P06CbYFQnoT0NKHVa0Tz%BzDda&==4iq2Qr|4wr}cAqYV5NYrN! zZ}6&M2J;4JCvOZ}9L&L0WTkEq!D%!iLHR%{oaUE?^FR~oM7z5i4q`(t$fP7G~ zl$L2!kq3b_!z8dpl}6}k?)L5wwir{vPi(syl)=b$-+A*jDaO)bS>_CBDWenCxC#Ab zwXq1^+PK48BXiv5 zcxuV!5=cA0e-QZ;3e!zS+1Lhsn)I%<{^&_`Qs5Kn3km1jd5TxaVw#2=&b3KmcSsNd z=MIiz8^+Fj*2QelUrCG(O|FqW95*(@c_55T&I}v&5=U^NxF*UDn7J24$wyGkpqnHn zkBKn$qYcE}_`gk(dnDF_J-w+OH}?dT`iRk;b3QnGpfoa(f?H z;ZM!bLvC3jA+(%|&;~VYD#wxJvk^=2?5Ix9tk=bpE8}Z#qt%z-rdFjdfp2EaKSkIn zU|cG0dDYNXYq}#x7|9Szs#Uh&Ui*kLR~IQ@(Z>rElQ04$tzaLSd@%UTLDxP)K@r^~ z&M%@HdS5)C0S%n*D`>dpG1Pa4q;`JfWtl^QwpV-g8#L_V9#K$@99`!KoVgZ@*ItII z?==Y%vE@3jYqTzZ`Y$|}Bjij8 zDZc#9`gvaKpr*?7eEjav*?v%v2vW-682Gx#3RpCnq&He9YF9e5N*Y1W5DE+ria$45 zURwU@%ra2A@?!c#O2c5wI3$ww<;~}))Kj11KwNa1Il?3zDsOVyUN*Z3vs1t{lTb%t zqj8obd6uW%nu`N&Z@ffIk7izW*~zjn%ezb~ssJG^4cnAMwY4bGk5w7hu}5RXrL2v~ zY7^z*BOJMn9gQKJzcJAIZEqKGnzY%jFSP>q3$uRV&CAgy+k=yXXjpa>3DeP z#0;x4hqAK)Wo8~A3&X@aKO@Gzske7+_T+hMKNxoMyE(Gu@v+=5dZlc+ZTI5Hic4B3 z3A>W7h5%f-7e**>RwyHajWe+4zy?mz^|Rk*(mUzkmF+|(#l_su>6b2WQCc@ywmudG zTGef82W>bKdW&d72v2F-~agh$E~|G0yH8?Z6@$CIu5 zB9n2-|G$!d;R>J2PY!#9;xOS4ojx`bFaD=VjUGDHsRL&d$PM|h9%1~mbDkzE=isn7 zMNba?X^i~rr6O@{XrX3IYN49OL1u&c43XRH1wXui05`4 z=Q$P5fk^;&cbvehFU^^d)6=ydR)~@8)e*%u6#&J;5{~}8l>zH16xQ_0)<|BDT_$UJ zeQjH(1r?cS=C*ME`LKJ$KR1cJSW*$56v?R$zlA#oM^UBe zjfcY`L1+29asKh13n_1hCpcaq`6;9lCpku|Y@=chCz z>n5m=45q5pJkg}2B{^n*=e>x7cM&^HImE_mWGyDx|NBP&N#s9%vRZj@kUbu6vWppt z5Llty-~_H+Qq)i+WRU-S|NRd&`OmYbPoF&7%YW`z{u7}07h$$WDM}|`h_pgotYims z?&t~y#9ZQ`GezlD=%XrsMfr*5Nx`WxN)gcEV|CL9|NMXD0L0TqY4}5F5hcn@H@w{P z3EMV3w~m)N|5f}hYW{Dw3iFGb$K=09zA&(YT)swLic)A}v8a8kw}lbuz{o{^lC<>C z0^$=hR7p$!j~cF#bR;1E`Sib07+*R{to?kbi1nkYKq9RcW*y4?k@GLb_-OW>Y~c=Gp{?-J#19ITTt&c|NrtxyhTam08CM5+%Y(_Do?5TTD= ziXI_a_u#ujZ8Pi}yEE>CjBCBgE}XoWG0o==1>Gpw1n<4vzjz3yrQVy(nFCY-FUspQ z43<>xg|5BT8XOC;5g?ce!;sFB82lMXSOJe371KN3xk)xojEER{Y2@Ia&f~|9JB8#sn+PKQ<1V4| z$B!wpw(tHItWyY6^gug?@9-d?S`xpVGD9H!)8+gH@6c{@*9Btn-WGee}X&#SSwR2M=hg1pe`3=M(Od9yj{yf7gIFrpxJ(@m9fbpK*&M zCR1jtLZ||%lObf;1&LfhzWjIQ{2MRHzn$#DTT}eBX^Zw(5OReQF?(D{!;jwI

^#Wu7Y7?`Vmng@jN!1QDzOUK1u!T4B_5;(yoE%Itrxe|$1j!_Xx#y7i2lRO7!33hB0eXYkS^@O9o?U_1&Z9Q&~o{ z(mhq;Ao5y>y{m9Zv^*CmTBGzKUfwWv=%sbYL?Oxv8iBGn^qs{5zeoxumYB4L?4Lx# zs9Q$tD6Zbw;@ z2I)?Wl{`q(l~N*PTEvDj5>s;z&FgU&a-qM^tiPOeD8*B*him;aIlFJ7AI;v}jqpc5 zfO{qW(U4Livf;Ozh9)-(df@p*EIt{!pqxKTn}ZEDknj$fY9DHc8T%{dv=c;`T#pJ4hEaRQvVE6TA1n< zDZ}t}n4Km85})`))c4(Ck%#hUlenW`7kf;zRK#$W1UCZ|FY}8oM8Sttv#Rc1SD;?x zZz3;GQf{~qAf~fKabBgZr7QA^Y1R9fJ<5X1$D2Hi9>GQa$b&kMDCXmNp{p?2WYJAA zaMpksuiZFJR$+#IR*khB%FEKYyp!i>wdRr^8yA*9zAXG#mSMssX*O2(;+vOT92%;kl2rkK+=I_7v8fUpQ|_hjh9_?t8hj| za?BKYt8NlSINp!C_LK+wXAuRgxACGZ_x#I3F2zRSF;0MjzAT$N4%gWZTJqN6JCtV3 zCR5*h&%Z#YrCd#yF?N$iV=v8gXf!WCC<1yJdj3NXfnZ2eivqB9+?dvRun23(vgTo& z|I|rS?*?NFJDE*>{!_EwphneKgRX)wgKPnBk}QXCWZ`wWaP$~aQE0#~Hs8f>flYyy-_ z9Zw=$#xk_Rm!;c&|7{)p#rXdF;pvO|`|pPrFJA25e|P%+lMxc(#fOOw^Trz{ z0c!SUjFSKxQt z_%cpD#xGlNz>+Ew^{hCSFUgqg;`zB9^S$Q{>%8H;eU5CS?7bU?_wS-~-}aGxw+{oo zIIS)%W2Izm_-kEzFZY_qz2E7vOdJis5i`%gYAH0kAiR#7I_~Cv>uh_kD&lkP_D>AXI z4Uqo+fAT_-|LMiEz5Msf%YVxwz-LOXE@vbKIIxShUhjmGe4jRj9>`liYB1FAj-0C` zv<}c;Z!4qR$S2`am0g=n!nmhIq$6~AQiDB z?@8H>GTM`V;TlFg(l_?dvA33S0i1n@FE!u<*Hq}-aj3Gk%r{$7Q5 zQc_IY=-xS3`G~a2x9H4c%oF20Zb^)sOLXJVG=ZcMq9dB6AxIN?$Pa;OWE-3-ii_$X zImj}aAkY|mim{}yh9@eq@Gs1>tAbFGf9o_^rrv55#>;^hFE`#2(P@mulB$~HMD*Lx zTOrF~eP;Ug6F@$k3feB(I$pQUa)~k~0j%Zf0sf+x#IYH8Ig0(8(=dv{4EaeMWJk^r zYh)iB1j*(sLI>X|T7sjR<=$$2gimtM%h7{_S^w0X&N`=Kbv1GrW=U~>+KoXr?+H3b zDT;lBQ)X9{Fo|Sp&- zAVbtnzzYHt^aIojy=9zadFW?H&c9%NxsQ;Ci#?T}1PHd&aZ)cX5BLOr^TiIyhgx7j z0(rk6msm3A<`G?{Fb58eUK=r>#%p?uDA=K{*rD1+^oPdeRMzw6T2aBg=#>CZlpzeck+?&LtZHtah5@sK4wtK>>@j=3W%KcT9F zxj&5i!`SXHVv=f0e*>Ib(;6I`4PFwHLJd@Tk4Z260o>u`E`%{(XnM z&kmU!yGu{OG$gqfwW`>TN!i4!B*2mPIt{OCJklZhh&QE09bi!m;J|UePs2P%ag$zZ z)hs${fFspLLpP^*@q7|0vGy1c%I@wZaO+2W#msFC%we44J}f!v2H4v2TyKMeO>sgo zf+lpA>9WmH1cEvBy|_*+%WrphG>Wm_sYO*g)eP=Es2 zn(>9-=HeBPz~e9u!g!h4o$76t{MZX4`Fb-YhQ&VkSt6i#d7v5XS8x_5XoZ51Ji=wm zBb2vXq^g>-Wi5whu{bO%nPV3b$--Aa=j8BdVbV>6v;ZJfN@9|gPuU3avLx05K#q0| zKp6YcCP3LSn2F`-1_4uk?nN0=?Cf!PeM00hHRhlzEv$O_v%zUKF3!%jq2)<~S7A0f zhdG}V(kb;l2roigXkoR#!(8$Y)kSP-sClMyV3>=hrRGRU%&7Zb#?mEb|H$lNtB@&`VH z1s7i434&9UW%YNnSi(}z_zI;NCPdbVup&*}hH3(yRS>A3kn{P;3CKk{gPA)Sc4qFP z4~ZQh?5RuD=fmk}xZva{Q!2|j9ZyE@+(mcPD?}@AM(-Ey?;U830(JW{cQGB! zCuKGF_wk_9A1(&{p}Tnf0sqgJK!b~^J8-+zXinUrJAt8g2cvnf6e2BV?&)~YnYlHn z`LI7*%-rd$7zQ*+OQB6>X)e4BU)*uHUZY%f3$-R55J>(Cxj~pG>5P*@XjB7$g|p;1 zOtZXuv57CORRd7*HOfCC6yu5of(hSQ9MH7K%Dm1uQB-JMBBHX;j)lIjO@gc4;78L>|&hmq^FnHP%#7cpK>w1*LfV#>+~5o_e2~o{K%%RFX}(Qt=y7#vJ@y=qz6z zXzK4ZC3mg1v)q{dHtud4`3rEakv#Y4ufE=Z(F!rK3 zy_)D%%v)ipK^Rt117#9e(W(|8rAwj`GP^)gWGXi|6O=9(dZv0>>P^*Lm zR#>fCH@Oh(SO>GabyJCv?3S%r?JZX=jA7hx2e9kZ=fAesz_t`lVZ&F8=j9YdI7b=0 zJ~BOINklpUe%v$wZ_;`XMNL}op~%oW2z84GjqcG?7~AS)`}o~H1+HvhB@ZAK+&HiS z-|{GynOC`+k^9(AT-`uh69%XY!DN#3=2oTB-3#ED?S#@sSf<_S=4=HP9~KhqAo1mw zOHU}+k}?)@AS=u(Ak9cuKpuyY4$=}i?8PZq#6bP_HDJXEhh@q|^%&2SC_pJ@D=oN@ zAo1TlQ|_Hmw4>cCZ*%D$TGo~Bs%2g2KCA8z+szbrDck8b$@!3;q-b|Y)@qAzy%yVp z>owRKEjqT_P5l5hJ1eiK+hslLo}(<681cem9mJ^>XLpb*?i63$_`Gl z#z!??PH(att*q)a(I^vdHI3>&43J5Ju#Ps%Fg8I&*;)@$EH@47sg_h>S8&CUKQmr? zg})?m_*42962D*8-LGJ`onIX9qZbyQgNGT4g9o%#0{{52^9grJ-7d@I(%>Cxa>0IN z^qt0VI34!?rYPT}ab~PSd|yA;bKD!cz@FxGW{|xeFA0;p-mWd$cfGM3Vlq4hX(|{h}HjGj>S$c-Q*e6T(VrLVh>orN#jnXtpoy7MyX^OMm z*`{+N)=s$9tRR`CR!`EZ~$oHmk=%3vTP6+&?I3JdA zf8?EL!v1KMtZ@_^O=#l9H(TP8FghV3!&~?yI_@V82FZZ;d+h(&$bZ1>5~^Peh}q9&wtpAu%D3A+la(rXJB1umbtN|yq3Z4?%dRa&s8;g7>jrPufcTwiuR5 z;>VwfX7WC+1GBVGT&A|-FR`VE+G*dZobTJ4<`TuJ-NI1}diEk~N~l z(t==?dj2JLsuWD^COVj6l6(@j41!FS^*~PcdNAt#N}~}D2BY`4V}~cjn4Jm_`3uw_ zIy8w3?S+35p5u|8U$7ATN$wQ2*iX`UJE5Pf*S*MZZ``*x?z?{iE0dIp=S&o@je9Dg z;`kMVkcg-HZKYEp3AO5WZ`}7a+5gSF?6Q+(VV3iO3mZrSwer8`PriTgV_p9D{j;Y} z_VT~Kq5MyE+IVT88pcc#9K|Nf=G%%wFDT=v*&- zv|0K#LOPpvA2wLLJCjrX-52Bw`l-U)o!rYV9S_f**f1{3`5)d#fu~`!?oj+`9?AU^ zh8pO2A)2cqAcCVRDvkJR-zzIVZOFs|>|>H%W^2#aWiPu3vmA#>`&SVi{|)(42{_BR z`P6RBna5Zln8eYIlf=lmL^t4jopE9QisU5gO%HL^%_;Lq zNd#CRH_qjdPVowAahQWJ#ff`wERP|&4ly6E4uH&GK|!*y#px^$P?}l+e{Q+g%P?nm z`h@-|*)O$*+LV{>iesVapJETDfXh;@Cq;1%xDm$7UW1K8@l}{6G2rAoFAcpj9K8Ks zbbvyU@-#|-4O%NvhE2>j`R_rHS zCYWS3M8b6nCn3LSK~##W?=07_fG;Q3pf_=yf-)Umk>jBJ(2NDo83w0UZ*(Rt)V;8j ze9N9q+OtUwUs(Hx)t7r%DL3BKN&A$arj}O{4&AOhopvTPhiT6pPuy;2=JpP(MLm>6qo5yyVGuRC ztc_zLfT)M{$y8N|7>UoCd{#{iXn~qqZPKtMvD6ctcKLPN=GwKPExMAnn9@Wt=s3jN z--uUI5e?B}2>iyR{{0&!OrI^dVbJO%5vu8A%1<)c*HWK%t=959jVyqvEuKb;Bf!#O zj#Xg>q?M+dGrv(i&}C{2%5_T%TAL}#;SHEEs+!`H*w=-Z!K6@}qhOYF(`FqSf!Mr6&tCu_&3!JFVGl_Pl{`){Gb(w2M8Opx8se?$E6Ojp{d)6K7W34;!bCa z&S2(FhMk$a=%0=UF6;nv<#)#8!G}e6bb2}(E?xutc+%<4`dxQQnS|5vWc1EmR5JYO zo6-A)`+Emkqd?vM%w0@J^GR9F{e3*>^oNTJHp)HJTH5=uTj$ z-N9(yE4h=!%sm|sIy1KhH6Qk8iv&0q_vaeXU(4{E{P>8@)<$tYWdN%lrzAv3L-aqp$zft(Wit=s z{HIQudN&WqI~pA>51rSW^K+CQf_>40gM;s!B*nlW6?0>FEv65?J4E;wl(*sW>L+-m zjb$Z8KY?Oeqgs71#PA5CGO=tckh}g}!c0{#VZ0p0(T$!X;=AVmBF1SRHnYQ~n!No^ zM^Ri`Nb=FVl#T6uvdwx8X`bTTOK;wzvq2bN7Wgrhl}Ry01}V|&rBOo~pNDzWSU*Nw zV;ghP^~0MoPL}`Tyfx)(Fk#bW)P-X{iZf)z+(XCMj>JwMv$1;f@IIuJJ)5q*f=7U# z3Kl5MZS-?kAYcM(PC(9+C`vwV*5fo;t&7|FnENPsWi~{C{mp8)S?jw*9~vwp3x7(n zf)+|pyX9-81*b?Y*aa4~iIVD%yScPd;MTj45s5KR00x$|h%(26DoFldI91 zQr&PFd-*19BfUsb04ji>obxR)G3sl&`d#fa)sa`%HTaubt-Hijm+iPIg;Ja3^3&t3 zZUr4{snb08nbm~86nBWXiL{=!Xa&hhh$XiYky0Q0j4cme+8q_q98U6vzC*L&ufaZ8 zA+-4$nf~s^gw008)5dsBV!9@FZdehM^nkNXlNzoyKC3lLG)p{eYhc#QysU|FSp(BD zYs0eU;vL4IOju|e6S8`HjQLo-y`~0ZZOz3L#$uKS#n$r6*6zznK-<9LtKOc(+N<7t zJIk)tc3sV^y4u@x)mMVE=W575C{4I@enSFFqbDW;<6$SFYsL`Yl7_aOe%8`#L^K+a zAzTalkk3+m=TgO-G&KVGL+&{t8h}XcQ57s)Ww@bYR@xe9G(3Mg#YtQ12wM|aE4v5@ zpDwY9_y!T{v*AjpnLLQE87l*a2IdX+#tkh@8`>E*SeiA+v|WrzL%r2)3>buqTVlK* z2(xw~iE3|y(8vP8B)sBn4=kqIR#?Xy7U<|vb1_3hLxBcrYFpaa$UwkmPo%ricwuCQ z0CJ-iR^xvwt9A>fI+kv|jCl6o=SrXdvgyX~rF%tzMp0m)fG^eW{E`cYZ%5koQn%h1 zhi+S&u4f$hBWR;Vw>YNKYhP%<~cD?z!uo7gG)+d+Ce@H@e%kPU~p9qZYc z?P#te)*UTNaxBsIHoB?ms$H2Ztr>l?)Z&V2>$}k4%I})$mw(~qvou^TQA#r;o_2=w z&VWjg`kj;EXgce63n2kUj_#X|LNwrSvOHOZe_;})PTc4?-V*N1B+kQlV~Qe$VIhtc z9pP1YhRApz%rd-{>zN}<5hRS7+h8nMSwyBOKpP1Br)Y z1%l#04?v<)!NEvJanrSf z4vV|1=f0z38g=i6M7%_UWH}=7yN}A)Y}{v-0xeT7-b5Z1KTceEOc!E^=&Q-%VPZ$xq!O{YhFc72pJrq?`9DyWx61lqoB#KR z=g(f$^M5>j_QO8^@82^22Y1?PSwCuJ`#iwfTpu#L)hEc1)sW@&knK^cY#zHAqBL`d z^sF?<*CFf3kflSpe63PZC|i4IT#CEP!|}~e`HN@T0Mxqg*)?R_a+f(Z6#d`BOd2xE z**J-A?xjnFnOz9$Qws6fk1|>4CmyU4krpmmq^yBRp9};9@Ytf384dT173Hcz-s>|b zw+nXIBFLfW%^{1vc;^FQ|N29zohUsPZO#yP65l3gCuy=-Yit$>8qAVQq|(S48nJQI~G5r))vWG`znSn_~tbR8t6vOIHTBw6Hz3-L4J5mDQ8x8B%slmMOdf~lR zbC+68sk}rZKE00`OqnD_rzDiVwOVN_m3M=6_xDLNY1aRxUYwQA+_#|r`|-*1=Ysz4 z`={UU^?!dy{U3MQYWlxg*)sX4`WP8*~|F@eVO7(xzv(iBSC+o^ z^~RwT8Hcc~Je0Tf6nZG0#6Q1vG zoF;!Fzn*I}svNl9cHVUsKao!G@25}MKVC3@JfkJu#q>>QGA^_tuSe8lZai4@DR_6l zy4%q6>c&^nF;2>2TUSQFcNqJ-({kwVPOFi_?-$kYXHR*5#30Fs*r|Hx&K5r|o)Ad* z<2n1s3-*tn*gyV<{iE>eSv*@j;rm&6VSJvFV|d!>5059EQ_c;E)sC(sFNYQ3V$aw1 zk^|vFDewXMj=fa~Zukf9`@`PoJw3I9{&4=gvU_q)I%yuBdw#AvO9f03_$x_mw~d@r zphVh!rUF>i6|ZbA&T$!9nro+^4ML>pJ2~{y81XD3Gz>Da-I>43b8mI_Z38SC?uWsQQt3Y*)Jv6Pt-ROM3 z{rP@Lg>SNE^u6V@sb9_g)BGy-=dKjL>hABE-d903W%^D#dDT_|I>oZ>Mn0z^zzXr) zwD1@s5gDn6Sf|@{$K_uW_pRG4|C-J^lk$)8#2t4gW&RQJXIVJt46EEE_^+a9Ht7tf z5NEe6F258Ya*s9ARA(~lcLpSYFk3L4jmG1$N&Ht;XFjbaG@YL++~0I!NbM#4$auTz zgpgWFE0IBJyJ#qa)c3uYK<*`wcPoM12Xp%t<%%k1LH%~PZ&F1C7on2sscz!NGDRJ& zx9xl{QT!_9fAe+VTYCzn%?h~=ubs8i44#4{bUp8R`Nay z8=)+lLzFL7E|H)}60d|fM>x|E^^!34OJDUUz~ir?ghWZal*TXnbCcyv226RNFqE#m z7{&SM3Z-cXDYC^(cWM!)YWH^`!BpNPr2zB)4}QoM5l3Pr78Dfam*EOLxU!;D&_d44 zymV;tC-RD#)6oRZ*&`3!I+oNENP+gE( z1W~0qI?_3MsLCK1UBuZO!P!3v_i$E`B#tcNts;oDdURZI6pVsVFbc>9 M01(PE3IJRY0NG)|@c;k- literal 0 HcmV?d00001 diff --git a/core/codewhisperer/amzn-codewhisperer-1.0.0.tgz b/core/codewhisperer/amzn-codewhisperer-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..18ab19948c28b062a636a4637d4e950b069ba11b GIT binary patch literal 47406 zcmZ^KWl$bX&@Jxn?izx-y9Rf6m*6fB8r%u)5D3A7ySoH;x8Uyj?9Kbty;a|zyS25o z(?5EqYj?U%pFTq#ivaQ81qGaUIry*hG&5{WgK<}~^D7pp=Tic5E)=a3%$cIg6D}R`0pcmsDdM4t0FuHpx7c_ZTKYMbux~+ z&VsHwJl~u2t5Zv;Dc-j1J(btW>32E?_EWVx0^Q~WpthUVst2@*1D0RELW4NZ#h*H~ z9bm&8oAfE3frR&vxSmU#Qwx|HMbcG*iysT`!G?|kJjb@xbkF#WHZyr)%9Wm_j$DtO zC#!vZ^Yf{2cD&j9322{}a79+AQLp^HuU-rN10koJYgk#XSeH> zTo2c9636#}pllF2>!L$;j~fu{yZDR~a>Nw9%iNbq;)QpFR!3nIkdrR5wn%!jc)bko zyw}JhsU3FXi{KSeWLO%7=gDRj0?1%sW)SoXWyR@}GFL5war|Klm5ZKrSKxxvhx+)o z2wY*5!u6KhE&OXNxFJ1~fq`N<-Z9(J=gFPlXx!Ipu8d^! zS%RKy{kv6gFi&=x`>OUH3feSGxA5@6-4r^!?BbR&8`071RzBl4j+m=qqo_E z{7$FElx{|rzvn3PZl+6Pqb)KeH6lH z{z|Y`hV}uw*ETa;N_S5f6IAy+O&J`lgbuqLhn6%Dg{t9Ar;+-ZA(Cn&l3#+yjj{rZ z@Ha!3$4HRn95FVZNBNA`!|XzVtSJn86?iE0K~f z!4M(z%G&B*_uVe{P-J9FWn;lDP}GGI76mL-Y5(wPt4MSU&eJg}G$ zUnoMI!RO1;kK)R0pDGz6PRZUp!CC$G0xLu@;cFk>;1XhZhv|1n4P`0e!aN08ivB`! zJ?k##h!!wNPC+-=aH7s7M;`uWWYcendlHipTNP1WSCI&77K}3QZdkuzbZ@J!j>XbU znple+{P}sO70f#FF!s5I4lT}>KRo$jb~SRx?p)VH4Pt~_whWaS@lWdQN`}V3=&f_; z^Zm^#^~R)~Y@d7eZZRTP*h6&L%#U1&!w58sP(#Z>B3xeZ+?Tatr12XPgsjzuDXib@aC(8P?nUN?xgDrIpIj?GsOY- z2Pt0vGK4ixL7&?XxlAbN3Oq$4m?$Jdzv6PGxNZ273t-|%0D{~ ztPf;A-AF8kcR#0MkXBA7wp;91R7~d*HXoWoZB9$ww-tFFA7g zqN=iAPJpMtSpKE`g=IH0kQ8OzBqWP2kuO9_MA`Su6}mcZ$C0h_w2?#VkG9&xB0;KzRL;nB z-fi-B1n!WN_T$;vXbKfu_e&rdEzlX6JDQ)5HXt|2qlm9yitMvS%VD@$IbJUB0IS9U zhgR$f{#V_opd8yn`1(wuiD)v~)7)`9nL^1Bv6du+O&hU1f!E@a3RygY$M+#Q%)v=Y z`(Q@mO0h1)_qc3R6mra_+ko(&INk{N9k-0y$hK_b1TkV zUd72e52kOL`CqjZj0Q}?L&rJG0IAPJ^TdK7G70T}6eE~u^f)~tj>E&NxW%K?e2;b0 z?*{KXSUaX3p?ZGx$p{RP5nu)&`b}=TB!5*_k_u0^eTCbieEEWcqyB;ML}RSVefso5 zaX$vdTg0gJ&al_hP?+#Vchr-vOzAn?H&OREKdLqO2cqI$d*ZPr1swfa1Izt66?(SU zd`k{2e!d_4qYyh^(SG4T5@oh!M8sO%SX+nuU~x#)<^oO};&`!f>&EknE`mg;ieae? zGcTQRAOQ~lKoQ&pPMc+>rNC;8dzY%~3tm7#;jBC-k(4d${ZRrrrRT-#A^5ga2b%14 zZ}x?5BH>9~@oN#et0y9rSiL$H=a&=O;9DaV1Vb3qQ;Tnkk)`tr;aD`T#*irZ_L>~O zLuM$s?j|cCWJCt$e1A;B37b+zMGMl(ocN}?H2wRZUDt4tm~{hA$qe+ zx(nvviJsP5$|b-+^j()h&Et8k7|Vey`VYK4 zG!fiO%a?c3WNKIjk<);0w^iYEIf0Hum`g=q97JaVxcd0jL0$uDl6_>nL*V5gZh}jo zF9-u#|8_{KL~939`q3^h7R{#4y+ zOeP)kzQ`isv2;vm>T_IvNkpDME~_XN4SYJSROTKmx(YaCC;Cx`5ePJ1l~nqCzuVLScrIXxKzv!LXTdH$v6HZLQ<=XJVlSX6cuG#d^w+z~PY#eI6G2 zDvi|lnKJGNicv(m$O${ys9D)o7(pP*UbZV|Y%wDn3Ur^M&cJq{f0Ig=@zc!#I>dp3qSa47q+m^Cej1BtHg^Xc-psIME}fa6ijqirK=f{Wm*NorZHPXp&q!X4yQ*U+?5PGTm{i!)ybGBxd(IZUh|xK) zc&O2SluyZn_b)0Vu(^?XRt0u}aXDrS(H#{muLW6S-ic8XBMC}c0<|-nn^nHgx-DCNsn-k7TJ?NCwiq|M!y$+x8LFBV| zVe^+jO5exd53O3n8t0lP)>@NoBjcWvt}~-;-oB2l z&6oAdhrp-Bzl(oArqd#fO}0#)UOxvGPMB?YU0t$HZ<}~t^xVTDwo%AdMcUc&qJd3#SJSk0ufj`Q5p5N)WZ#k4_X1PPUfFh z>q>G$awfwCwrzgQ>bjP2pGU-S1r`Q??lObMV2@#;IL*k)& z`B@yax>GLfU0M1joJCVY6UTpc4|gQx&hGo_&51RRN+p{0Zfx@nD*D9W5Ssg#!HpU# z5#f>fokch$B>3dAH6W1fgiwu~hG9Q-lEZF9h)PTzncf8_em8X~NI@)0H|zF`ZPS{nnB%Htu+%nS^iVYq^=B zhPc#l4-3Ms30Fx9)0Xz|3q zU}&=_Eb)WcYWc{kEW(ME#v=#C65;pw;wUoF;$>66rl9%0!VS|Ez=*bmgxN6dh;q*? zMk`Y^?0hkvbLZ7u=r4Zeqbu|GXdC85)@WG|VA3QPM2iible4jG$Qw3#Kdp2)*@=#pmaend z2|$3FrgS#+WFhf62pvxmBzWvD|(+q9zQFSlBi>r!sj9+z|S&;UrY_}5;b z1oCH#@}{Pcmvy?h;yVQTB`Jcv!AcIT1MIXDdJrOyM1{sQ#!Rm)OkuG{nBon za!_fsYdki!FH1S6A2bIr}hq+$vyr?4K5`rdCCiS`j1N&9%tL^7WPT4teTuqo{(X?F!z`VzqtAEG{)V~7K|X8C?tpu_ zlrU9ss}feb!nZR1yk-#zOq_QsG1P*h3TWiD5<(J6HaD_lhY@$cM~JrZ*wxK&ZOePn zWDKN{52!plm;k8c7$I;@(BvM`NkFh8G@;JaF_hjRwcAlG=@VLAZkoHc#v3YYDzJUp zn22ui0^|)m+EtDN+k+l^DHJm zYdVCA_EI-mAEPAcGC!~R)QvFN`|81W!UUyW4X7k0*aa`e3KPM>ZPE+5U_OE)NIQgW z!!o+7s+YMgOiu;!O9b&mq86xM!?+7FznM`|S;G^w!No{Ci~5-R?Z1fYIutA+tv4V+ zZ&Deg-wvOH-l~x7vbbZxx+f%5{ygGbKa!PbM-6NM&XAU5tZk zJzlfglKpRI@zGb|w8a-0T6H+*Ig$))_>tC1$*6|UxI+?hg!I}GbK#yX5(zzU{;G(h z^laHH{49!3TBZj&o2;qlzb*udNi91NB&TWLc@Kh!8J_1%AHl4wkKJw?E?r9>E27>g z_pXk6jBd&6HfDqR*b5xx5vl|5R?7~Ud`EH3zP-4o@jfEs4~OR*&!*4A>^& z3q+b1!eErJCBaLW^;`Ly;Oq7JR(AhP`&c>yHR3%K6ank9dGq05XHPVykDh4Jba!|# z1S|~vYCfat3)4ESvc@v&Ba~3_D}`;aQMg$R-pDH~j zsZjA#lf0!2`08;JjQ!();PI=V>XAps!h2r(O-o2(&!?AdJ965O9_5Y{K=2&+Ymqnp zVG#M2;eOe}e#L5`?RMH2;NDSqm4WWlex`%)ZQ*XB%fo%C>b;xv0njc3H+=MH&jEtJ z_Ih%jfZOEUHjwYxW&4wkYTjl0U5k~U8)jE)8rl2d6Mz%Tm6&TH1#U5@9`G^*x2Wik zlz)HU)&r)+ps~DO5dWO09hY|46!yI_@{9YP3D6W!|B$hSoj6-1BdPGlL*;6nX6WIl z^G28D^NdVc-Y2lIia_WW8lbhg$X%4+r*poB^IdIt{6?PHey5SC&eqDt{`q_^)oWDZ zgv*+{zE0R%4X))k(P~nAEQ)0as#9(goXa6mFaI*clp!>q1?o<&1B6XAq@gY9PJjah zz7aIvG*K_?5`?h}>dqv0uzL+;ZX2A-6n8Mb9(3yrQPj6<%Vz7u!>g=>JcJV^5@@|= zil$_Y?UE*VW?X_EA;%)YuR=%&1=k`xBIHTMx)CNr+~{j6Y~beOgiCwUeGVq*)q|0Xyb?KX6;IC!i6u(x%R3}5ST|0h(?EYXd`98 zK|AFIk7L}fqPZdDK9|&#bA8S$bs$slhz{JbxPRu7!>YlA&~G7N|+!oR|a4E}?t4D93$*Qs|{;KOqubEEMhn6au>DJ5*sE8RSh;Lng2@iRYj`n3wi{U8``&x~f)7bq-FAAt#K zEAh76;Uix=jx}VjUieDY!l`>NLTh_N>6lELHkOj*N%ekl(P@W6J|Hu+zZQK_!Ave) zB(@b`@To)cwDHE#mJ$h?j&1Q@g6i&QDz%g7+o4diI5aYWc1v3G$D`Mhm($S;; zl61V_AjX(k+V7`&O_ty_3?n++;DZFo)fy(yvx|E+)AxDx3GDOsfgGu1NXG|j;Ophe zm)^^9<8DET?!cgFUHcLyjpiPDCQR)Tp@txDypky3b&1N8kTss~>JQr-&7YHCi!+lf96#?Pug>fT%bb4bcY*0zLosO=4$9Z#y<&S{l=YWyjI?KH*iz38>#ipFu(Z|=(5zKI;aOmKGR%~5P{raO7?Mmxb? zgaQZMd@h@HqZVU~ikXQkZFXijQxQD3e<3@ZQG8 z=YjmY`FzxAs!W=9C;TK>rBybhyG02vSI7C=!5|!FP`elz7qej@ZrfCJ!Uri8zJyhk z(<+*o_Cx3t{6uT{7e>$r;idpvdxb3Wp5x~ViPc74&-4J@v@*fVl(MFW0r}=!+4iV=VehDbs;b@Pr)_I~ z?wTD|YT=fx(b4MK=iAlrKDq*Ar-3*G(U}1lX`(a?iqyN>WY0A*%T}THDI)b4Lf%I0 z1H-5?yH2O;Xp9S#pV7)4%0-<%3E>aQPcO&nevA^0B(@tjk^X)`-(}eFFm06hhC>Pz zRmj8qAhZm#4h9i^dU}$Y1%x|prMvBuD2pYLBLctME z6}sWR4eOYw(O{@DY|_sY_k{8V)R(GF`@l(mVRnuxkHXnwThMna9`w{<$&t4QGek9o zG#CrPqMF+*YQrx71P6p>^vbC8zj0)HtlbfR-^)c@kIF84S&_mxL}AU5fj&VSbN_NJ zC){gXbI>C*nRj4bLttBtl9qX!XGPXzq)|7cuP4WTBRC;vhj-Z0tH5N5`d9Pvv->FX zi$Z_Z_jsDr?gkW^r|M5|`b^OBbb;RSmhv(bl-UBGGD9(`E4LftIFVvWXm#n{x~pXjyN=6Vziq7M97Q;yDmU)zs7CN2PL0BJe=`-qCq7k9Ny{RTus zF1e(7H#}O?&@ltv1ua@{T{{cs4AvWYq3Z1q{VPJYB|sWKLEor7Ofy&3WuN~a+CLWA z4Vm!9Twincxe?K?UK*RlObT>vQeL~*m%QHGy^*in6ydic4Y|_4*q>L14_ICsgqi#e zzj>wq;^FGmVe`mC9R09xsrf~T``?5`;%9X_8R_Np$x4E$!#=$Mq9$9={ ziL#~Jm_2bjb7H9#`;-O+^M;uaXuh@0hx9eU*RGHK8ODdLmkWU_Gfd}tqxfxSX{r)# z)fIh3k6JpV$SvhP5@o`tQ=N7D**(-2)V%pfrG^8@X~ZQ5NCjD%81{yBLG+=GkEm?bvDQ z%s2AS@Ml2*0Tv#*7u5TLb|2N(c2`QtPOvIIOmeio)ds~uOAl-!o-FY^v7KA*irNbt ziA>HZ#<4=hRaCPHT^T6aAFnrbC(VOQBS^PSui_TJf5Auda$g{e2pQV8w@^ei-rx1+ z6p!>zL$FF=-VAMHMb&3V`tizS|0O$MCR?58m{mK^GC~Zl_EE#Hx|H7d<0j?1PQ2d8 zS@%uHK4ZOsVgEw!cfGeI?@)hiH-6>84zmvtp3uLoB#(86OZ6om> zrPUl%FPd7;)uLK<`3{}2&R0Hthd9ohdt!5cz0awJvgZ}9$jXp!Zg>-Ty`v|b^{l81 z-Cm(c`DIdDTRGM!#wJ&toK{mJQCRY44LyHy-p!2Z=|JdsLa4>YI8pQn^uA_#KK(CQ zbj}JD6InE+YO^enmX^0}T062pC1w@bPui1${ni~NZ>I@8H_7F8%m zXQi7F7PmXLS^MH1#hBZl&T-cUx;l1E5Uj9*C*$S?X0CP0ojM%~3hgS~~JezZcTDrz(@qw@BGS)DrH~{9kwD9(^X(Q`4eF3vSKJ z2aP@EXFvFNs_2Ya8wFiKaSp+8Qij<{?Xhg z#ePbHNtzX~drViJkgkOSZ*l0iP#Eo#-e^jj7Tu3#k*Az%<01=6d!{9b_=FH8-z8N~ z8%h;|Pw8BL^RuUE;fehf5&d~d!5j5^{eHk>yk;&ZdZ$YwwdN-|)TFDm6rzyqdRl_H z-TsSzG`HeOF`pybx*G{&T7@lpsch-~EK|6s)wh`T|UakWHOhS=7lIDtUi( zqV%V-t3XX?f?u?vv)ff+NdA7~j1X9`EFdIkg8OHT`XA$nN(~D4stp=lOSb@1DOuC| zcS5R@we!y!^7bdV@5(~_jA;Vu8fk1k{Ee%6BAyk0fBrb;{87&JOsHx>boV)uW2ydE zxX}>TR+gcaeM&7QN?ZCr-`UyiNs!8?9h?>I3n}D;5Lx+x8b1}39<##K>{}W%ttu*z zrF&i5D0R}Z&pDx~)m&}dNGs&KdF=S6LJ4F81<5A+-4az&17Jbtfm(ja$=j@trRYc+ zW1FP$hFnybx^PWuPo7SkNTo;$v|E6YVfOxI$FnNDlQNlWk6w3gdyN_~ zo)chz(}U&s%JD0BXrG0h4M|W9RteJ+Gg!eE3}dmC=&ZmYFOz!KuE;zS8U$8 z$&`!Roo}UrEa!y3CVz@P;Lkk5xSYTj~Fca?5-b59^WlZkf7lSe@Q z?3(W@K<+K~F%AZyz4hdNH-YN$U_%g*=KUrgqwIYc|Mp6tB=?k97P8@ENH*1Z6Vho< zVCZerY@>|f|C<7hQa#glp86~~hFrSix5SE{K8l`3wVF%^l`8eUR_k_6R(9ph7-FnHWthSBhTq#fmW(R0H3~f)8A@Zk} z^X+?d2(%c!Z2f+UC~1}M+IHKuG|gVgzoKJH5$^6+Ln6+TdDD6ETpmpvOc!zQ&f4x2 z#Tu8~)@4>>Q{Vnt+WkjLvIP8oesv7Ryq)Sz>d}WfMZJzJ(8NzHW@lsV)oK4pD-c_2 zV&Xow9@!Qy=}tqV(80OszR_N0SKx6YoNO}KFm>P>3u%*pC$Hkbz3-q;OnIgJF4Z3Z zC6rP_P?|Pk*37R6%jA%|yk&9VHAdeP2|*9Lp^U|Hgid}y`a%f5tQ{#Fp&@P6S0%b3^I$2~; zRd5i|Uq-bH=jzqbMqy5IEI99y#1PJ~$oVBspsWHUN42TKS zHUvj0wTp)utVkmH7 zgUc9S7gF&lDjZv_>+5!=WYwY#5O-}Y4qXwrCWaEdDD;skC|bSAa~LCFlaS;Omu35g z9Y;)O*mW2JCqpX>XcQ)K5&SR$v#hDg$kCysygq5933vurX)CE>%r@627~$klM<-|7 zmZ4D%ju8+n^ee)Mm~*1CA%BVz99PVnx5C~Y&~Zw*p1CI%$4(-uO?Ux|muUIDjd7dI zG-cd5vRnzvhZ-8Uhex`%?IR_pOzfuDmK)}K#%xUe6|6isdu$z*SJPhMjH#KD&i(>3 zL}j{{ZHq}zT(9RycW`Q5bR#!-<0f)QXEf$?PighbQ98)tFLj{C5r{q^q$-n~phu~+ zP&V@tXj(6)X9sHM1!~@Vj_LtooBUDb-=%Er^qu+f^*$|MoU?`?%N+A*zg4Zte9?TT zHq#btgrGn0QN{R$Cc;RNOhYtHIX%6NQW0ZYwqLIF@v7G+g~+ZkQ3-@(kp&D0AAwJUp!D}ExdTw8)+W$!^1dDN zE<#lG$p`PTO~OkAc_IK?f?WgQ5Z_OW&ARd&^dL=Bxe3@6)#sb0@hRRqDz@c+slf38YMnEMY^#*iX zodV=E0rNGDXgQAXxEb9GkQkP^|phF7$^K9}N3{oEh+|EJr@1pyko{gGc3T)m%?*BJ} z@9f=1kD$x5!G;BirI$p@ci_6wXbd222HYEz|Ke5+FpY|SY-iRc3A6Kmw+itN!M|m4 z8&G-Ti3v@9rI5yR2ahlACSA+}w#=uZckd%==D^YQ^UrZ$trO7MDPl3KdaZej8R9;z z@lP_S_=K++Kk=*Ic?^&QJB2d&y>os6x1cAkmq$N|q9<0qiFz#q`z<$h6Kt#(Mf=;y z8P^x-{=m==(#{AU#VwDwQ&7IdGN*8n<#f-tS}(c{^nU$)PVv@yzk$H>$`Hj6^hR(Sqjj8&642)XT0}2AauxNSA?EKaT7UoJ8=Jprn=6x#Ao;)r6SsGIa z&RhV*v2UT)r!o?Hvg$JBhHDD!o8r+Z*;vB*g^tOYCiCj(wxQ}1IJPR?KMl-&njR5O zF&xVw9k}n{M==N44KMAG5*4x96h3Z05Q4G)fWzlS+21uHLCP})F3;t5|3t}i&rdy1 zz{gcNpaj^wUtPiaB+hUbUC?URAAC}FBWyvX|LG<3H{_Dwc&tT_ts$sUltA5tn=hnC zkf*KdpY*gYM9r3r1T*>eB;)uZ?+>nNohVni52Pj*ZDSflC2b5(@Z-Wl)CzOlZ}u=e zx|SS;?5|!@Or(l<{WrAzvSKdl%NK@gUs|;4|FFt`)_m|=xJc2-D_b{cyyp15+TSEw z2a-VV9N#NhS%Yo+hRM>PpmctqU&g7gRc$SA77`&a0DyVz8eabX^8Rgox;E!FNQJdI47T%2_&$EW&$*|=na@4thX zZLDo)W}cFH-VASvrs5}vqJ=au`29oBz7&$>+gogIpdscGXK<@Ie|wT2;UBsl_0_C2 zQP(_3DdUTxnG!57m@f4e2HL_a1`x^YO@&ET##Qtx|S6k#^(YnS-WknjK&LZZFQ;b9H zJb?0OdBv3h>!zU1C7B+CoC`QMt>4@gT%<19d4k=arU1P%ZJYPAh~u?#u~Kh2k%ek2+_0-e(2KqW~J zDqoQCgSIKN2(qtMLdF$iRa6I_Q$uUPA#RWwTUY!Br$)7rwEW*#VGY1p>t7}TZ%@ff z00oV|p0CP2dOFpAB@rJn7NlyXUv%yt3Liz%ELZX3tEc;>Sx{O%qh0}hS-c_y{#%WL zcf(!ZEul*%fPu$ZwY`t+edX^!LkE~#lop)sKD#;jIEiR3M8g+CebA+3)fn!bSuVYa z+fkwyuV}763JqP*@E_R6pu5c0HH!V-quPWs$2boW&MOJy;(<>%`lx72>yJNf9HlNY zDL=G}@|)~*7LB;>U5m%L%&Cxd$IAS9ZKg5)i@NT}J#rTFBWwJ})f@z?NjJ=_m$=@( zbSbAh!f9t^25VnX2c>+OQXyO3u4@1WE6z*J0lFT+-;mhy^a|>4D%g!V6gK1%0xl?) z!XjkKc_C?b=D)GR@AOJojxv2r?7?65TNfZ<2@Z&LK3T?f-X-~-K~dAgVHrUnrYAz; zjeqwk>wA8snv9>KcjGt<_ckew;r|+nh{aHsZ4u`_{6~nn&qt3&vk`^ybKXp$mSu|7 zT{`^7eL963@y_^=BCql?sn7as6w-c?xX*R~t2@+aH-#JUTC}K6n&V2MZ{1L4r!D3&Q zH~Z%S=GMbGZ!ciVbZ*o06`k3ZSkx2*w}Z_k3@f$nO7B5TIa5jE9N+YHfp}+HRJ@C2 z=K}DxSoVeD@q-dx_T2FMr#qzDl!SZ!&JD)(LGuwaB$_s~3@+LaH5q&HqACN2{+ZpM zt>x}pdR|L(pfnU9GH#_gA zbPpoRVbxEy{d4S*3Vj|UxrP`cJF{2nI6fI^H)C`adnEC%plX0Qs}~F^S+OjhsCIyo zeavG)Tx18=LZP4I>c&&*^MckMK5t&!S~DRE18y@I$3 z&$^cOWn3J!u{t*x#NIQ)GZKu@R{X78dT6ewM^imCIuOFF9Nt4a7944Rf}kTV z>sYFb^vzbAOT7QHoG}AwOZLH2Mw*%6P^3n$oI;#`M^(`{+bYXIDZ_})qx_r*BvU<= z=B+dPgqiogs5lfu{CUj*ZWPJ~Xia_ta9!Z9*%R%+2h3u}2hv|KP`}TpNO9h9II)?E zy^(pG?fS-t)mZVXkS94&?2i)~QA`9#UA{N%Z&9BAI|2e59i}8olLr53IN_@Vy7V0I zHCd3I9j^g17DBijN+o|$mt?B?3`NPIZr6wcxf%)^&W2G@5oMWuS&#lBrtdbr;1?6N ze+=Z_B7`AkCi}%$cVx+rwVswPD@w)q?^RxKHd)*oJFeMzGA1e{-k6VK1Zu3{6)=1RA$&S6(w!_3!oU{tFroEh;Q zxFe|Nt?B8Jnk?uYi=D`dkkyX_yhxTrt5etLrXd$SAf#2Qtx+iR^4=S&wLWdzzl%;$ zRcb;LK8boIU_JGa<&$aO0tWX$|NaNE0oUTT`kCm03R5a1;Tgc?3w}B-{f9?ym}`J9 z>ynokrwFxETR8{{%^p?7)A^V)x)Ziqn{T2XKvVe_geTfR z{_*PXC`eCAi7tfNl~X=~LV%7D+uSroo$LhbQeQriJ}ACv62V#P(sJ$9H_dNwbMwsVqC#+i6x$3o5q|hDMsp~e0hx+Af&D8f3 z@}8mW577_)NRnWU0Jf2N*29o`bI)i z&dPi6t7X5I4@d2XAh>v-`FONgz}1XYSNfo{bYhJxcJfYPw(VP zCSiw?cKt|GPrG|3pXmPr;f4?f(@S-zypnnV7OSy+KZ8b|3U`UX?U1F`HI8rhFyj_>w)nzE5faF+%t?qmpt+oVT2XiWlyBY+MqxM2?%DIY<6*%qmq0y!>$ zGZ1iQzh#ue!d1t%!$cg^%%~^|(4hndaqAt}7v^&C!L@h)4Bup4)uR9>;s-);41fiN z`4zhX7u^d$xa1jx`><`f&=d1;=c~)+SGU&+HlKZ$Hh;ED_LuGy0lj;h-4xIQf+J&3 zpf&o%7vOfk=R|G$i1;k<5pxSwZa5(2ci}75wi;N zAjo1l;2;B%@MXJtU+TRj(Cr_v6DoOjj`RG*c1_pcdm|4Fm-K->J`=pk8J2dZthk`q z*J0Fky4J|Kx`|tBRdj|s_k&HsUZ*Dk5h0~x&?}wc58z7zFe1mY4JW7R_q7A^lkn>X z4=hg&1v2B{5RNJBjt(K9V%VRef@nDeBx2w8xEtmHpoAMxK?u)pRE$(qSTAU-P{)WI zsD79#2WJX)7iI%19YNUd@6!nY>wob8^wD>sc_qrY!1~EEC|f7V@r!mP`V5qp+UW@`J->dNXooB<4%Y=e2~*#f@}-&8!PWX9eBVOPE3vEU8ItL{_IK8 z6@&G)HTe(nqO^DB?qUuKCb0LXHek1P99X@0F3A1&t#-2egJVv>kHsN%(W6%oOk1Qz zd^`-18H7}dPGvDTpYU_qlN@Rnp117>LDuhAG_K%S+h7H71}2c2Due+2E2co4i%l|A zB&=}fP})LSO;__?%dF#J6?li#1qf%FdH|mlk&{NOD^W79U(ehB3icTK%PWk00UnuJ zr3vc(vEecskzytrnpW6Zo(e723U#^a;=u!uH9|S>#dMhlvQpB8_}NCC@cj>$kGB_` zAIm#3+;AC!#Q33&veT~u23W8 zp3?4n$(5V~BEOAFHz!90C=?7V30UEn;iqNvX@&!pq17T>JA=tO zQx&h;EYO)Xp8DZuG{!G624{(GC%z0JMy8KNF`tR6XCLneoeSjKWIf8k{Tl`E+#NLS zcX?SiQ-(j-0kkytlV|y4pJ4L0z$ZFK^(FKOGama#v4h8`;LgEAQ3Slz-Ue zi*N0=DD=NxjMa?j*2c#|&qe+d+!62cQy0)q{v4LOolhPPDfa1^}W3C>gap`I!5FIC|f&KLq9bUWL1?pf#5 zs{JFUwe+SpHb#Z z9eBm6A0_I|&cj~ewS56_9Y4Nhd=#!k@Q?{y(j4D`Yy3Asf$mQ%a}HHoviCE2%BfB8 znoEiH~G2j7<+W41R9?`z8z5u75!m0Wec=ON0hk< zFxYG3Kk;nHr^6(j8Eb;J9Z}^jl`#EOCA?EuF{ZAYC$OT$ZfD-~GtS3ZFYOKIN zCFLjdpwkbb*4A_Ej$8$Lt*op2!3pTqxi?=Ie|Jw`a07}$eR^#c>)TcP(~+}3evnad zIySj9ds{YPVs;hW-x#>Od90{k4MQEmB?RM7pWL!(8Y0mmj(;5*+-SO9lS>^7>6!czOLM zR(f+ic-_6c5+Q`&e1U)0<9+adiQgG~|DTZ(5q9hguXoXlU@87g)DWRbz6SM4gpNaF z|BRGGp+vs;G3wh3K3e{-$oH^y)Shq+G%M&7G%R!SNQUF8I>YEoC-iuWml}?gp*f`2admV4_L^;0`Tq=d-}?7- zvn`0-f9!QXgo6@(F-{}qP;~n}Vh=@&e1jgwhr5w_(2yo*;?H|IZ*rAz)F2QN)@QNz0EUH?qw_4Uum zmBJHgq)UaD#n%e|yv$XNG$QsYccp3eqq0OS2Rx z+5N0ks->lqiV`k8?KHhKD*4nYu57+_NInD~?8PF=%u7kZh zWT8iBd+*2|nLT2I;OwR@=j&Tpu4FycB&Bj&j+x733$ ztPw4?K2w8>1>0=?N{RUS-!&ZnN8A?3c}&txCm|LJ-W*;hN#XftnR!*FGu_4h0i^COItmY<)_GF8U?hBNLt4}P;b z^bx*IOQlce+bTJJ86K<>-nS>=JzqLI@Q>|3)13B*SWu_7rwfHDS$%PFP$i*nX%f0T z**q#0b~ood$F__=$SMbX_jAA_6y4cW@cc}>k@RdykI!5dR9VxJtZ6}wSIN`6oIIVH zBh7h#xkPCn$SSj?fh+@J#VON4AIs)VOV&!2KE2!N)9FdloO9NiDIM+Od8bQ9w+T0v zHNDa->7}xwm&k(7W8qX;%UhGRoIf8KC{uzrmXw@@$jWn*m&iq4XYMg5F;_TM9F~|K zoQoaQ8HZraxw`oszqMxBZc|pRYOXVhwB0GNS@e?)uX-5aTYdk*o!Oo_A@Xu)j# zM(0hm!GNU`Um&{8SC706#~Nv*Q7yb42#;as_+-F&Id(}pe8T&>JD+;a0jsyq>xHZ=cr-VVL$KNpBb!Xo_qD+4@`#gV);+>%}JJ!7=6o3)v%Yte6!J ziB1Zsz0YbZCYk0rr9hzNVVj7o8sIT>QTz$um^@>3mb*S*z}H|*hzI1nM2;Eo>+h5L z$vKd$8~z}a;2yH7KBRY!f%pT&X&7mokuHR0tPlS+zQ&6rbXMcmbskLvxuhG4huC+$ zp?PCu*W;(9EC(8_IeF5FcS{;X`eD`klqesFF!3K#mQyw%SYpU??=*CyHBC!)(To(c z_qIX@mw`V6HJ>_RnK48DHW5)DlJDpZ`o*IGPSEeP%%qy$TwJ z{pc>DF*j)O+4SiW_NS~u`mNUo%-*E`y>*?5iIL_aBJt}sdICMyb=-RGJOBbr3?|H6 zt~DBs#6-Nu$n6ptm&8O>gCgSds!XKv_p>h)?Hlz!0A?plE{!t@|7byJlb3!#E~a_$ zQI+DOs6Dds!08}=6Zoa;d1x{v9)v$8;bTBYF0izV-s|rBtNX#b?tcxs_as65zArEp z8c_^=XNE5LK>SDiTlKxDpCA8P%<6F<0@@jmp>mgbq5Q3gm z4n(^3+&Nhe;@J2nIy{Kyw$53u4xgZ@kS+B_LumQupYqwg>)qe|OmiCr9GKP)5n#Vb z?{U4a_2~zpspld%Id?1zkt8GmMznwclg?MyzgH1@4M$e4SLrXw>Ov9_u^8W5%+V7r8tNM3wQte^0uGo znS}aM&B6Gm%H!My{|~Lj{mbzGjt)Vh6op$p6m!s3l{;&3bRob1gm3Pirwl?b=1=ON)FNr<`I zJ5(8CkGeY1(MR#<6u={wZ$tv&u`V<;F};t_wMn|p@V!kkt{m4x2DeNb^{MNSyLf!7 zROTvWY>=@D`8IaPNJ}OPmz&us%eW4R`G@}{G}-uv@GgoKdWn=R*S;yo8Dp)kqgvhg zj-Fq8om+4INOxu5jf_FAUW8@Us3$d;c71cv6FpFp-uwFU&EV#iULMutJvQ=g+~vR` zxpzX5xa++kXFucp{}FP2Mw8cTiUPjMV`}RvQyWI6p z&@95ii^c_(Ml=#OD1sxCm)+@<%Eu5z;d=oL6+)V#*}c6Tu=|5DajW)WtG{LTe^(Oz z$%y})w2u!H@t+p`e-;1P%KhIA?}6;|!6!_uYyVSXdzS`Y1eh^{m%vcl&PiyhNQ}@! zn(RzBew*35)6&k;Otv&Lu!z>oskjR4cN6m@Q9le3#Rr*YPiL8F@m><~Bcqq{`cWY<^Mn5{11LI=Qo^r822}< z+Dw<8w$$VY7#2EW$=muix^(X~JX^HD(ZpB>IW1ZjLEYPD3$s?>7!;Z8$O)(_I9&Z@ z#D7;J{xjr%>!g*4{~mWv4lDV;!T4{ULp{IY95JR>Os3@vGA)0YA}OO4IBbnHPDfRhNU;pGAlN26 ztol}3S%n5x_0Q0cKCD7D7A+-Vpc;I_8d-aP!RF}kDE58|y`7X_{u_?9ZccT|MCMc{ z%l|S~qaFv^NJ7Qt$fgNu=*iDh?LOhY@wsn~J{kGuOJMazlvI z`Jd>L5Co4#|MA|ngy!DxZ;2Hud<<3Hi&9@xRUbfB998;LfF4XvyTBq+Aq0h31;jFd_f56Ny5(oqvE9-yXAed>YWTCL)qveAFI@_Lr*4njl5SH8X=6X~sh&noy1nkxlHJnl@`1^MlExelbvL zrr&C^GbLOWultwt)}s;mCja^_+cM)D+0b|2;WP zYTA9q3Y>xPWzhybB1wgI-0k6TUVyK3qIC;m3?$P` zC7Xd&?KRr))y%Z$;T`ta+(dZXl-Fwl9s8$tn!ss9_ZB_{f|mF^$$2LZZlC<~)|!n> z+s}k<0&i^6^J6Bo%-<3JZJ^)_m%zV}he8={xL)gi>_=j?eHO;8H9<|705ZdVBfB1r z?w&JxMH~2(;cbR>#*9tQlz#unt;hIM!)TC%!|NL;QQb(X{y-=}=)U(geeoneu1H12 z{l7Jc|1A06K25}bPmbHimHglE{;z~hn*hr{e-&*u9 z6i3dJ-G2xzLf3 zXLs#?8S7LYz#2RN=|q29K0ss&@~J%8tS#mT$RMS90x1n-zJOvO$v!XW4=C;b)rtQs z`QMSq|JHH4lK-2w|79en9)P@H$9;fQ*}3Chz~+QvrVz|8^eSU~yX^m|0X=j+!=5uS zf2TVn3#x&P{r~o1{Qi$l>*%;T|GC5Vzmj$Gcmd?LKMN092?u}`9Qfs-;a>R-Mg0af zfxa>CAvqB_)unOOaf>J4&4Y>$DEr)&Box{l8)oO7Q*SS~+s=FGb!k&oZTW*Zs?E9lPsZ z<~o(~n?ed={4ZCWK<9 z5X>+1s$k4k+5aDqZTy7hZ(L}5YnA_}Es6YZRq>zQwf`loQlR|oVfp`eSCCU$^T9KF;P{s;RMyr z$h|3(-|Yi(0pU~ZZp4~_u&45<5&xt5vU&4!TuC@m}`M!C(Ih_@^H=57SOf^0fD#e**Ny^gv65GIbGI{RECZoshRp00m5-_#YT~ z*!>usj1y?mzO^uRVA=-yqWy+_N(Ym}>#$+4T88EY^(M@v3@f4}ENmL6Hyk3Ja*l8r zY|TJZWE;rVO%!7)4_oE~0sG$_?L_N{gO0w({NA+%b(5@|QC)i742YdTt1Pz9HT5m!tb}wsz1}@TPbUE)E$V0j>1#-3yUrNtv zq`0psqgB9YX_ew{whQzw(kx1!XdA`r>VyN2v{sCmL1o4#|9z;njl<++=&hsyohhZ(h*Cy*C5eX2FRw)9o_ z>=ucMC)GQ$>d`yDQfUCqD{Wq->vk?S)iqtrbBN(wfNR5`(j-kkG2`;2!&FS!{MMuj2KcWvilJN(` zY5z@Y|EG5HpV5ILdt}=20s3wJ@v{9l+HIr>h0AZYk2U=Jk=BZQVFL|KkRNMjf?qDH zL2a#rA8V0HzXZR&Mo=O9S~vodf%@^_M-G8skzNaVTR>NnzrGQ*hvYBkMbL=6MYn7Z z91QDV?`!2LKX3p4uGhVI*V87(8v01{|J$d>op$2=zt-_lmH)AkzrX*-{yrEX8@bR! z1|X8G2@D6=jt7uodcZJUq!V9!fBzqQdw&5EzkhG1T6kY>yWqQwcl_P@TWTg3CG?MaR#p06STCCOB;L8vP^rlckcj`{i5+w z!1=fdusNApb3mjxfQA7aH>fB>eTGeY1m@1n1w;7gxTc4ESYQHeNM5tp+XufAM>qw} zucXc#x;E`oRbfh?C@YW=zCoTx5bAr-^^ifn{RLdoQ25^7{TKm%W=#yJ*KGcd4Dc}L zp%+Xi&fmk)$Sh$*V&`-#6Jf7Oh6)_pngbgl19%SLfp%|k))4x2y%2z-s+ z+nEETyCSrCkKqXIDJJ@CZ*L!5+NNhh4{;KK zC(|1PJ#t%a9cd#CguwvpU$EZLA^E?P#n5-O}14iDB9DI(iXZ1uyp}}PV?gF#pZzfK#Yeba1M0ZpMkLFI`ewtSHe!Z z7%_ z+FkF><;``C?vwlPH;`!}Hyi%}4u1SGF?Zm{1F}KnKN9NiwvxUitWjss8X*__1$6P; z)(_wlG`+pOj|jMkfFT^gCh`+4`lU|h5uY6#7{uTvB+@3%@1|uz&2dKu$lib7KQJ5} zAACd)2chIVxI=VebaZe->FT(c_14&P_y;oiig5C1T)5p-XG0`G~*&m?(8Ec&8 zyb9ji``MXMW`-6f?GgACX>Qu1#VP-0W*X?=Jwa-~DT@E%gKg}24nSX!KJ!qFw!w;% zQAzX0$gb}JP$vWuF7-~3j(ZnA<;03{@)1A5Uljh_gwyhX=nNu%Mf|E!o*+_#kmpy8 z6PtcWvLzeE9^HBr20}j2vE&&Dt<8GPIUd@=N30&L9xx}Mk|vY|=RTuQNx*HXxIhTF z2|OSj5}t8};FJFqjFDwAo;f=>@V}Cen(j;v8qK|j8CBVHDy;ErO4J)$;$-P7SmEG6 zfg;D%B<9m0X{_zN zb)L{8(KjZ&t)4#cZrT8X2a~=k_An#*2w?MfM6n_&=>Y-5b*58fkg7KN;(-bL&2a(W zjncq7$3?(E9yBcqj?CAC<&418!QP%@gHP13g061|(pqwhHeA;9O|=R9o!-wrIUoRW zxYiFi$bBE=zG?6C0Q3IParb|NkC55V2Mynb;Wo>UWI2%T)9ew6mh67)YY|PU)RDzS zz9neIP#rEI`6&{<(9nd{F6(LCi=ItMa-~RcS$x5Od)JvgSO||DhnW0(dmqQh=BtYcYXo2`e{q;dmrH!9D-vZ^15I> z9~_3=k3SN!{|Jaw`i$n78pNhByO@eoDy3*R-OyNrK*8&DY~C16s5Lc3x;dN^0Txa@ z*-FP}terXJBiG1R@bcwL@I&93AfBz$^BeuZbB2Bd;maB{xi%O-?Fw2yq4}j9G<(6? z&|u_`2fmdgxRGy>HQn30wGhOJ8YbQtVdhB8Y}1?5M?lD}OqdF`5pOm|)>I?Pi#Gvp zOz-XN0hk!icva7Z`e#!2VK!o3=MX_}=AuBdHv!R6WB7=GWll`0ouF+znT9teb`~@Y z*Pl#{I7%N(YvBbU*e(k>9`giF9E>4`Gk*Qd79p0UIOzGjN!04z&sf9vqDj_uM}H>P!CL z@UOWwhzCapVY>r545pUC343KZBZ5X3e+CdxGH?g*Q=e>)-8>?9XgN<|r*zlM;h$;0 zek**ya27gkP&#{XL=-X|iZ~L|@xL6dPzhc_;3s4_g3HJxW_XAM`>mN1(wETR{^MbT zyQQWFm@H&-3%$Sxr3^N7X4Lt9n2nlX%GmuA^+BP{xHi(;c=kZYn&|F;arl9ao(}Y} z<6uO@;k^S0v00R8W}C#6fL3&T1|n8M5XX8D;#gu>9w7VCbRBy_f;G*(N6PX9>?aBW z(`W?|(^E%<@jkC4VouP*4HhIjcWlo!A7)Ic+>fcF#4Iq1B^JVcaOOEgOX$>+1zmei zqDtn_)FBgxRK+|XKv?9-C3Ir+rG^#REnsmYSv)HUqnQ}Y=m{W$2BdT!Kg7ZX6ty`Q zusUBrF8JhQ8HBcY-cU|TdM-i-BuC|dw>$6w@=aHNzOGCi*%gA~Z+x2`)5t_)Z}0Eil>Nuv-|=iRf$sbtdtKr?eV{t<${AfC zi?Hncwd4Ai@a_HmAgH|e$q#w0MkKP?jWUCuR(_C)8OP^YOA@D97?E4PwGkNF z472?xW|y{y+#%FaZrmtV48fb3w~ZJwv<@13e?JJhL&hfVlH7;dZCmIJpkc_24- zC2~e?9P{$a8}9Yq`5REoeJqVf6!?_L7wH(4#|!Cr<)^>59ZElrNU0R}woBbB5Xwtq z5(-jCi}DtF8d4?FJ_lOm@j(vc7Uqd9;)JcD{}xhxXTCBrbXB8F~DyG>XceU@L>BGCazostlXlbWJ`RP#$%aPZ*R!Vv+qdcNYkSVr@-E}>42zBrM)N-Kl z-nB~J%}(G``o6Xbqq29nRd^Mne}DE697(=+KBKbpRucG>PJb0fWz%1US26nEL;Sgm zF^R1>HqF`Hg5)JRQl)c3Dq3Z;Ln?B`cw$?0!S?8YZIk`W$^7>ix$n@#apyhTbLVAK zIf_mBw3gyiI>n_}6{Gt{$Nh|_P%k@UF~FmATE{Udo62!~isi9wnJ!O5s`MSg&0hcYvQA}b} zetu#Sry{wDj)A&1wC32vrKTndc$A!(n8c*q#Ka^%1?l_R{PHj7p=|0hEXt>C1dq}w z8^NXkUCZ7G3sESSqT8|smO!NdE$@)$n&=T)rApusi*hNNz@t>6Ca@_$SJBrp5LeeF z9|2I|R4&akuqu@UGH@%x4+wi(!UYjbN~XOGmvSjC!>90gZAgokXNm5+~6qlI!1n zgr-H_h~A>ZTMC>?&izlvs@yXG>9{S#5APfUSzE#f43}-8e*~K?p?d_Uh3LH%2e}g1 zYzxh|>S&h=tA*$;CckY7@gpd03kS%M+7dR9p;qWDuMl#7ZQ6!uk4iquD?zC2le}t_ zN*$65{X!)95jol+xdT)U_pG2o*8Y>Yhm)=UW ziqJlq@nV*2&n2)aner-p$|bxCt0Hs{a$w%^hYL!jdjgx1>8`@3T)L~U%1ig#86Mvw z3r)zY!Bkt6M)V{qB~o08OnKy1qLi1`cL>iWXiK(QWXP0A?-X>(qj(BZd1>B9wy`Da zJBdn(^j0EM9<`My<)<|@18!ZPjwO;hhDoWEmg7<;q2(CmrZahIcPp|`6PT1qX9X@L z(piB~VLF$bjT*ya8)&>G8L4u73ek7#GTu_LDx3COoAs6lyJCE?9hq+uTuSGG?aF>r z<5Y~^+u@c;a4DVM+vSw0amr6`XSy}yj-yg4wH3&eNo)m5#qMC+hV-`tCZ*rSwoOTJ zDva{dx%Y*m$y7be(35>Sj z46q8P@=pS*Fe}Ojq3K_8Qo9VDE#LqtLgkZRidONrNFCcoy0;CF)hbciiuXqqNNvN* zqYBgt^TL%gGVKe8JmXwG7YN8~1O1ceYystyNadyZE9mLt3qH?j^XC zNO3hbpbP+LT1ONcF^REXAZkhcxXIzXdr8pjbSnZ9v!iqduq zmavb-7EpGJ7H$li#qLnwlB?6V=En3byC{7z+G1>u>`9qfOmRfYr*9mU(kUEAs2GiV zUp!>v@~=G)@F<QQVvYQ64w-|B`7;f=A>e7m__G-S$xiy zWy$YSC-*}*zVZi z8g>>da1B$H?(-Hl)@c;pdhQ~F<<;yg`krqcLkqt1TgO%{*)NIAmqyl0CgVD?UGSNv zl!XP$bV<%K6huYM!dg zdl}@s9P(Wzxz>@V6bZCg!OF}mSi%~17AtBEQ&nVs4*U4+5?lzQ;AO!QS97yifvb6{ zCU1O$7c6CbgBLE_l!rx2H07jf?xV%$J6eVuN6VAfsHz-KA;xFuzhi_Kn9L^SVUbyE z3S2BOeNBNEYk8uGT)&!+!dskVRopC6#s+>CC~X5*_W6qbgPbJ@o0RxiXqF-sCyPu_ zq~fPaZlcAfBwB_{M9Y(as9xTo!2O6YxjT8GlH@!rSeAJ%7Aws>FBS97EJ0**fs@7O zo>`*kW*tWr^G@WVdX^)ll!mFrXQD8%weXY_Cg!FY6Y0ev-ESiw21}8lq@2Sg8!aXt zmuu*lIJF%|=dizU>@&l|0>?s;i^WO1$cuFzlOSFKiRQRiWd0Hb9}CP~qTr@lewrn? z<40y>;n``H=#C!^L)B!w6bgNjm4(ZBsZ@F`OVwn(;3H32CKfK=B{}${V5XW(B_)m5 zvEXY2%2`{u{4JPU^r*04(R!@lg-?FG1T!Bm&9uj;?s-QVHMk6ilyi(M_H>+zm4zOP zQ!!LEcNk3|9fd>wIbL}7Fqxqx$RDO*Y4I7vG>kRAlb_#r^0(&SBL0oIFkKJFYw=`+ zuo%gBqvQMG-6s^d$UO@C2gvtsQ8X!r_N}|?F*eZH+}zyT-36-Wo10skyU(`4-*%qv zZEkJt?QQOYzin>sZf=qPKSl?PaSWrsZB9*#Hf9qf|NlY$c|(%C6?_L|>HREb?>?Q; z6uQ1e?tU0td;J#Zq3G6g5M4>m$xuliu?bC|fd_CMg+s8izP_QTbLIIj3CYs&#Uq?r zHYHiY(Jb|0=prBU|6OioDU1C8V(@qITYULD9(wU$vcdkx7q{%kLP2?hV1y!4$K|E; zOsB>0E3rTk!pt2Yq8gI<7!?{n(9R1G-9U z*!XJ|B}f|RBFBdj0!|p<*qVvUD~M4WeE$Ui00MLeR;h5?)kN~74cO3K)eP+?>!SE@ zyn3GY%H`$eX|MEA+zs4O=mqg9jNlN(C^`&q9F1w@AYN6p ze(1TbkM3ZE))4=8<;l9Sn&-cy3lUZK0_al}I}QOH$Ad8P{zL%gTL&WE1$2$NrF{ha zun%0`OY3wgK;PhS10x{vg*(w_~d!|3EN~|g72ha+ohg- z4ifQqqTmf8p%r4FxNWe~J3l)-es}q)b9B*NX_3l#!(8^U7$ZGVMd>#W8Lq`ZVJ)@o zU$*FGTOSE!<0XK1&=Wnlj#1#Qaw4q!#)fql@r3v6BLIfXU@Eka7og4JW19c^eMIJH z#qD~n>c&bxd!Y0p6py0-SFM39SF8$*P(23d;=#N69~gY4GWrVe0FKal-Ksffa@|7Q zy6Q_8Z*ULT6k=5?$`dlINQMZd6Az;BF6m>j%952IMcr=>8j+Rw0jy&B1YE(QlqA&uXnIAz(LM5K zcnu((TL{M*{>}$c7{|UB^s~J21;&~;P6OOQ3|tg=lp{ozb@3)n=x7-E1bxqiEb68{ zBXO!v6Oe*%K>UdKdcrpzvKc}zh%vw;_h{I zNsW-I6B_PvvxRFsDVOAf7o%5iAVwL+93Ns#=Nj~VA&K-oX8UzsEfMm1u`zm;tf&Pu zEm7nt1?w%^+K$L-{#^0j`0Y3FyC>8uY9|Kp*6Y*J4F<>`p{PZ>+Y3N64q|VJ)(Okx z<53jGY>ML;#-0N%FR3jmtP1iEj=b!j}j0N3gqSgWktRwEi(h)Jn+p(emJZ zb|Rb?+-FUF!Dye|;?D3oj}C`x4@DN>UOJlEjFg4~xCm&OFz_cJ3=p_M6EKPpCK30v zCP3{_C3Z$<3mK1^w-2on)X+{$(}IQue6PxmyjF4ZG@yG`*0&sB0=?fSb(SKB=eHw+=o{v;i^RG(j<%?%2v9#QVR_Y5FsOmo|(pI)o^{SMfp_Q5R z(^ezS{sR+N)|F&=6=x{U5UB_SZZTm_tE7;DC-aASK4QbL(7ZKLj>`rF&B>$gD5?Dx zB@L`td~Iaw6N+qjl8RMfNcz;sO&J??=<5jcDW)JPy(u9km6pjEu0w8tvb%}3MAaW< zX=|<}X#w3GAxc`s!dV*HYcg6ue`ke~j;eT$5<54qpTznCCaT(xinNt$yXsXbJ^k8F zG>;Ex@-Bk;ODS5aHwHS2(pfU^<9H+-UesBbdC=l-IWm}eE%`GAW-nCpHF9(-OQnY* zm)vv^qi>u{?n#M95~Ik2zV|1}Dg3tjnbI7km?uV;ww1K&1-G{dCDO#U)Z{1N*Kl^=J837%kD6H>PMg8XHk8o-(gBWoOQ`$_zEKt@*{R?XLA(e`OoYqyGpJypxAVEN?@uVZGrC1&6zY+F=8A{wiE`c~AG$P7$xx1#AiRa+~1{K|WvuKn#=*x%E% z)W&yc)4I6wbkiH*)3qm_W};1HiMzIz_%sc)c6QciY`rGVt6@_&$J!=$t!(m{Hcsgd zwriucVeaY-^J!b6bnn_RU)4HyORV#0n_}`Em$#^jiSBAl^l4h4^F)_(Ud>K-wRZY6 z-0MBu7W~&R*4+|geX6#Uc+YKHR6)nnSnSicqMnXd$!vFZX8SbUYhC=Wp8vIOB2~oy z=EBhHNBvsH|L$yVKi!h!e|Mj4H|PHse*QlVcbWPo&)EbI{{XSW%Mv>L$dSVf2^@ap zxZ$M?8(zYw;e`baFHg+yvV{yUIAZuQ1BMq7FZ_t%!jBX!ypUkwM~)SKq)_2Xk;3m` z;QA;!;m1Ogh+yftE}pk=>rMVhX>x*-oi(g?OXdUrn4Rc^WnZnrsE;d0^@gmWuiMJ@ zKWW$ZP0o>N=c)}>Q53ZS3??l=?gDyU^{zQ;rQU{~`=m|(_xurhS>4I=Y>#dTT3+## zAAuzwiLR-nklByFioTz@ajX$m74|e^Z;t(2apXfSA*tM1V0d!*VJsK=#I?D>6PC2(FM*D$5pQBlYm^t1+HQ)j8Dn1oriwRHq& z&yz-UdW%0VK(|?zhuok98(8iRksJpU^uDU~~?~!T(ug9fP?4}v(W=rH6Hr)E^t_$O;oAos9uPWboMw)~LFrOE)Z}@;W*xsjLE&M7md^6`#Edy(o)bf}| zKUNz=Q#QbMKv@nWdO5RwWTU1IO~=h_*v*y?OS#k<yhg6uFj=K z>_wk`Ufda1Ja3dXl)zfNhQRQOB-I_Ht6$wQ)mvCiT-CVIh)ER_kr&iBC^p0pl3^_@ zV;p=9!s<@aQ&D$Qz1CI}TveWQqSHo}NCGUD6Add1c(E5|`9XjwSev?lx0^H$@+?Wi2<; z36aWF)g7cIq3)kL?W`uT3Jg6Mvf1Tx668bBMCJk2aRZNJv=}0ib3=|>d-!Xe%2}TC zKTI^!odPo7|G)QiuWzv3$mwzQCKuY6W;W!>_ z402^pqwv;qNnW((tWa}Ss5vXtoE2)$3N>einzKU9S)t~v&{SuI&RAl#F0rP_lx!8A z;DUY@$t7}!k3t;3N6;k+f3vDz@>rwx{SNQ&8g_58>4XO%j@JhCtDFchiaLE1#5oGd z(+UJgQol9Wmkyze)WtYgfAUn$uY893UKr%cvPU{b_*pBK%yTVbrE)DiLvb{bYK)^v zNrjn)MWndqOc?1Xmeo~06_&oS&KJQgZd#MbKzx8`W<~rlba^g{?2{Jg(K=Zp#u3Z+ z$5KrcUx?EArYpWu7m(YL&(odN)9>(pglLvw=!@jj!s=*&^p}wKb(lVT6S|Wl6!hc4 zKJ=Zj4`Y&`k?^K^(*pYgR$6N@p!l&@@(3Ikm3aq1j*%Z#(6gknDe_hn{J zQbO}}HG=}&+vxSQRBU3&R!3G9RVl8ja;gF<<&VEIXl&qKr&xh|y*@vXl$(X*cZtC9KnVrMf1y+`UZ^&& zSFegk+|LIHygxrb1p`);Bzq>=vcm{?G3JTB+1|;0ChOoWik$(;UwlOpKa+hcaOoaO zlWHG_F8U8%&-tKu_HxdS>|II}w1T6nlVgA;h~{pS#2F&ewR3k^Zb$qd3jN_B?O8#E zrrstA!^bhgw6fm&&f50VJ@EcxXPNc!---8Dp&R#yx!!YE~rFDLCV!n|MDtH!4Q07~={#WsLuxs>?3U-~MyD4jaeU|D1DoU7WvN`zNT> zTZAjyzT$udK*6mSg#lR%OKRs|yl!)53e^&g;>t(Bodj^`Inehfz!|`xFIHKxijb*8 z{$?g86|xIx2O&W4jnfESd*6};Hi91g1O^}+A+|-W7mhJr`RIM}?dvwU3PT^kpuput z;Qe=uNX`qQ^Z}3Bwbx$x3d}7XSKk5MfN+7q;py$(#^LGhE^x=t$1!wnlD6j=A7gYN ziU=?z<()3;!XSLXAHLF(eS3J?qdO6dJtBv~qMguu>y2=2a%A*$KKDRGt$s3C?*^VT z0P(=XLZoz*V-&bz?Z(oMPCiXKGEbO2E7I+unC{n55E(Ir33wP_Z|M1u>K`~Mb_@M6 zqWgY4NVelNh-k%x_Y9L5+zn8K$V4ClaI!j^ zsD(0&zIiytEpY82-^FP`GAgbnOj5LINlh$6xat2$v3EYGlN-w1q>TEw}4YjAhAq4l4U4^m=)I|Zck+-iIb*1 z2ghLy;4SogI^i;=4&Or4{&mqPLJkp^nc?Fe3rraeHIK4IR7=@9;Vt!au`c-3f;qozK00!CTmK zB5xG;4nAz$?rf0xf#Z!+9-g(v5%6*B`OHhO(GAAKjkE6g*}pG8o*Z<08>;z8ixT+0 z;zlN5Y~V9Am~=k*$>zen6nYfbY z>W?qVi7Q#iIj6z@$oeuK)OxOqVuJDnh>kM{MKSb(Wa{S^;ZVTn5dz#5DSGBwKSG~{q zSDiDrFktepO=BjRyLAT7Iyfi#mWR`7$Os9DW zdWq=%5AIcj)?XK0#v5Do6{~v}f@}*+{d|GzD zIfxFSN(Tar@&B8f&vu?l@&DUfyIb2${QslI|H~5Qu^iIVR-s%jo<#SuES@K;*nBtD zlZyZ;u>7Fe>E9455GBRfzD1pF6ar)@Yw{j5X7fjoc&T;EeXzhsHM+t-;T zK6AQD(^XF_*BZtAw>S+@?L3fi{%>vW?Q9n2|Mt`7{LjMk|Hu)OR_aGV#Qo*tTsu>DbQ1wkNi2+qP{d6WezB%k#YNS9{mqRbA^x|GBHW>aM=76UTCI zb8maSZ)u7#^rz13heCjcaT|TswCB&*?3bBrwlk>a(O_4*|G?Nv{QB)3NU|RC(cK$5 zOekW0Nd>2{S4AQX#_IBN#{fODSW1{Yhxm^nWaE@DOyPFS3+(@D!2#pnT5u8jqX!wX z?~7TjV5h0;-g(loz7e>S=Z?`ybXZ0t65#YCgB;M8eFiJ&}~zIv2cu1UmPfy|*KDT*3tkc5=R+_L#Eu z@CrUtCp^ZGb?P`Ty(@AI&0!`Xz9cFYDIovi6wrr1xS(Uy50~oiaB%)|_EYT+6$%;< z4@SW+<8}Ll9omZ|FDONsRB12dLg1TcA%%}9`c3p0yhFT?QW-%J3pFwSa|HJ8P+#8F zkcc^mL`h7Hb2zuL5z<=+7rEW=ieqXlh2I6iQO6SsoeqNUQK1(iv{kJa*r^--`reNge@-8}=H;~=n)GwwI6CWAH{V}yh7C1NqvyvijGAQGb>5=8EW9_f}w+MzD* zjg%Pefvt`Omn3nS%<}*vN`T?T9#4c`>|=~{)^^2ZLPsc-C_c;#G6!K7NxhTW_q=&| zTX#%_6r(iR5Dm0ecWm;u>0liMP&tFWT*OVe@(FY zwdm%wv488$arZif_+12Hlw%^$Lw}M{<~$HuI}4W^Y8%bh%i>Z#QD#4t%slNMFWjqJ zM}OI@me2pf`;X9ESCYv;WF)D}MND{mbCYTl;P653dsHwjD`5IzYi8yN7zU1Fz<)ij z^a5XA;$wRbECOG#82L}7gozW2xe`+K9`EZ*gKw71B*M-l_jAFrQ))VYj43vr$J%OBOJe~PQ%R?H1hY`K4+VBS{U3IrBSt!) z%C0F0Ad?Xe)w6p3i%fn#uMn{VEZU~LR7}y?zmM?NL3}VnLdw%Ux)MI_QN57Gng8ta zNd<{6SrC-akVv3w=66xIol)tTst>qD=0}XS7)OR3&sGJ~-9fW6YcnGE9&EKWS9N#X!c228`Jb>y&A0b(5CzXDsJhWA6) z3knY;pVCU*QG*8*y#@{U-1`QQ%2UzEIzkkuUjz}h(NR(#FN3w2c42H z>Bnk17~1=YC9Vvh3?FEZem`n>@R+a%w@?Il7iw;W>j1oSC@-Dn`}}!WMe1 zyacdx6MV`naq5p>VWN2^>x!Xu2{#xk-l1X*hbQ$&$V;5FQk`~(<0Y5fYfmo4JT$a8 zgJzR1i*Zh=R!{j=>4fo9a+-F~AP{$D9v!eTA!}FOOY}&Y>PQ?wvcncuz}2o0>%HNn zqXXynRZVclG+!ZeN2u6^s|BBR>5Qd&SS$L9 zuYaNSRmRhb%NG5ya%a)6zy+o`eq0|lWMx@@8!>^v578TZ&M$z+x;~%S-{zbdeSbyx{Y0U)$m5=lxRV>sC@3E&daT zc3Mkxo>mF*hsqR9u9?jW3m}?-S0~BDWWtYrc|&C-_CTS=daEMpSHASGe6#6(s4u-+ zgCjoKg1Nyiq4}<`<#m<3-Jzd=(**trDXp1hV04(@-4ce)>@m!`oR>hF-f6azmOI0ozLFCx46Ws^=}fB{)Ty%d4J~gpTt)?) zqQYUNHyQrV+JDCDLVxnpxG2QA`51wmRh6+?uUQkV40wpzW;qK%85mI7(P1U@u{;iF zalV!u1hl@ixwK||*)G`g9Xc4r@;pSSF?c5PuRSOVC@+ z)SHA4<q)aJP=U^F|${#D=P7Tj8ESUPi_d{_R~=V8E{|z8o2QN8XT8+Z@;{<`0(9FE^+ox z>K%T%o2IEg>`n#hi~#^le=9#6O#?J@GDTa|9#}ONSL@HR+uk<5q%L*+=w%yGCR%2| zm=JXkA;BU^lapc1Yumrg3~jyq9jAuQqXQah(suQqY3|M@bY$pX$z2=|)^8#&rCv_I z$zuXn&wQprjRk7nkao#xJ5tin*mQWg!~1=Hgb350e2W15f4vj`RZ@Q=Ef61H6O6R@ z4&IAGZZ@#`jrfPH?RfBX^UR%tr=`C51hykFDCiHp=iPX)U(G`UFyFkKLN^>dhXBD^ zS!gEnc;o>*!MD9nch@lBFba>OcHFnIwky`OIflY5w-5COAvRrhksWkno#IzrqWJeB za*w3-XrKc6rwQj)k%sOhr#2`)=4EuSKD9D;X1X(`_UG1NU`d<4)bLv*IR;l{m?jUf z1Y}~(5=T{^t&)79ObLfEo0S7?4g%>3^U@$*GlHOMH59@9it&wgofqo%M&0@Se^PD^ zTiF8)X$kpZ@j>@KLJgN-$dZKpwKUHJeMop;;(?BsdoOUWC+Lv3;xTW2zfS*A{OAKJ zN$xUqcpht_EV%0|>yb?}T{F#0owwb3nBr(zOig#s{ghlStq<;n!ZAz=AgpXP2O~%a z33dM|z;gB8e)W#*Sn`8JgO0sxjZKMrOgb?o+{ZHltr;0-!Y*_y5;(G;_hn`OW!8`i zygh9g1_Cj9fkuyqJwq7qdo`jT`&6!Hmf;hazC3}jzGed&pwltu+xHcO1|T>48e1M# z<>e+e@0oRPIrU+%euwwWhMXWzFG#k>OUha-g?KXuy1FQk7&H6hI;{7|XONfkvY>Vm zL@q31JA6Kv4-LJ)n!h*rO(?;>fD8>zFBC8v)5;+>lVE8dX<+e9Fyb<4doV^Gv_Bml zGr3?AaLIBvdy@!Cx``LBZYVBbYZX3ID~*0Q)eAK{7}es@jX7x$Gh%`4$4S#Qo()>N z7(x%5J0E`B7`3?mdvz-ps9%dEIK`!W$5+HHS_8J<-Dm2DpmK=vl9RkXPx`fOn(6Mm z7-3`~-LMLJLLgFuPPKQx8iKzJp{HnNNLdhcxAr$J51&y7c-TAUIR_rmB2HN$K+^Jm zA5&0__DyEVz^$-A23NnZ&9jbFv6v#M|G`;n=bHUOrn=#e0J+vU0rmrg)9Gp#f5Q0m_(hZ+c#UFh%k~ zN)gqQfb`%0Ne2Lqc5^~_-cMVVX9C#Nqw2jE)Lhq4ZthgayvqC41|xrvma*-`%5?@VXw676!-GSR%8_D;+HoTs1m2E)Vu@7G~T+b}-O-EY~UEl&8maxhO z8bkMkoY*UKjp%Fdb2n4iUA~!V!!V;lb=HRqF^?SsG9F++l%V7q((Q= zt?+qLde&Ml&H7=eg10qzTiGbK0DIE{1+E8XSFPds5{;O8m`IYtA`^=zmWpyyxyH|n z^GWO^rvM);={`8qSRmwGv8WrZ>I@;)?o>OD+q3}gTwngrR&J{7PF$dF?Z_kgi@Uj!dkn%_O?XqfHo z7*?ads>PdhWo~_Sck*qSTYrpJ0&RJ>HWD6zB^fj6AGR@fG4g-6k&SEqe~C1A9I<}e z0npP2?A*x~7YwB`zO5KU6>^cql<8wIg`|ZNjm4Da(xtaE+NG5vef>v_I%|~BZLI<1 z>N}01{v7o`l56apMib##1ANUmHpjKLif2Tjm*aD-KR2RHizY^3(j@U`4|IM6a?my} zzRXl6dvCnwJh8!^1E*aAfi&iy0AcPU!*686$>iMXkCrL7XrfazIA+CKV3QL@&423Qf!nTcBxg zV3g=XS{eDL&oq4{6L_khYKlaW2JFZPe(h;l*aWt^0c{~-t}U2M%XP{$d8o>60jE$< zt-8vk}zvT;6P6pvD_-u4*>fwsqu< z`NFvR3z4Zo9#zDN2Dn8@Rgv|x&yp&PlYT-=tNJ7am5uua+-e&H0DDM9#=z3y3fuY#D%Yw7>^_z1Pz3a`)bx)00EM3Vl} zugOyrYSf7Q6?47?q7?wNwL!Z9R#j~c1D{t0fbgZhfscURH)^AUe zbsN~0s2jH{uvDPcarb6R^A)0UdUnf> ztY84<*s#6;^?m^{_NA{OC8SyYfoR$Ku~=0Jx}J6*Z~KvSSm^vlj)68m6AS8gNDP{17`v%{7{E=B_rVeO5nqZoL8?g7 zVVn(Z(Wi3+;!{R{ytfz&aNxYpny={NFW=uB^|d@~o^6L6^|>7zUQt~7#aMyr^|)}e zBsT<*7y;0d>J2q|!C21cIO}kI!^D?lVgNgyUkIc{$*rapE2?(%lr0wy^a=4hPSa$p zm3m0_stlQ?JAm=wv1_{O0}!=(x4zGB z;)7p4;<@L-hW)vRZWYK3A8&XJPxTMybAU6Lk97Dj(o6VEx8{gQDO_ZqlIk8Pk>aw_ z4mo`RT=Q;!uZ#trucOI8@8sAAYjhvBVI{5-gFu43UNJ6k%f`IMXzy zdk}f16~fF3t>@A%?ZU_lxLFjUQW4J?5)m0$&jYZyz8Cp141V4$B7&RtnRYTZNKplh zV9(Dx*l*vt4FHkzTIDA39d^2|>7brn3=}=!=yPZ2EawPuZ3;m_MxQY{0RJdQ%}zoe z7mupq;!&;;17gJwV+Ruwq5LEkgy2Ct1in+aWjzHm#EgZui@+B$;9~rW`^~WsPb-YU!8i>bs_tZ<7h-%YG`Z``EysJMz=LNV6h2{a z{I{OLz7(Weq7$C%9f!XeJO_^_7!MUyLRu{QO2eBiP9O3=a)!G+YE3vdJ@sM*CRpB% z@wc3z?X}6z>d4?sK6@;*uJ|Uxfv$J^b{S zkfX^{Wo$gUE=*~IM8ZyNF!VsYricOWcu6V*G hyS{`bDq zE z*EtWcQ@rUtkIe> ziHc_#t~uSMt?6!S46Z93or)C9ibx47lvT<0W)(8Vdb)shwe~k#<(eTp)zcl}&{>yy z%(mrI7j|o%focm`4<@RHKTv|rxr!M7>1C#&WMd=v9$&uY3H!s<|0SkVfDt5!M*g$_ zwUE^(T~swbgq(P{#Ei8~I^b3z=8=j$l=%l^6v%6EaIs*DSa$cN%QXFT zd&&s;aY|Rj!a_pB{nfWn7!;UA#baF?FN4`F+>mw1-rJF0iZKo&+Eys}Fas|L5z=?wtQh*N zkK1~(4jZdQkZlg#W|>CD<+8`12`^5x|^R(9Dekufps3RV}K{SASKWSo}s&_A9d}GDA8A%Adnlo`3>EyWbI>W_t{)g+l zp+EHU&vF#=RWc-|PThwBD`Ndhh*^MT+?5c%1nrqnmUcZW)Svs~ahn)b9K}K00LROh z;ZhEpN$ovBWAuI_kHu-qa}n+~?v5}w*oF!L%$hd|E&kL)dt#*W0StnoRHFld%b1tz z{A(t{=K8|{c(C`<39p7Ke@Ms0bEVVi?b+)4{gd?=Q*ZhlH#YdXec3W?J=h+G^JU}a z^Z;&hy=*PVTdrtLc*Xa6gOCv;Xqn~+8{EzBr97;^3XxElAL= z~nZ^;P{ z4+Fx`H$R^bPsiqVzj{=c(4^5K_XqxsOuv4;U-`d;st*T;sKGQ8iz_*6C==AsSiz_& zCZ+wNI!|}#ue(-KISKz8h&%(P7#9aVf;kt1j5;t-s>w0(SGyE za^{%FM1811KKfcV4H2$PF&&Hx*I7_B3H#XfGmQnd(=uH<&obC)`T#|ta}wC4Yc7>< za4=!QF`t+!c0YPgagM`UuxcVE?G+e|XjFrimH+fGfYRLVB z2_}rxBltr~P0yi=ynFm%&ucMj6En*{-Vx!wli&QMS=t(A*9qtxS(Zv z!g{L%4ItIUs(sg7mBsqF`|%?+$P8kYcqQ<6@F$x(e9hMao0srUL^!gUb6B=xmFY3d zaoST5q~KwO$UloW4xF-mk&;VlOS=Xy1*=$Uooau8+^F(|vfS9gnbKkTi8D>cgUeKy zGHXwv85JX%Z&$=JzU?D?Q)XNw5`*BDP*YQ@Mvqsb5 zuGAiH7y!8^f{NvsXmnN%*AkB`74^<0&T49A_m-PkIAr8nDf-(kM$_OjZia6s?Q>-r z_kRH!Mnd*Sbhm*vtUPV_PPm2r{=xX2{&7fx%fZ#_zQn~#ayHha8}PZSTn&#<#56XM zu7PTfzxdKvApm?OugYJfs1-wxd4Lryoexp!!irgjGnv#^<6=EBQA!mdSHmNtZk^;? z91jb&IJp={#Mb&>IWd#WIBiwSwo#nxijHYhk9VX6wa0EX+WbmLl@$JlCM1$SHJH{Y zp`SmKM_kaHPiU6~9m7PxOKVA7G0a2<-r00=@G{Wwe$a-&n)RGjZ3VQYXN{U?bT9zO zc3Zrl9F{HN1*L@fe+*gm!Q%v=s~ah%jqXGar63Qh)97QJYA#MVaPhLNN%EkT_oYx? zp{q4jpS(ozLn<< zn6Yw9AY!>JJcZ42pqaz*W*yWi*Fada;FZET1{gQmgZDKCmt)W#u_EKa3+ z8iqPIsI4VFxU)CL%MqBtT)G?Dq8x5YVI?1=QuWVAbRyGqHLCcn0hEcR47d)A|5!BhvozT|`55p1Kh{PNuC6SWZlvBp;j(2UIF0V&7 zk?IYn_%I~7O!zwZd#jHBqC!Zb+cT4{6iZxvT76%y_V#g*g%jR8AccVn_28KNS$t_m z2po?FGW%K_w%-v&%nduYSBv-f%)TT}v>E)UeP9q^84h@U5EZ`do7I^XJQyQnhB!-n zc{tCaZ8GVSI8slf?Zj1rpp4SNZfW4(&85O0~zZJ?Uq@>`G-HIW=+*vwBT*? zn{MuRYe8p>e!Y95mAldGH8P56kX#Y?v4{Hnogfcad1iA6bI|V_+%7{Z3odR0^*5UVGzr zEai~NNtAPIULMChdC90~UUyH{IF*^5-qazWIk*YOBWhaKadPbo=-Y?v>wBIP-fB{1 zpOsRolyJca2^J*e>XNJE)hv42*7zY1Bwv7AzbS(&qpegU|j)GW~8 z?DDCKB$a{=vT(NzkaVqgUifW;;&E*{A{I@!u*om<9a!m?Lz4%Se91>9Pf3S~Du?I? z$O%j^N3Ug!nvP}s4UWLN;_l30dpbv^6hzh5x_VmQtz?h<(DdV!v6ajI{xXn`1Jx)Z z-Qc3?P(rg5!~n~(WmM8Pn&WY=EjkxFq$6dxmKEzq3Ys^*!okFvjUf}4^``U5#I_d} zso%du^)qpWut`bP|3K={A2^M|5z0x;54;0NQUf+~rlL=euOb(F4@m4Cv`7?uY=)+j z@VVHFE@mT0YereMRo(O5vl2e0*(x$kd`r%A4u8HT&D{}Cur8!RYkhOyJ8%k8vni-I zv2A=I+hYwjnzc%D=+-(Hb+SX>JYOZI+_a;Cvfo4jU^6a*X!zQkq8IhAU_)rDHZ%Ui zD%7!-B(EjDuRdnovJVO@99gDr=Qy^8o6{8IPHO@p66T%2MyAD87T*`hb zb}vdk_0^{jU=NhzW+3DB`3-)Oht;Y(h3;&LFIe>RYEZH=KfTz*F}au&&6I>^i^yXk$8OFggL}o~x>hL{ zScb5w?u^4rw9v$%zK|5XI~q(JqV2%;dTeIZawNv#9>Ku_w1+&LxK%&FHGV zwZPIgR8*T>Hha8DEgg~WYlJd#h4!SSQKFgp`rcmuX=RiyXF=Sc*w=d$NphZzRsIJm zW`2s+B)}$eVRiCVn2;vuHnK#JMZ-zK*_rHA<}fS$Z>pT9w5mxN%4I}K>b^brGHnyw zn}tE~iZt6?ai$2{edFC^sKKK6?Wy*WconG9FJ-Q%|C+K&dr**{jE|*zx1os29&qFA z;EH*rG4}`e{EyUaIvv{{-3RaYbIzGOq-lDMN>6X#9r1~k z1%|&`lD2fYb9omA-k_dj^1fl_B}na${ft-bgN7vB*vM-W!SpLQ`TzA^&!wgAJmhV^ zZCzCIAiiTp!rS==m#toHuy4di4x}!VJ*}|pp;s}~poCttb@@ph2oAXKJ&1AS7GW%c zaLeRRO-3l+Wrm1=L}Uj}-g6%=p0*PmmtP1o^3!yl#}_{m@@|yto}dncgTLrC&kf2r&o(t+^2JTVEqEw;UIJ9gx4}_^ zD=s0f6$E75NZi}+&#s)?7Y>@UII}9U0>L68K1Ch@sz6!S2>&u}Sy!yo?h3Mb;cO_@ zIz5YbDcQWc;kxk0DE;dS#td6KkGwx&*l9lu5DAOf^~)n;3_|yr4+^v}2l08+Cn6c8 zdJcKyiSNBo9<~zb*$XVvnYjwh(U;jd^A|KGlp}$66FialYCQ|WS;ZZx_@)an;ZYu)vqVgsx)&9CWUMzln5?AKjU2U0%xP1urz*nj88{yZns@r+p{PZGm1F1N0nsO-@LxVvA6$_Ht522MkBO^A0< zV!;s9Lnma{ivPyvK%rmo-kw6Aii^pQDU3fd+lI93r{St@0q!;jkaV`~Ldq7DwL9=e zZV@p_LHfxB{xIjLgTK`WmFDHTKgu7B#5M(lRV3+hv9x^#i7SNoTjS<`!M^3^+u$*V z5n>Fd?I!p!BZn&3tZt0M99;v{h{Ap)DpK`F<)?e*BdHd1y7W$9%Dvl+wm>zV7Bw5B z9hKpMs~&JFnqxhzR7hUh4f*Uo?I3>3e$SGG!S%UMqUfPZtgyL@S4hbIye0Lt)v2fI zYEG?@G&oFxy-+n{85iHwl>7RVRHO2VBc7luBQx}M&{Ss2d-9UhzAK;u6 z7G|@sUeASU9b;kc?-G#k*!I6IF(@4LX>CD9gu5IJ@#{CpZ!iPAb6pboIj8DLSAAlo zw0AFI`eD+V^JU zJ3{<10`;i9YVl>o>?Qb^%hTFy5BN_PsD0fAaEP7Mbau{h#u~7@b#xfdEtR2w7MG z-s-tOkXa@&oDrleb-c2VU6w?@uoH6yq5o&R=d1(WK!^{f=f1W*+B;Mmfv!*3?>%+E z`=_31C+|NC)sz3ybqT#1y1htii`vIu&qE2hAp)#xu@9d`Fl97J3m1e}98-Y@sqAptopGE7oio`>TF{gC zz_sNDp^xK+60NAO7Q0V*zqmj8%>psk-Nx6%?6o@wb7LInGxMTCCG=z@5kF6~#+5JA zutV}9ye5IJZD}zaMZ$?cs=stTl7-doX8}h>_MDSAKZwykJlrXH6V44ag-&UCx6xR6 zF-W`3)KwQBU}YTxL6+Fe-x9BT-gWK3!!D7vp1aS`7LF5cH*rNifN*Is4$wqQjK4m0$-4HmLLk zzY9;a$W;>3>)$PZ2Jyeq_6tbGyWU2IilF#vdAt8a+u@S9Z+W z9fVB3v8(x1LApvm+cEM~Nt?(MaVha2foCS6j8dHuy7PjS1mldLd%uu#Y9Ve&U*xFh z=rjs*ogBxcu0JkrUbYTPrsqUmi$uHkc{(atI(!d*=@Pcl7pp^({21EyD}-+;&HC7H zSo3lr=e)h}5^2~CnYqD0-PZaZ0M zm}LCHoc&(Sa0A8puW7_4pOl^xs%Td}vU8uo2PYcb6`O7?Y92sC7@+=7fX9!~PB=)? zM!MO|!tHc+67y$cLCGcU-k@w5!VWE%o0s<`=bxT}L<#n21*hL)!iWjjgj)`*n}?>b zD=@Bp1cbopL%AmGxm7Hx_7N&c1bOBTxK;y1{iKAo0n-= zGt0`y=YvjyLG4tnd>`~dUWrkg%rQLtq0F^rwDoWsETrjvKH%E9OIAg?9EGcK+|~Qm zOY4|yC0|F(I1Z(r{WFc=1E#!&ZDrhrH$>F8yKL=g<-Xo@wjEo2FID~l9MhR$g8)&eMJH3L zGH3NCa#^YB4d=@ZL!gVNY7ll->0;;C7Vkl;Ohb3zZ7$FQhdGJv-jjNX_BRZ?VS$qW z@8Ik&*lb8_KX%CDDYv#3RGp>39B@cRBB=~dM0>>)Bcf&F3XAq89GQE*O-k7Q72F)VfJK* zIfiyQF|(jfMh*uiGE(>3Jb9P})X&vesOvXGnEiojx%vlC4Hufbm|Oz@_+U7x;n}tA z`oGN(0k;Qs$r(w5&eL4(OM+}-KR~@>P11EMBtwnyEv=9TsYp4fr^zCYTaEwo5&U(W z|E{MT53MU4)&!WT9LJMRIE>C*l-B`q`VKCqT_n;cg+B3XDoOjjrtrGjv|OJ*KzHQ`*7g;`r4-QpszK*^-WI? z%NcW_$YY_s0_e;HKsVrkvb`9+x~R0o z#QcJI$Aw>d0^M)EZh04<=0chvtLTLiz-ysGQb-j)+=N~|8Qz<>?;J#&i9uZm$*22 zj;bswJn`}=tp_*4NjUg_Dha)0|EVMpkb2!!9=4|{73I4cVZbwt7KV@&7rry{sSIC-E$dl(=YHV&Y0>pNJSxL`8dhb!lbuZ< z?ODVGx+?7=l_@4n3S#+1N(F7@CZ2+l?JI7WfBr=r8#pSD(^yr{k>oeW)GmG}RyJlr zcp1>-MH=os9ALbUZ?V@C3_M1G+59i==78zw4MQL~^E(LnkM28Aw({cZ;{%j;@glv- z`4|{}FSz}pI4YiA$)`wv{-iiin0sXY%^trm&I(rf!53cMWP`6$qVf=RQf_g&!3oHj zkzcF~#(gm>_ReWUXr(AFMj7OA;*oIb`Ofh`ZN!^Pv&2XwGB)S#2kjF;hM5HT12^N!k3@Gk2q=!vwY$>dMW1yZ!jWw?bzu*eh5EbPL3f8z)pjGZ)mfpfeU0 zta95R)2(dC%mu0)Vx^mYmpknr2DGB$6l2>cUGk!V(rsz#$kqC{r29_w9O>Q10N;UE MtlMZHAW$Ix2Pl;9lK=n! literal 0 HcmV?d00001 diff --git a/integration-tests/q-agentic-chat-server/package.json b/integration-tests/q-agentic-chat-server/package.json index 9bbb5ab9d4..ba8312a569 100644 --- a/integration-tests/q-agentic-chat-server/package.json +++ b/integration-tests/q-agentic-chat-server/package.json @@ -9,7 +9,7 @@ "test-integ": "npm run compile && mocha --timeout 30000 \"./out/**/*.test.js\" --retries 2" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-core": "*" }, "devDependencies": { diff --git a/package-lock.json b/package-lock.json index 6f80254f7a..a830bf52df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "integration-tests/*" ], "dependencies": { - "@aws/language-server-runtimes": "^0.2.116", + "@aws/language-server-runtimes": "^0.3.0", "@smithy/types": "4.2.0", "clean": "^4.0.2", "typescript": "^5.8.2" @@ -48,10 +48,10 @@ "name": "@aws/lsp-antlr4-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-antlr4": "*", - "antlr4-c3": "^3.4.1", - "antlr4ng": "^3.0.4" + "antlr4-c3": "^3.4.2", + "antlr4ng": "^3.0.14" }, "devDependencies": { "@types/chai": "^4.3.5", @@ -62,7 +62,7 @@ "chai-as-promised": "^7.1.1", "mocha": "^11.0.1", "ts-loader": "^9.4.4", - "ts-lsp-client": "^1.0.3", + "ts-lsp-client": "1.0.3", "webpack": "^5.94.0", "webpack-cli": "^6.0.1" } @@ -71,7 +71,7 @@ "name": "@aws/lsp-buildspec-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-buildspec": "^0.0.1" } }, @@ -79,7 +79,7 @@ "name": "@aws/lsp-cloudformation-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-cloudformation": "^0.0.1" } }, @@ -87,7 +87,7 @@ "name": "@aws/lsp-codewhisperer-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", @@ -99,6 +99,7 @@ "process": "^0.11.10", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", + "url": "^0.11.4", "vscode-languageserver": "^9.0.1", "wdio": "^6.0.1", "webpack-dev-server": "^5.2.0" @@ -116,11 +117,26 @@ "webpack-cli": "^6.0.1" } }, + "app/aws-lsp-codewhisperer-runtimes/node_modules/punycode": { + "version": "1.4.1", + "license": "MIT" + }, + "app/aws-lsp-codewhisperer-runtimes/node_modules/url": { + "version": "0.11.4", + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" + } + }, "app/aws-lsp-identity-runtimes": { "name": "@aws/lsp-identity-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-identity": "^0.0.1" } }, @@ -128,7 +144,7 @@ "name": "@aws/lsp-json-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-json": "*" }, "devDependencies": { @@ -139,7 +155,7 @@ "chai-as-promised": "^7.1.1", "mocha": "^11.0.1", "ts-loader": "^9.4.4", - "ts-lsp-client": "^1.0.3", + "ts-lsp-client": "1.0.3", "webpack": "^5.94.0", "webpack-cli": "^6.0.1" } @@ -148,7 +164,7 @@ "name": "@aws/lsp-notification-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-notification": "^0.0.1" } }, @@ -156,32 +172,21 @@ "name": "@aws/lsp-partiql-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.128", - "@aws/lsp-partiql": "^0.0.5" + "@aws/language-server-runtimes": "^0.3.0", + "@aws/lsp-partiql": "^0.0.18" }, "devDependencies": { "ts-loader": "^9.4.4", - "ts-lsp-client": "^1.0.3", + "ts-lsp-client": "1.0.3", "webpack": "^5.94.0", "webpack-cli": "^6.0.1" } }, - "app/aws-lsp-partiql-runtimes/node_modules/@aws/lsp-partiql": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/@aws/lsp-partiql/-/lsp-partiql-0.0.5.tgz", - "integrity": "sha512-WGRJIR2H13avwNWtTp8od1q1s2IJlUNLXft1OQxDV7xKnL4AJ0O/r3+X2oTg3PbT7j8n5a9CY9HzIU8LTMaR0Q==", - "dependencies": { - "@aws/language-server-runtimes": "^0.2.40", - "antlr4-c3": "3.4.2", - "antlr4ng": "3.0.14", - "web-tree-sitter": "0.22.6" - } - }, "app/aws-lsp-s3-runtimes": { "name": "@aws/lsp-s3-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-s3": "^0.0.1" }, "bin": { @@ -192,7 +197,7 @@ "name": "@aws/lsp-yaml-json-webworker", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, @@ -212,7 +217,7 @@ "name": "@aws/lsp-yaml-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-yaml": "*" }, "devDependencies": { @@ -223,7 +228,7 @@ "chai-as-promised": "^7.1.1", "mocha": "^11.0.1", "ts-loader": "^9.4.4", - "ts-lsp-client": "^1.0.3", + "ts-lsp-client": "1.0.3", "umd-compat-loader": "^2.1.2", "webpack": "^5.94.0", "webpack-cli": "^6.0.1" @@ -234,7 +239,7 @@ "version": "0.0.1", "dependencies": { "@aws/hello-world-lsp": "^0.0.1", - "@aws/language-server-runtimes": "^0.2.128" + "@aws/language-server-runtimes": "^0.3.0" }, "devDependencies": { "@types/chai": "^4.3.5", @@ -244,7 +249,7 @@ "chai-as-promised": "^7.1.1", "mocha": "^11.0.1", "ts-loader": "^9.4.4", - "ts-lsp-client": "^1.0.3", + "ts-lsp-client": "1.0.3", "webpack": "^5.94.0", "webpack-cli": "^6.0.1" } @@ -255,8 +260,8 @@ "license": "Apache-2.0", "dependencies": { "@aws/chat-client-ui-types": "^0.1.57", - "@aws/language-server-runtimes": "^0.2.129", - "@aws/language-server-runtimes-types": "^0.1.50", + "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes-types": "^0.1.56", "@aws/mynah-ui": "^4.36.8" }, "devDependencies": { @@ -272,6 +277,42 @@ "webpack-cli": "^6.0.1" } }, + "chat-client/node_modules/ts-mocha": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "bin": { + "ts-mocha": "bin/ts-mocha" + }, + "engines": { + "node": ">= 6.X.X" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X || ^11.X.X", + "ts-node": "^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X", + "tsconfig-paths": "^4.X.X" + }, + "peerDependenciesMeta": { + "tsconfig-paths": { + "optional": true + } + } + }, + "chat-client/node_modules/tsconfig-paths": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "client/vscode": { "name": "awsdocuments-ls-client", "version": "0.1.0", @@ -280,7 +321,7 @@ "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", "@aws/chat-client-ui-types": "^0.1.57", - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", @@ -296,7 +337,7 @@ "version": "0.0.16", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", @@ -327,7 +368,7 @@ "name": "@aws/q-agentic-chat-server-integration-tests", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-core": "*" }, "devDependencies": { @@ -345,19 +386,6 @@ "yauzl-promise": "^4.0.0" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@amzn/amazon-q-developer-streaming-client": { "version": "1.0.0", "resolved": "file:core/q-developer-streaming-client/amzn-amazon-q-developer-streaming-client-1.0.0.tgz", @@ -421,45 +449,127 @@ "node": ">=18.0.0" } }, - "node_modules/@amzn/amazon-q-developer-streaming-client/node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", + "node_modules/@amzn/amazon-q-developer-streaming-client/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@amzn/codewhisperer": { + "version": "1.0.0", + "resolved": "file:core/codewhisperer/amzn-codewhisperer-1.0.0.tgz", + "integrity": "sha512-ukYWlVbn0d2d+ERE/uPaYatbpsob3RNDfRIDgH3V/MWVSNjX+Kgdzo9QgKwXYBLf9rWtIOkviGxi9INr3qV3MA==", "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.731.0", + "@aws-sdk/credential-provider-node": "3.731.1", + "@aws-sdk/middleware-host-header": "3.731.0", + "@aws-sdk/middleware-logger": "3.731.0", + "@aws-sdk/middleware-recursion-detection": "3.731.0", + "@aws-sdk/middleware-user-agent": "3.731.0", + "@aws-sdk/region-config-resolver": "3.731.0", + "@aws-sdk/types": "3.731.0", + "@aws-sdk/util-user-agent-browser": "3.731.0", + "@aws-sdk/util-user-agent-node": "3.731.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.1", + "@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-retry": "^4.0.3", + "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@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.3", + "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "@types/uuid": "^9.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@amzn/amazon-q-developer-streaming-client/node_modules/@smithy/node-http-handler": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", - "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", + "node_modules/@amzn/codewhisperer-runtime": { + "version": "1.0.0", + "resolved": "file:core/codewhisperer-runtime/amzn-codewhisperer-runtime-1.0.0.tgz", + "integrity": "sha512-M4ijcbACU/FCCyMhamVGqCaK01/hyz8lJaUmACeIgYYlFOF4BrKivs24N2nLMCQx78mEg/Z/6mmWT6bw7MjOug==", "dependencies": { - "@smithy/abort-controller": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.731.0", + "@aws-sdk/middleware-host-header": "3.731.0", + "@aws-sdk/middleware-logger": "3.731.0", + "@aws-sdk/middleware-recursion-detection": "3.731.0", + "@aws-sdk/middleware-user-agent": "3.731.0", + "@aws-sdk/region-config-resolver": "3.731.0", + "@aws-sdk/token-providers": "3.731.1", + "@aws-sdk/types": "3.731.0", + "@aws-sdk/util-user-agent-browser": "3.731.0", + "@aws-sdk/util-user-agent-node": "3.731.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.1", + "@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-retry": "^4.0.3", + "@smithy/middleware-serde": "^4.0.1", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.2", + "@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.3", + "@smithy/util-defaults-mode-node": "^4.0.3", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "@types/uuid": "^9.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@amzn/amazon-q-developer-streaming-client/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "node_modules/@amzn/codewhisperer-runtime/node_modules/@aws-sdk/types": { + "version": "3.731.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.731.0.tgz", + "integrity": "sha512-NrdkJg6oOUbXR2r9WvHP408CLyvST8cJfp1/jP9pemtjvjPoh6NukbCtiSFdOOb1eryP02CnqQWItfJC1p2Y/Q==", "dependencies": { + "@smithy/types": "^4.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@amzn/amazon-q-developer-streaming-client/node_modules/uuid": { + "node_modules/@amzn/codewhisperer-runtime/node_modules/uuid": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", @@ -522,22 +632,6 @@ "node": ">=18.0.0" } }, - "node_modules/@amzn/codewhisperer-streaming/node_modules/@aws-sdk/token-providers": { - "version": "3.731.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.731.1.tgz", - "integrity": "sha512-t34GOPwBZsX7zGHjiTXmMHGY3kHM7fLiQ60Jqk0On9P0ASHTDE5U75RgCXboE3u+qEv9wyKyaqMNyMWj9qQlFg==", - "dependencies": { - "@aws-sdk/nested-clients": "3.731.1", - "@aws-sdk/types": "3.731.0", - "@smithy/property-provider": "^4.0.0", - "@smithy/shared-ini-file-loader": "^4.0.0", - "@smithy/types": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@amzn/codewhisperer-streaming/node_modules/@aws-sdk/types": { "version": "3.731.0", "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.731.0.tgz", @@ -550,45 +644,31 @@ "node": ">=18.0.0" } }, - "node_modules/@amzn/codewhisperer-streaming/node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@amzn/codewhisperer-streaming/node_modules/@smithy/node-http-handler": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", - "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", - "dependencies": { - "@smithy/abort-controller": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "node_modules/@amzn/codewhisperer-streaming/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" } }, - "node_modules/@amzn/codewhisperer-streaming/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "node_modules/@amzn/codewhisperer/node_modules/@aws-sdk/types": { + "version": "3.731.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.731.0.tgz", + "integrity": "sha512-NrdkJg6oOUbXR2r9WvHP408CLyvST8cJfp1/jP9pemtjvjPoh6NukbCtiSFdOOb1eryP02CnqQWItfJC1p2Y/Q==", "dependencies": { + "@smithy/types": "^4.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@amzn/codewhisperer-streaming/node_modules/uuid": { + "node_modules/@amzn/codewhisperer/node_modules/uuid": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", @@ -617,12 +697,6 @@ "lru-cache": "^10.4.3" } }, - "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true - }, "node_modules/@aws-crypto/crc32": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", @@ -810,49 +884,49 @@ } }, "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.839.0.tgz", - "integrity": "sha512-Pq/A5W46Z0JrRTIl4eVvguQjXWwVHiiBC3WyrLxlIH0hMS6bILgC7H+z+JiCm4mXR/oF2ZobQ8Wei/Sga1Uxkw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.901.0.tgz", + "integrity": "sha512-cDJ+npYeAiS9u/52RwR0AHgneEF+rnyxiYm4d/c4FTI6xTQId3hSD0zdK0EgZ1wfoMk0/+5Ft6mYk0V6JN+cbQ==", "dev": true, "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/credential-provider-node": "3.839.0", - "@aws-sdk/middleware-host-header": "3.821.0", - "@aws-sdk/middleware-logger": "3.821.0", - "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/region-config-resolver": "3.821.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.839.0", - "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.6.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/hash-node": "^4.0.4", - "@smithy/invalid-dependency": "^4.0.4", - "@smithy/middleware-content-length": "^4.0.4", - "@smithy/middleware-endpoint": "^4.1.13", - "@smithy/middleware-retry": "^4.1.14", - "@smithy/middleware-serde": "^4.0.8", - "@smithy/middleware-stack": "^4.0.4", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/url-parser": "^4.0.4", - "@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.21", - "@smithy/util-defaults-mode-node": "^4.0.21", - "@smithy/util-endpoints": "^3.0.6", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.6", - "@smithy/util-utf8": "^4.0.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/credential-provider-node": "3.901.0", + "@aws-sdk/middleware-host-header": "3.901.0", + "@aws-sdk/middleware-logger": "3.901.0", + "@aws-sdk/middleware-recursion-detection": "3.901.0", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/region-config-resolver": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@aws-sdk/util-user-agent-browser": "3.901.0", + "@aws-sdk/util-user-agent-node": "3.901.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.14.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/hash-node": "^4.2.0", + "@smithy/invalid-dependency": "^4.2.0", + "@smithy/middleware-content-length": "^4.2.0", + "@smithy/middleware-endpoint": "^4.3.0", + "@smithy/middleware-retry": "^4.4.0", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.0", + "@smithy/util-defaults-mode-browser": "^4.2.0", + "@smithy/util-defaults-mode-node": "^4.2.0", + "@smithy/util-endpoints": "^3.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -860,48 +934,48 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/client-sso": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.839.0.tgz", - "integrity": "sha512-AZABysUhbfcwXVlMo97/vwHgsfJNF81wypCAowpqAJkSjP2KrqsqHpb71/RoR2w8JGmEnBBXRD4wIxDhnmifWg==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.901.0.tgz", + "integrity": "sha512-sGyDjjkJ7ppaE+bAKL/Q5IvVCxtoyBIzN+7+hWTS/mUxWJ9EOq9238IqmVIIK6sYNIzEf9yhobfMARasPYVTNg==", "dev": true, "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/middleware-host-header": "3.821.0", - "@aws-sdk/middleware-logger": "3.821.0", - "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/region-config-resolver": "3.821.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.839.0", - "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.6.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/hash-node": "^4.0.4", - "@smithy/invalid-dependency": "^4.0.4", - "@smithy/middleware-content-length": "^4.0.4", - "@smithy/middleware-endpoint": "^4.1.13", - "@smithy/middleware-retry": "^4.1.14", - "@smithy/middleware-serde": "^4.0.8", - "@smithy/middleware-stack": "^4.0.4", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/url-parser": "^4.0.4", - "@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.21", - "@smithy/util-defaults-mode-node": "^4.0.21", - "@smithy/util-endpoints": "^3.0.6", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.6", - "@smithy/util-utf8": "^4.0.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/middleware-host-header": "3.901.0", + "@aws-sdk/middleware-logger": "3.901.0", + "@aws-sdk/middleware-recursion-detection": "3.901.0", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/region-config-resolver": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@aws-sdk/util-user-agent-browser": "3.901.0", + "@aws-sdk/util-user-agent-node": "3.901.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.14.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/hash-node": "^4.2.0", + "@smithy/invalid-dependency": "^4.2.0", + "@smithy/middleware-content-length": "^4.2.0", + "@smithy/middleware-endpoint": "^4.3.0", + "@smithy/middleware-retry": "^4.4.0", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.0", + "@smithy/util-defaults-mode-browser": "^4.2.0", + "@smithy/util-defaults-mode-node": "^4.2.0", + "@smithy/util-endpoints": "^3.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -909,25 +983,23 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/core": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.839.0.tgz", - "integrity": "sha512-KdwL5RaK7eUIlOpdOoZ5u+2t4X1rdX/MTZgz3IV/aBzjVUoGsp+uUnbyqXomLQSUitPHp72EE/NHDsvWW/IHvQ==", - "dev": true, - "dependencies": { - "@aws-sdk/types": "3.821.0", - "@aws-sdk/xml-builder": "3.821.0", - "@smithy/core": "^3.6.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/property-provider": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/signature-v4": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-utf8": "^4.0.0", - "fast-xml-parser": "4.4.1", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.901.0.tgz", + "integrity": "sha512-brKAc3y64tdhyuEf+OPIUln86bRTqkLgb9xkd6kUdIeA5+qmp/N6amItQz+RN4k4O3kqkCPYnAd3LonTKluobw==", + "dev": true, + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@aws-sdk/xml-builder": "3.901.0", + "@smithy/core": "^3.14.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/signature-v4": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -935,15 +1007,15 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.839.0.tgz", - "integrity": "sha512-cWTadewPPz1OvObZJB+olrgh8VwcgIVcT293ZUT9V0CMF0UU7QaPwJP7uNXcNxltTh+sk1yhjH4UlcnJigZZbA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.901.0.tgz", + "integrity": "sha512-5hAdVl3tBuARh3zX5MLJ1P/d+Kr5kXtDU3xm1pxUEF4xt2XkEEpwiX5fbkNkz2rbh3BCt2gOHsAbh6b3M7n+DA==", "dev": true, "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -951,20 +1023,20 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.839.0.tgz", - "integrity": "sha512-fv0BZwrDhWDju4D1MCLT4I2aPjr0dVQ6P+MpqvcGNOA41Oa9UdRhYTV5iuy5NLXzIzoCmnS+XfSq5Kbsf6//xw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.901.0.tgz", + "integrity": "sha512-Ggr7+0M6QZEsrqRkK7iyJLf4LkIAacAxHz9c4dm9hnDdU7vqrlJm6g73IxMJXWN1bIV7IxfpzB11DsRrB/oNjQ==", "dev": true, "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/property-provider": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/util-stream": "^4.2.2", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/util-stream": "^4.4.0", "tslib": "^2.6.2" }, "engines": { @@ -972,23 +1044,23 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.839.0.tgz", - "integrity": "sha512-GHm0hF4CiDxIDR7TauMaA6iI55uuSqRxMBcqTAHaTPm6+h1A+MS+ysQMxZ+Jvwtoy8WmfTIGrJVxSCw0sK2hvA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.901.0.tgz", + "integrity": "sha512-zxadcDS0hNJgv8n4hFYJNOXyfjaNE1vvqIiF/JzZSQpSSYXzCd+WxXef5bQh+W3giDtRUmkvP5JLbamEFjZKyw==", "dev": true, "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/credential-provider-env": "3.839.0", - "@aws-sdk/credential-provider-http": "3.839.0", - "@aws-sdk/credential-provider-process": "3.839.0", - "@aws-sdk/credential-provider-sso": "3.839.0", - "@aws-sdk/credential-provider-web-identity": "3.839.0", - "@aws-sdk/nested-clients": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/credential-provider-imds": "^4.0.6", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/credential-provider-env": "3.901.0", + "@aws-sdk/credential-provider-http": "3.901.0", + "@aws-sdk/credential-provider-process": "3.901.0", + "@aws-sdk/credential-provider-sso": "3.901.0", + "@aws-sdk/credential-provider-web-identity": "3.901.0", + "@aws-sdk/nested-clients": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/credential-provider-imds": "^4.2.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -996,22 +1068,22 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.839.0.tgz", - "integrity": "sha512-7bR+U2h+ft0V8chyeu9Bh/pvau4ZkQMeRt5f0dAULoepZQ77QQVRP4H04yJPTg9DCtqbVULQ3uf5YOp1/08vQw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.901.0.tgz", + "integrity": "sha512-dPuFzMF7L1s/lQyT3wDxqLe82PyTH+5o1jdfseTEln64LJMl0ZMWaKX/C1UFNDxaTd35Cgt1bDbjjAWHMiKSFQ==", "dev": true, "dependencies": { - "@aws-sdk/credential-provider-env": "3.839.0", - "@aws-sdk/credential-provider-http": "3.839.0", - "@aws-sdk/credential-provider-ini": "3.839.0", - "@aws-sdk/credential-provider-process": "3.839.0", - "@aws-sdk/credential-provider-sso": "3.839.0", - "@aws-sdk/credential-provider-web-identity": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/credential-provider-imds": "^4.0.6", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/credential-provider-env": "3.901.0", + "@aws-sdk/credential-provider-http": "3.901.0", + "@aws-sdk/credential-provider-ini": "3.901.0", + "@aws-sdk/credential-provider-process": "3.901.0", + "@aws-sdk/credential-provider-sso": "3.901.0", + "@aws-sdk/credential-provider-web-identity": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/credential-provider-imds": "^4.2.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1019,16 +1091,16 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.839.0.tgz", - "integrity": "sha512-qShpekjociUZ+isyQNa0P7jo+0q3N2+0eJDg8SGyP6K6hHTcGfiqxTDps+IKl6NreCPhZCBzyI9mWkP0xSDR6g==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.901.0.tgz", + "integrity": "sha512-/IWgmgM3Cl1wTdJA5HqKMAojxLkYchh5kDuphApxKhupLu6Pu0JBOHU8A5GGeFvOycyaVwosod6zDduINZxe+A==", "dev": true, "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1036,18 +1108,18 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.839.0.tgz", - "integrity": "sha512-w10zBLHhU8SBQcdrSPMI02haLoRGZg+gP7mH/Er8VhIXfHefbr7o4NirmB0hwdw/YAH8MLlC9jj7c2SJlsNhYA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.901.0.tgz", + "integrity": "sha512-SjmqZQHmqFSET7+6xcZgtH7yEyh5q53LN87GqwYlJZ6KJ5oNw11acUNEhUOL1xTSJEvaWqwTIkS2zqrzLcM9bw==", "dev": true, "dependencies": { - "@aws-sdk/client-sso": "3.839.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/token-providers": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/client-sso": "3.901.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/token-providers": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1055,16 +1127,17 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.839.0.tgz", - "integrity": "sha512-EvqTc7J1kgmiuxknpCp1S60hyMQvmKxsI5uXzQtcogl/N55rxiXEqnCLI5q6p33q91PJegrcMCM5Q17Afhm5qA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.901.0.tgz", + "integrity": "sha512-NYjy/6NLxH9m01+pfpB4ql8QgAorJcu8tw69kzHwUd/ql6wUDTbC7HcXqtKlIwWjzjgj2BKL7j6SyFapgCuafA==", "dev": true, "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/nested-clients": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/nested-clients": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1072,14 +1145,14 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.821.0.tgz", - "integrity": "sha512-xSMR+sopSeWGx5/4pAGhhfMvGBHioVBbqGvDs6pG64xfNwM5vq5s5v6D04e2i+uSTj4qGa71dLUs5I0UzAK3sw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.901.0.tgz", + "integrity": "sha512-yWX7GvRmqBtbNnUW7qbre3GvZmyYwU0WHefpZzDTYDoNgatuYq6LgUIQ+z5C04/kCRoFkAFrHag8a3BXqFzq5A==", "dev": true, "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1087,13 +1160,13 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/middleware-logger": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.821.0.tgz", - "integrity": "sha512-0cvI0ipf2tGx7fXYEEN5fBeZDz2RnHyb9xftSgUsEq7NBxjV0yTZfLJw6Za5rjE6snC80dRN8+bTNR1tuG89zA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.901.0.tgz", + "integrity": "sha512-UoHebjE7el/tfRo8/CQTj91oNUm+5Heus5/a4ECdmWaSCHCS/hXTsU3PTTHAY67oAQR8wBLFPfp3mMvXjB+L2A==", "dev": true, "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1101,14 +1174,15 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.821.0.tgz", - "integrity": "sha512-efmaifbhBoqKG3bAoEfDdcM8hn1psF+4qa7ykWuYmfmah59JBeqHLfz5W9m9JoTwoKPkFcVLWZxnyZzAnVBOIg==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.901.0.tgz", + "integrity": "sha512-Wd2t8qa/4OL0v/oDpCHHYkgsXJr8/ttCxrvCKAt0H1zZe2LlRhY9gpDVKqdertfHrHDj786fOvEQA28G1L75Dg==", "dev": true, "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@aws/lambda-invoke-store": "^0.0.1", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1116,17 +1190,17 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.839.0.tgz", - "integrity": "sha512-2u74uRM1JWq6Sf7+3YpjejPM9YkomGt4kWhrmooIBEq1k5r2GTbkH7pNCxBQwBueXM21jAGVDxxeClpTx+5hig==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.901.0.tgz", + "integrity": "sha512-Zby4F03fvD9xAgXGPywyk4bC1jCbnyubMEYChLYohD+x20ULQCf+AimF/Btn7YL+hBpzh1+RmqmvZcx+RgwgNQ==", "dev": true, "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@smithy/core": "^3.6.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@smithy/core": "^3.14.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1134,48 +1208,48 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/nested-clients": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.839.0.tgz", - "integrity": "sha512-Glic0pg2THYP3aRhJORwJJBe1JLtJoEdWV/MFZNyzCklfMwEzpWtZAyxy+tQyFmMeW50uBAnh2R0jhMMcf257w==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.901.0.tgz", + "integrity": "sha512-feAAAMsVwctk2Tms40ONybvpfJPLCmSdI+G+OTrNpizkGLNl6ik2Ng2RzxY6UqOfN8abqKP/DOUj1qYDRDG8ag==", "dev": true, "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/middleware-host-header": "3.821.0", - "@aws-sdk/middleware-logger": "3.821.0", - "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/region-config-resolver": "3.821.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.839.0", - "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.6.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/hash-node": "^4.0.4", - "@smithy/invalid-dependency": "^4.0.4", - "@smithy/middleware-content-length": "^4.0.4", - "@smithy/middleware-endpoint": "^4.1.13", - "@smithy/middleware-retry": "^4.1.14", - "@smithy/middleware-serde": "^4.0.8", - "@smithy/middleware-stack": "^4.0.4", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/url-parser": "^4.0.4", - "@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.21", - "@smithy/util-defaults-mode-node": "^4.0.21", - "@smithy/util-endpoints": "^3.0.6", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.6", - "@smithy/util-utf8": "^4.0.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/middleware-host-header": "3.901.0", + "@aws-sdk/middleware-logger": "3.901.0", + "@aws-sdk/middleware-recursion-detection": "3.901.0", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/region-config-resolver": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@aws-sdk/util-user-agent-browser": "3.901.0", + "@aws-sdk/util-user-agent-node": "3.901.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.14.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/hash-node": "^4.2.0", + "@smithy/invalid-dependency": "^4.2.0", + "@smithy/middleware-content-length": "^4.2.0", + "@smithy/middleware-endpoint": "^4.3.0", + "@smithy/middleware-retry": "^4.4.0", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.0", + "@smithy/util-defaults-mode-browser": "^4.2.0", + "@smithy/util-defaults-mode-node": "^4.2.0", + "@smithy/util-endpoints": "^3.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -1183,16 +1257,34 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.821.0.tgz", - "integrity": "sha512-t8og+lRCIIy5nlId0bScNpCkif8sc0LhmtaKsbm0ZPm3sCa/WhCbSZibjbZ28FNjVCV+p0D9RYZx0VDDbtWyjw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.901.0.tgz", + "integrity": "sha512-7F0N888qVLHo4CSQOsnkZ4QAp8uHLKJ4v3u09Ly5k4AEStrSlFpckTPyUx6elwGL+fxGjNE2aakK8vEgzzCV0A==", "dev": true, "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/types": "^4.3.1", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", + "@aws-sdk/types": "3.901.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/token-providers": { + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.901.0.tgz", + "integrity": "sha512-pJEr1Ggbc/uVTDqp9IbNu9hdr0eQf3yZix3s4Nnyvmg4xmJSGAlbPC9LrNr5u3CDZoc8Z9CuLrvbP4MwYquNpQ==", + "dev": true, + "dependencies": { + "@aws-sdk/core": "3.901.0", + "@aws-sdk/nested-clients": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1200,27 +1292,27 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.821.0.tgz", - "integrity": "sha512-irWZHyM0Jr1xhC+38OuZ7JB6OXMLPZlj48thElpsO1ZSLRkLZx5+I7VV6k3sp2yZ7BYbKz/G2ojSv4wdm7XTLw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.901.0.tgz", + "integrity": "sha512-Ntb6V/WFI21Ed4PDgL/8NSfoZQQf9xzrwNgiwvnxgAl/KvAvRBgQtqj5gHsDX8Nj2YmJuVoHfH9BGjL9VQ4WNg==", "dev": true, "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.839.0.tgz", - "integrity": "sha512-MuunkIG1bJVMtTH7MbjXOrhHleU5wjHz5eCAUc6vj7M9rwol71nqjj9b8RLnkO5gsJcKc29Qk8iV6xQuzKWNMw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.901.0.tgz", + "integrity": "sha512-l59KQP5TY7vPVUfEURc7P5BJKuNg1RSsAKBQW7LHLECXjLqDUbo2SMLrexLBEoArSt6E8QOrIN0C8z/0Xk0jYw==", "dev": true, "dependencies": { - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/types": "^4.3.1", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1235,182 +1327,150 @@ } } }, - "node_modules/@aws-sdk/client-cognito-identity/node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@smithy/types": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dev": true, "dependencies": { - "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-cognito-identity/node_modules/@smithy/node-http-handler": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", - "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", - "dev": true, + "node_modules/@aws-sdk/client-s3": { + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.901.0.tgz", + "integrity": "sha512-wyKhZ51ur1tFuguZ6PgrUsot9KopqD0Tmxw8O8P/N3suQDxFPr0Yo7Y77ezDRDZQ95Ml3C0jlvx79HCo8VxdWA==", "dependencies": { - "@smithy/abort-controller": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-crypto/sha1-browser": "5.2.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/credential-provider-node": "3.901.0", + "@aws-sdk/middleware-bucket-endpoint": "3.901.0", + "@aws-sdk/middleware-expect-continue": "3.901.0", + "@aws-sdk/middleware-flexible-checksums": "3.901.0", + "@aws-sdk/middleware-host-header": "3.901.0", + "@aws-sdk/middleware-location-constraint": "3.901.0", + "@aws-sdk/middleware-logger": "3.901.0", + "@aws-sdk/middleware-recursion-detection": "3.901.0", + "@aws-sdk/middleware-sdk-s3": "3.901.0", + "@aws-sdk/middleware-ssec": "3.901.0", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/region-config-resolver": "3.901.0", + "@aws-sdk/signature-v4-multi-region": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@aws-sdk/util-user-agent-browser": "3.901.0", + "@aws-sdk/util-user-agent-node": "3.901.0", + "@aws-sdk/xml-builder": "3.901.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.14.0", + "@smithy/eventstream-serde-browser": "^4.2.0", + "@smithy/eventstream-serde-config-resolver": "^4.3.0", + "@smithy/eventstream-serde-node": "^4.2.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/hash-blob-browser": "^4.2.0", + "@smithy/hash-node": "^4.2.0", + "@smithy/hash-stream-node": "^4.2.0", + "@smithy/invalid-dependency": "^4.2.0", + "@smithy/md5-js": "^4.2.0", + "@smithy/middleware-content-length": "^4.2.0", + "@smithy/middleware-endpoint": "^4.3.0", + "@smithy/middleware-retry": "^4.4.0", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.0", + "@smithy/util-defaults-mode-browser": "^4.2.0", + "@smithy/util-defaults-mode-node": "^4.2.0", + "@smithy/util-endpoints": "^3.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/util-stream": "^4.4.0", + "@smithy/util-utf8": "^4.2.0", + "@smithy/util-waiter": "^4.2.0", + "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-cognito-identity/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", - "dev": true, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/client-sso": { + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.901.0.tgz", + "integrity": "sha512-sGyDjjkJ7ppaE+bAKL/Q5IvVCxtoyBIzN+7+hWTS/mUxWJ9EOq9238IqmVIIK6sYNIzEf9yhobfMARasPYVTNg==", "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/middleware-host-header": "3.901.0", + "@aws-sdk/middleware-logger": "3.901.0", + "@aws-sdk/middleware-recursion-detection": "3.901.0", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/region-config-resolver": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@aws-sdk/util-user-agent-browser": "3.901.0", + "@aws-sdk/util-user-agent-node": "3.901.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.14.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/hash-node": "^4.2.0", + "@smithy/invalid-dependency": "^4.2.0", + "@smithy/middleware-content-length": "^4.2.0", + "@smithy/middleware-endpoint": "^4.3.0", + "@smithy/middleware-retry": "^4.4.0", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.0", + "@smithy/util-defaults-mode-browser": "^4.2.0", + "@smithy/util-defaults-mode-node": "^4.2.0", + "@smithy/util-endpoints": "^3.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-s3": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.839.0.tgz", - "integrity": "sha512-7zDInY+qltKxeG+9d/97nbs+FWINcAi5bChBrleUQkuQ/dA9pSP1URo/6JlVzD2Ejvksm+hVK6z3VUWZaIAVOw==", + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/core": { + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.901.0.tgz", + "integrity": "sha512-brKAc3y64tdhyuEf+OPIUln86bRTqkLgb9xkd6kUdIeA5+qmp/N6amItQz+RN4k4O3kqkCPYnAd3LonTKluobw==", "dependencies": { - "@aws-crypto/sha1-browser": "5.2.0", - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/credential-provider-node": "3.839.0", - "@aws-sdk/middleware-bucket-endpoint": "3.830.0", - "@aws-sdk/middleware-expect-continue": "3.821.0", - "@aws-sdk/middleware-flexible-checksums": "3.839.0", - "@aws-sdk/middleware-host-header": "3.821.0", - "@aws-sdk/middleware-location-constraint": "3.821.0", - "@aws-sdk/middleware-logger": "3.821.0", - "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-sdk-s3": "3.839.0", - "@aws-sdk/middleware-ssec": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/region-config-resolver": "3.821.0", - "@aws-sdk/signature-v4-multi-region": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.839.0", - "@aws-sdk/xml-builder": "3.821.0", - "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.6.0", - "@smithy/eventstream-serde-browser": "^4.0.4", - "@smithy/eventstream-serde-config-resolver": "^4.1.2", - "@smithy/eventstream-serde-node": "^4.0.4", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/hash-blob-browser": "^4.0.4", - "@smithy/hash-node": "^4.0.4", - "@smithy/hash-stream-node": "^4.0.4", - "@smithy/invalid-dependency": "^4.0.4", - "@smithy/md5-js": "^4.0.4", - "@smithy/middleware-content-length": "^4.0.4", - "@smithy/middleware-endpoint": "^4.1.13", - "@smithy/middleware-retry": "^4.1.14", - "@smithy/middleware-serde": "^4.0.8", - "@smithy/middleware-stack": "^4.0.4", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/url-parser": "^4.0.4", - "@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.21", - "@smithy/util-defaults-mode-node": "^4.0.21", - "@smithy/util-endpoints": "^3.0.6", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.6", - "@smithy/util-stream": "^4.2.2", - "@smithy/util-utf8": "^4.0.0", - "@smithy/util-waiter": "^4.0.6", - "@types/uuid": "^9.0.1", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/client-sso": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.839.0.tgz", - "integrity": "sha512-AZABysUhbfcwXVlMo97/vwHgsfJNF81wypCAowpqAJkSjP2KrqsqHpb71/RoR2w8JGmEnBBXRD4wIxDhnmifWg==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/middleware-host-header": "3.821.0", - "@aws-sdk/middleware-logger": "3.821.0", - "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/region-config-resolver": "3.821.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.839.0", - "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.6.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/hash-node": "^4.0.4", - "@smithy/invalid-dependency": "^4.0.4", - "@smithy/middleware-content-length": "^4.0.4", - "@smithy/middleware-endpoint": "^4.1.13", - "@smithy/middleware-retry": "^4.1.14", - "@smithy/middleware-serde": "^4.0.8", - "@smithy/middleware-stack": "^4.0.4", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/url-parser": "^4.0.4", - "@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.21", - "@smithy/util-defaults-mode-node": "^4.0.21", - "@smithy/util-endpoints": "^3.0.6", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.6", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/core": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.839.0.tgz", - "integrity": "sha512-KdwL5RaK7eUIlOpdOoZ5u+2t4X1rdX/MTZgz3IV/aBzjVUoGsp+uUnbyqXomLQSUitPHp72EE/NHDsvWW/IHvQ==", - "dependencies": { - "@aws-sdk/types": "3.821.0", - "@aws-sdk/xml-builder": "3.821.0", - "@smithy/core": "^3.6.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/property-provider": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/signature-v4": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-utf8": "^4.0.0", - "fast-xml-parser": "4.4.1", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/xml-builder": "3.901.0", + "@smithy/core": "^3.14.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/signature-v4": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -1418,14 +1478,14 @@ } }, "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.839.0.tgz", - "integrity": "sha512-cWTadewPPz1OvObZJB+olrgh8VwcgIVcT293ZUT9V0CMF0UU7QaPwJP7uNXcNxltTh+sk1yhjH4UlcnJigZZbA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.901.0.tgz", + "integrity": "sha512-5hAdVl3tBuARh3zX5MLJ1P/d+Kr5kXtDU3xm1pxUEF4xt2XkEEpwiX5fbkNkz2rbh3BCt2gOHsAbh6b3M7n+DA==", "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1433,19 +1493,19 @@ } }, "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.839.0.tgz", - "integrity": "sha512-fv0BZwrDhWDju4D1MCLT4I2aPjr0dVQ6P+MpqvcGNOA41Oa9UdRhYTV5iuy5NLXzIzoCmnS+XfSq5Kbsf6//xw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.901.0.tgz", + "integrity": "sha512-Ggr7+0M6QZEsrqRkK7iyJLf4LkIAacAxHz9c4dm9hnDdU7vqrlJm6g73IxMJXWN1bIV7IxfpzB11DsRrB/oNjQ==", "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/property-provider": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/util-stream": "^4.2.2", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/util-stream": "^4.4.0", "tslib": "^2.6.2" }, "engines": { @@ -1453,22 +1513,22 @@ } }, "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.839.0.tgz", - "integrity": "sha512-GHm0hF4CiDxIDR7TauMaA6iI55uuSqRxMBcqTAHaTPm6+h1A+MS+ysQMxZ+Jvwtoy8WmfTIGrJVxSCw0sK2hvA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.901.0.tgz", + "integrity": "sha512-zxadcDS0hNJgv8n4hFYJNOXyfjaNE1vvqIiF/JzZSQpSSYXzCd+WxXef5bQh+W3giDtRUmkvP5JLbamEFjZKyw==", "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/credential-provider-env": "3.839.0", - "@aws-sdk/credential-provider-http": "3.839.0", - "@aws-sdk/credential-provider-process": "3.839.0", - "@aws-sdk/credential-provider-sso": "3.839.0", - "@aws-sdk/credential-provider-web-identity": "3.839.0", - "@aws-sdk/nested-clients": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/credential-provider-imds": "^4.0.6", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/credential-provider-env": "3.901.0", + "@aws-sdk/credential-provider-http": "3.901.0", + "@aws-sdk/credential-provider-process": "3.901.0", + "@aws-sdk/credential-provider-sso": "3.901.0", + "@aws-sdk/credential-provider-web-identity": "3.901.0", + "@aws-sdk/nested-clients": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/credential-provider-imds": "^4.2.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1476,21 +1536,21 @@ } }, "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.839.0.tgz", - "integrity": "sha512-7bR+U2h+ft0V8chyeu9Bh/pvau4ZkQMeRt5f0dAULoepZQ77QQVRP4H04yJPTg9DCtqbVULQ3uf5YOp1/08vQw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.901.0.tgz", + "integrity": "sha512-dPuFzMF7L1s/lQyT3wDxqLe82PyTH+5o1jdfseTEln64LJMl0ZMWaKX/C1UFNDxaTd35Cgt1bDbjjAWHMiKSFQ==", "dependencies": { - "@aws-sdk/credential-provider-env": "3.839.0", - "@aws-sdk/credential-provider-http": "3.839.0", - "@aws-sdk/credential-provider-ini": "3.839.0", - "@aws-sdk/credential-provider-process": "3.839.0", - "@aws-sdk/credential-provider-sso": "3.839.0", - "@aws-sdk/credential-provider-web-identity": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/credential-provider-imds": "^4.0.6", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/credential-provider-env": "3.901.0", + "@aws-sdk/credential-provider-http": "3.901.0", + "@aws-sdk/credential-provider-ini": "3.901.0", + "@aws-sdk/credential-provider-process": "3.901.0", + "@aws-sdk/credential-provider-sso": "3.901.0", + "@aws-sdk/credential-provider-web-identity": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/credential-provider-imds": "^4.2.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1498,15 +1558,15 @@ } }, "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.839.0.tgz", - "integrity": "sha512-qShpekjociUZ+isyQNa0P7jo+0q3N2+0eJDg8SGyP6K6hHTcGfiqxTDps+IKl6NreCPhZCBzyI9mWkP0xSDR6g==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.901.0.tgz", + "integrity": "sha512-/IWgmgM3Cl1wTdJA5HqKMAojxLkYchh5kDuphApxKhupLu6Pu0JBOHU8A5GGeFvOycyaVwosod6zDduINZxe+A==", "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1514,17 +1574,17 @@ } }, "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.839.0.tgz", - "integrity": "sha512-w10zBLHhU8SBQcdrSPMI02haLoRGZg+gP7mH/Er8VhIXfHefbr7o4NirmB0hwdw/YAH8MLlC9jj7c2SJlsNhYA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.901.0.tgz", + "integrity": "sha512-SjmqZQHmqFSET7+6xcZgtH7yEyh5q53LN87GqwYlJZ6KJ5oNw11acUNEhUOL1xTSJEvaWqwTIkS2zqrzLcM9bw==", "dependencies": { - "@aws-sdk/client-sso": "3.839.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/token-providers": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/client-sso": "3.901.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/token-providers": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1532,15 +1592,16 @@ } }, "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.839.0.tgz", - "integrity": "sha512-EvqTc7J1kgmiuxknpCp1S60hyMQvmKxsI5uXzQtcogl/N55rxiXEqnCLI5q6p33q91PJegrcMCM5Q17Afhm5qA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.901.0.tgz", + "integrity": "sha512-NYjy/6NLxH9m01+pfpB4ql8QgAorJcu8tw69kzHwUd/ql6wUDTbC7HcXqtKlIwWjzjgj2BKL7j6SyFapgCuafA==", "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/nested-clients": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/nested-clients": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1548,13 +1609,13 @@ } }, "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.821.0.tgz", - "integrity": "sha512-xSMR+sopSeWGx5/4pAGhhfMvGBHioVBbqGvDs6pG64xfNwM5vq5s5v6D04e2i+uSTj4qGa71dLUs5I0UzAK3sw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.901.0.tgz", + "integrity": "sha512-yWX7GvRmqBtbNnUW7qbre3GvZmyYwU0WHefpZzDTYDoNgatuYq6LgUIQ+z5C04/kCRoFkAFrHag8a3BXqFzq5A==", "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1562,12 +1623,12 @@ } }, "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-logger": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.821.0.tgz", - "integrity": "sha512-0cvI0ipf2tGx7fXYEEN5fBeZDz2RnHyb9xftSgUsEq7NBxjV0yTZfLJw6Za5rjE6snC80dRN8+bTNR1tuG89zA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.901.0.tgz", + "integrity": "sha512-UoHebjE7el/tfRo8/CQTj91oNUm+5Heus5/a4ECdmWaSCHCS/hXTsU3PTTHAY67oAQR8wBLFPfp3mMvXjB+L2A==", "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1575,13 +1636,14 @@ } }, "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.821.0.tgz", - "integrity": "sha512-efmaifbhBoqKG3bAoEfDdcM8hn1psF+4qa7ykWuYmfmah59JBeqHLfz5W9m9JoTwoKPkFcVLWZxnyZzAnVBOIg==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.901.0.tgz", + "integrity": "sha512-Wd2t8qa/4OL0v/oDpCHHYkgsXJr8/ttCxrvCKAt0H1zZe2LlRhY9gpDVKqdertfHrHDj786fOvEQA28G1L75Dg==", "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@aws/lambda-invoke-store": "^0.0.1", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1589,16 +1651,16 @@ } }, "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.839.0.tgz", - "integrity": "sha512-2u74uRM1JWq6Sf7+3YpjejPM9YkomGt4kWhrmooIBEq1k5r2GTbkH7pNCxBQwBueXM21jAGVDxxeClpTx+5hig==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.901.0.tgz", + "integrity": "sha512-Zby4F03fvD9xAgXGPywyk4bC1jCbnyubMEYChLYohD+x20ULQCf+AimF/Btn7YL+hBpzh1+RmqmvZcx+RgwgNQ==", "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@smithy/core": "^3.6.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@smithy/core": "^3.14.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1606,47 +1668,47 @@ } }, "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/nested-clients": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.839.0.tgz", - "integrity": "sha512-Glic0pg2THYP3aRhJORwJJBe1JLtJoEdWV/MFZNyzCklfMwEzpWtZAyxy+tQyFmMeW50uBAnh2R0jhMMcf257w==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.901.0.tgz", + "integrity": "sha512-feAAAMsVwctk2Tms40ONybvpfJPLCmSdI+G+OTrNpizkGLNl6ik2Ng2RzxY6UqOfN8abqKP/DOUj1qYDRDG8ag==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/middleware-host-header": "3.821.0", - "@aws-sdk/middleware-logger": "3.821.0", - "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/region-config-resolver": "3.821.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.839.0", - "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.6.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/hash-node": "^4.0.4", - "@smithy/invalid-dependency": "^4.0.4", - "@smithy/middleware-content-length": "^4.0.4", - "@smithy/middleware-endpoint": "^4.1.13", - "@smithy/middleware-retry": "^4.1.14", - "@smithy/middleware-serde": "^4.0.8", - "@smithy/middleware-stack": "^4.0.4", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/url-parser": "^4.0.4", - "@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.21", - "@smithy/util-defaults-mode-node": "^4.0.21", - "@smithy/util-endpoints": "^3.0.6", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.6", - "@smithy/util-utf8": "^4.0.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/middleware-host-header": "3.901.0", + "@aws-sdk/middleware-logger": "3.901.0", + "@aws-sdk/middleware-recursion-detection": "3.901.0", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/region-config-resolver": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@aws-sdk/util-user-agent-browser": "3.901.0", + "@aws-sdk/util-user-agent-node": "3.901.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.14.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/hash-node": "^4.2.0", + "@smithy/invalid-dependency": "^4.2.0", + "@smithy/middleware-content-length": "^4.2.0", + "@smithy/middleware-endpoint": "^4.3.0", + "@smithy/middleware-retry": "^4.4.0", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.0", + "@smithy/util-defaults-mode-browser": "^4.2.0", + "@smithy/util-defaults-mode-node": "^4.2.0", + "@smithy/util-endpoints": "^3.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -1654,15 +1716,32 @@ } }, "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.821.0.tgz", - "integrity": "sha512-t8og+lRCIIy5nlId0bScNpCkif8sc0LhmtaKsbm0ZPm3sCa/WhCbSZibjbZ28FNjVCV+p0D9RYZx0VDDbtWyjw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.901.0.tgz", + "integrity": "sha512-7F0N888qVLHo4CSQOsnkZ4QAp8uHLKJ4v3u09Ly5k4AEStrSlFpckTPyUx6elwGL+fxGjNE2aakK8vEgzzCV0A==", "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/types": "^4.3.1", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", + "@aws-sdk/types": "3.901.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/token-providers": { + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.901.0.tgz", + "integrity": "sha512-pJEr1Ggbc/uVTDqp9IbNu9hdr0eQf3yZix3s4Nnyvmg4xmJSGAlbPC9LrNr5u3CDZoc8Z9CuLrvbP4MwYquNpQ==", + "dependencies": { + "@aws-sdk/core": "3.901.0", + "@aws-sdk/nested-clients": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1670,25 +1749,25 @@ } }, "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.821.0.tgz", - "integrity": "sha512-irWZHyM0Jr1xhC+38OuZ7JB6OXMLPZlj48thElpsO1ZSLRkLZx5+I7VV6k3sp2yZ7BYbKz/G2ojSv4wdm7XTLw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.901.0.tgz", + "integrity": "sha512-Ntb6V/WFI21Ed4PDgL/8NSfoZQQf9xzrwNgiwvnxgAl/KvAvRBgQtqj5gHsDX8Nj2YmJuVoHfH9BGjL9VQ4WNg==", "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.839.0.tgz", - "integrity": "sha512-MuunkIG1bJVMtTH7MbjXOrhHleU5wjHz5eCAUc6vj7M9rwol71nqjj9b8RLnkO5gsJcKc29Qk8iV6xQuzKWNMw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.901.0.tgz", + "integrity": "sha512-l59KQP5TY7vPVUfEURc7P5BJKuNg1RSsAKBQW7LHLECXjLqDUbo2SMLrexLBEoArSt6E8QOrIN0C8z/0Xk0jYw==", "dependencies": { - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/types": "^4.3.1", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1703,37 +1782,10 @@ } } }, - "node_modules/@aws-sdk/client-s3/node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@smithy/node-http-handler": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", - "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", - "dependencies": { - "@smithy/abort-controller": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@aws-sdk/client-s3/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -1741,18 +1793,6 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-s3/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/@aws-sdk/client-sso": { "version": "3.731.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.731.0.tgz", @@ -1802,48 +1842,48 @@ } }, "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.839.0.tgz", - "integrity": "sha512-7QnMApYfQBT441YkxObxt1hZ8TdqZH7h0NdYsvbLdEqGROXBDDT+Wq7ZVfsnKjuVUGQ/t75bIqFn7M8cdyESfA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.901.0.tgz", + "integrity": "sha512-b2BJ8WU7hIDkUsaNYK/VX/gTYV9ywN2SXddPcuHvvX8wxb9bfqBz1vNE+30oDh6/SLEjJt8gAVYQGlxpoAGa8g==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/credential-provider-node": "3.839.0", - "@aws-sdk/middleware-host-header": "3.821.0", - "@aws-sdk/middleware-logger": "3.821.0", - "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/region-config-resolver": "3.821.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.839.0", - "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.6.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/hash-node": "^4.0.4", - "@smithy/invalid-dependency": "^4.0.4", - "@smithy/middleware-content-length": "^4.0.4", - "@smithy/middleware-endpoint": "^4.1.13", - "@smithy/middleware-retry": "^4.1.14", - "@smithy/middleware-serde": "^4.0.8", - "@smithy/middleware-stack": "^4.0.4", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/url-parser": "^4.0.4", - "@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.21", - "@smithy/util-defaults-mode-node": "^4.0.21", - "@smithy/util-endpoints": "^3.0.6", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.6", - "@smithy/util-utf8": "^4.0.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/credential-provider-node": "3.901.0", + "@aws-sdk/middleware-host-header": "3.901.0", + "@aws-sdk/middleware-logger": "3.901.0", + "@aws-sdk/middleware-recursion-detection": "3.901.0", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/region-config-resolver": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@aws-sdk/util-user-agent-browser": "3.901.0", + "@aws-sdk/util-user-agent-node": "3.901.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.14.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/hash-node": "^4.2.0", + "@smithy/invalid-dependency": "^4.2.0", + "@smithy/middleware-content-length": "^4.2.0", + "@smithy/middleware-endpoint": "^4.3.0", + "@smithy/middleware-retry": "^4.4.0", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.0", + "@smithy/util-defaults-mode-browser": "^4.2.0", + "@smithy/util-defaults-mode-node": "^4.2.0", + "@smithy/util-endpoints": "^3.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -1851,47 +1891,47 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/client-sso": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.839.0.tgz", - "integrity": "sha512-AZABysUhbfcwXVlMo97/vwHgsfJNF81wypCAowpqAJkSjP2KrqsqHpb71/RoR2w8JGmEnBBXRD4wIxDhnmifWg==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.901.0.tgz", + "integrity": "sha512-sGyDjjkJ7ppaE+bAKL/Q5IvVCxtoyBIzN+7+hWTS/mUxWJ9EOq9238IqmVIIK6sYNIzEf9yhobfMARasPYVTNg==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/middleware-host-header": "3.821.0", - "@aws-sdk/middleware-logger": "3.821.0", - "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/region-config-resolver": "3.821.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.839.0", - "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.6.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/hash-node": "^4.0.4", - "@smithy/invalid-dependency": "^4.0.4", - "@smithy/middleware-content-length": "^4.0.4", - "@smithy/middleware-endpoint": "^4.1.13", - "@smithy/middleware-retry": "^4.1.14", - "@smithy/middleware-serde": "^4.0.8", - "@smithy/middleware-stack": "^4.0.4", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/url-parser": "^4.0.4", - "@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.21", - "@smithy/util-defaults-mode-node": "^4.0.21", - "@smithy/util-endpoints": "^3.0.6", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.6", - "@smithy/util-utf8": "^4.0.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/middleware-host-header": "3.901.0", + "@aws-sdk/middleware-logger": "3.901.0", + "@aws-sdk/middleware-recursion-detection": "3.901.0", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/region-config-resolver": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@aws-sdk/util-user-agent-browser": "3.901.0", + "@aws-sdk/util-user-agent-node": "3.901.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.14.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/hash-node": "^4.2.0", + "@smithy/invalid-dependency": "^4.2.0", + "@smithy/middleware-content-length": "^4.2.0", + "@smithy/middleware-endpoint": "^4.3.0", + "@smithy/middleware-retry": "^4.4.0", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.0", + "@smithy/util-defaults-mode-browser": "^4.2.0", + "@smithy/util-defaults-mode-node": "^4.2.0", + "@smithy/util-endpoints": "^3.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -1899,24 +1939,22 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/core": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.839.0.tgz", - "integrity": "sha512-KdwL5RaK7eUIlOpdOoZ5u+2t4X1rdX/MTZgz3IV/aBzjVUoGsp+uUnbyqXomLQSUitPHp72EE/NHDsvWW/IHvQ==", - "dependencies": { - "@aws-sdk/types": "3.821.0", - "@aws-sdk/xml-builder": "3.821.0", - "@smithy/core": "^3.6.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/property-provider": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/signature-v4": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-utf8": "^4.0.0", - "fast-xml-parser": "4.4.1", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.901.0.tgz", + "integrity": "sha512-brKAc3y64tdhyuEf+OPIUln86bRTqkLgb9xkd6kUdIeA5+qmp/N6amItQz+RN4k4O3kqkCPYnAd3LonTKluobw==", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@aws-sdk/xml-builder": "3.901.0", + "@smithy/core": "^3.14.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/signature-v4": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -1924,14 +1962,14 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.839.0.tgz", - "integrity": "sha512-cWTadewPPz1OvObZJB+olrgh8VwcgIVcT293ZUT9V0CMF0UU7QaPwJP7uNXcNxltTh+sk1yhjH4UlcnJigZZbA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.901.0.tgz", + "integrity": "sha512-5hAdVl3tBuARh3zX5MLJ1P/d+Kr5kXtDU3xm1pxUEF4xt2XkEEpwiX5fbkNkz2rbh3BCt2gOHsAbh6b3M7n+DA==", "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1939,19 +1977,19 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.839.0.tgz", - "integrity": "sha512-fv0BZwrDhWDju4D1MCLT4I2aPjr0dVQ6P+MpqvcGNOA41Oa9UdRhYTV5iuy5NLXzIzoCmnS+XfSq5Kbsf6//xw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.901.0.tgz", + "integrity": "sha512-Ggr7+0M6QZEsrqRkK7iyJLf4LkIAacAxHz9c4dm9hnDdU7vqrlJm6g73IxMJXWN1bIV7IxfpzB11DsRrB/oNjQ==", "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/property-provider": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/util-stream": "^4.2.2", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/util-stream": "^4.4.0", "tslib": "^2.6.2" }, "engines": { @@ -1959,22 +1997,22 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.839.0.tgz", - "integrity": "sha512-GHm0hF4CiDxIDR7TauMaA6iI55uuSqRxMBcqTAHaTPm6+h1A+MS+ysQMxZ+Jvwtoy8WmfTIGrJVxSCw0sK2hvA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.901.0.tgz", + "integrity": "sha512-zxadcDS0hNJgv8n4hFYJNOXyfjaNE1vvqIiF/JzZSQpSSYXzCd+WxXef5bQh+W3giDtRUmkvP5JLbamEFjZKyw==", "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/credential-provider-env": "3.839.0", - "@aws-sdk/credential-provider-http": "3.839.0", - "@aws-sdk/credential-provider-process": "3.839.0", - "@aws-sdk/credential-provider-sso": "3.839.0", - "@aws-sdk/credential-provider-web-identity": "3.839.0", - "@aws-sdk/nested-clients": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/credential-provider-imds": "^4.0.6", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/credential-provider-env": "3.901.0", + "@aws-sdk/credential-provider-http": "3.901.0", + "@aws-sdk/credential-provider-process": "3.901.0", + "@aws-sdk/credential-provider-sso": "3.901.0", + "@aws-sdk/credential-provider-web-identity": "3.901.0", + "@aws-sdk/nested-clients": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/credential-provider-imds": "^4.2.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -1982,21 +2020,21 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.839.0.tgz", - "integrity": "sha512-7bR+U2h+ft0V8chyeu9Bh/pvau4ZkQMeRt5f0dAULoepZQ77QQVRP4H04yJPTg9DCtqbVULQ3uf5YOp1/08vQw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.901.0.tgz", + "integrity": "sha512-dPuFzMF7L1s/lQyT3wDxqLe82PyTH+5o1jdfseTEln64LJMl0ZMWaKX/C1UFNDxaTd35Cgt1bDbjjAWHMiKSFQ==", "dependencies": { - "@aws-sdk/credential-provider-env": "3.839.0", - "@aws-sdk/credential-provider-http": "3.839.0", - "@aws-sdk/credential-provider-ini": "3.839.0", - "@aws-sdk/credential-provider-process": "3.839.0", - "@aws-sdk/credential-provider-sso": "3.839.0", - "@aws-sdk/credential-provider-web-identity": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/credential-provider-imds": "^4.0.6", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/credential-provider-env": "3.901.0", + "@aws-sdk/credential-provider-http": "3.901.0", + "@aws-sdk/credential-provider-ini": "3.901.0", + "@aws-sdk/credential-provider-process": "3.901.0", + "@aws-sdk/credential-provider-sso": "3.901.0", + "@aws-sdk/credential-provider-web-identity": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/credential-provider-imds": "^4.2.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2004,15 +2042,15 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.839.0.tgz", - "integrity": "sha512-qShpekjociUZ+isyQNa0P7jo+0q3N2+0eJDg8SGyP6K6hHTcGfiqxTDps+IKl6NreCPhZCBzyI9mWkP0xSDR6g==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.901.0.tgz", + "integrity": "sha512-/IWgmgM3Cl1wTdJA5HqKMAojxLkYchh5kDuphApxKhupLu6Pu0JBOHU8A5GGeFvOycyaVwosod6zDduINZxe+A==", "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2020,17 +2058,17 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.839.0.tgz", - "integrity": "sha512-w10zBLHhU8SBQcdrSPMI02haLoRGZg+gP7mH/Er8VhIXfHefbr7o4NirmB0hwdw/YAH8MLlC9jj7c2SJlsNhYA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.901.0.tgz", + "integrity": "sha512-SjmqZQHmqFSET7+6xcZgtH7yEyh5q53LN87GqwYlJZ6KJ5oNw11acUNEhUOL1xTSJEvaWqwTIkS2zqrzLcM9bw==", "dependencies": { - "@aws-sdk/client-sso": "3.839.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/token-providers": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/client-sso": "3.901.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/token-providers": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2038,15 +2076,16 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.839.0.tgz", - "integrity": "sha512-EvqTc7J1kgmiuxknpCp1S60hyMQvmKxsI5uXzQtcogl/N55rxiXEqnCLI5q6p33q91PJegrcMCM5Q17Afhm5qA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.901.0.tgz", + "integrity": "sha512-NYjy/6NLxH9m01+pfpB4ql8QgAorJcu8tw69kzHwUd/ql6wUDTbC7HcXqtKlIwWjzjgj2BKL7j6SyFapgCuafA==", "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/nested-clients": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/nested-clients": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2054,13 +2093,13 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.821.0.tgz", - "integrity": "sha512-xSMR+sopSeWGx5/4pAGhhfMvGBHioVBbqGvDs6pG64xfNwM5vq5s5v6D04e2i+uSTj4qGa71dLUs5I0UzAK3sw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.901.0.tgz", + "integrity": "sha512-yWX7GvRmqBtbNnUW7qbre3GvZmyYwU0WHefpZzDTYDoNgatuYq6LgUIQ+z5C04/kCRoFkAFrHag8a3BXqFzq5A==", "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2068,12 +2107,12 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-logger": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.821.0.tgz", - "integrity": "sha512-0cvI0ipf2tGx7fXYEEN5fBeZDz2RnHyb9xftSgUsEq7NBxjV0yTZfLJw6Za5rjE6snC80dRN8+bTNR1tuG89zA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.901.0.tgz", + "integrity": "sha512-UoHebjE7el/tfRo8/CQTj91oNUm+5Heus5/a4ECdmWaSCHCS/hXTsU3PTTHAY67oAQR8wBLFPfp3mMvXjB+L2A==", "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2081,13 +2120,14 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.821.0.tgz", - "integrity": "sha512-efmaifbhBoqKG3bAoEfDdcM8hn1psF+4qa7ykWuYmfmah59JBeqHLfz5W9m9JoTwoKPkFcVLWZxnyZzAnVBOIg==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.901.0.tgz", + "integrity": "sha512-Wd2t8qa/4OL0v/oDpCHHYkgsXJr8/ttCxrvCKAt0H1zZe2LlRhY9gpDVKqdertfHrHDj786fOvEQA28G1L75Dg==", "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@aws/lambda-invoke-store": "^0.0.1", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2095,16 +2135,16 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.839.0.tgz", - "integrity": "sha512-2u74uRM1JWq6Sf7+3YpjejPM9YkomGt4kWhrmooIBEq1k5r2GTbkH7pNCxBQwBueXM21jAGVDxxeClpTx+5hig==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.901.0.tgz", + "integrity": "sha512-Zby4F03fvD9xAgXGPywyk4bC1jCbnyubMEYChLYohD+x20ULQCf+AimF/Btn7YL+hBpzh1+RmqmvZcx+RgwgNQ==", "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@smithy/core": "^3.6.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@smithy/core": "^3.14.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2112,47 +2152,47 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/nested-clients": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.839.0.tgz", - "integrity": "sha512-Glic0pg2THYP3aRhJORwJJBe1JLtJoEdWV/MFZNyzCklfMwEzpWtZAyxy+tQyFmMeW50uBAnh2R0jhMMcf257w==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.901.0.tgz", + "integrity": "sha512-feAAAMsVwctk2Tms40ONybvpfJPLCmSdI+G+OTrNpizkGLNl6ik2Ng2RzxY6UqOfN8abqKP/DOUj1qYDRDG8ag==", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/middleware-host-header": "3.821.0", - "@aws-sdk/middleware-logger": "3.821.0", - "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/region-config-resolver": "3.821.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.839.0", - "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.6.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/hash-node": "^4.0.4", - "@smithy/invalid-dependency": "^4.0.4", - "@smithy/middleware-content-length": "^4.0.4", - "@smithy/middleware-endpoint": "^4.1.13", - "@smithy/middleware-retry": "^4.1.14", - "@smithy/middleware-serde": "^4.0.8", - "@smithy/middleware-stack": "^4.0.4", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/url-parser": "^4.0.4", - "@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.21", - "@smithy/util-defaults-mode-node": "^4.0.21", - "@smithy/util-endpoints": "^3.0.6", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.6", - "@smithy/util-utf8": "^4.0.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/middleware-host-header": "3.901.0", + "@aws-sdk/middleware-logger": "3.901.0", + "@aws-sdk/middleware-recursion-detection": "3.901.0", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/region-config-resolver": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@aws-sdk/util-user-agent-browser": "3.901.0", + "@aws-sdk/util-user-agent-node": "3.901.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.14.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/hash-node": "^4.2.0", + "@smithy/invalid-dependency": "^4.2.0", + "@smithy/middleware-content-length": "^4.2.0", + "@smithy/middleware-endpoint": "^4.3.0", + "@smithy/middleware-retry": "^4.4.0", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.0", + "@smithy/util-defaults-mode-browser": "^4.2.0", + "@smithy/util-defaults-mode-node": "^4.2.0", + "@smithy/util-endpoints": "^3.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -2160,15 +2200,32 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.821.0.tgz", - "integrity": "sha512-t8og+lRCIIy5nlId0bScNpCkif8sc0LhmtaKsbm0ZPm3sCa/WhCbSZibjbZ28FNjVCV+p0D9RYZx0VDDbtWyjw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.901.0.tgz", + "integrity": "sha512-7F0N888qVLHo4CSQOsnkZ4QAp8uHLKJ4v3u09Ly5k4AEStrSlFpckTPyUx6elwGL+fxGjNE2aakK8vEgzzCV0A==", "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/types": "^4.3.1", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", + "@aws-sdk/types": "3.901.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/token-providers": { + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.901.0.tgz", + "integrity": "sha512-pJEr1Ggbc/uVTDqp9IbNu9hdr0eQf3yZix3s4Nnyvmg4xmJSGAlbPC9LrNr5u3CDZoc8Z9CuLrvbP4MwYquNpQ==", + "dependencies": { + "@aws-sdk/core": "3.901.0", + "@aws-sdk/nested-clients": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2176,25 +2233,25 @@ } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.821.0.tgz", - "integrity": "sha512-irWZHyM0Jr1xhC+38OuZ7JB6OXMLPZlj48thElpsO1ZSLRkLZx5+I7VV6k3sp2yZ7BYbKz/G2ojSv4wdm7XTLw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.901.0.tgz", + "integrity": "sha512-Ntb6V/WFI21Ed4PDgL/8NSfoZQQf9xzrwNgiwvnxgAl/KvAvRBgQtqj5gHsDX8Nj2YmJuVoHfH9BGjL9VQ4WNg==", "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.839.0.tgz", - "integrity": "sha512-MuunkIG1bJVMtTH7MbjXOrhHleU5wjHz5eCAUc6vj7M9rwol71nqjj9b8RLnkO5gsJcKc29Qk8iV6xQuzKWNMw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.901.0.tgz", + "integrity": "sha512-l59KQP5TY7vPVUfEURc7P5BJKuNg1RSsAKBQW7LHLECXjLqDUbo2SMLrexLBEoArSt6E8QOrIN0C8z/0Xk0jYw==", "dependencies": { - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/types": "^4.3.1", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2209,37 +2266,10 @@ } } }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/node-http-handler": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", - "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", - "dependencies": { - "@smithy/abort-controller": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -2273,44 +2303,6 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/node-http-handler": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", - "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", - "dependencies": { - "@smithy/abort-controller": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@aws-sdk/core": { "version": "3.731.0", "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.731.0.tgz", @@ -2345,15 +2337,15 @@ } }, "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.839.0.tgz", - "integrity": "sha512-dXJsdSEVzG+8nIihqVnWzyW8Dc41kNKZEXYguHDb+VM/cIjRSVkaw9jXc+KAvbwcGkEB7BfAuW9VMjxpTR5eAA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.901.0.tgz", + "integrity": "sha512-irVFwiiEC+JRFQTZwI7264LOGXRjqdp3AvmqiEmmZS0+sJsEaF65prCs+nzw6J1WqQ6IZKClKKQsH7x8FfOPrQ==", "dev": true, "dependencies": { - "@aws-sdk/client-cognito-identity": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/client-cognito-identity": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2361,9 +2353,9 @@ } }, "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dev": true, "dependencies": { "tslib": "^2.6.2" @@ -2431,44 +2423,6 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", - "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", - "dependencies": { - "@smithy/abort-controller": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@aws-sdk/credential-provider-ini": { "version": "3.731.1", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.731.1.tgz", @@ -2584,22 +2538,6 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { - "version": "3.731.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.731.1.tgz", - "integrity": "sha512-t34GOPwBZsX7zGHjiTXmMHGY3kHM7fLiQ60Jqk0On9P0ASHTDE5U75RgCXboE3u+qEv9wyKyaqMNyMWj9qQlFg==", - "dependencies": { - "@aws-sdk/nested-clients": "3.731.1", - "@aws-sdk/types": "3.731.0", - "@smithy/property-provider": "^4.0.0", - "@smithy/shared-ini-file-loader": "^4.0.0", - "@smithy/types": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/types": { "version": "3.731.0", "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.731.0.tgz", @@ -2641,29 +2579,29 @@ } }, "node_modules/@aws-sdk/credential-providers": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.839.0.tgz", - "integrity": "sha512-hiM7vY2qYAdNT87+Qd3vvfNA+bqhtecsPIduIxkhwispEs9NGcQYtOaG3KQRcHkJBb4kaMYpudVNMXeYUYi2Aw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.901.0.tgz", + "integrity": "sha512-jaJ+sVF9xuBwYiQznjrbDkw2W8/aQijGGdzroDL1mJfwyZA0hj3zfYUion+iWwjYhb0vS0bAyrIHtjtTfA2Qpw==", "dev": true, "dependencies": { - "@aws-sdk/client-cognito-identity": "3.839.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/credential-provider-cognito-identity": "3.839.0", - "@aws-sdk/credential-provider-env": "3.839.0", - "@aws-sdk/credential-provider-http": "3.839.0", - "@aws-sdk/credential-provider-ini": "3.839.0", - "@aws-sdk/credential-provider-node": "3.839.0", - "@aws-sdk/credential-provider-process": "3.839.0", - "@aws-sdk/credential-provider-sso": "3.839.0", - "@aws-sdk/credential-provider-web-identity": "3.839.0", - "@aws-sdk/nested-clients": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.6.0", - "@smithy/credential-provider-imds": "^4.0.6", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/property-provider": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/client-cognito-identity": "3.901.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/credential-provider-cognito-identity": "3.901.0", + "@aws-sdk/credential-provider-env": "3.901.0", + "@aws-sdk/credential-provider-http": "3.901.0", + "@aws-sdk/credential-provider-ini": "3.901.0", + "@aws-sdk/credential-provider-node": "3.901.0", + "@aws-sdk/credential-provider-process": "3.901.0", + "@aws-sdk/credential-provider-sso": "3.901.0", + "@aws-sdk/credential-provider-web-identity": "3.901.0", + "@aws-sdk/nested-clients": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.14.0", + "@smithy/credential-provider-imds": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2671,48 +2609,48 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/client-sso": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.839.0.tgz", - "integrity": "sha512-AZABysUhbfcwXVlMo97/vwHgsfJNF81wypCAowpqAJkSjP2KrqsqHpb71/RoR2w8JGmEnBBXRD4wIxDhnmifWg==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.901.0.tgz", + "integrity": "sha512-sGyDjjkJ7ppaE+bAKL/Q5IvVCxtoyBIzN+7+hWTS/mUxWJ9EOq9238IqmVIIK6sYNIzEf9yhobfMARasPYVTNg==", "dev": true, "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/middleware-host-header": "3.821.0", - "@aws-sdk/middleware-logger": "3.821.0", - "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/region-config-resolver": "3.821.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.839.0", - "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.6.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/hash-node": "^4.0.4", - "@smithy/invalid-dependency": "^4.0.4", - "@smithy/middleware-content-length": "^4.0.4", - "@smithy/middleware-endpoint": "^4.1.13", - "@smithy/middleware-retry": "^4.1.14", - "@smithy/middleware-serde": "^4.0.8", - "@smithy/middleware-stack": "^4.0.4", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/url-parser": "^4.0.4", - "@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.21", - "@smithy/util-defaults-mode-node": "^4.0.21", - "@smithy/util-endpoints": "^3.0.6", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.6", - "@smithy/util-utf8": "^4.0.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/middleware-host-header": "3.901.0", + "@aws-sdk/middleware-logger": "3.901.0", + "@aws-sdk/middleware-recursion-detection": "3.901.0", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/region-config-resolver": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@aws-sdk/util-user-agent-browser": "3.901.0", + "@aws-sdk/util-user-agent-node": "3.901.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.14.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/hash-node": "^4.2.0", + "@smithy/invalid-dependency": "^4.2.0", + "@smithy/middleware-content-length": "^4.2.0", + "@smithy/middleware-endpoint": "^4.3.0", + "@smithy/middleware-retry": "^4.4.0", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.0", + "@smithy/util-defaults-mode-browser": "^4.2.0", + "@smithy/util-defaults-mode-node": "^4.2.0", + "@smithy/util-endpoints": "^3.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -2720,25 +2658,23 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/core": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.839.0.tgz", - "integrity": "sha512-KdwL5RaK7eUIlOpdOoZ5u+2t4X1rdX/MTZgz3IV/aBzjVUoGsp+uUnbyqXomLQSUitPHp72EE/NHDsvWW/IHvQ==", - "dev": true, - "dependencies": { - "@aws-sdk/types": "3.821.0", - "@aws-sdk/xml-builder": "3.821.0", - "@smithy/core": "^3.6.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/property-provider": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/signature-v4": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-utf8": "^4.0.0", - "fast-xml-parser": "4.4.1", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.901.0.tgz", + "integrity": "sha512-brKAc3y64tdhyuEf+OPIUln86bRTqkLgb9xkd6kUdIeA5+qmp/N6amItQz+RN4k4O3kqkCPYnAd3LonTKluobw==", + "dev": true, + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@aws-sdk/xml-builder": "3.901.0", + "@smithy/core": "^3.14.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/signature-v4": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -2746,15 +2682,15 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.839.0.tgz", - "integrity": "sha512-cWTadewPPz1OvObZJB+olrgh8VwcgIVcT293ZUT9V0CMF0UU7QaPwJP7uNXcNxltTh+sk1yhjH4UlcnJigZZbA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.901.0.tgz", + "integrity": "sha512-5hAdVl3tBuARh3zX5MLJ1P/d+Kr5kXtDU3xm1pxUEF4xt2XkEEpwiX5fbkNkz2rbh3BCt2gOHsAbh6b3M7n+DA==", "dev": true, "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2762,20 +2698,20 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.839.0.tgz", - "integrity": "sha512-fv0BZwrDhWDju4D1MCLT4I2aPjr0dVQ6P+MpqvcGNOA41Oa9UdRhYTV5iuy5NLXzIzoCmnS+XfSq5Kbsf6//xw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.901.0.tgz", + "integrity": "sha512-Ggr7+0M6QZEsrqRkK7iyJLf4LkIAacAxHz9c4dm9hnDdU7vqrlJm6g73IxMJXWN1bIV7IxfpzB11DsRrB/oNjQ==", "dev": true, "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/property-provider": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/util-stream": "^4.2.2", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/util-stream": "^4.4.0", "tslib": "^2.6.2" }, "engines": { @@ -2783,23 +2719,23 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.839.0.tgz", - "integrity": "sha512-GHm0hF4CiDxIDR7TauMaA6iI55uuSqRxMBcqTAHaTPm6+h1A+MS+ysQMxZ+Jvwtoy8WmfTIGrJVxSCw0sK2hvA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.901.0.tgz", + "integrity": "sha512-zxadcDS0hNJgv8n4hFYJNOXyfjaNE1vvqIiF/JzZSQpSSYXzCd+WxXef5bQh+W3giDtRUmkvP5JLbamEFjZKyw==", "dev": true, "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/credential-provider-env": "3.839.0", - "@aws-sdk/credential-provider-http": "3.839.0", - "@aws-sdk/credential-provider-process": "3.839.0", - "@aws-sdk/credential-provider-sso": "3.839.0", - "@aws-sdk/credential-provider-web-identity": "3.839.0", - "@aws-sdk/nested-clients": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/credential-provider-imds": "^4.0.6", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/credential-provider-env": "3.901.0", + "@aws-sdk/credential-provider-http": "3.901.0", + "@aws-sdk/credential-provider-process": "3.901.0", + "@aws-sdk/credential-provider-sso": "3.901.0", + "@aws-sdk/credential-provider-web-identity": "3.901.0", + "@aws-sdk/nested-clients": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/credential-provider-imds": "^4.2.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2807,22 +2743,22 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.839.0.tgz", - "integrity": "sha512-7bR+U2h+ft0V8chyeu9Bh/pvau4ZkQMeRt5f0dAULoepZQ77QQVRP4H04yJPTg9DCtqbVULQ3uf5YOp1/08vQw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.901.0.tgz", + "integrity": "sha512-dPuFzMF7L1s/lQyT3wDxqLe82PyTH+5o1jdfseTEln64LJMl0ZMWaKX/C1UFNDxaTd35Cgt1bDbjjAWHMiKSFQ==", "dev": true, "dependencies": { - "@aws-sdk/credential-provider-env": "3.839.0", - "@aws-sdk/credential-provider-http": "3.839.0", - "@aws-sdk/credential-provider-ini": "3.839.0", - "@aws-sdk/credential-provider-process": "3.839.0", - "@aws-sdk/credential-provider-sso": "3.839.0", - "@aws-sdk/credential-provider-web-identity": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/credential-provider-imds": "^4.0.6", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/credential-provider-env": "3.901.0", + "@aws-sdk/credential-provider-http": "3.901.0", + "@aws-sdk/credential-provider-ini": "3.901.0", + "@aws-sdk/credential-provider-process": "3.901.0", + "@aws-sdk/credential-provider-sso": "3.901.0", + "@aws-sdk/credential-provider-web-identity": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/credential-provider-imds": "^4.2.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2830,16 +2766,16 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.839.0.tgz", - "integrity": "sha512-qShpekjociUZ+isyQNa0P7jo+0q3N2+0eJDg8SGyP6K6hHTcGfiqxTDps+IKl6NreCPhZCBzyI9mWkP0xSDR6g==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.901.0.tgz", + "integrity": "sha512-/IWgmgM3Cl1wTdJA5HqKMAojxLkYchh5kDuphApxKhupLu6Pu0JBOHU8A5GGeFvOycyaVwosod6zDduINZxe+A==", "dev": true, "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2847,18 +2783,18 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.839.0.tgz", - "integrity": "sha512-w10zBLHhU8SBQcdrSPMI02haLoRGZg+gP7mH/Er8VhIXfHefbr7o4NirmB0hwdw/YAH8MLlC9jj7c2SJlsNhYA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.901.0.tgz", + "integrity": "sha512-SjmqZQHmqFSET7+6xcZgtH7yEyh5q53LN87GqwYlJZ6KJ5oNw11acUNEhUOL1xTSJEvaWqwTIkS2zqrzLcM9bw==", "dev": true, "dependencies": { - "@aws-sdk/client-sso": "3.839.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/token-providers": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/client-sso": "3.901.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/token-providers": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2866,16 +2802,17 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.839.0.tgz", - "integrity": "sha512-EvqTc7J1kgmiuxknpCp1S60hyMQvmKxsI5uXzQtcogl/N55rxiXEqnCLI5q6p33q91PJegrcMCM5Q17Afhm5qA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.901.0.tgz", + "integrity": "sha512-NYjy/6NLxH9m01+pfpB4ql8QgAorJcu8tw69kzHwUd/ql6wUDTbC7HcXqtKlIwWjzjgj2BKL7j6SyFapgCuafA==", "dev": true, "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/nested-clients": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/nested-clients": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2883,14 +2820,14 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.821.0.tgz", - "integrity": "sha512-xSMR+sopSeWGx5/4pAGhhfMvGBHioVBbqGvDs6pG64xfNwM5vq5s5v6D04e2i+uSTj4qGa71dLUs5I0UzAK3sw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.901.0.tgz", + "integrity": "sha512-yWX7GvRmqBtbNnUW7qbre3GvZmyYwU0WHefpZzDTYDoNgatuYq6LgUIQ+z5C04/kCRoFkAFrHag8a3BXqFzq5A==", "dev": true, "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2898,13 +2835,13 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/middleware-logger": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.821.0.tgz", - "integrity": "sha512-0cvI0ipf2tGx7fXYEEN5fBeZDz2RnHyb9xftSgUsEq7NBxjV0yTZfLJw6Za5rjE6snC80dRN8+bTNR1tuG89zA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.901.0.tgz", + "integrity": "sha512-UoHebjE7el/tfRo8/CQTj91oNUm+5Heus5/a4ECdmWaSCHCS/hXTsU3PTTHAY67oAQR8wBLFPfp3mMvXjB+L2A==", "dev": true, "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2912,14 +2849,15 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.821.0.tgz", - "integrity": "sha512-efmaifbhBoqKG3bAoEfDdcM8hn1psF+4qa7ykWuYmfmah59JBeqHLfz5W9m9JoTwoKPkFcVLWZxnyZzAnVBOIg==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.901.0.tgz", + "integrity": "sha512-Wd2t8qa/4OL0v/oDpCHHYkgsXJr8/ttCxrvCKAt0H1zZe2LlRhY9gpDVKqdertfHrHDj786fOvEQA28G1L75Dg==", "dev": true, "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@aws/lambda-invoke-store": "^0.0.1", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2927,17 +2865,17 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.839.0.tgz", - "integrity": "sha512-2u74uRM1JWq6Sf7+3YpjejPM9YkomGt4kWhrmooIBEq1k5r2GTbkH7pNCxBQwBueXM21jAGVDxxeClpTx+5hig==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.901.0.tgz", + "integrity": "sha512-Zby4F03fvD9xAgXGPywyk4bC1jCbnyubMEYChLYohD+x20ULQCf+AimF/Btn7YL+hBpzh1+RmqmvZcx+RgwgNQ==", "dev": true, "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@smithy/core": "^3.6.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@smithy/core": "^3.14.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -2945,48 +2883,48 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/nested-clients": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.839.0.tgz", - "integrity": "sha512-Glic0pg2THYP3aRhJORwJJBe1JLtJoEdWV/MFZNyzCklfMwEzpWtZAyxy+tQyFmMeW50uBAnh2R0jhMMcf257w==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.901.0.tgz", + "integrity": "sha512-feAAAMsVwctk2Tms40ONybvpfJPLCmSdI+G+OTrNpizkGLNl6ik2Ng2RzxY6UqOfN8abqKP/DOUj1qYDRDG8ag==", "dev": true, "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/middleware-host-header": "3.821.0", - "@aws-sdk/middleware-logger": "3.821.0", - "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/region-config-resolver": "3.821.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.839.0", - "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.6.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/hash-node": "^4.0.4", - "@smithy/invalid-dependency": "^4.0.4", - "@smithy/middleware-content-length": "^4.0.4", - "@smithy/middleware-endpoint": "^4.1.13", - "@smithy/middleware-retry": "^4.1.14", - "@smithy/middleware-serde": "^4.0.8", - "@smithy/middleware-stack": "^4.0.4", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/url-parser": "^4.0.4", - "@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.21", - "@smithy/util-defaults-mode-node": "^4.0.21", - "@smithy/util-endpoints": "^3.0.6", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.6", - "@smithy/util-utf8": "^4.0.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/middleware-host-header": "3.901.0", + "@aws-sdk/middleware-logger": "3.901.0", + "@aws-sdk/middleware-recursion-detection": "3.901.0", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/region-config-resolver": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@aws-sdk/util-user-agent-browser": "3.901.0", + "@aws-sdk/util-user-agent-node": "3.901.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.14.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/hash-node": "^4.2.0", + "@smithy/invalid-dependency": "^4.2.0", + "@smithy/middleware-content-length": "^4.2.0", + "@smithy/middleware-endpoint": "^4.3.0", + "@smithy/middleware-retry": "^4.4.0", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.0", + "@smithy/util-defaults-mode-browser": "^4.2.0", + "@smithy/util-defaults-mode-node": "^4.2.0", + "@smithy/util-endpoints": "^3.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -2994,16 +2932,34 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.821.0.tgz", - "integrity": "sha512-t8og+lRCIIy5nlId0bScNpCkif8sc0LhmtaKsbm0ZPm3sCa/WhCbSZibjbZ28FNjVCV+p0D9RYZx0VDDbtWyjw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.901.0.tgz", + "integrity": "sha512-7F0N888qVLHo4CSQOsnkZ4QAp8uHLKJ4v3u09Ly5k4AEStrSlFpckTPyUx6elwGL+fxGjNE2aakK8vEgzzCV0A==", "dev": true, "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/types": "^4.3.1", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", + "@aws-sdk/types": "3.901.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/token-providers": { + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.901.0.tgz", + "integrity": "sha512-pJEr1Ggbc/uVTDqp9IbNu9hdr0eQf3yZix3s4Nnyvmg4xmJSGAlbPC9LrNr5u3CDZoc8Z9CuLrvbP4MwYquNpQ==", + "dev": true, + "dependencies": { + "@aws-sdk/core": "3.901.0", + "@aws-sdk/nested-clients": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -3011,27 +2967,27 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.821.0.tgz", - "integrity": "sha512-irWZHyM0Jr1xhC+38OuZ7JB6OXMLPZlj48thElpsO1ZSLRkLZx5+I7VV6k3sp2yZ7BYbKz/G2ojSv4wdm7XTLw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.901.0.tgz", + "integrity": "sha512-Ntb6V/WFI21Ed4PDgL/8NSfoZQQf9xzrwNgiwvnxgAl/KvAvRBgQtqj5gHsDX8Nj2YmJuVoHfH9BGjL9VQ4WNg==", "dev": true, "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.839.0.tgz", - "integrity": "sha512-MuunkIG1bJVMtTH7MbjXOrhHleU5wjHz5eCAUc6vj7M9rwol71nqjj9b8RLnkO5gsJcKc29Qk8iV6xQuzKWNMw==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.901.0.tgz", + "integrity": "sha512-l59KQP5TY7vPVUfEURc7P5BJKuNg1RSsAKBQW7LHLECXjLqDUbo2SMLrexLBEoArSt6E8QOrIN0C8z/0Xk0jYw==", "dev": true, "dependencies": { - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/types": "^4.3.1", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -3046,39 +3002,10 @@ } } }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", - "dev": true, - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/node-http-handler": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", - "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", - "dev": true, - "dependencies": { - "@smithy/abort-controller": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dev": true, "dependencies": { "tslib": "^2.6.2" @@ -3088,16 +3015,16 @@ } }, "node_modules/@aws-sdk/middleware-bucket-endpoint": { - "version": "3.830.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.830.0.tgz", - "integrity": "sha512-ElVeCReZSH5Ds+/pkL5ebneJjuo8f49e9JXV1cYizuH0OAOQfYaBU9+M+7+rn61pTttOFE8W//qKzrXBBJhfMg==", - "dependencies": { - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-arn-parser": "3.804.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", - "@smithy/util-config-provider": "^4.0.0", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.901.0.tgz", + "integrity": "sha512-mPF3N6eZlVs9G8aBSzvtoxR1RZqMo1aIwR+X8BAZSkhfj55fVF2no4IfPXfdFO3I66N+zEQ8nKoB0uTATWrogQ==", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-arn-parser": "3.893.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-config-provider": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -3105,9 +3032,9 @@ } }, "node_modules/@aws-sdk/middleware-bucket-endpoint/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -3116,13 +3043,13 @@ } }, "node_modules/@aws-sdk/middleware-expect-continue": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.821.0.tgz", - "integrity": "sha512-zAOoSZKe1njOrtynvK6ZORU57YGv5I7KP4+rwOvUN3ZhJbQ7QPf8gKtFUCYAPRMegaXCKF/ADPtDZBAmM+zZ9g==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.901.0.tgz", + "integrity": "sha512-bwq9nj6MH38hlJwOY9QXIDwa6lI48UsaZpaXbdD71BljEIRlxDzfB4JaYb+ZNNK7RIAdzsP/K05mJty6KJAQHw==", "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -3130,9 +3057,9 @@ } }, "node_modules/@aws-sdk/middleware-expect-continue/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -3141,22 +3068,22 @@ } }, "node_modules/@aws-sdk/middleware-flexible-checksums": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.839.0.tgz", - "integrity": "sha512-2LEuDUviV3wardiHoHCKx0WUvmiK1gBGmnw12aj5f/KKcWOaqnWI2h1K7nDQC/ZARQ1bbMZZ5kvOv5ueuMg1RA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.901.0.tgz", + "integrity": "sha512-63lcKfggVUFyXhE4SsFXShCTCyh7ZHEqXLyYEL4DwX+VWtxutf9t9m3fF0TNUYDE8eEGWiRXhegj8l4FjuW+wA==", "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/is-array-buffer": "^4.0.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-stream": "^4.2.2", - "@smithy/util-utf8": "^4.0.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/is-array-buffer": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-stream": "^4.4.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -3164,24 +3091,22 @@ } }, "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@aws-sdk/core": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.839.0.tgz", - "integrity": "sha512-KdwL5RaK7eUIlOpdOoZ5u+2t4X1rdX/MTZgz3IV/aBzjVUoGsp+uUnbyqXomLQSUitPHp72EE/NHDsvWW/IHvQ==", - "dependencies": { - "@aws-sdk/types": "3.821.0", - "@aws-sdk/xml-builder": "3.821.0", - "@smithy/core": "^3.6.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/property-provider": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/signature-v4": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-utf8": "^4.0.0", - "fast-xml-parser": "4.4.1", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.901.0.tgz", + "integrity": "sha512-brKAc3y64tdhyuEf+OPIUln86bRTqkLgb9xkd6kUdIeA5+qmp/N6amItQz+RN4k4O3kqkCPYnAd3LonTKluobw==", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@aws-sdk/xml-builder": "3.901.0", + "@smithy/core": "^3.14.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/signature-v4": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -3189,9 +3114,9 @@ } }, "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -3226,12 +3151,12 @@ } }, "node_modules/@aws-sdk/middleware-location-constraint": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.821.0.tgz", - "integrity": "sha512-sKrm80k0t3R0on8aA/WhWFoMaAl4yvdk+riotmMElLUpcMcRXAd1+600uFVrxJqZdbrKQ0mjX0PjT68DlkYXLg==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.901.0.tgz", + "integrity": "sha512-MuCS5R2ngNoYifkVt05CTULvYVWX0dvRT0/Md4jE3a0u0yMygYy31C1zorwfE/SUgAQXyLmUx8ATmPp9PppImQ==", "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -3239,9 +3164,9 @@ } }, "node_modules/@aws-sdk/middleware-location-constraint/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -3301,23 +3226,23 @@ } }, "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.839.0.tgz", - "integrity": "sha512-NwprpzJdkuUnUWxoZwKqAcL1/AsrM1YESVpLeL0pW747Vq6rIiUgkuoyQ1fASV9r5mUoWor7iMu8k5ZCisAh7A==", - "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-arn-parser": "3.804.0", - "@smithy/core": "^3.6.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/protocol-http": "^5.1.2", - "@smithy/signature-v4": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-stream": "^4.2.2", - "@smithy/util-utf8": "^4.0.0", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.901.0.tgz", + "integrity": "sha512-prgjVC3fDT2VIlmQPiw/cLee8r4frTam9GILRUVQyDdNtshNwV3MiaSCLzzQJjKJlLgnBLNUHJCSmvUVtg+3iA==", + "dependencies": { + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-arn-parser": "3.893.0", + "@smithy/core": "^3.14.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/signature-v4": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-stream": "^4.4.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -3325,24 +3250,22 @@ } }, "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@aws-sdk/core": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.839.0.tgz", - "integrity": "sha512-KdwL5RaK7eUIlOpdOoZ5u+2t4X1rdX/MTZgz3IV/aBzjVUoGsp+uUnbyqXomLQSUitPHp72EE/NHDsvWW/IHvQ==", - "dependencies": { - "@aws-sdk/types": "3.821.0", - "@aws-sdk/xml-builder": "3.821.0", - "@smithy/core": "^3.6.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/property-provider": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/signature-v4": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-utf8": "^4.0.0", - "fast-xml-parser": "4.4.1", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.901.0.tgz", + "integrity": "sha512-brKAc3y64tdhyuEf+OPIUln86bRTqkLgb9xkd6kUdIeA5+qmp/N6amItQz+RN4k4O3kqkCPYnAd3LonTKluobw==", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@aws-sdk/xml-builder": "3.901.0", + "@smithy/core": "^3.14.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/signature-v4": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -3350,9 +3273,9 @@ } }, "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -3361,12 +3284,12 @@ } }, "node_modules/@aws-sdk/middleware-ssec": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.821.0.tgz", - "integrity": "sha512-YYi1Hhr2AYiU/24cQc8HIB+SWbQo6FBkMYojVuz/zgrtkFmALxENGF/21OPg7f/QWd+eadZJRxCjmRwh5F2Cxg==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.901.0.tgz", + "integrity": "sha512-YiLLJmA3RvjL38mFLuu8fhTTGWtp2qT24VqpucgfoyziYcTgIQkJJmKi90Xp6R6/3VcArqilyRgM1+x8i/em+Q==", "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/types": "^4.3.1", + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -3374,9 +3297,9 @@ } }, "node_modules/@aws-sdk/middleware-ssec/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -3501,44 +3424,6 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", - "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", - "dependencies": { - "@smithy/abort-controller": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@aws-sdk/region-config-resolver": { "version": "3.731.0", "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.731.0.tgz", @@ -3568,15 +3453,15 @@ } }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.839.0.tgz", - "integrity": "sha512-/O+lh6qXKTMWPcip8ccGL7OgTceUTDmy3wBD22+tPHLeOUSMGUQTZcsmHeDB7vSHLpVY9H6GhOsdes7uQQMUwA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.901.0.tgz", + "integrity": "sha512-2IWxbll/pRucp1WQkHi2W5E2SVPGBvk4Is923H7gpNksbVFws18ItjMM8ZpGm44cJEoy1zR5gjhLFklatpuoOw==", "dependencies": { - "@aws-sdk/middleware-sdk-s3": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/signature-v4": "^5.1.2", - "@smithy/types": "^4.3.1", + "@aws-sdk/middleware-sdk-s3": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/signature-v4": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -3584,9 +3469,9 @@ } }, "node_modules/@aws-sdk/signature-v4-multi-region/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -3595,235 +3480,27 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.839.0.tgz", - "integrity": "sha512-2nlafqdSbet/2WtYIoZ7KEGFowFonPBDYlTjrUvwU2yooE10VhvzhLSCTB2aKIVzo2Z2wL5WGFQsqAY5QwK6Bw==", - "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/nested-clients": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/core": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.839.0.tgz", - "integrity": "sha512-KdwL5RaK7eUIlOpdOoZ5u+2t4X1rdX/MTZgz3IV/aBzjVUoGsp+uUnbyqXomLQSUitPHp72EE/NHDsvWW/IHvQ==", - "dependencies": { - "@aws-sdk/types": "3.821.0", - "@aws-sdk/xml-builder": "3.821.0", - "@smithy/core": "^3.6.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/property-provider": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/signature-v4": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-utf8": "^4.0.0", - "fast-xml-parser": "4.4.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.821.0.tgz", - "integrity": "sha512-xSMR+sopSeWGx5/4pAGhhfMvGBHioVBbqGvDs6pG64xfNwM5vq5s5v6D04e2i+uSTj4qGa71dLUs5I0UzAK3sw==", - "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/middleware-logger": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.821.0.tgz", - "integrity": "sha512-0cvI0ipf2tGx7fXYEEN5fBeZDz2RnHyb9xftSgUsEq7NBxjV0yTZfLJw6Za5rjE6snC80dRN8+bTNR1tuG89zA==", - "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.821.0.tgz", - "integrity": "sha512-efmaifbhBoqKG3bAoEfDdcM8hn1psF+4qa7ykWuYmfmah59JBeqHLfz5W9m9JoTwoKPkFcVLWZxnyZzAnVBOIg==", - "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.839.0.tgz", - "integrity": "sha512-2u74uRM1JWq6Sf7+3YpjejPM9YkomGt4kWhrmooIBEq1k5r2GTbkH7pNCxBQwBueXM21jAGVDxxeClpTx+5hig==", - "dependencies": { - "@aws-sdk/core": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@smithy/core": "^3.6.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/nested-clients": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.839.0.tgz", - "integrity": "sha512-Glic0pg2THYP3aRhJORwJJBe1JLtJoEdWV/MFZNyzCklfMwEzpWtZAyxy+tQyFmMeW50uBAnh2R0jhMMcf257w==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.839.0", - "@aws-sdk/middleware-host-header": "3.821.0", - "@aws-sdk/middleware-logger": "3.821.0", - "@aws-sdk/middleware-recursion-detection": "3.821.0", - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/region-config-resolver": "3.821.0", - "@aws-sdk/types": "3.821.0", - "@aws-sdk/util-endpoints": "3.828.0", - "@aws-sdk/util-user-agent-browser": "3.821.0", - "@aws-sdk/util-user-agent-node": "3.839.0", - "@smithy/config-resolver": "^4.1.4", - "@smithy/core": "^3.6.0", - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/hash-node": "^4.0.4", - "@smithy/invalid-dependency": "^4.0.4", - "@smithy/middleware-content-length": "^4.0.4", - "@smithy/middleware-endpoint": "^4.1.13", - "@smithy/middleware-retry": "^4.1.14", - "@smithy/middleware-serde": "^4.0.8", - "@smithy/middleware-stack": "^4.0.4", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/protocol-http": "^5.1.2", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/url-parser": "^4.0.4", - "@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.21", - "@smithy/util-defaults-mode-node": "^4.0.21", - "@smithy/util-endpoints": "^3.0.6", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.6", - "@smithy/util-utf8": "^4.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.821.0.tgz", - "integrity": "sha512-t8og+lRCIIy5nlId0bScNpCkif8sc0LhmtaKsbm0ZPm3sCa/WhCbSZibjbZ28FNjVCV+p0D9RYZx0VDDbtWyjw==", - "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/types": "^4.3.1", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.821.0.tgz", - "integrity": "sha512-irWZHyM0Jr1xhC+38OuZ7JB6OXMLPZlj48thElpsO1ZSLRkLZx5+I7VV6k3sp2yZ7BYbKz/G2ojSv4wdm7XTLw==", - "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/types": "^4.3.1", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.839.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.839.0.tgz", - "integrity": "sha512-MuunkIG1bJVMtTH7MbjXOrhHleU5wjHz5eCAUc6vj7M9rwol71nqjj9b8RLnkO5gsJcKc29Qk8iV6xQuzKWNMw==", - "dependencies": { - "@aws-sdk/middleware-user-agent": "3.839.0", - "@aws-sdk/types": "3.821.0", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/node-http-handler": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", - "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", + "version": "3.731.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.731.1.tgz", + "integrity": "sha512-t34GOPwBZsX7zGHjiTXmMHGY3kHM7fLiQ60Jqk0On9P0ASHTDE5U75RgCXboE3u+qEv9wyKyaqMNyMWj9qQlFg==", "dependencies": { - "@smithy/abort-controller": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", + "@aws-sdk/nested-clients": "3.731.1", + "@aws-sdk/types": "3.731.0", + "@smithy/property-provider": "^4.0.0", + "@smithy/shared-ini-file-loader": "^4.0.0", + "@smithy/types": "^4.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "node_modules/@aws-sdk/token-providers/node_modules/@aws-sdk/types": { + "version": "3.731.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.731.0.tgz", + "integrity": "sha512-NrdkJg6oOUbXR2r9WvHP408CLyvST8cJfp1/jP9pemtjvjPoh6NukbCtiSFdOOb1eryP02CnqQWItfJC1p2Y/Q==", "dependencies": { + "@smithy/types": "^4.0.0", "tslib": "^2.6.2" }, "engines": { @@ -3831,11 +3508,11 @@ } }, "node_modules/@aws-sdk/types": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.821.0.tgz", - "integrity": "sha512-Znroqdai1a90TlxGaJ+FK1lwC0fHpo97Xjsp5UKGR5JODYm7f9+/fF17ebO1KdoBr/Rm0UIFiF5VmI8ts9F1eA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.901.0.tgz", + "integrity": "sha512-FfEM25hLEs4LoXsLXQ/q6X6L4JmKkKkbVFpKD4mwfVHtRVQG6QxJiCPcrkcPISquiy6esbwK2eh64TWbiD60cg==", "dependencies": { - "@smithy/types": "^4.3.1", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -3843,9 +3520,9 @@ } }, "node_modules/@aws-sdk/types/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -3854,9 +3531,9 @@ } }, "node_modules/@aws-sdk/util-arn-parser": { - "version": "3.804.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.804.0.tgz", - "integrity": "sha512-wmBJqn1DRXnZu3b4EkE6CWnoWMo1ZMvlfkqU5zPz67xx1GMaXlDCchFvKAXMjk4jn/L1O3tKnoFDNsoLV1kgNQ==", + "version": "3.893.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.893.0.tgz", + "integrity": "sha512-u8H4f2Zsi19DGnwj5FSZzDMhytYF/bCh37vAtBsn3cNDL3YG578X5oc+wSX54pM3tOxS+NY7tvOAo52SW7koUA==", "dependencies": { "tslib": "^2.6.2" }, @@ -3865,13 +3542,14 @@ } }, "node_modules/@aws-sdk/util-endpoints": { - "version": "3.828.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.828.0.tgz", - "integrity": "sha512-RvKch111SblqdkPzg3oCIdlGxlQs+k+P7Etory9FmxPHyPDvsP1j1c74PmgYqtzzMWmoXTjd+c9naUHh9xG8xg==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.901.0.tgz", + "integrity": "sha512-5nZP3hGA8FHEtKvEQf4Aww5QZOkjLW1Z+NixSd+0XKfHvA39Ah5sZboScjLx0C9kti/K3OGW1RCx5K9Zc3bZqg==", "dependencies": { - "@aws-sdk/types": "3.821.0", - "@smithy/types": "^4.3.1", - "@smithy/util-endpoints": "^3.0.6", + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-endpoints": "^3.2.0", "tslib": "^2.6.2" }, "engines": { @@ -3879,9 +3557,9 @@ } }, "node_modules/@aws-sdk/util-endpoints/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -3890,9 +3568,9 @@ } }, "node_modules/@aws-sdk/util-locate-window": { - "version": "3.804.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.804.0.tgz", - "integrity": "sha512-zVoRfpmBVPodYlnMjgVjfGoEZagyRF5IPn3Uo6ZvOZp24chnW/FRstH7ESDHDDRga4z3V+ElUQHKpFDXWyBW5A==", + "version": "3.893.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.893.0.tgz", + "integrity": "sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg==", "dependencies": { "tslib": "^2.6.2" }, @@ -3992,11 +3670,12 @@ } }, "node_modules/@aws-sdk/xml-builder": { - "version": "3.821.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.821.0.tgz", - "integrity": "sha512-DIIotRnefVL6DiaHtO6/21DhJ4JZnnIwdNbpwiAhdt/AVbttcE4yw925gsjur0OGv5BTYXQXU3YnANBYnZjuQA==", + "version": "3.901.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.901.0.tgz", + "integrity": "sha512-pxFCkuAP7Q94wMTNPAwi6hEtNrp/BdFf+HOrIEeFQsk4EoOmpKY3I6S+u6A9Wg295J80Kh74LqDWM22ux3z6Aw==", "dependencies": { - "@smithy/types": "^4.3.1", + "@smithy/types": "^4.6.0", + "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" }, "engines": { @@ -4004,9 +3683,9 @@ } }, "node_modules/@aws-sdk/xml-builder/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -4014,6 +3693,34 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/xml-builder/node_modules/fast-xml-parser": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz", + "integrity": "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "dependencies": { + "strnum": "^2.1.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/@aws-sdk/xml-builder/node_modules/strnum": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", + "integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ] + }, "node_modules/@aws/chat-client": { "resolved": "chat-client", "link": true @@ -4034,13 +3741,20 @@ "resolved": "app/hello-world-lsp-runtimes", "link": true }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.0.1.tgz", + "integrity": "sha512-ORHRQ2tmvnBXc8t/X9Z8IcSbBA4xTLKuN873FopzklHMeqBst7YG0d+AX97inkvDX+NChYtSr+qGfcqGFaI8Zw==", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws/language-server-runtimes": { - "version": "0.2.129", - "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.2.129.tgz", - "integrity": "sha512-ZTObivXrC04FIZHlRgL/E3Dx+hq4wFMOXCGTMHlVUiRs8FaXLXvENZbi0+5/I3Ex/CNwazQWgVaBHJ+dMw42nw==", - "license": "Apache-2.0", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@aws/language-server-runtimes/-/language-server-runtimes-0.3.1.tgz", + "integrity": "sha512-Ttn7r/xwP0Q2c4nquRJYEDuwvd8N1DUsrFuaq9zstuj3Y1G4WD9hBV773CaGuqgEdqE5+n2hyeOxfkwTAbzddg==", "dependencies": { - "@aws/language-server-runtimes-types": "^0.1.56", + "@aws/language-server-runtimes-types": "^0.1.57", "@opentelemetry/api": "^1.9.0", "@opentelemetry/api-logs": "^0.200.0", "@opentelemetry/core": "^2.0.0", @@ -4051,7 +3765,6 @@ "@opentelemetry/sdk-metrics": "^2.0.1", "@smithy/node-http-handler": "^4.0.4", "ajv": "^8.17.1", - "aws-sdk": "^2.1692.0", "hpagent": "^1.2.0", "jose": "^5.9.6", "mac-ca": "^3.1.1", @@ -4075,44 +3788,6 @@ "vscode-languageserver-types": "^3.17.5" } }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/node-http-handler": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", - "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", - "dependencies": { - "@smithy/abort-controller": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/language-server-runtimes/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@aws/lsp-antlr4": { "resolved": "server/aws-lsp-antlr4", "link": true @@ -4242,30 +3917,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.7.tgz", - "integrity": "sha512-xgu/ySj2mTiUFmdE9yCMfBxLp4DHd5DwmbbD05YAuICfodYT3VvRxbrh81LGQ/8UpSdtMdfKMn3KouYDX59DGQ==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.7.tgz", - "integrity": "sha512-BU2f9tlKQ5CAthiMIgpzAh4eDTLWo1mqi9jqE2OxMG0E/OM199VJt2q8BztTxpnSW0i1ymdwLXRJnYzvDM5r2w==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "dev": true, "dependencies": { - "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.5", + "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.27.3", - "@babel/helpers": "^7.27.6", - "@babel/parser": "^7.27.7", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.27.7", - "@babel/types": "^7.27.7", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -4280,22 +3955,41 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/generator": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.5.tgz", - "integrity": "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", "dev": true, "dependencies": { - "@babel/parser": "^7.27.5", - "@babel/types": "^7.27.3", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@babel/helper-compilation-targets": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", @@ -4312,6 +4006,33 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", @@ -4326,14 +4047,14 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", - "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.3" + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -4379,25 +4100,25 @@ } }, "node_modules/@babel/helpers": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", - "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "dev": true, "dependencies": { "@babel/template": "^7.27.2", - "@babel/types": "^7.27.6" + "@babel/types": "^7.28.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.7.tgz", - "integrity": "sha512-qnzXzDXdr/po3bOTbTIQZ7+TxNKxpkN5IifVLXS+r7qwynkZfPyjZfE7hCXbo7IoO9TNcSyibgONsf2HauUd3Q==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", "dev": true, "dependencies": { - "@babel/types": "^7.27.7" + "@babel/types": "^7.28.4" }, "bin": { "parser": "bin/babel-parser.js" @@ -4644,16 +4365,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/runtime": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", - "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/template": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", @@ -4669,27 +4380,27 @@ } }, "node_modules/@babel/traverse": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.7.tgz", - "integrity": "sha512-X6ZlfR/O/s5EQ/SnUSLzr+6kGnkg8HXGMzpgsMsrJVcfDtH1vIp6ctCN4eZ1LS5c0+te5Cb6Y514fASjMRJ1nw==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.5", - "@babel/parser": "^7.27.7", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", - "@babel/types": "^7.27.7", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/types": "^7.28.4", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.7.tgz", - "integrity": "sha512-8OLQgDScAOHXnAz2cV+RfzzNMipuLVBz2biuAJFMV9bfkNf393je3VM8CLkjQodW5+iWsSJdSgSWT6rsZoXHPw==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -4819,18 +4530,6 @@ "node": ">=v18" } }, - "node_modules/@commitlint/is-ignored/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@commitlint/lint": { "version": "19.8.1", "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-19.8.1.tgz", @@ -4984,20 +4683,10 @@ "node": ">=12" } }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, "node_modules/@csstools/color-helpers": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz", - "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", "dev": true, "funding": [ { @@ -5037,9 +4726,9 @@ } }, "node_modules/@csstools/css-color-parser": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz", - "integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", "dev": true, "funding": [ { @@ -5052,7 +4741,7 @@ } ], "dependencies": { - "@csstools/color-helpers": "^5.0.2", + "@csstools/color-helpers": "^5.1.0", "@csstools/css-calc": "^2.1.4" }, "engines": { @@ -5114,43 +4803,40 @@ } }, "node_modules/@emnapi/core": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.4.tgz", - "integrity": "sha512-A9CnAbC6ARNMKcIcrQwq6HeHCjpcBZ5wSx4U01WXCqEKlrzB9F9315WDNHkrs2xbx7YjjSxbUYxuN6EQzpcY2g==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", + "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", "dev": true, - "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.0.3", + "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.4.tgz", - "integrity": "sha512-hHyapA4A3gPaDCNfiqyZUStTMqIkKRshqPIuDOXv1hcBnD4U3l8cP0T1HMCfGRxQ6V64TGCcoswChANyOAwbQg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", + "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", "dev": true, - "license": "MIT", "optional": true, "dependencies": { "tslib": "^2.4.0" } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.3.tgz", - "integrity": "sha512-8K5IFFsQqF9wQNJptGbS6FNKgUTsSRYnTqNCG1vPP8jFdjSv18n2mQfJpkt2Oibo9iBEzcDnDxNwKTzC7svlJw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", "dev": true, - "license": "MIT", "optional": true, "dependencies": { "tslib": "^2.4.0" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", - "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", + "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", "cpu": [ "ppc64" ], @@ -5164,9 +4850,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", - "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", + "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", "cpu": [ "arm" ], @@ -5180,9 +4866,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", - "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", + "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", "cpu": [ "arm64" ], @@ -5196,9 +4882,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", - "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", + "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", "cpu": [ "x64" ], @@ -5212,9 +4898,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", - "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", + "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", "cpu": [ "arm64" ], @@ -5228,9 +4914,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", - "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", + "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", "cpu": [ "x64" ], @@ -5244,9 +4930,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", - "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", + "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", "cpu": [ "arm64" ], @@ -5260,9 +4946,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", - "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", + "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", "cpu": [ "x64" ], @@ -5276,9 +4962,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", - "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", + "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", "cpu": [ "arm" ], @@ -5292,9 +4978,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", - "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", + "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", "cpu": [ "arm64" ], @@ -5308,9 +4994,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", - "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", + "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", "cpu": [ "ia32" ], @@ -5324,9 +5010,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", - "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", + "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", "cpu": [ "loong64" ], @@ -5340,9 +5026,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", - "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", + "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", "cpu": [ "mips64el" ], @@ -5356,9 +5042,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", - "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", + "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", "cpu": [ "ppc64" ], @@ -5372,9 +5058,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", - "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", + "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", "cpu": [ "riscv64" ], @@ -5388,9 +5074,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", - "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", + "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", "cpu": [ "s390x" ], @@ -5404,9 +5090,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", - "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", + "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", "cpu": [ "x64" ], @@ -5420,9 +5106,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", - "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", + "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", "cpu": [ "arm64" ], @@ -5436,9 +5122,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", - "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", + "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", "cpu": [ "x64" ], @@ -5452,9 +5138,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", - "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", + "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", "cpu": [ "arm64" ], @@ -5468,9 +5154,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", - "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", + "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", "cpu": [ "x64" ], @@ -5483,10 +5169,26 @@ "node": ">=18" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", + "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", - "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", + "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", "cpu": [ "x64" ], @@ -5500,9 +5202,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", - "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", + "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", "cpu": [ "arm64" ], @@ -5516,9 +5218,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", - "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", + "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", "cpu": [ "ia32" ], @@ -5532,9 +5234,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", - "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", + "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", "cpu": [ "x64" ], @@ -5548,9 +5250,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", - "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", "dev": true, "dependencies": { "eslint-visitor-keys": "^3.4.3" @@ -5623,21 +5325,6 @@ "concat-map": "0.0.1" } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@eslint/eslintrc/node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -5665,18 +5352,6 @@ "node": "*" } }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@eslint/js": { "version": "8.57.1", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", @@ -5757,79 +5432,96 @@ "deprecated": "Use @eslint/object-schema instead", "dev": true }, + "node_modules/@inquirer/ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.0.tgz", + "integrity": "sha512-JWaTfCxI1eTmJ1BIv86vUfjVatOdxwD0DAVKYevY8SazeUUZtW+tNbsdejVO1GYE0GXJW1N1ahmiC3TFd+7wZA==", + "dev": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@inquirer/checkbox": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-3.0.1.tgz", - "integrity": "sha512-0hm2nrToWUdD6/UHnel/UKGdk1//ke5zGUpHIvk5ZWmaKezlGxZkOJXNSWsdxO/rEqTkbB3lNC2J6nBElV2aAQ==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.4.tgz", + "integrity": "sha512-2n9Vgf4HSciFq8ttKXk+qy+GsyTXPV1An6QAwe/8bkbbqvG4VW1I/ZY1pNu2rf+h9bdzMLPbRSfcNxkHBy/Ydw==", "dev": true, "dependencies": { - "@inquirer/core": "^9.2.1", - "@inquirer/figures": "^1.0.6", - "@inquirer/type": "^2.0.0", - "ansi-escapes": "^4.3.2", + "@inquirer/ansi": "^1.0.0", + "@inquirer/core": "^10.2.2", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/@inquirer/confirm": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-4.0.1.tgz", - "integrity": "sha512-46yL28o2NJ9doViqOy0VDcoTzng7rAb6yPQKU7VDLqkmbCaH4JqK4yk4XqlzNWy9PVC5pG1ZUXPBQv+VqnYs2w==", + "version": "5.1.18", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.18.tgz", + "integrity": "sha512-MilmWOzHa3Ks11tzvuAmFoAd/wRuaP3SwlT1IZhyMke31FKLxPiuDWcGXhU+PKveNOpAc4axzAgrgxuIJJRmLw==", "dev": true, "dependencies": { - "@inquirer/core": "^9.2.1", - "@inquirer/type": "^2.0.0" + "@inquirer/core": "^10.2.2", + "@inquirer/type": "^3.0.8" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/@inquirer/core": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.2.1.tgz", - "integrity": "sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.2.tgz", + "integrity": "sha512-yXq/4QUnk4sHMtmbd7irwiepjB8jXU0kkFRL4nr/aDBA2mDz13cMakEWdDwX3eSCTkk03kwcndD1zfRAIlELxA==", "dev": true, "dependencies": { - "@inquirer/figures": "^1.0.6", - "@inquirer/type": "^2.0.0", - "@types/mute-stream": "^0.0.4", - "@types/node": "^22.5.5", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", + "@inquirer/ansi": "^1.0.0", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", + "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", "wrap-ansi": "^6.2.0", "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@inquirer/core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@inquirer/core/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@inquirer/core/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "node_modules/@inquirer/core/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -5859,158 +5551,272 @@ } }, "node_modules/@inquirer/editor": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-3.0.1.tgz", - "integrity": "sha512-VA96GPFaSOVudjKFraokEEmUQg/Lub6OXvbIEZU1SDCmBzRkHGhxoFAVaF30nyiB4m5cEbDgiI2QRacXZ2hw9Q==", + "version": "4.2.20", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.20.tgz", + "integrity": "sha512-7omh5y5bK672Q+Brk4HBbnHNowOZwrb/78IFXdrEB9PfdxL3GudQyDk8O9vQ188wj3xrEebS2M9n18BjJoI83g==", "dev": true, "dependencies": { - "@inquirer/core": "^9.2.1", - "@inquirer/type": "^2.0.0", - "external-editor": "^3.1.0" + "@inquirer/core": "^10.2.2", + "@inquirer/external-editor": "^1.0.2", + "@inquirer/type": "^3.0.8" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/@inquirer/expand": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-3.0.1.tgz", - "integrity": "sha512-ToG8d6RIbnVpbdPdiN7BCxZGiHOTomOX94C2FaT5KOHupV40tKEDozp12res6cMIfRKrXLJyexAZhWVHgbALSQ==", + "version": "4.0.20", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.20.tgz", + "integrity": "sha512-Dt9S+6qUg94fEvgn54F2Syf0Z3U8xmnBI9ATq2f5h9xt09fs2IJXSCIXyyVHwvggKWFXEY/7jATRo2K6Dkn6Ow==", "dev": true, "dependencies": { - "@inquirer/core": "^9.2.1", - "@inquirer/type": "^2.0.0", + "@inquirer/core": "^10.2.2", + "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.2.tgz", + "integrity": "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==", + "dev": true, + "dependencies": { + "chardet": "^2.1.0", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/@inquirer/figures": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.12.tgz", - "integrity": "sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", + "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", "dev": true, "engines": { "node": ">=18" } }, "node_modules/@inquirer/input": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-3.0.1.tgz", - "integrity": "sha512-BDuPBmpvi8eMCxqC5iacloWqv+5tQSJlUafYWUe31ow1BVXjW2a5qe3dh4X/Z25Wp22RwvcaLCc2siHobEOfzg==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.4.tgz", + "integrity": "sha512-cwSGpLBMwpwcZZsc6s1gThm0J+it/KIJ+1qFL2euLmSKUMGumJ5TcbMgxEjMjNHRGadouIYbiIgruKoDZk7klw==", "dev": true, "dependencies": { - "@inquirer/core": "^9.2.1", - "@inquirer/type": "^2.0.0" + "@inquirer/core": "^10.2.2", + "@inquirer/type": "^3.0.8" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/@inquirer/number": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-2.0.1.tgz", - "integrity": "sha512-QpR8jPhRjSmlr/mD2cw3IR8HRO7lSVOnqUvQa8scv1Lsr3xoAMMworcYW3J13z3ppjBFBD2ef1Ci6AE5Qn8goQ==", + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.20.tgz", + "integrity": "sha512-bbooay64VD1Z6uMfNehED2A2YOPHSJnQLs9/4WNiV/EK+vXczf/R988itL2XLDGTgmhMF2KkiWZo+iEZmc4jqg==", "dev": true, "dependencies": { - "@inquirer/core": "^9.2.1", - "@inquirer/type": "^2.0.0" + "@inquirer/core": "^10.2.2", + "@inquirer/type": "^3.0.8" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/@inquirer/password": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-3.0.1.tgz", - "integrity": "sha512-haoeEPUisD1NeE2IanLOiFr4wcTXGWrBOyAyPZi1FfLJuXOzNmxCJPgUrGYKVh+Y8hfGJenIfz5Wb/DkE9KkMQ==", + "version": "4.0.20", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.20.tgz", + "integrity": "sha512-nxSaPV2cPvvoOmRygQR+h0B+Av73B01cqYLcr7NXcGXhbmsYfUb8fDdw2Us1bI2YsX+VvY7I7upgFYsyf8+Nug==", "dev": true, "dependencies": { - "@inquirer/core": "^9.2.1", - "@inquirer/type": "^2.0.0", - "ansi-escapes": "^4.3.2" + "@inquirer/ansi": "^1.0.0", + "@inquirer/core": "^10.2.2", + "@inquirer/type": "^3.0.8" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/@inquirer/prompts": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-6.0.1.tgz", - "integrity": "sha512-yl43JD/86CIj3Mz5mvvLJqAOfIup7ncxfJ0Btnl0/v5TouVUyeEdcpknfgc+yMevS/48oH9WAkkw93m7otLb/A==", + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.6.tgz", + "integrity": "sha512-68JhkiojicX9SBUD8FE/pSKbOKtwoyaVj1kwqLfvjlVXZvOy3iaSWX4dCLsZyYx/5Ur07Fq+yuDNOen+5ce6ig==", "dev": true, "dependencies": { - "@inquirer/checkbox": "^3.0.1", - "@inquirer/confirm": "^4.0.1", - "@inquirer/editor": "^3.0.1", - "@inquirer/expand": "^3.0.1", - "@inquirer/input": "^3.0.1", - "@inquirer/number": "^2.0.1", - "@inquirer/password": "^3.0.1", - "@inquirer/rawlist": "^3.0.1", - "@inquirer/search": "^2.0.1", - "@inquirer/select": "^3.0.1" + "@inquirer/checkbox": "^4.2.4", + "@inquirer/confirm": "^5.1.18", + "@inquirer/editor": "^4.2.20", + "@inquirer/expand": "^4.0.20", + "@inquirer/input": "^4.2.4", + "@inquirer/number": "^3.0.20", + "@inquirer/password": "^4.0.20", + "@inquirer/rawlist": "^4.1.8", + "@inquirer/search": "^3.1.3", + "@inquirer/select": "^4.3.4" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/@inquirer/rawlist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-3.0.1.tgz", - "integrity": "sha512-VgRtFIwZInUzTiPLSfDXK5jLrnpkuSOh1ctfaoygKAdPqjcjKYmGh6sCY1pb0aGnCGsmhUxoqLDUAU0ud+lGXQ==", + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.8.tgz", + "integrity": "sha512-CQ2VkIASbgI2PxdzlkeeieLRmniaUU1Aoi5ggEdm6BIyqopE9GuDXdDOj9XiwOqK5qm72oI2i6J+Gnjaa26ejg==", "dev": true, "dependencies": { - "@inquirer/core": "^9.2.1", - "@inquirer/type": "^2.0.0", + "@inquirer/core": "^10.2.2", + "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/@inquirer/search": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-2.0.1.tgz", - "integrity": "sha512-r5hBKZk3g5MkIzLVoSgE4evypGqtOannnB3PKTG9NRZxyFRKcfzrdxXXPcoJQsxJPzvdSU2Rn7pB7lw0GCmGAg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.1.3.tgz", + "integrity": "sha512-D5T6ioybJJH0IiSUK/JXcoRrrm8sXwzrVMjibuPs+AgxmogKslaafy1oxFiorNI4s3ElSkeQZbhYQgLqiL8h6Q==", "dev": true, "dependencies": { - "@inquirer/core": "^9.2.1", - "@inquirer/figures": "^1.0.6", - "@inquirer/type": "^2.0.0", + "@inquirer/core": "^10.2.2", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/@inquirer/select": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-3.0.1.tgz", - "integrity": "sha512-lUDGUxPhdWMkN/fHy1Lk7pF3nK1fh/gqeyWXmctefhxLYxlDsc7vsPBEpxrfVGDsVdyYJsiJoD4bJ1b623cV1Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.4.tgz", + "integrity": "sha512-Qp20nySRmfbuJBBsgPU7E/cL62Hf250vMZRzYDcBHty2zdD1kKCnoDFWRr0WO2ZzaXp3R7a4esaVGJUx0E6zvA==", "dev": true, "dependencies": { - "@inquirer/core": "^9.2.1", - "@inquirer/figures": "^1.0.6", - "@inquirer/type": "^2.0.0", - "ansi-escapes": "^4.3.2", + "@inquirer/ansi": "^1.0.0", + "@inquirer/core": "^10.2.2", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/@inquirer/type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-2.0.0.tgz", - "integrity": "sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", + "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", "dev": true, - "dependencies": { - "mute-stream": "^1.0.0" - }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/@isaacs/cliui": { @@ -6030,9 +5836,9 @@ } }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "engines": { "node": ">=12" }, @@ -6040,10 +5846,42 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -6054,6 +5892,22 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -6079,10 +5933,19 @@ "sprintf-js": "~1.0.2" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "dependencies": { "locate-path": "^5.0.0", @@ -6179,21 +6042,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/console/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@jest/console/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -6257,21 +6105,6 @@ } } }, - "node_modules/@jest/core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@jest/core/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -6355,9 +6188,9 @@ } }, "node_modules/@jest/get-type": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.0.1.tgz", - "integrity": "sha512-AyYdemXCptSRFirI5EPazNxyPwAL0jXt3zceFjaj8NFiKP9pOi0bfXonf6qkf82z2t3QWPeLCWWw4stPBzctLw==", + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", "dev": true, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -6449,29 +6282,14 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "node_modules/@jest/reporters/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/reporters/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/@jest/reporters/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@jest/reporters/node_modules/chalk": { @@ -6490,37 +6308,34 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/reporters/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "node_modules/@jest/reporters/node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/reporters/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@jest/reporters/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "has-flag": "^4.0.0" }, "engines": { - "node": "*" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/@jest/schemas": { @@ -6549,6 +6364,16 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/source-map/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@jest/test-result": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", @@ -6605,19 +6430,14 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/transform/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@jest/transform/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@jest/transform/node_modules/chalk": { @@ -6653,21 +6473,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@jest/types/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -6685,15 +6490,45 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.9.tgz", - "integrity": "sha512-xpz6C/vXOegF9VEtlMBlkNNIjHrLhKaFBsO4lmQGr00x5BHp7p+oliR6i7LwIcM5cZU2VjLSwm2R+/zj5IjPWg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "devOptional": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, + "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "devOptional": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -6704,29 +6539,39 @@ } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "devOptional": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "devOptional": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "devOptional": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "devOptional": true, + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, "node_modules/@jsonjoy.com/base64": { @@ -6744,15 +6589,67 @@ "tslib": "2" } }, - "node_modules/@jsonjoy.com/json-pack": { + "node_modules/@jsonjoy.com/buffers": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.2.0.tgz", - "integrity": "sha512-io1zEbbYcElht3tdlqEOFxZ0dMTYrHz9iMf0gqn1pPjZFTCgM5R4R5IMA20Chb2UPYYsxjzs8CgZ7Nb5n2K2rA==", - "dependencies": { - "@jsonjoy.com/base64": "^1.1.1", - "@jsonjoy.com/util": "^1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.0.tgz", + "integrity": "sha512-6RX+W5a+ZUY/c/7J5s5jK9UinLfJo5oWKh84fb4X0yK2q4WXEWUWZWuEMjvCb1YNUQhEAhUfr5scEGOH7jC4YQ==", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/codegen": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz", + "integrity": "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.16.0.tgz", + "integrity": "sha512-L4/W6WRI7pXYJbPGqzYH1zJfckE/0ZP8ttNg/EPLwC+P23wSZYRmz2DNydAu2a8uc20bPlxsvWcYvDYoBJ5BYQ==", + "dependencies": { + "@jsonjoy.com/base64": "^1.1.2", + "@jsonjoy.com/buffers": "^1.2.0", + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/json-pointer": "^1.0.2", + "@jsonjoy.com/util": "^1.9.0", "hyperdyperid": "^1.2.0", - "thingies": "^1.20.0" + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pointer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz", + "integrity": "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==", + "dependencies": { + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/util": "^1.9.0" }, "engines": { "node": ">=10.0" @@ -6766,9 +6663,13 @@ } }, "node_modules/@jsonjoy.com/util": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.6.0.tgz", - "integrity": "sha512-sw/RMbehRhN68WRtcKCpQOPfnH6lLP4GJfqzi3iYej8tnzpZUDr6UkZYJjcjjC0FWEJOJbyM3PTIwxucUmDG2A==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.9.0.tgz", + "integrity": "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==", + "dependencies": { + "@jsonjoy.com/buffers": "^1.0.0", + "@jsonjoy.com/codegen": "^1.0.0" + }, "engines": { "node": ">=10.0" }, @@ -6786,10 +6687,9 @@ "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==" }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.15.0.tgz", - "integrity": "sha512-67hnl/ROKdb03Vuu0YOr+baKTvf1/5YBHBm9KnZdjdAh8hjt4FRCPD5ucwxGB237sBpzlqQsLy1PFu7z/ekZ9Q==", - "license": "MIT", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.19.1.tgz", + "integrity": "sha512-3Y2h3MZKjec1eAqSTBclATlX+AbC6n1LgfVzRMJLt3v6w0RCYgwLrjbxPDbhsYHt6Wdqc/aCceNJYgj448ELQQ==", "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", @@ -6829,16 +6729,15 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.11.tgz", - "integrity": "sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==", + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", "dev": true, - "license": "MIT", "optional": true, "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.9.0" + "@tybys/wasm-util": "^0.10.0" } }, "node_modules/@node-rs/crc32": { @@ -6846,7 +6745,6 @@ "resolved": "https://registry.npmjs.org/@node-rs/crc32/-/crc32-1.10.6.tgz", "integrity": "sha512-+llXfqt+UzgoDzT9of5vPQPGqTAVCohU74I9zIBkNo5TH6s2P31DFJOGsJQKN207f0GHnYv5pV3wh3BCY/un/A==", "dev": true, - "license": "MIT", "engines": { "node": ">= 10" }, @@ -6879,7 +6777,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -6896,7 +6793,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -6913,7 +6809,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -6930,7 +6825,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -6947,7 +6841,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -6964,7 +6857,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -6981,7 +6873,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -6998,7 +6889,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -7015,7 +6905,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -7032,7 +6921,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -7049,7 +6937,6 @@ "wasm32" ], "dev": true, - "license": "MIT", "optional": true, "dependencies": { "@napi-rs/wasm-runtime": "^0.2.5" @@ -7066,7 +6953,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -7083,7 +6969,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -7100,7 +6985,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -7205,9 +7089,9 @@ } }, "node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, @@ -7406,11 +7290,11 @@ } }, "node_modules/@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.1.0.tgz", + "integrity": "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw==", "dependencies": { - "@opentelemetry/core": "2.0.1", + "@opentelemetry/core": "2.1.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -7466,12 +7350,12 @@ } }, "node_modules/@opentelemetry/sdk-metrics": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", - "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.1.0.tgz", + "integrity": "sha512-J9QX459mzqHLL9Y6FZ4wQPRZG4TOpMCyPOh6mkr/humxE1W2S3Bvf4i75yiMW9uyed2Kf5rxmLhTm/UK8vNkAw==", "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -7526,9 +7410,9 @@ } }, "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.34.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.34.0.tgz", - "integrity": "sha512-aKcOkyrorBGlajjRdVoJWHTxfxO1vCNHLJVlSDaRHDIdjU+pX8IYQPvPDkYiujKLbRnWU+1TBwEt0QRgSm4SGA==", + "version": "1.37.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.37.0.tgz", + "integrity": "sha512-JD6DerIKdJGmRp4jQyX5FlrQjA4tjOw1cvfsPAZXfOOEErMUHjPcPSICS+6WnM0nB0efSFARh0KAZss+bvExOA==", "engines": { "node": ">=14" } @@ -7543,9 +7427,9 @@ } }, "node_modules/@pkgr/core": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.7.tgz", - "integrity": "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==", + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "dev": true, "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" @@ -7628,17 +7512,17 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@puppeteer/browsers": { - "version": "2.10.5", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.10.5.tgz", - "integrity": "sha512-eifa0o+i8dERnngJwKrfp3dEq7ia5XFyoqB17S4gK8GhsQE4/P8nxOfQSE0zQHxzzLo/cmF+7+ywEQ7wK7Fb+w==", + "version": "2.10.10", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.10.10.tgz", + "integrity": "sha512-3ZG500+ZeLql8rE0hjfhkycJjDj0pI/btEh3L9IkWUYcOrgP0xCNRq3HbtbqOPbvDhFaAWD88pDFtlLv8ns8gA==", "dev": true, "dependencies": { - "debug": "^4.4.1", + "debug": "^4.4.3", "extract-zip": "^2.0.1", "progress": "^2.0.3", "proxy-agent": "^6.5.0", "semver": "^7.7.2", - "tar-fs": "^3.0.8", + "tar-fs": "^3.1.0", "yargs": "^17.7.2" }, "bin": { @@ -7648,22 +7532,10 @@ "node": ">=18" } }, - "node_modules/@puppeteer/browsers/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@puppeteer/browsers/node_modules/tar-fs": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.10.tgz", - "integrity": "sha512-C1SwlQGNLe/jPNqapK8epDsXME7CAJR5RL3GcE6KWx1d9OUByzoHVcbu1VPI8tevg9H8Alae0AApHHFGzrD5zA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz", + "integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==", "dev": true, "dependencies": { "pump": "^3.0.0", @@ -7674,6 +7546,17 @@ "bare-path": "^3.0.0" } }, + "node_modules/@puppeteer/browsers/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -7743,13 +7626,12 @@ } }, "node_modules/@sinonjs/samsam": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", - "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.3.tgz", + "integrity": "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.1", - "lodash.get": "^4.4.2", "type-detect": "^4.1.0" } }, @@ -7760,32 +7642,32 @@ "dev": true }, "node_modules/@smithy/abort-controller": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.9.tgz", - "integrity": "sha512-yiW0WI30zj8ZKoSYNx90no7ugVn3khlyH/z5W8qtKBtVE6awRALbhSG+2SAHA1r6bO/6M9utxYKVZ3PCJ1rWxw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.0.tgz", + "integrity": "sha512-PLUYa+SUKOEZtXFURBu/CNxlsxfaFGxSBPcStL13KpVeVWIfdezWyDqkz7iDLmwnxojXD0s5KzuB5HGHvt4Aeg==", "dependencies": { - "@smithy/types": "^3.7.2", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, "node_modules/@smithy/abort-controller/node_modules/@smithy/types": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.7.2.tgz", - "integrity": "sha512-bNwBYYmN8Eh9RyjS1p2gW6MIhSO2rl7X9QeLM8iTdcGRP+eDiIWDt66c9IysCc22gefKszZv+ubV9qZc7hdESg==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, "node_modules/@smithy/chunked-blob-reader": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.0.0.tgz", - "integrity": "sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.2.0.tgz", + "integrity": "sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA==", "dependencies": { "tslib": "^2.6.2" }, @@ -7794,11 +7676,11 @@ } }, "node_modules/@smithy/chunked-blob-reader-native": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-4.0.0.tgz", - "integrity": "sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-4.2.0.tgz", + "integrity": "sha512-HNbGWdyTfSM1nfrZKQjYTvD8k086+M8s1EYkBUdGC++lhxegUp2HgNf5RIt6oOGVvsC26hBCW/11tv8KbwLn/Q==", "dependencies": { - "@smithy/util-base64": "^4.0.0", + "@smithy/util-base64": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -7806,14 +7688,14 @@ } }, "node_modules/@smithy/config-resolver": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.1.4.tgz", - "integrity": "sha512-prmU+rDddxHOH0oNcwemL+SwnzcG65sBF2yXRO7aeXIn/xTlq2pX7JLVbkBnVLowHLg4/OL4+jBmv9hVrVGS+w==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.3.0.tgz", + "integrity": "sha512-9oH+n8AVNiLPK/iK/agOsoWfrKZ3FGP3502tkksd6SRsKMYiu7AFX0YXo6YBADdsAj7C+G/aLKdsafIJHxuCkQ==", "dependencies": { - "@smithy/node-config-provider": "^4.1.3", - "@smithy/types": "^4.3.1", - "@smithy/util-config-provider": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -7821,9 +7703,9 @@ } }, "node_modules/@smithy/config-resolver/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -7832,18 +7714,19 @@ } }, "node_modules/@smithy/core": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.6.0.tgz", - "integrity": "sha512-Pgvfb+TQ4wUNLyHzvgCP4aYZMh16y7GcfF59oirRHcgGgkH1e/s9C0nv/v3WP+Quymyr5je71HeFQCwh+44XLg==", + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.14.0.tgz", + "integrity": "sha512-XJ4z5FxvY/t0Dibms/+gLJrI5niRoY0BCmE02fwmPcRYFPI4KI876xaE79YGWIKnEslMbuQPsIEsoU/DXa0DoA==", "dependencies": { - "@smithy/middleware-serde": "^4.0.8", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", - "@smithy/util-base64": "^4.0.0", - "@smithy/util-body-length-browser": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-stream": "^4.2.2", - "@smithy/util-utf8": "^4.0.0", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-stream": "^4.4.0", + "@smithy/util-utf8": "^4.2.0", + "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" }, "engines": { @@ -7851,9 +7734,9 @@ } }, "node_modules/@smithy/core/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -7862,14 +7745,14 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.6.tgz", - "integrity": "sha512-hKMWcANhUiNbCJouYkZ9V3+/Qf9pteR1dnwgdyzR09R4ODEYx8BbUysHwRSyex4rZ9zapddZhLFTnT4ZijR4pw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.0.tgz", + "integrity": "sha512-SOhFVvFH4D5HJZytb0bLKxCrSnwcqPiNlrw+S4ZXjMnsC+o9JcUQzbZOEQcA8yv9wJFNhfsUiIUKiEnYL68Big==", "dependencies": { - "@smithy/node-config-provider": "^4.1.3", - "@smithy/property-provider": "^4.0.4", - "@smithy/types": "^4.3.1", - "@smithy/url-parser": "^4.0.4", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -7877,9 +7760,9 @@ } }, "node_modules/@smithy/credential-provider-imds/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -7888,13 +7771,13 @@ } }, "node_modules/@smithy/eventstream-codec": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.0.4.tgz", - "integrity": "sha512-7XoWfZqWb/QoR/rAU4VSi0mWnO2vu9/ltS6JZ5ZSZv0eovLVfDfu0/AX4ub33RsJTOth3TiFWSHS5YdztvFnig==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.0.tgz", + "integrity": "sha512-XE7CtKfyxYiNZ5vz7OvyTf1osrdbJfmUy+rbh+NLQmZumMGvY0mT0Cq1qKSfhrvLtRYzMsOBuRpi10dyI0EBPg==", "dependencies": { "@aws-crypto/crc32": "5.2.0", - "@smithy/types": "^4.3.1", - "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/types": "^4.6.0", + "@smithy/util-hex-encoding": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -7902,9 +7785,9 @@ } }, "node_modules/@smithy/eventstream-codec/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -7913,12 +7796,12 @@ } }, "node_modules/@smithy/eventstream-serde-browser": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.0.4.tgz", - "integrity": "sha512-3fb/9SYaYqbpy/z/H3yIi0bYKyAa89y6xPmIqwr2vQiUT2St+avRt8UKwsWt9fEdEasc5d/V+QjrviRaX1JRFA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.0.tgz", + "integrity": "sha512-U53p7fcrk27k8irLhOwUu+UYnBqsXNLKl1XevOpsxK3y1Lndk8R7CSiZV6FN3fYFuTPuJy5pP6qa/bjDzEkRvA==", "dependencies": { - "@smithy/eventstream-serde-universal": "^4.0.4", - "@smithy/types": "^4.3.1", + "@smithy/eventstream-serde-universal": "^4.2.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -7926,9 +7809,9 @@ } }, "node_modules/@smithy/eventstream-serde-browser/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -7937,11 +7820,11 @@ } }, "node_modules/@smithy/eventstream-serde-config-resolver": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.1.2.tgz", - "integrity": "sha512-JGtambizrWP50xHgbzZI04IWU7LdI0nh/wGbqH3sJesYToMi2j/DcoElqyOcqEIG/D4tNyxgRuaqBXWE3zOFhQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.0.tgz", + "integrity": "sha512-uwx54t8W2Yo9Jr3nVF5cNnkAAnMCJ8Wrm+wDlQY6rY/IrEgZS3OqagtCu/9ceIcZFQ1zVW/zbN9dxb5esuojfA==", "dependencies": { - "@smithy/types": "^4.3.1", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -7949,9 +7832,9 @@ } }, "node_modules/@smithy/eventstream-serde-config-resolver/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -7960,12 +7843,12 @@ } }, "node_modules/@smithy/eventstream-serde-node": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.0.4.tgz", - "integrity": "sha512-RD6UwNZ5zISpOWPuhVgRz60GkSIp0dy1fuZmj4RYmqLVRtejFqQ16WmfYDdoSoAjlp1LX+FnZo+/hkdmyyGZ1w==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.0.tgz", + "integrity": "sha512-yjM2L6QGmWgJjVu/IgYd6hMzwm/tf4VFX0lm8/SvGbGBwc+aFl3hOzvO/e9IJ2XI+22Tx1Zg3vRpFRs04SWFcg==", "dependencies": { - "@smithy/eventstream-serde-universal": "^4.0.4", - "@smithy/types": "^4.3.1", + "@smithy/eventstream-serde-universal": "^4.2.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -7973,9 +7856,9 @@ } }, "node_modules/@smithy/eventstream-serde-node/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -7984,12 +7867,12 @@ } }, "node_modules/@smithy/eventstream-serde-universal": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.0.4.tgz", - "integrity": "sha512-UeJpOmLGhq1SLox79QWw/0n2PFX+oPRE1ZyRMxPIaFEfCqWaqpB7BU9C8kpPOGEhLF7AwEqfFbtwNxGy4ReENA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.0.tgz", + "integrity": "sha512-C3jxz6GeRzNyGKhU7oV656ZbuHY93mrfkT12rmjDdZch142ykjn8do+VOkeRNjSGKw01p4g+hdalPYPhmMwk1g==", "dependencies": { - "@smithy/eventstream-codec": "^4.0.4", - "@smithy/types": "^4.3.1", + "@smithy/eventstream-codec": "^4.2.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -7997,9 +7880,9 @@ } }, "node_modules/@smithy/eventstream-serde-universal/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8008,14 +7891,14 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.4.tgz", - "integrity": "sha512-AMtBR5pHppYMVD7z7G+OlHHAcgAN7v0kVKEpHuTO4Gb199Gowh0taYi9oDStFeUhetkeP55JLSVlTW1n9rFtUw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.0.tgz", + "integrity": "sha512-BG3KSmsx9A//KyIfw+sqNmWFr1YBUr+TwpxFT7yPqAk0yyDh7oSNgzfNH7pS6OC099EGx2ltOULvumCFe8bcgw==", "dependencies": { - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", - "@smithy/util-base64": "^4.0.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/querystring-builder": "^4.2.0", + "@smithy/types": "^4.6.0", + "@smithy/util-base64": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -8023,9 +7906,9 @@ } }, "node_modules/@smithy/fetch-http-handler/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8034,13 +7917,13 @@ } }, "node_modules/@smithy/hash-blob-browser": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.0.4.tgz", - "integrity": "sha512-WszRiACJiQV3QG6XMV44i5YWlkrlsM5Yxgz4jvsksuu7LDXA6wAtypfPajtNTadzpJy3KyJPoWehYpmZGKUFIQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.0.tgz", + "integrity": "sha512-MWmrRTPqVKpN8NmxmJPTeQuhewTt8Chf+waB38LXHZoA02+BeWYVQ9ViAwHjug8m7lQb1UWuGqp3JoGDOWvvuA==", "dependencies": { - "@smithy/chunked-blob-reader": "^5.0.0", - "@smithy/chunked-blob-reader-native": "^4.0.0", - "@smithy/types": "^4.3.1", + "@smithy/chunked-blob-reader": "^5.2.0", + "@smithy/chunked-blob-reader-native": "^4.2.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -8048,9 +7931,9 @@ } }, "node_modules/@smithy/hash-blob-browser/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8059,13 +7942,13 @@ } }, "node_modules/@smithy/hash-node": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.4.tgz", - "integrity": "sha512-qnbTPUhCVnCgBp4z4BUJUhOEkVwxiEi1cyFM+Zj6o+aY8OFGxUQleKWq8ltgp3dujuhXojIvJWdoqpm6dVO3lQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.0.tgz", + "integrity": "sha512-ugv93gOhZGysTctZh9qdgng8B+xO0cj+zN0qAZ+Sgh7qTQGPOJbMdIuyP89KNfUyfAqFSNh5tMvC+h2uCpmTtA==", "dependencies": { - "@smithy/types": "^4.3.1", - "@smithy/util-buffer-from": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", + "@smithy/types": "^4.6.0", + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -8073,9 +7956,9 @@ } }, "node_modules/@smithy/hash-node/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8084,12 +7967,12 @@ } }, "node_modules/@smithy/hash-stream-node": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.0.4.tgz", - "integrity": "sha512-wHo0d8GXyVmpmMh/qOR0R7Y46/G1y6OR8U+bSTB4ppEzRxd1xVAQ9xOE9hOc0bSjhz0ujCPAbfNLkLrpa6cevg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.2.0.tgz", + "integrity": "sha512-8dELAuGv+UEjtzrpMeNBZc1sJhO8GxFVV/Yh21wE35oX4lOE697+lsMHBoUIFAUuYkTMIeu0EuJSEsH7/8Y+UQ==", "dependencies": { - "@smithy/types": "^4.3.1", - "@smithy/util-utf8": "^4.0.0", + "@smithy/types": "^4.6.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -8097,9 +7980,9 @@ } }, "node_modules/@smithy/hash-stream-node/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8108,11 +7991,11 @@ } }, "node_modules/@smithy/invalid-dependency": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.4.tgz", - "integrity": "sha512-bNYMi7WKTJHu0gn26wg8OscncTt1t2b8KcsZxvOv56XA6cyXtOAAAaNP7+m45xfppXfOatXF3Sb1MNsLUgVLTw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.0.tgz", + "integrity": "sha512-ZmK5X5fUPAbtvRcUPtk28aqIClVhbfcmfoS4M7UQBTnDdrNxhsrxYVv0ZEl5NaPSyExsPWqL4GsPlRvtlwg+2A==", "dependencies": { - "@smithy/types": "^4.3.1", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -8120,9 +8003,9 @@ } }, "node_modules/@smithy/invalid-dependency/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8131,9 +8014,9 @@ } }, "node_modules/@smithy/is-array-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", - "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.2.0.tgz", + "integrity": "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==", "dependencies": { "tslib": "^2.6.2" }, @@ -8142,12 +8025,12 @@ } }, "node_modules/@smithy/md5-js": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.0.4.tgz", - "integrity": "sha512-uGLBVqcOwrLvGh/v/jw423yWHq/ofUGK1W31M2TNspLQbUV1Va0F5kTxtirkoHawODAZcjXTSGi7JwbnPcDPJg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.2.0.tgz", + "integrity": "sha512-LFEPniXGKRQArFmDQ3MgArXlClFJMsXDteuQQY8WG1/zzv6gVSo96+qpkuu1oJp4MZsKrwchY0cuAoPKzEbaNA==", "dependencies": { - "@smithy/types": "^4.3.1", - "@smithy/util-utf8": "^4.0.0", + "@smithy/types": "^4.6.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -8155,9 +8038,9 @@ } }, "node_modules/@smithy/md5-js/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8166,12 +8049,12 @@ } }, "node_modules/@smithy/middleware-content-length": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.4.tgz", - "integrity": "sha512-F7gDyfI2BB1Kc+4M6rpuOLne5LOcEknH1n6UQB69qv+HucXBR1rkzXBnQTB2q46sFy1PM/zuSJOB532yc8bg3w==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.0.tgz", + "integrity": "sha512-6ZAnwrXFecrA4kIDOcz6aLBhU5ih2is2NdcZtobBDSdSHtE9a+MThB5uqyK4XXesdOCvOcbCm2IGB95birTSOQ==", "dependencies": { - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -8179,9 +8062,9 @@ } }, "node_modules/@smithy/middleware-content-length/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8190,17 +8073,17 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.1.13.tgz", - "integrity": "sha512-xg3EHV/Q5ZdAO5b0UiIMj3RIOCobuS40pBBODguUDVdko6YK6QIzCVRrHTogVuEKglBWqWenRnZ71iZnLL3ZAQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.3.0.tgz", + "integrity": "sha512-jFVjuQeV8TkxaRlcCNg0GFVgg98tscsmIrIwRFeC74TIUyLE3jmY9xgc1WXrPQYRjQNK3aRoaIk6fhFRGOIoGw==", "dependencies": { - "@smithy/core": "^3.6.0", - "@smithy/middleware-serde": "^4.0.8", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", - "@smithy/url-parser": "^4.0.4", - "@smithy/util-middleware": "^4.0.4", + "@smithy/core": "^3.14.0", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -8208,9 +8091,9 @@ } }, "node_modules/@smithy/middleware-endpoint/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8219,28 +8102,28 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.1.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.1.14.tgz", - "integrity": "sha512-eoXaLlDGpKvdmvt+YBfRXE7HmIEtFF+DJCbTPwuLunP0YUnrydl+C4tS+vEM0+nyxXrX3PSUFqC+lP1+EHB1Tw==", - "dependencies": { - "@smithy/node-config-provider": "^4.1.3", - "@smithy/protocol-http": "^5.1.2", - "@smithy/service-error-classification": "^4.0.6", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-retry": "^4.0.6", - "tslib": "^2.6.2", - "uuid": "^9.0.1" + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.0.tgz", + "integrity": "sha512-yaVBR0vQnOnzex45zZ8ZrPzUnX73eUC8kVFaAAbn04+6V7lPtxn56vZEBBAhgS/eqD6Zm86o6sJs6FuQVoX5qg==", + "dependencies": { + "@smithy/node-config-provider": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/service-error-classification": "^4.2.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/uuid": "^1.1.0", + "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, "node_modules/@smithy/middleware-retry/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8248,25 +8131,13 @@ "node": ">=18.0.0" } }, - "node_modules/@smithy/middleware-retry/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/@smithy/middleware-serde": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.8.tgz", - "integrity": "sha512-iSSl7HJoJaGyMIoNn2B7czghOVwJ9nD7TMvLhMWeSB5vt0TnEYyRRqPJu/TqW76WScaNvYYB8nRoiBHR9S1Ddw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.0.tgz", + "integrity": "sha512-rpTQ7D65/EAbC6VydXlxjvbifTf4IH+sADKg6JmAvhkflJO2NvDeyU9qsWUNBelJiQFcXKejUHWRSdmpJmEmiw==", "dependencies": { - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -8274,9 +8145,9 @@ } }, "node_modules/@smithy/middleware-serde/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8285,11 +8156,11 @@ } }, "node_modules/@smithy/middleware-stack": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.4.tgz", - "integrity": "sha512-kagK5ggDrBUCCzI93ft6DjteNSfY8Ulr83UtySog/h09lTIOAJ/xUSObutanlPT0nhoHAkpmW9V5K8oPyLh+QA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.0.tgz", + "integrity": "sha512-G5CJ//eqRd9OARrQu9MK1H8fNm2sMtqFh6j8/rPozhEL+Dokpvi1Og+aCixTuwDAGZUkJPk6hJT5jchbk/WCyg==", "dependencies": { - "@smithy/types": "^4.3.1", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -8297,9 +8168,9 @@ } }, "node_modules/@smithy/middleware-stack/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8308,13 +8179,13 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.1.3.tgz", - "integrity": "sha512-HGHQr2s59qaU1lrVH6MbLlmOBxadtzTsoO4c+bF5asdgVik3I8o7JIOzoeqWc5MjVa+vD36/LWE0iXKpNqooRw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.0.tgz", + "integrity": "sha512-5QgHNuWdT9j9GwMPPJCKxy2KDxZ3E5l4M3/5TatSZrqYVoEiqQrDfAq8I6KWZw7RZOHtVtCzEPdYz7rHZixwcA==", "dependencies": { - "@smithy/property-provider": "^4.0.4", - "@smithy/shared-ini-file-loader": "^4.0.4", - "@smithy/types": "^4.3.1", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -8322,9 +8193,9 @@ } }, "node_modules/@smithy/node-config-provider/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8333,73 +8204,37 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.3.3.tgz", - "integrity": "sha512-BrpZOaZ4RCbcJ2igiSNG16S+kgAc65l/2hmxWdmhyoGWHTLlzQzr06PXavJp9OBlPEG/sHlqdxjWmjzV66+BSQ==", - "dependencies": { - "@smithy/abort-controller": "^3.1.9", - "@smithy/protocol-http": "^4.1.8", - "@smithy/querystring-builder": "^3.0.11", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/node-http-handler/node_modules/@smithy/protocol-http": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.8.tgz", - "integrity": "sha512-hmgIAVyxw1LySOwkgMIUN0kjN8TG9Nc85LJeEmEE/cNEe2rkHDUWhnJf2gxcSRFLWsyqWsrZGw40ROjUogg+Iw==", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/node-http-handler/node_modules/@smithy/querystring-builder": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.11.tgz", - "integrity": "sha512-u+5HV/9uJaeLj5XTb6+IEF/dokWWkEqJ0XiaRRogyREmKGUgZnNecLucADLdauWFKUNbQfulHFEZEdjwEBjXRg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.3.0.tgz", + "integrity": "sha512-RHZ/uWCmSNZ8cneoWEVsVwMZBKy/8123hEpm57vgGXA3Irf/Ja4v9TVshHK2ML5/IqzAZn0WhINHOP9xl+Qy6Q==", "dependencies": { - "@smithy/types": "^3.7.2", - "@smithy/util-uri-escape": "^3.0.0", + "@smithy/abort-controller": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/querystring-builder": "^4.2.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, "node_modules/@smithy/node-http-handler/node_modules/@smithy/types": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.7.2.tgz", - "integrity": "sha512-bNwBYYmN8Eh9RyjS1p2gW6MIhSO2rl7X9QeLM8iTdcGRP+eDiIWDt66c9IysCc22gefKszZv+ubV9qZc7hdESg==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/node-http-handler/node_modules/@smithy/util-uri-escape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", - "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, "node_modules/@smithy/property-provider": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.4.tgz", - "integrity": "sha512-qHJ2sSgu4FqF4U/5UUp4DhXNmdTrgmoAai6oQiM+c5RZ/sbDwJ12qxB1M6FnP+Tn/ggkPZf9ccn4jqKSINaquw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.0.tgz", + "integrity": "sha512-rV6wFre0BU6n/tx2Ztn5LdvEdNZ2FasQbPQmDOPfV9QQyDmsCkOAB0osQjotRCQg+nSKFmINhyda0D3AnjSBJw==", "dependencies": { - "@smithy/types": "^4.3.1", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -8407,9 +8242,9 @@ } }, "node_modules/@smithy/property-provider/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8418,11 +8253,11 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.1.2.tgz", - "integrity": "sha512-rOG5cNLBXovxIrICSBm95dLqzfvxjEmuZx4KK3hWwPFHGdW3lxY0fZNXfv2zebfRO7sJZ5pKJYHScsqopeIWtQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.0.tgz", + "integrity": "sha512-6POSYlmDnsLKb7r1D3SVm7RaYW6H1vcNcTWGWrF7s9+2noNYvUsm7E4tz5ZQ9HXPmKn6Hb67pBDRIjrT4w/d7Q==", "dependencies": { - "@smithy/types": "^4.3.1", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -8430,9 +8265,9 @@ } }, "node_modules/@smithy/protocol-http/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8441,12 +8276,12 @@ } }, "node_modules/@smithy/querystring-builder": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.4.tgz", - "integrity": "sha512-SwREZcDnEYoh9tLNgMbpop+UTGq44Hl9tdj3rf+yeLcfH7+J8OXEBaMc2kDxtyRHu8BhSg9ADEx0gFHvpJgU8w==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.0.tgz", + "integrity": "sha512-Q4oFD0ZmI8yJkiPPeGUITZj++4HHYCW3pYBYfIobUCkYpI6mbkzmG1MAQQ3lJYYWj3iNqfzOenUZu+jqdPQ16A==", "dependencies": { - "@smithy/types": "^4.3.1", - "@smithy/util-uri-escape": "^4.0.0", + "@smithy/types": "^4.6.0", + "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -8454,9 +8289,9 @@ } }, "node_modules/@smithy/querystring-builder/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8465,11 +8300,11 @@ } }, "node_modules/@smithy/querystring-parser": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.4.tgz", - "integrity": "sha512-6yZf53i/qB8gRHH/l2ZwUG5xgkPgQF15/KxH0DdXMDHjesA9MeZje/853ifkSY0x4m5S+dfDZ+c4x439PF0M2w==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.0.tgz", + "integrity": "sha512-BjATSNNyvVbQxOOlKse0b0pSezTWGMvA87SvoFoFlkRsKXVsN3bEtjCxvsNXJXfnAzlWFPaT9DmhWy1vn0sNEA==", "dependencies": { - "@smithy/types": "^4.3.1", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -8477,9 +8312,9 @@ } }, "node_modules/@smithy/querystring-parser/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8488,20 +8323,20 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.6.tgz", - "integrity": "sha512-RRoTDL//7xi4tn5FrN2NzH17jbgmnKidUqd4KvquT0954/i6CXXkh1884jBiunq24g9cGtPBEXlU40W6EpNOOg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.0.tgz", + "integrity": "sha512-Ylv1ttUeKatpR0wEOMnHf1hXMktPUMObDClSWl2TpCVT4DwtJhCeighLzSLbgH3jr5pBNM0LDXT5yYxUvZ9WpA==", "dependencies": { - "@smithy/types": "^4.3.1" + "@smithy/types": "^4.6.0" }, "engines": { "node": ">=18.0.0" } }, "node_modules/@smithy/service-error-classification/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8510,11 +8345,11 @@ } }, "node_modules/@smithy/shared-ini-file-loader": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.4.tgz", - "integrity": "sha512-63X0260LoFBjrHifPDs+nM9tV0VMkOTl4JRMYNuKh/f5PauSjowTfvF3LogfkWdcPoxsA9UjqEOgjeYIbhb7Nw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.3.0.tgz", + "integrity": "sha512-VCUPPtNs+rKWlqqntX0CbVvWyjhmX30JCtzO+s5dlzzxrvSfRh5SY0yxnkirvc1c80vdKQttahL71a9EsdolSQ==", "dependencies": { - "@smithy/types": "^4.3.1", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -8522,9 +8357,9 @@ } }, "node_modules/@smithy/shared-ini-file-loader/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8533,17 +8368,17 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.1.2.tgz", - "integrity": "sha512-d3+U/VpX7a60seHziWnVZOHuEgJlclufjkS6zhXvxcJgkJq4UWdH5eOBLzHRMx6gXjsdT9h6lfpmLzbrdupHgQ==", - "dependencies": { - "@smithy/is-array-buffer": "^4.0.0", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", - "@smithy/util-hex-encoding": "^4.0.0", - "@smithy/util-middleware": "^4.0.4", - "@smithy/util-uri-escape": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.0.tgz", + "integrity": "sha512-MKNyhXEs99xAZaFhm88h+3/V+tCRDQ+PrDzRqL0xdDpq4gjxcMmf5rBA3YXgqZqMZ/XwemZEurCBQMfxZOWq/g==", + "dependencies": { + "@smithy/is-array-buffer": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-hex-encoding": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-uri-escape": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -8551,9 +8386,9 @@ } }, "node_modules/@smithy/signature-v4/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8562,16 +8397,16 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.4.5.tgz", - "integrity": "sha512-+lynZjGuUFJaMdDYSTMnP/uPBBXXukVfrJlP+1U/Dp5SFTEI++w6NMga8DjOENxecOF71V9Z2DllaVDYRnGlkg==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.7.0.tgz", + "integrity": "sha512-3BDx/aCCPf+kkinYf5QQhdQ9UAGihgOVqI3QO5xQfSaIWvUE4KYLtiGRWsNe1SR7ijXC0QEPqofVp5Sb0zC8xQ==", "dependencies": { - "@smithy/core": "^3.6.0", - "@smithy/middleware-endpoint": "^4.1.13", - "@smithy/middleware-stack": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/types": "^4.3.1", - "@smithy/util-stream": "^4.2.2", + "@smithy/core": "^3.14.0", + "@smithy/middleware-endpoint": "^4.3.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-stream": "^4.4.0", "tslib": "^2.6.2" }, "engines": { @@ -8579,9 +8414,9 @@ } }, "node_modules/@smithy/smithy-client/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8601,12 +8436,12 @@ } }, "node_modules/@smithy/url-parser": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.4.tgz", - "integrity": "sha512-eMkc144MuN7B0TDA4U2fKs+BqczVbk3W+qIvcoCY6D1JY3hnAdCuhCZODC+GAeaxj0p6Jroz4+XMUn3PCxQQeQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.0.tgz", + "integrity": "sha512-AlBmD6Idav2ugmoAL6UtR6ItS7jU5h5RNqLMZC7QrLCoITA9NzIN3nx9GWi8g4z1pfWh2r9r96SX/jHiNwPJ9A==", "dependencies": { - "@smithy/querystring-parser": "^4.0.4", - "@smithy/types": "^4.3.1", + "@smithy/querystring-parser": "^4.2.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -8614,9 +8449,9 @@ } }, "node_modules/@smithy/url-parser/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8625,12 +8460,12 @@ } }, "node_modules/@smithy/util-base64": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", - "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.2.0.tgz", + "integrity": "sha512-+erInz8WDv5KPe7xCsJCp+1WCjSbah9gWcmUXc9NqmhyPx59tf7jqFz+za1tRG1Y5KM1Cy1rWCcGypylFp4mvA==", "dependencies": { - "@smithy/util-buffer-from": "^4.0.0", - "@smithy/util-utf8": "^4.0.0", + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -8638,9 +8473,9 @@ } }, "node_modules/@smithy/util-body-length-browser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", - "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.0.tgz", + "integrity": "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg==", "dependencies": { "tslib": "^2.6.2" }, @@ -8649,9 +8484,9 @@ } }, "node_modules/@smithy/util-body-length-node": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.0.0.tgz", - "integrity": "sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.0.tgz", + "integrity": "sha512-U8q1WsSZFjXijlD7a4wsDQOvOwV+72iHSfq1q7VD+V75xP/pdtm0WIGuaFJ3gcADDOKj2MIBn4+zisi140HEnQ==", "dependencies": { "tslib": "^2.6.2" }, @@ -8660,11 +8495,11 @@ } }, "node_modules/@smithy/util-buffer-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", - "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.0.tgz", + "integrity": "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew==", "dependencies": { - "@smithy/is-array-buffer": "^4.0.0", + "@smithy/is-array-buffer": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -8672,9 +8507,9 @@ } }, "node_modules/@smithy/util-config-provider": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.0.0.tgz", - "integrity": "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.0.tgz", + "integrity": "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==", "dependencies": { "tslib": "^2.6.2" }, @@ -8683,13 +8518,13 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.0.21", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.21.tgz", - "integrity": "sha512-wM0jhTytgXu3wzJoIqpbBAG5U6BwiubZ6QKzSbP7/VbmF1v96xlAbX2Am/mz0Zep0NLvLh84JT0tuZnk3wmYQA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.2.0.tgz", + "integrity": "sha512-qzHp7ZDk1Ba4LDwQVCNp90xPGqSu7kmL7y5toBpccuhi3AH7dcVBIT/pUxYcInK4jOy6FikrcTGq5wxcka8UaQ==", "dependencies": { - "@smithy/property-provider": "^4.0.4", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", + "@smithy/property-provider": "^4.2.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", "bowser": "^2.11.0", "tslib": "^2.6.2" }, @@ -8698,9 +8533,9 @@ } }, "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8709,16 +8544,16 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.0.21", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.21.tgz", - "integrity": "sha512-/F34zkoU0GzpUgLJydHY8Rxu9lBn8xQC/s/0M0U9lLBkYbA1htaAFjWYJzpzsbXPuri5D1H8gjp2jBum05qBrA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.0.tgz", + "integrity": "sha512-FxUHS3WXgx3bTWR6yQHNHHkQHZm/XKIi/CchTnKvBulN6obWpcbzJ6lDToXn+Wp0QlVKd7uYAz2/CTw1j7m+Kg==", "dependencies": { - "@smithy/config-resolver": "^4.1.4", - "@smithy/credential-provider-imds": "^4.0.6", - "@smithy/node-config-provider": "^4.1.3", - "@smithy/property-provider": "^4.0.4", - "@smithy/smithy-client": "^4.4.5", - "@smithy/types": "^4.3.1", + "@smithy/config-resolver": "^4.3.0", + "@smithy/credential-provider-imds": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -8726,9 +8561,9 @@ } }, "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8737,12 +8572,12 @@ } }, "node_modules/@smithy/util-endpoints": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.6.tgz", - "integrity": "sha512-YARl3tFL3WgPuLzljRUnrS2ngLiUtkwhQtj8PAL13XZSyUiNLQxwG3fBBq3QXFqGFUXepIN73pINp3y8c2nBmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.0.tgz", + "integrity": "sha512-TXeCn22D56vvWr/5xPqALc9oO+LN+QpFjrSM7peG/ckqEPoI3zaKZFp+bFwfmiHhn5MGWPaLCqDOJPPIixk9Wg==", "dependencies": { - "@smithy/node-config-provider": "^4.1.3", - "@smithy/types": "^4.3.1", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -8750,9 +8585,9 @@ } }, "node_modules/@smithy/util-endpoints/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8761,9 +8596,9 @@ } }, "node_modules/@smithy/util-hex-encoding": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", - "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.0.tgz", + "integrity": "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==", "dependencies": { "tslib": "^2.6.2" }, @@ -8772,11 +8607,11 @@ } }, "node_modules/@smithy/util-middleware": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.4.tgz", - "integrity": "sha512-9MLKmkBmf4PRb0ONJikCbCwORACcil6gUWojwARCClT7RmLzF04hUR4WdRprIXal7XVyrddadYNfp2eF3nrvtQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.0.tgz", + "integrity": "sha512-u9OOfDa43MjagtJZ8AapJcmimP+K2Z7szXn8xbty4aza+7P1wjFmy2ewjSbhEiYQoW1unTlOAIV165weYAaowA==", "dependencies": { - "@smithy/types": "^4.3.1", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -8784,9 +8619,9 @@ } }, "node_modules/@smithy/util-middleware/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8795,12 +8630,12 @@ } }, "node_modules/@smithy/util-retry": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.6.tgz", - "integrity": "sha512-+YekoF2CaSMv6zKrA6iI/N9yva3Gzn4L6n35Luydweu5MMPYpiGZlWqehPHDHyNbnyaYlz/WJyYAZnC+loBDZg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.0.tgz", + "integrity": "sha512-BWSiuGbwRnEE2SFfaAZEX0TqaxtvtSYPM/J73PFVm+A29Fg1HTPiYFb8TmX1DXp4hgcdyJcNQmprfd5foeORsg==", "dependencies": { - "@smithy/service-error-classification": "^4.0.6", - "@smithy/types": "^4.3.1", + "@smithy/service-error-classification": "^4.2.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { @@ -8808,9 +8643,9 @@ } }, "node_modules/@smithy/util-retry/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8819,44 +8654,17 @@ } }, "node_modules/@smithy/util-stream": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.2.2.tgz", - "integrity": "sha512-aI+GLi7MJoVxg24/3J1ipwLoYzgkB4kUfogZfnslcYlynj3xsQ0e7vk4TnTro9hhsS5PvX1mwmkRqqHQjwcU7w==", - "dependencies": { - "@smithy/fetch-http-handler": "^5.0.4", - "@smithy/node-http-handler": "^4.0.6", - "@smithy/types": "^4.3.1", - "@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": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-stream/node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", - "dependencies": { - "@smithy/types": "^4.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-stream/node_modules/@smithy/node-http-handler": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.6.tgz", - "integrity": "sha512-NqbmSz7AW2rvw4kXhKGrYTiJVDHnMsFnX4i+/FzcZAfbOBauPYs2ekuECkSbtqaxETLLTu9Rl/ex6+I2BKErPA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.4.0.tgz", + "integrity": "sha512-vtO7ktbixEcrVzMRmpQDnw/Ehr9UWjBvSJ9fyAbadKkC4w5Cm/4lMO8cHz8Ysb8uflvQUNRcuux/oNHKPXkffg==", "dependencies": { - "@smithy/abort-controller": "^4.0.4", - "@smithy/protocol-http": "^5.1.2", - "@smithy/querystring-builder": "^4.0.4", - "@smithy/types": "^4.3.1", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-hex-encoding": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -8864,9 +8672,9 @@ } }, "node_modules/@smithy/util-stream/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8875,9 +8683,9 @@ } }, "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==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.0.tgz", + "integrity": "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==", "dependencies": { "tslib": "^2.6.2" }, @@ -8886,11 +8694,11 @@ } }, "node_modules/@smithy/util-utf8": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", - "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.0.tgz", + "integrity": "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==", "dependencies": { - "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-buffer-from": "^4.2.0", "tslib": "^2.6.2" }, "engines": { @@ -8898,34 +8706,33 @@ } }, "node_modules/@smithy/util-waiter": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.0.6.tgz", - "integrity": "sha512-slcr1wdRbX7NFphXZOxtxRNA7hXAAtJAXJDE/wdoMAos27SIquVCKiSqfB6/28YzQ8FCsB5NKkhdM5gMADbqxg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.2.0.tgz", + "integrity": "sha512-0Z+nxUU4/4T+SL8BCNN4ztKdQjToNvUYmkF1kXO5T7Yz3Gafzh0HeIG6mrkN8Fz3gn9hSyxuAT+6h4vM+iQSBQ==", "dependencies": { - "@smithy/abort-controller": "^4.0.4", - "@smithy/types": "^4.3.1", + "@smithy/abort-controller": "^4.2.0", + "@smithy/types": "^4.6.0", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@smithy/util-waiter/node_modules/@smithy/abort-controller": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.4.tgz", - "integrity": "sha512-gJnEjZMvigPDQWHrW3oPrFhQtkrgqBkyjj3pCIdF3A5M6vsZODG93KNlfJprv6bp4245bdT32fsHK4kkH3KYDA==", + "node_modules/@smithy/util-waiter/node_modules/@smithy/types": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.6.0.tgz", + "integrity": "sha512-4lI9C8NzRPOv66FaY1LL1O/0v0aLVrq/mXP/keUa9mJOApEeae43LsLd2kZRUJw91gxOQfLIrV3OvqPgWz1YsA==", "dependencies": { - "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@smithy/util-waiter/node_modules/@smithy/types": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.3.1.tgz", - "integrity": "sha512-UqKOQBL2x6+HWl3P+3QqFD4ncKq0I8Nuz9QItGv5WuKuMHuuwlhvqcZCoXGfc+P1QmfJE7VieykoYYmrOoFJxA==", + "node_modules/@smithy/uuid": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.0.tgz", + "integrity": "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==", "dependencies": { "tslib": "^2.6.2" }, @@ -8975,11 +8782,10 @@ "dev": true }, "node_modules/@tybys/wasm-util": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", - "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", "dev": true, - "license": "MIT", "optional": true, "dependencies": { "tslib": "^2.4.0" @@ -9036,12 +8842,12 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", - "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, "dependencies": { - "@babel/types": "^7.20.7" + "@babel/types": "^7.28.2" } }, "node_modules/@types/body-parser": { @@ -9132,15 +8938,13 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/@types/encoding-japanese/-/encoding-japanese-2.2.1.tgz", "integrity": "sha512-6jjepuTusvySxMLP7W6usamlbgf0F4sIDvm7EzYePjLHY7zWUv4yz2PLUnu0vuNVtXOTLu2cRdFcDg40J5Owsw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/escape-html": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-1.0.4.tgz", "integrity": "sha512-qZ72SFTgUAZ5a7Tj6kf2SHLetiH5S6f8G5frB2SPQ3EyF02kxdyBFf4Tz4banE3xCgGnKgWLt//a6VuYHKYJTg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/eslint": { "version": "9.6.1", @@ -9180,9 +8984,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.6", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", - "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "version": "4.19.7", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz", + "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -9328,27 +9132,18 @@ "@types/node": "*" } }, - "node_modules/@types/mute-stream": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz", - "integrity": "sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/node": { - "version": "22.15.34", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.34.tgz", - "integrity": "sha512-8Y6E5WUupYy1Dd0II32BsWAx5MWdcnRd8L84Oys3veg1YrYtNtzgO4CFhiBg6MDSjk7Ay36HYOnU7/tuOzIzcw==", + "version": "22.18.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.8.tgz", + "integrity": "sha512-pAZSHMiagDR7cARo/cch1f3rXy0AEXwsVsVH09FcyeJVAzCnGgmYis7P3JidtTUjyadhTeSo8TgRPswstghDaw==", "dependencies": { "undici-types": "~6.21.0" } }, "node_modules/@types/node-forge": { - "version": "1.3.11", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", - "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "version": "1.3.14", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.14.tgz", + "integrity": "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==", "dependencies": { "@types/node": "*" } @@ -9392,11 +9187,10 @@ "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==" }, "node_modules/@types/send": { - "version": "0.17.5", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", - "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.0.tgz", + "integrity": "sha512-zBF6vZJn1IaMpg3xUF25VK3gd3l8zwE0ZLRX7dsQyQi+jp4E8mMDJNGDYnYse+bQhYwWERTxVwHpi3dMOq7RKQ==", "dependencies": { - "@types/mime": "^1", "@types/node": "*" } }, @@ -9409,13 +9203,22 @@ } }, "node_modules/@types/serve-static": { - "version": "1.15.8", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", - "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.9.tgz", + "integrity": "sha512-dOTIuqpWLyl3BBXU3maNQsS4A3zuuoYRNIvYSxxhebPfXg2mzWQEPne/nlJ37yOse6uGgR386uTpdsx4D0QZWA==", "dependencies": { "@types/http-errors": "*", "@types/node": "*", - "@types/send": "*" + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", + "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" } }, "node_modules/@types/sinon": { @@ -9469,9 +9272,9 @@ "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==" }, "node_modules/@types/vscode": { - "version": "1.101.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.101.0.tgz", - "integrity": "sha512-ZWf0IWa+NGegdW3iU42AcDTFHWW7fApLdkdnBqwYEtHVIBGbTu0ZNQKP/kX3Ds/uMJXIMQNAojHR4vexCEEz5Q==", + "version": "1.104.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.104.0.tgz", + "integrity": "sha512-0KwoU2rZ2ecsTGFxo4K1+f+AErRsYW0fsp6A0zufzGuhyczc2IoKqYqcwXidKXmy2u8YB2GsYsOtiI9Izx3Tig==", "dev": true }, "node_modules/@types/which": { @@ -9480,12 +9283,6 @@ "integrity": "sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==", "dev": true }, - "node_modules/@types/wrap-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", - "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==", - "dev": true - }, "node_modules/@types/ws": { "version": "8.18.1", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", @@ -9533,22 +9330,21 @@ "resolved": "https://registry.npmjs.org/@types/yauzl-promise/-/yauzl-promise-4.0.1.tgz", "integrity": "sha512-qYEC3rJwqiJpdQ9b+bPNeuSY0c3JUM8vIuDy08qfuVN7xHm3ZDsHn2kGphUIB0ruEXrPGNXZ64nMUcu4fDjViQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.35.0.tgz", - "integrity": "sha512-ijItUYaiWuce0N1SoSMrEd0b6b6lYkYt99pqCPfybd+HKVXtEvYhICfLdwp42MhiI5mp0oq7PKEL+g1cNiz/Eg==", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.0.tgz", + "integrity": "sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.35.0", - "@typescript-eslint/type-utils": "8.35.0", - "@typescript-eslint/utils": "8.35.0", - "@typescript-eslint/visitor-keys": "8.35.0", + "@typescript-eslint/scope-manager": "8.46.0", + "@typescript-eslint/type-utils": "8.46.0", + "@typescript-eslint/utils": "8.46.0", + "@typescript-eslint/visitor-keys": "8.46.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -9562,21 +9358,21 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.35.0", + "@typescript-eslint/parser": "^8.46.0", "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.35.0.tgz", - "integrity": "sha512-6sMvZePQrnZH2/cJkwRpkT7DxoAWh+g6+GFRK6bV3YQo7ogi3SX5rgF6099r5Q53Ma5qeT7LGmOmuIutF4t3lA==", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.0.tgz", + "integrity": "sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.35.0", - "@typescript-eslint/types": "8.35.0", - "@typescript-eslint/typescript-estree": "8.35.0", - "@typescript-eslint/visitor-keys": "8.35.0", + "@typescript-eslint/scope-manager": "8.46.0", + "@typescript-eslint/types": "8.46.0", + "@typescript-eslint/typescript-estree": "8.46.0", + "@typescript-eslint/visitor-keys": "8.46.0", "debug": "^4.3.4" }, "engines": { @@ -9588,17 +9384,17 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.35.0.tgz", - "integrity": "sha512-41xatqRwWZuhUMF/aZm2fcUsOFKNcG28xqRSS6ZVr9BVJtGExosLAm5A1OxTjRMagx8nJqva+P5zNIGt8RIgbQ==", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.0.tgz", + "integrity": "sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==", "dev": true, "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.35.0", - "@typescript-eslint/types": "^8.35.0", + "@typescript-eslint/tsconfig-utils": "^8.46.0", + "@typescript-eslint/types": "^8.46.0", "debug": "^4.3.4" }, "engines": { @@ -9609,17 +9405,17 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.35.0.tgz", - "integrity": "sha512-+AgL5+mcoLxl1vGjwNfiWq5fLDZM1TmTPYs2UkyHfFhgERxBbqHlNjRzhThJqz+ktBqTChRYY6zwbMwy0591AA==", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.0.tgz", + "integrity": "sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.35.0", - "@typescript-eslint/visitor-keys": "8.35.0" + "@typescript-eslint/types": "8.46.0", + "@typescript-eslint/visitor-keys": "8.46.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9630,9 +9426,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.35.0.tgz", - "integrity": "sha512-04k/7247kZzFraweuEirmvUj+W3bJLI9fX6fbo1Qm2YykuBvEhRTPl8tcxlYO8kZZW+HIXfkZNoasVb8EV4jpA==", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.0.tgz", + "integrity": "sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9642,17 +9438,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.35.0.tgz", - "integrity": "sha512-ceNNttjfmSEoM9PW87bWLDEIaLAyR+E6BoYJQ5PfaDau37UGca9Nyq3lBk8Bw2ad0AKvYabz6wxc7DMTO2jnNA==", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.0.tgz", + "integrity": "sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.35.0", - "@typescript-eslint/utils": "8.35.0", + "@typescript-eslint/types": "8.46.0", + "@typescript-eslint/typescript-estree": "8.46.0", + "@typescript-eslint/utils": "8.46.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -9665,13 +9462,13 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.35.0.tgz", - "integrity": "sha512-0mYH3emanku0vHw2aRLNGqe7EXh9WHEhi7kZzscrMDf6IIRUQ5Jk4wp1QrledE/36KtdZrVfKnE32eZCf/vaVQ==", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.0.tgz", + "integrity": "sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9682,15 +9479,15 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.35.0.tgz", - "integrity": "sha512-F+BhnaBemgu1Qf8oHrxyw14wq6vbL8xwWKKMwTMwYIRmFFY/1n/9T/jpbobZL8vp7QyEUcC6xGrnAO4ua8Kp7w==", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.0.tgz", + "integrity": "sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==", "dev": true, "dependencies": { - "@typescript-eslint/project-service": "8.35.0", - "@typescript-eslint/tsconfig-utils": "8.35.0", - "@typescript-eslint/types": "8.35.0", - "@typescript-eslint/visitor-keys": "8.35.0", + "@typescript-eslint/project-service": "8.46.0", + "@typescript-eslint/tsconfig-utils": "8.46.0", + "@typescript-eslint/types": "8.46.0", + "@typescript-eslint/visitor-keys": "8.46.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -9706,31 +9503,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.35.0.tgz", - "integrity": "sha512-nqoMu7WWM7ki5tPgLVsmPM8CkqtoPUG6xXGeefM5t4x3XumOEKMoUZPdi+7F+/EotukN4R9OWdmDxN80fqoZeg==", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.0.tgz", + "integrity": "sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.35.0", - "@typescript-eslint/types": "8.35.0", - "@typescript-eslint/typescript-estree": "8.35.0" + "@typescript-eslint/scope-manager": "8.46.0", + "@typescript-eslint/types": "8.46.0", + "@typescript-eslint/typescript-estree": "8.46.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9741,16 +9526,16 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.35.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.35.0.tgz", - "integrity": "sha512-zTh2+1Y8ZpmeQaQVIc/ZZxsx8UzgKJyNg1PTvjzC7WMhPSVS8bfDX34k1SrwOf016qd5RU3az2UxUNue3IfQ5g==", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.0.tgz", + "integrity": "sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.35.0", + "@typescript-eslint/types": "8.46.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -9806,34 +9591,30 @@ } }, "node_modules/@wdio/cli": { - "version": "9.16.2", - "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-9.16.2.tgz", - "integrity": "sha512-mb17CsZ+mM5WBSDA3/Nx0snCitqTWyRVzRfTjP1yOMMgVmc6toZ8b7Nfbv30nvn/bZiZ/jQFAL2SyafpJEMYcw==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-9.20.0.tgz", + "integrity": "sha512-dGkZFp09aIyoN6HlJah7zJApG/FzN0O/HaTfTkWrOM5GBli9th/9VIfbsT3vx4I9mBdETiYPmgfl4LqDP2p0VQ==", "dev": true, "dependencies": { - "@types/node": "^20.1.1", "@vitest/snapshot": "^2.1.1", - "@wdio/config": "9.16.2", - "@wdio/globals": "9.16.2", - "@wdio/logger": "9.16.2", + "@wdio/config": "9.20.0", + "@wdio/globals": "9.17.0", + "@wdio/logger": "9.18.0", "@wdio/protocols": "9.16.2", - "@wdio/types": "9.16.2", - "@wdio/utils": "9.16.2", + "@wdio/types": "9.20.0", + "@wdio/utils": "9.20.0", "async-exit-hook": "^2.0.1", - "chalk": "^5.2.0", + "chalk": "^5.4.1", "chokidar": "^4.0.0", - "dotenv": "^16.3.1", - "ejs": "^3.1.9", - "execa": "^9.2.0", + "create-wdio": "9.18.2", + "dotenv": "^17.2.0", "import-meta-resolve": "^4.0.0", - "inquirer": "^11.0.1", "lodash.flattendeep": "^4.4.0", "lodash.pickby": "^4.6.0", "lodash.union": "^4.6.0", "read-pkg-up": "^10.0.0", - "recursive-readdir": "^2.2.3", "tsx": "^4.7.2", - "webdriverio": "9.16.2", + "webdriverio": "9.20.0", "yargs": "^17.7.2" }, "bin": { @@ -9843,167 +9624,190 @@ "node": ">=18.20.0" } }, - "node_modules/@wdio/cli/node_modules/@types/node": { - "version": "20.19.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.2.tgz", - "integrity": "sha512-9pLGGwdzOUBDYi0GNjM97FIA+f92fqSke6joWeBjWXllfNxZBs7qeMF7tvtOIsbY45xkWkxrdwUfUf3MnQa9gA==", - "dev": true, - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@wdio/cli/node_modules/execa": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.0.tgz", - "integrity": "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==", + "node_modules/@wdio/cli/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", "dev": true, "dependencies": { - "@sindresorhus/merge-streams": "^4.0.0", - "cross-spawn": "^7.0.6", - "figures": "^6.1.0", - "get-stream": "^9.0.0", - "human-signals": "^8.0.1", - "is-plain-obj": "^4.1.0", - "is-stream": "^4.0.1", - "npm-run-path": "^6.0.0", - "pretty-ms": "^9.2.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^4.0.0", - "yoctocolors": "^2.1.1" + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" }, "engines": { - "node": "^18.19.0 || >=20.5.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/cli/node_modules/get-stream": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", - "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "node_modules/@wdio/cli/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", "dev": true, "dependencies": { - "@sec-ant/readable-stream": "^0.4.1", - "is-stream": "^4.0.1" + "lru-cache": "^10.0.1" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@wdio/cli/node_modules/human-signals": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", - "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "node_modules/@wdio/cli/node_modules/json-parse-even-better-errors": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", "dev": true, "engines": { - "node": ">=18.18.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/@wdio/cli/node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "node_modules/@wdio/cli/node_modules/lines-and-columns": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", + "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", "dev": true, "engines": { - "node": ">=12" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@wdio/cli/node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@wdio/cli/node_modules/is-stream": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", - "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "node_modules/@wdio/cli/node_modules/parse-json": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.1.1.tgz", + "integrity": "sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==", "dev": true, + "dependencies": { + "@babel/code-frame": "^7.21.4", + "error-ex": "^1.3.2", + "json-parse-even-better-errors": "^3.0.0", + "lines-and-columns": "^2.0.3", + "type-fest": "^3.8.0" + }, "engines": { - "node": ">=18" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/cli/node_modules/npm-run-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", - "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "node_modules/@wdio/cli/node_modules/parse-json/node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", "dev": true, - "dependencies": { - "path-key": "^4.0.0", - "unicorn-magic": "^0.3.0" - }, "engines": { - "node": ">=18" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/cli/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "node_modules/@wdio/cli/node_modules/read-pkg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.1.0.tgz", + "integrity": "sha512-PORM8AgzXeskHO/WEv312k9U03B8K9JSiWF/8N9sUuFjBa+9SF2u6K7VClzXwDXab51jCd8Nd36CNM+zR97ScQ==", "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^6.0.0", + "parse-json": "^7.0.0", + "type-fest": "^4.2.0" + }, "engines": { - "node": ">=12" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/cli/node_modules/strip-final-newline": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", - "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "node_modules/@wdio/cli/node_modules/read-pkg-up": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-10.1.0.tgz", + "integrity": "sha512-aNtBq4jR8NawpKJQldrQcSW9y/d+KWH4v24HWkHljOZ7H0av+YTGANBzRh9A5pw7v/bLVsLVPpOhJ7gHNVy8lA==", "dev": true, + "dependencies": { + "find-up": "^6.3.0", + "read-pkg": "^8.1.0", + "type-fest": "^4.2.0" + }, "engines": { - "node": ">=18" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@wdio/cli/node_modules/unicorn-magic": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", - "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "node_modules/@wdio/cli/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "dev": true, "engines": { - "node": ">=18" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@wdio/config": { - "version": "9.16.2", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-9.16.2.tgz", - "integrity": "sha512-a7zDSNzpGgkb6mWrg9GWPmvh/sZFzaf86/iBjCv+n2DTY0+8v8NLruRQmWuCaQAlLVhM3XAqmB+fWLqxDhdvOA==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-9.20.0.tgz", + "integrity": "sha512-ggwd3EMsVj/LTcbYw2h+hma+/7fQ1cTXMuy9B5WTkLjDlOtbLjsqs9QLt4BLIo1cdsxvAw/UVpRVUuYy7rTmtQ==", "dev": true, "dependencies": { - "@wdio/logger": "9.16.2", - "@wdio/types": "9.16.2", - "@wdio/utils": "9.16.2", + "@wdio/logger": "9.18.0", + "@wdio/types": "9.20.0", + "@wdio/utils": "9.20.0", "deepmerge-ts": "^7.0.3", "glob": "^10.2.2", - "import-meta-resolve": "^4.0.0" + "import-meta-resolve": "^4.0.0", + "jiti": "^2.5.1" }, "engines": { "node": ">=18.20.0" } }, + "node_modules/@wdio/config/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@wdio/dot-reporter": { - "version": "9.16.2", - "resolved": "https://registry.npmjs.org/@wdio/dot-reporter/-/dot-reporter-9.16.2.tgz", - "integrity": "sha512-JzFegviZdpzgvt8w8uwI0pyJguIuJzfzlkkyWz1WUoqtilH4yrf5IYKzObnm3peh7iQ/y2J1SSeAjKr0Hr5xTg==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@wdio/dot-reporter/-/dot-reporter-9.20.0.tgz", + "integrity": "sha512-lRhihDQ56dApJcKOIEkVHThl8t2e5h7f3FW3JVmMLcGgbbkkLgXqVWPpbEGJcLld3wL4CipAPojVE/YEWp80hw==", "dev": true, "dependencies": { - "@wdio/reporter": "9.16.2", - "@wdio/types": "9.16.2", + "@wdio/reporter": "9.20.0", + "@wdio/types": "9.20.0", "chalk": "^5.0.1" }, "engines": { @@ -10011,15 +9815,15 @@ } }, "node_modules/@wdio/globals": { - "version": "9.16.2", - "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-9.16.2.tgz", - "integrity": "sha512-PBPBfNPIVC76g6IXadZQeqo6TwjVnfCW31PBVgYsTuhb1MB2wQi00rkBP8JFndr7C0Lhyce+gdIJl6VXURO0FA==", + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-9.17.0.tgz", + "integrity": "sha512-i38o7wlipLllNrk2hzdDfAmk6nrqm3lR2MtAgWgtHbwznZAKkB84KpkNFfmUXw5Kg3iP1zKlSjwZpKqenuLc+Q==", "dev": true, "engines": { "node": ">=18.20.0" }, "peerDependencies": { - "expect-webdriverio": "^5.3.2", + "expect-webdriverio": "^5.3.4", "webdriverio": "^9.0.0" }, "peerDependenciesMeta": { @@ -10032,18 +9836,19 @@ } }, "node_modules/@wdio/local-runner": { - "version": "9.16.2", - "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-9.16.2.tgz", - "integrity": "sha512-ChHTXXknq8hDXhyMjjtWiPqsXenyvxrHqqgq3zDI8EXuGNjVfG6/CzcKXyry7LBXq2Bu78LoymKfvoLdZu+7JQ==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-9.20.0.tgz", + "integrity": "sha512-Q2zuSlWVf/GEuzV1c5xGHSH8Y/l9GXZQBZgXeNLp9unVMP4dqQToHgadMihW+8owdva7LVMjoGa2dxcdE6m8HQ==", "dev": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/logger": "9.16.2", + "@wdio/logger": "9.18.0", "@wdio/repl": "9.16.2", - "@wdio/runner": "9.16.2", - "@wdio/types": "9.16.2", + "@wdio/runner": "9.20.0", + "@wdio/types": "9.20.0", + "@wdio/xvfb": "9.20.0", "exit-hook": "^4.0.0", - "expect-webdriverio": "^5.3.2", + "expect-webdriverio": "^5.3.4", "split2": "^4.1.0", "stream-buffers": "^3.0.2" }, @@ -10052,23 +9857,24 @@ } }, "node_modules/@wdio/local-runner/node_modules/@types/node": { - "version": "20.19.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.2.tgz", - "integrity": "sha512-9pLGGwdzOUBDYi0GNjM97FIA+f92fqSke6joWeBjWXllfNxZBs7qeMF7tvtOIsbY45xkWkxrdwUfUf3MnQa9gA==", + "version": "20.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.19.tgz", + "integrity": "sha512-pb1Uqj5WJP7wrcbLU7Ru4QtA0+3kAXrkutGiD26wUKzSMgNNaPARTUDQmElUXp64kh3cWdou3Q0C7qwwxqSFmg==", "dev": true, "dependencies": { "undici-types": "~6.21.0" } }, "node_modules/@wdio/logger": { - "version": "9.16.2", - "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-9.16.2.tgz", - "integrity": "sha512-6A1eVpNPToWupLIo8CXStth4HJGTfxKsAiKtwE0xQFKyDM8uPTm3YO3Nf15vCSHbmsncbYVEo7QrUwRUEB4YUg==", + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-9.18.0.tgz", + "integrity": "sha512-HdzDrRs+ywAqbXGKqe1i/bLtCv47plz4TvsHFH3j729OooT5VH38ctFn5aLXgECmiAKDkmH/A6kOq2Zh5DIxww==", "dev": true, "dependencies": { "chalk": "^5.1.2", "loglevel": "^1.6.0", "loglevel-plugin-prefix": "^0.8.4", + "safe-regex2": "^5.0.0", "strip-ansi": "^7.1.0" }, "engines": { @@ -10076,9 +9882,9 @@ } }, "node_modules/@wdio/logger/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, "engines": { "node": ">=12" @@ -10088,9 +9894,9 @@ } }, "node_modules/@wdio/logger/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "dev": true, "dependencies": { "ansi-regex": "^6.0.1" @@ -10103,16 +9909,16 @@ } }, "node_modules/@wdio/mocha-framework": { - "version": "9.16.2", - "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-9.16.2.tgz", - "integrity": "sha512-t+SxdS539Gy0iYudmCWV8FSDGQLdTKR8dnYTaPePCGXI3kkeh95h9ODloLOITOi/ndjLe5vsFH/Vd5rBr12rFA==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-9.20.0.tgz", + "integrity": "sha512-kqLaGJ2okdNyOjBsTJcmZ9fvl2nrcdbgaXHk9V1znhAzuHiTEPicaIRPG5T0Itb/vOKb72rp0BdisuJ/PBfs7g==", "dev": true, "dependencies": { "@types/mocha": "^10.0.6", "@types/node": "^20.11.28", - "@wdio/logger": "9.16.2", - "@wdio/types": "9.16.2", - "@wdio/utils": "9.16.2", + "@wdio/logger": "9.18.0", + "@wdio/types": "9.20.0", + "@wdio/utils": "9.20.0", "mocha": "^10.3.0" }, "engines": { @@ -10120,29 +9926,14 @@ } }, "node_modules/@wdio/mocha-framework/node_modules/@types/node": { - "version": "20.19.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.2.tgz", - "integrity": "sha512-9pLGGwdzOUBDYi0GNjM97FIA+f92fqSke6joWeBjWXllfNxZBs7qeMF7tvtOIsbY45xkWkxrdwUfUf3MnQa9gA==", + "version": "20.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.19.tgz", + "integrity": "sha512-pb1Uqj5WJP7wrcbLU7Ru4QtA0+3kAXrkutGiD26wUKzSMgNNaPARTUDQmElUXp64kh3cWdou3Q0C7qwwxqSFmg==", "dev": true, "dependencies": { "undici-types": "~6.21.0" } }, - "node_modules/@wdio/mocha-framework/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@wdio/mocha-framework/node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -10187,12 +9978,6 @@ "node": ">=0.3.1" } }, - "node_modules/@wdio/mocha-framework/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "node_modules/@wdio/mocha-framework/node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -10241,6 +10026,15 @@ "node": ">= 6" } }, + "node_modules/@wdio/mocha-framework/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/@wdio/mocha-framework/node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -10303,6 +10097,21 @@ "node": ">= 14.0.0" } }, + "node_modules/@wdio/mocha-framework/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@wdio/mocha-framework/node_modules/p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", @@ -10327,18 +10136,6 @@ "node": ">=8" } }, - "node_modules/@wdio/mocha-framework/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/@wdio/mocha-framework/node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -10386,23 +10183,6 @@ "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", "dev": true }, - "node_modules/@wdio/mocha-framework/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@wdio/mocha-framework/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -10430,6 +10210,18 @@ "node": ">=10" } }, + "node_modules/@wdio/mocha-framework/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@wdio/protocols": { "version": "9.16.2", "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.16.2.tgz", @@ -10449,24 +10241,24 @@ } }, "node_modules/@wdio/repl/node_modules/@types/node": { - "version": "20.19.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.2.tgz", - "integrity": "sha512-9pLGGwdzOUBDYi0GNjM97FIA+f92fqSke6joWeBjWXllfNxZBs7qeMF7tvtOIsbY45xkWkxrdwUfUf3MnQa9gA==", + "version": "20.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.19.tgz", + "integrity": "sha512-pb1Uqj5WJP7wrcbLU7Ru4QtA0+3kAXrkutGiD26wUKzSMgNNaPARTUDQmElUXp64kh3cWdou3Q0C7qwwxqSFmg==", "dev": true, "dependencies": { "undici-types": "~6.21.0" } }, "node_modules/@wdio/reporter": { - "version": "9.16.2", - "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-9.16.2.tgz", - "integrity": "sha512-th+APMRuK03OzpiJKnfhCwnXoJb57mRmP/NQYGc+k9GEF3Z3yPDD7LxnBlwPANGxt/hdzirQ6OvQyJYLwpmmuQ==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-9.20.0.tgz", + "integrity": "sha512-HjKJzm8o0MCcnwGVGprzaCAyau0OB8mWHwH1ZI/ka+z1nmVBr2tsr7H53SdHsGIhAg/XuZObobqdzeVF63ApeA==", "dev": true, "dependencies": { "@types/node": "^20.1.0", - "@wdio/logger": "9.16.2", - "@wdio/types": "9.16.2", - "diff": "^7.0.0", + "@wdio/logger": "9.18.0", + "@wdio/types": "9.20.0", + "diff": "^8.0.2", "object-inspect": "^1.12.0" }, "engines": { @@ -10474,36 +10266,45 @@ } }, "node_modules/@wdio/reporter/node_modules/@types/node": { - "version": "20.19.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.2.tgz", - "integrity": "sha512-9pLGGwdzOUBDYi0GNjM97FIA+f92fqSke6joWeBjWXllfNxZBs7qeMF7tvtOIsbY45xkWkxrdwUfUf3MnQa9gA==", + "version": "20.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.19.tgz", + "integrity": "sha512-pb1Uqj5WJP7wrcbLU7Ru4QtA0+3kAXrkutGiD26wUKzSMgNNaPARTUDQmElUXp64kh3cWdou3Q0C7qwwxqSFmg==", "dev": true, "dependencies": { "undici-types": "~6.21.0" } }, + "node_modules/@wdio/reporter/node_modules/diff": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/@wdio/runner": { - "version": "9.16.2", - "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-9.16.2.tgz", - "integrity": "sha512-cETsJivOD2yzJfzwKi1n7NNXL3zF/yTcA+578fiu48iGVmhOJNhgW9sv4oVH/aDCt09PPUZw6DEBOT3mcKDSGw==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-9.20.0.tgz", + "integrity": "sha512-z6CFANs5F02ww5mDTF1WUc1DA2mqJiCPKGr+xNXhpd3YH+537aFSsjww/S5SO4gFlAwf0cQiQZTKWUY3uJUGJQ==", "dev": true, "dependencies": { "@types/node": "^20.11.28", - "@wdio/config": "9.16.2", - "@wdio/dot-reporter": "9.16.2", - "@wdio/globals": "9.16.2", - "@wdio/logger": "9.16.2", - "@wdio/types": "9.16.2", - "@wdio/utils": "9.16.2", + "@wdio/config": "9.20.0", + "@wdio/dot-reporter": "9.20.0", + "@wdio/globals": "9.17.0", + "@wdio/logger": "9.18.0", + "@wdio/types": "9.20.0", + "@wdio/utils": "9.20.0", "deepmerge-ts": "^7.0.3", - "webdriver": "9.16.2", - "webdriverio": "9.16.2" + "webdriver": "9.20.0", + "webdriverio": "9.20.0" }, "engines": { "node": ">=18.20.0" }, "peerDependencies": { - "expect-webdriverio": "^5.3.2", + "expect-webdriverio": "^5.3.4", "webdriverio": "^9.0.0" }, "peerDependenciesMeta": { @@ -10516,22 +10317,22 @@ } }, "node_modules/@wdio/runner/node_modules/@types/node": { - "version": "20.19.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.2.tgz", - "integrity": "sha512-9pLGGwdzOUBDYi0GNjM97FIA+f92fqSke6joWeBjWXllfNxZBs7qeMF7tvtOIsbY45xkWkxrdwUfUf3MnQa9gA==", + "version": "20.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.19.tgz", + "integrity": "sha512-pb1Uqj5WJP7wrcbLU7Ru4QtA0+3kAXrkutGiD26wUKzSMgNNaPARTUDQmElUXp64kh3cWdou3Q0C7qwwxqSFmg==", "dev": true, "dependencies": { "undici-types": "~6.21.0" } }, "node_modules/@wdio/spec-reporter": { - "version": "9.16.2", - "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-9.16.2.tgz", - "integrity": "sha512-14HhLSvc+sHns0v07yL8MTfd9BVQ1VhEsywQFA6RbFvKc5PkyoLcxmQSzcH0FOjHhXAfwBh6YxL1mbJwy6+L+w==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-9.20.0.tgz", + "integrity": "sha512-YHj3kF86RoOVVR+k3eb+e/Fki6Mq1FIrJQ380Cz5SSWbIc9gL8HXG3ydReldY6/80KLFOuHn9ZHvDHrCIXRjiw==", "dev": true, "dependencies": { - "@wdio/reporter": "9.16.2", - "@wdio/types": "9.16.2", + "@wdio/reporter": "9.20.0", + "@wdio/types": "9.20.0", "chalk": "^5.1.2", "easy-table": "^1.2.0", "pretty-ms": "^9.0.0" @@ -10541,9 +10342,9 @@ } }, "node_modules/@wdio/types": { - "version": "9.16.2", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-9.16.2.tgz", - "integrity": "sha512-P86FvM/4XQGpJKwlC2RKF3I21TglPvPOozJGG9HoL0Jmt6jRF20ggO/nRTxU0XiWkRdqESUTmfA87bdCO4GRkQ==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-9.20.0.tgz", + "integrity": "sha512-zMmAtse2UMCSOW76mvK3OejauAdcFGuKopNRH7crI0gwKTZtvV89yXWRziz9cVXpFgfmJCjf9edxKFWdhuF5yw==", "dev": true, "dependencies": { "@types/node": "^20.1.0" @@ -10553,30 +10354,31 @@ } }, "node_modules/@wdio/types/node_modules/@types/node": { - "version": "20.19.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.2.tgz", - "integrity": "sha512-9pLGGwdzOUBDYi0GNjM97FIA+f92fqSke6joWeBjWXllfNxZBs7qeMF7tvtOIsbY45xkWkxrdwUfUf3MnQa9gA==", + "version": "20.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.19.tgz", + "integrity": "sha512-pb1Uqj5WJP7wrcbLU7Ru4QtA0+3kAXrkutGiD26wUKzSMgNNaPARTUDQmElUXp64kh3cWdou3Q0C7qwwxqSFmg==", "dev": true, "dependencies": { "undici-types": "~6.21.0" } }, "node_modules/@wdio/utils": { - "version": "9.16.2", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-9.16.2.tgz", - "integrity": "sha512-bsRdEUXUTYvznXH/Z+p6HDzHSjMI6I6bnu8WXWTeDDDyqybWK5D8cbZvs8A/kMmGXoz1GZkSBHxy4Z5NTg8OQg==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-9.20.0.tgz", + "integrity": "sha512-T1ze005kncUTocYImSBQc/FAVcOwP/vOU4MDJFgzz/RTcps600qcKX98sVdWM5/ukXCVkjOufWteDHIbX5/tEA==", "dev": true, "dependencies": { "@puppeteer/browsers": "^2.2.0", - "@wdio/logger": "9.16.2", - "@wdio/types": "9.16.2", + "@wdio/logger": "9.18.0", + "@wdio/types": "9.20.0", "decamelize": "^6.0.0", "deepmerge-ts": "^7.0.3", - "edgedriver": "^6.1.1", + "edgedriver": "^6.1.2", "geckodriver": "^5.0.0", "get-port": "^7.0.0", "import-meta-resolve": "^4.0.0", "locate-app": "^2.2.24", + "mitt": "^3.0.1", "safaridriver": "^1.0.0", "split2": "^4.2.0", "wait-port": "^1.1.0" @@ -10586,9 +10388,9 @@ } }, "node_modules/@wdio/utils/node_modules/decamelize": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", - "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.1.tgz", + "integrity": "sha512-G7Cqgaelq68XHJNGlZ7lrNQyhZGsFqpwtGFexqUv4IQdjKoSYF7ipZ9UuTJZUSQXFj/XaoBLuEVIVqr8EJngEQ==", "dev": true, "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -10597,6 +10399,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@wdio/xvfb": { + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/@wdio/xvfb/-/xvfb-9.20.0.tgz", + "integrity": "sha512-shllZH9CsLiZqTXkqBTJrwi6k/ajBE7/78fQgvafMUIQU1Hpb2RdsmydKfPFZ5NDoA+LNm67PD2cPkvkXy4pSw==", + "dev": true, + "dependencies": { + "@wdio/logger": "9.18.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -10800,14 +10614,14 @@ "devOptional": true }, "node_modules/@zip.js/zip.js": { - "version": "2.7.62", - "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.62.tgz", - "integrity": "sha512-OaLvZ8j4gCkLn048ypkZu29KX30r8/OfFF2w4Jo5WXFr+J04J+lzJ5TKZBVgFXhlvSkqNFQdfnY1Q8TMTCyBVA==", + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.8.7.tgz", + "integrity": "sha512-8daf29EMM3gUpH/vSBSCYo2bY/wbamgRPxPpE2b+cDnbOLBHAcZikWad79R4Guemth/qtipzEHrZMq1lFXxWIA==", "dev": true, "engines": { "bun": ">=0.7.0", "deno": ">=1.0.0", - "node": ">=16.5.0" + "node": ">=18.0.0" } }, "node_modules/abbrev": { @@ -10839,6 +10653,17 @@ "node": ">= 0.6" } }, + "node_modules/accepts/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -10851,6 +10676,18 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "devOptional": true, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -10881,9 +10718,9 @@ } }, "node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "engines": { "node": ">= 14" } @@ -10954,6 +10791,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-html-community": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", @@ -10974,38 +10823,38 @@ } }, "node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/antlr4-c3": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/antlr4-c3/-/antlr4-c3-3.4.2.tgz", - "integrity": "sha512-rISIjeelkeun6Y/YrdVqWtJBDg7SRT9d0Cqov8f6vGe5O5w8wY9HE00jcdevcRjwYOSExHjFi/gUqC3BMSvBuQ==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/antlr4-c3/-/antlr4-c3-3.4.4.tgz", + "integrity": "sha512-ixp1i17ypbRzZnffdarIfCVEXJwPydtDt61SHMGkc+UCD7rrbfvHESTMTgx8jFhUgKAgcHyt9060kQ8nU3vlxA==", "dependencies": { - "antlr4ng": "3.0.14" + "antlr4ng": "3.0.16" } }, "node_modules/antlr4ng": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/antlr4ng/-/antlr4ng-3.0.14.tgz", - "integrity": "sha512-EVEn3B3zpxgbq/731dhwMYCls9e8mAudBvo479hoXbX/yTL24Do1HNZEU+v1U6GayIFrow5EcHMdyXqqRXTtBw==", - "peerDependencies": { - "antlr4ng-cli": "^2.0.0" - } + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/antlr4ng/-/antlr4ng-3.0.16.tgz", + "integrity": "sha512-DQuJkC7kX3xunfF4K2KsWTSvoxxslv+FQp/WHQZTJSsH2Ec3QfFmrxC3Nky2ok9yglXn6nHM4zUaVDxcN5f6kA==" }, "node_modules/antlr4ng-cli": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/antlr4ng-cli/-/antlr4ng-cli-2.0.0.tgz", "integrity": "sha512-oAt5OSSYhRQn1PgahtpAP4Vp3BApCoCqlzX7Q8ZUWWls4hX59ryYuu0t7Hwrnfk796OxP/vgIJaqxdltd/oEvQ==", "deprecated": "This package is deprecated and will no longer be updated. Please use the new antlr-ng package instead: https://github.com/mike-lischke/antlr-ng", + "dev": true, "bin": { "antlr4ng": "index.js" } @@ -11022,22 +10871,10 @@ "node": ">= 8" } }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "license": "ISC" + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, "node_modules/archiver": { "version": "7.0.1", @@ -11073,78 +10910,211 @@ "node": ">= 14" } }, - "node_modules/are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "deprecated": "This package is no longer supported.", - "license": "ISC", + "node_modules/archiver-utils/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, - "node_modules/are-we-there-yet/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", + "node_modules/archiver-utils/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/are-we-there-yet/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } }, - "node_modules/are-we-there-yet/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dependencies": { - "safe-buffer": "~5.1.0" + "safe-buffer": "~5.2.0" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "node_modules/archiver/node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "node_modules/archiver/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } }, - "node_modules/args": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/args/-/args-5.0.3.tgz", - "integrity": "sha512-h6k/zfFgusnv3i5TU08KQkVKuCPBtL/PWQbWkHUxvJrZ2nAyeaUupneemcrgn1xmqxPQsPIzwkUhOpoqPDRZuA==", - "dev": true, + "node_modules/archiver/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "dependencies": { - "camelcase": "5.0.0", - "chalk": "2.4.2", - "leven": "2.1.0", - "mri": "1.1.4" + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" }, "engines": { - "node": ">= 6.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/args/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/archiver/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/archiver/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/archiver/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "deprecated": "This package is no longer supported.", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/args": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/args/-/args-5.0.3.tgz", + "integrity": "sha512-h6k/zfFgusnv3i5TU08KQkVKuCPBtL/PWQbWkHUxvJrZ2nAyeaUupneemcrgn1xmqxPQsPIzwkUhOpoqPDRZuA==", + "dev": true, + "dependencies": { + "camelcase": "5.0.0", + "chalk": "2.4.2", + "leven": "2.1.0", + "mri": "1.1.4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/args/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "dependencies": { "color-convert": "^1.9.0" @@ -11440,9 +11410,9 @@ } }, "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==" }, "node_modules/async-exit-hook": { "version": "2.0.1", @@ -11498,44 +11468,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/aws-sdk": { - "version": "2.1692.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1692.0.tgz", - "integrity": "sha512-x511uiJ/57FIsbgUe5csJ13k3uzu25uWQE+XqfBis/sB0SFoiElJWXRkgEAUh0U6n40eT3ay5Ue4oPkRMu1LYw==", - "hasInstallScript": true, - "dependencies": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.16.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "util": "^0.12.4", - "uuid": "8.0.0", - "xml2js": "0.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/aws-sdk/node_modules/uuid": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", - "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/awsdocuments-ls-client": { "resolved": "client/vscode", "link": true }, "node_modules/axios": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", - "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", - "license": "MIT", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", + "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", @@ -11543,9 +11483,17 @@ } }, "node_modules/b4a": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", - "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==" + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", + "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } }, "node_modules/babel-jest": { "version": "29.7.0", @@ -11568,21 +11516,6 @@ "@babel/core": "^7.8.0" } }, - "node_modules/babel-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/babel-jest/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -11625,27 +11558,6 @@ "concat-map": "0.0.1" } }, - "node_modules/babel-plugin-istanbul/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", @@ -11674,6 +11586,15 @@ "node": "*" } }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/babel-plugin-istanbul/node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -11717,9 +11638,9 @@ } }, "node_modules/babel-preset-current-node-syntax": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", - "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", "dev": true, "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -11739,7 +11660,7 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@babel/core": "^7.0.0 || ^8.0.0-0" } }, "node_modules/babel-preset-jest": { @@ -11764,21 +11685,22 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/bare-events": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", - "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", - "optional": true + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.7.0.tgz", + "integrity": "sha512-b3N5eTW1g7vXkw+0CXh/HazGTcO5KYuu/RCNaJbDMPI6LHDi+7qe8EmxKUVe1sUbY2KZOVZFyj62x0OEz9qyAA==" }, "node_modules/bare-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.1.5.tgz", - "integrity": "sha512-1zccWBMypln0jEE05LzZt+V/8y8AQsQQqxtklqaIyg5nu6OAYFhZxPXinJTSG+kU5qyNmeLgcn9AW7eHiCHVLA==", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.4.5.tgz", + "integrity": "sha512-TCtu93KGLu6/aiGWzMr12TmSRS6nKdfhAnzTQRbXoSWxkbb9eRd53jQ51jG7g1gYjjtto3hbBrrhzg6djcgiKg==", "dev": true, "optional": true, "dependencies": { "bare-events": "^2.5.4", "bare-path": "^3.0.0", - "bare-stream": "^2.6.4" + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" }, "engines": { "bare": ">=1.16.0" @@ -11793,9 +11715,9 @@ } }, "node_modules/bare-os": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.1.tgz", - "integrity": "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.2.tgz", + "integrity": "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==", "dev": true, "optional": true, "engines": { @@ -11813,9 +11735,9 @@ } }, "node_modules/bare-stream": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz", - "integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.7.0.tgz", + "integrity": "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==", "dev": true, "optional": true, "dependencies": { @@ -11834,6 +11756,16 @@ } } }, + "node_modules/bare-url": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.2.2.tgz", + "integrity": "sha512-g+ueNGKkrjMazDG3elZO1pNs3HY5+mMmOet1jtKyhOaCnkLzitxf26z7hoAEkDNgdNmnc1KIlt/dw6Po6xZMpA==", + "dev": true, + "optional": true, + "dependencies": { + "bare-path": "^3.0.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -11853,6 +11785,15 @@ } ] }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.13.tgz", + "integrity": "sha512-7s16KR8io8nIBWQyCYhmFhd+ebIzb9VKTzki+wOJXHTxTnV6+mFGH3+Jwn1zoKaY9/H9T/0BcKCZnzXljPnpSQ==", + "devOptional": true, + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, "node_modules/basic-ftp": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", @@ -11891,42 +11832,16 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "license": "MIT", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, - "node_modules/bl/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/bl/node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -12010,16 +11925,6 @@ "node": ">=0.10.0" } }, - "node_modules/bower-json/node_modules/deep-extend": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.1.tgz", - "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, "node_modules/bower-license": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/bower-license/-/bower-license-0.4.4.tgz", @@ -12086,9 +11991,9 @@ } }, "node_modules/bowser": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", - "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.12.1.tgz", + "integrity": "sha512-z4rE2Gxh7tvshQ4hluIT7XcFrgLIQaw9X3A+kTTRdovCz5PMukm/0QC/BKSYPj3omF5Qfypn9O/c5kgpmvYUCw==" }, "node_modules/brace-expansion": { "version": "2.0.2", @@ -12167,71 +12072,76 @@ "node": ">= 0.10" } }, + "node_modules/browserify-rsa/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/browserify-sign": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", - "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", + "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", "dependencies": { - "bn.js": "^5.2.1", - "browserify-rsa": "^4.1.0", + "bn.js": "^5.2.2", + "browserify-rsa": "^4.1.1", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.5", - "hash-base": "~3.0", + "elliptic": "^6.6.1", "inherits": "^2.0.4", - "parse-asn1": "^5.1.7", + "parse-asn1": "^5.1.9", "readable-stream": "^2.3.8", "safe-buffer": "^5.2.1" }, "engines": { - "node": ">= 0.12" - } - }, - "node_modules/browserify-sign/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/browserify-sign/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" + "node": ">= 0.10" } }, - "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/browserslist": { - "version": "4.25.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", - "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", - "devOptional": true, + "node_modules/browserify-sign/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" + "type": "github", + "url": "https://github.com/sponsors/feross" }, { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/browserslist": { + "version": "4.26.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", + "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", + "devOptional": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" }, { "type": "github", @@ -12239,9 +12149,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001726", - "electron-to-chromium": "^1.5.173", - "node-releases": "^2.0.19", + "baseline-browser-mapping": "^2.8.9", + "caniuse-lite": "^1.0.30001746", + "electron-to-chromium": "^1.5.227", + "node-releases": "^2.0.21", "update-browserslist-db": "^1.1.3" }, "bin": { @@ -12273,13 +12184,26 @@ } }, "node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" } }, "node_modules/buffer-crc32": { @@ -12392,6 +12316,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/c8/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/c8/node_modules/p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", @@ -12416,6 +12355,18 @@ "node": ">=8" } }, + "node_modules/c8/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", @@ -12441,6 +12392,20 @@ "node": ">=8" } }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -12505,18 +12470,18 @@ } }, "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", "dev": true, "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001726", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001726.tgz", - "integrity": "sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw==", + "version": "1.0.30001748", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001748.tgz", + "integrity": "sha512-5P5UgAr0+aBmNiplks08JLw+AW/XG/SurlgZLgB1dDLfAw7EfRGxIwzPHxdSCGY/BTKDqIVyJL87cCN6s0ZR0w==", "devOptional": true, "funding": [ { @@ -12564,9 +12529,9 @@ } }, "node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -12585,9 +12550,9 @@ } }, "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", + "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==", "dev": true }, "node_modules/check-error": { @@ -12603,25 +12568,25 @@ } }, "node_modules/cheerio": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.1.0.tgz", - "integrity": "sha512-+0hMx9eYhJvWbgpKV9hN7jg0JcwydpopZE4hgi+KvQtByZXPp04NiCWU0LzcAbP63abZckIHkTQaXVF52mX3xQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.1.2.tgz", + "integrity": "sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==", "dev": true, "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", - "encoding-sniffer": "^0.2.0", + "encoding-sniffer": "^0.2.1", "htmlparser2": "^10.0.0", "parse5": "^7.3.0", "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", - "undici": "^7.10.0", + "undici": "^7.12.0", "whatwg-mimetype": "^4.0.0" }, "engines": { - "node": ">=18.17" + "node": ">=20.18.1" }, "funding": { "url": "https://github.com/cheeriojs/cheerio?sponsor=1" @@ -12778,9 +12743,9 @@ } }, "node_modules/cheerio/node_modules/undici": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.11.0.tgz", - "integrity": "sha512-heTSIac3iLhsmZhUCjyS3JQEkZELateufzZuBaVM5RHXdSBMb1LPMQf5x+FH7qjsZYDP0ttAc3nnVpUB+wYbOg==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.16.0.tgz", + "integrity": "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==", "dev": true, "engines": { "node": ">=20.18.1" @@ -12803,8 +12768,7 @@ "node_modules/chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "license": "ISC" + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "node_modules/chrome-trace-event": { "version": "1.0.4", @@ -12831,17 +12795,37 @@ } }, "node_modules/cipher-base": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", - "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", "dependencies": { "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" }, "engines": { "node": ">= 0.10" } }, + "node_modules/cipher-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/cjs-module-lexer": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", @@ -12871,11 +12855,6 @@ "node": ">= 10.0" } }, - "node_modules/clean/node_modules/async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==" - }, "node_modules/cli-width": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", @@ -12899,27 +12878,15 @@ "node": ">=12" } }, - "node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "node_modules/cliui/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -12934,23 +12901,6 @@ "node": ">=8" } }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", @@ -12975,6 +12925,18 @@ "node": ">=6" } }, + "node_modules/clone-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/clone-response": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", @@ -12986,6 +12948,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/clone-response/node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -13000,7 +12970,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -13074,6 +13043,71 @@ "node": ">= 14" } }, + "node_modules/compress-commons/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/compress-commons/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/compress-commons/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/compress-commons/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -13089,7 +13123,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", - "license": "MIT", "dependencies": { "bytes": "3.1.2", "compressible": "~2.0.18", @@ -13124,6 +13157,25 @@ "node": ">= 0.6" } }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -13140,8 +13192,7 @@ "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "license": "ISC" + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" }, "node_modules/content-disposition": { "version": "1.0.0", @@ -13154,16 +13205,35 @@ "node": ">= 0.6" } }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/conventional-changelog-angular": { - "version": "7.0.0", + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "7.0.0", "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", "dev": true, @@ -13244,20 +13314,6 @@ "copyup": "copyfiles" } }, - "node_modules/copyfiles/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/copyfiles/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -13277,29 +13333,12 @@ "wrap-ansi": "^7.0.0" } }, - "node_modules/copyfiles/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/copyfiles/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, + "node_modules/copyfiles/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=8" } }, "node_modules/copyfiles/node_modules/minimatch": { @@ -13313,6 +13352,17 @@ "node": "*" } }, + "node_modules/copyfiles/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/copyfiles/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -13326,22 +13376,6 @@ "node": ">=8" } }, - "node_modules/copyfiles/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/copyfiles/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -13450,6 +13484,71 @@ "node": ">= 14" } }, + "node_modules/crc32-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/crc32-stream/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/crc32-stream/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/crc32-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/create-ecdh": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", @@ -13510,21 +13609,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/create-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/create-jest/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -13547,97 +13631,297 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, - "node_modules/cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "node_modules/create-wdio": { + "version": "9.18.2", + "resolved": "https://registry.npmjs.org/create-wdio/-/create-wdio-9.18.2.tgz", + "integrity": "sha512-atf81YJfyTNAJXsNu3qhpqF4OO43tHGTpr88duAc1Hk4a0uXJAPUYLnYxshOuMnfmeAxlWD+NqGU7orRiXEuJg==", + "dev": true, "dependencies": { - "cross-spawn": "^7.0.1" + "chalk": "^5.3.0", + "commander": "^14.0.0", + "cross-spawn": "^7.0.3", + "ejs": "^3.1.10", + "execa": "^9.6.0", + "import-meta-resolve": "^4.1.0", + "inquirer": "^12.7.0", + "normalize-package-data": "^7.0.0", + "read-pkg-up": "^10.1.0", + "recursive-readdir": "^2.2.3", + "semver": "^7.6.3", + "type-fest": "^4.41.0", + "yargs": "^17.7.2" }, "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" + "create-wdio": "bin/wdio.js" }, "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" + "node": ">=12.0.0" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, + "node_modules/create-wdio/node_modules/commander": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.1.tgz", + "integrity": "sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==", + "dev": true, "engines": { - "node": ">= 8" + "node": ">=20" } }, - "node_modules/crypto-browserify": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", - "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "node_modules/create-wdio/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, "dependencies": { - "browserify-cipher": "^1.0.1", - "browserify-sign": "^4.2.3", - "create-ecdh": "^4.0.4", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "diffie-hellman": "^5.0.3", - "hash-base": "~3.0.4", - "inherits": "^2.0.4", - "pbkdf2": "^3.1.2", - "public-encrypt": "^4.0.3", - "randombytes": "^2.1.0", - "randomfill": "^1.0.4" + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" }, "engines": { - "node": ">= 0.10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "node_modules/create-wdio/node_modules/hosted-git-info": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", "dev": true, "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" + "lru-cache": "^10.0.1" }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "engines": { + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/css-shorthand-properties": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/css-shorthand-properties/-/css-shorthand-properties-1.1.2.tgz", - "integrity": "sha512-C2AugXIpRGQTxaCW0N7n5jD/p5irUmCrwl03TrnMFBHDbdq44CFWR2zO7rK9xPN4Eo3pUxC4vQzQgbIpzrD1PQ==", - "dev": true - }, - "node_modules/css-value": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", - "integrity": "sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==", - "dev": true - }, - "node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "node_modules/create-wdio/node_modules/json-parse-even-better-errors": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", "dev": true, "engines": { - "node": ">= 6" - }, + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/create-wdio/node_modules/lines-and-columns": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", + "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/create-wdio/node_modules/normalize-package-data": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-7.0.1.tgz", + "integrity": "sha512-linxNAT6M0ebEYZOx2tO6vBEFsVgnPpv+AVjk0wJHfaUIbq31Jm3T6vvZaarnOeWDh8ShnwXuaAyM7WT3RzErA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^8.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/create-wdio/node_modules/parse-json": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.1.1.tgz", + "integrity": "sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.21.4", + "error-ex": "^1.3.2", + "json-parse-even-better-errors": "^3.0.0", + "lines-and-columns": "^2.0.3", + "type-fest": "^3.8.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/create-wdio/node_modules/parse-json/node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/create-wdio/node_modules/read-pkg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.1.0.tgz", + "integrity": "sha512-PORM8AgzXeskHO/WEv312k9U03B8K9JSiWF/8N9sUuFjBa+9SF2u6K7VClzXwDXab51jCd8Nd36CNM+zR97ScQ==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^6.0.0", + "parse-json": "^7.0.0", + "type-fest": "^4.2.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/create-wdio/node_modules/read-pkg-up": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-10.1.0.tgz", + "integrity": "sha512-aNtBq4jR8NawpKJQldrQcSW9y/d+KWH4v24HWkHljOZ7H0av+YTGANBzRh9A5pw7v/bLVsLVPpOhJ7gHNVy8lA==", + "dev": true, + "dependencies": { + "find-up": "^6.3.0", + "read-pkg": "^8.1.0", + "type-fest": "^4.2.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/create-wdio/node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/create-wdio/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/create-wdio/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "dependencies": { + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-shorthand-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-shorthand-properties/-/css-shorthand-properties-1.1.2.tgz", + "integrity": "sha512-C2AugXIpRGQTxaCW0N7n5jD/p5irUmCrwl03TrnMFBHDbdq44CFWR2zO7rK9xPN4Eo3pUxC4vQzQgbIpzrD1PQ==", + "dev": true + }, + "node_modules/css-value": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", + "integrity": "sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==", + "dev": true + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "engines": { + "node": ">= 6" + }, "funding": { "url": "https://github.com/sponsors/fb55" } @@ -13756,9 +14040,9 @@ } }, "node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dependencies": { "ms": "^2.1.3" }, @@ -13782,52 +14066,35 @@ } }, "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, "node_modules/decimal.js": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", - "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", "dev": true }, "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" + "mimic-response": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/dedent": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz", - "integrity": "sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", "dev": true, "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -13851,13 +14118,14 @@ } }, "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "license": "MIT", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.1.tgz", + "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", + "dev": true, "engines": { - "node": ">=4.0.0" - } + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } }, "node_modules/deep-is": { "version": "0.1.4", @@ -13998,8 +14266,7 @@ "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "license": "MIT" + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, "node_modules/depd": { "version": "2.0.0", @@ -14031,7 +14298,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "license": "Apache-2.0", "bin": { "detect-libc": "bin/detect-libc.js" }, @@ -14064,9 +14330,10 @@ } }, "node_modules/diff": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", - "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, "engines": { "node": ">=0.3.1" } @@ -14213,9 +14480,9 @@ } }, "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "dev": true, "engines": { "node": ">=12" @@ -14297,9 +14564,9 @@ } }, "node_modules/edgedriver": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/edgedriver/-/edgedriver-6.1.1.tgz", - "integrity": "sha512-/dM/PoBf22Xg3yypMWkmRQrBKEnSyNaZ7wHGCT9+qqT14izwtFT+QvdR89rjNkMfXwW+bSFoqOfbcvM+2Cyc7w==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/edgedriver/-/edgedriver-6.1.2.tgz", + "integrity": "sha512-UvFqd/IR81iPyWMcxXbUNi+xKWR7JjfoHjfuwjqsj9UHQKn80RpQmS0jf+U25IPi+gKVPcpOSKm0XkqgGMq4zQ==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -14307,7 +14574,7 @@ "@zip.js/zip.js": "^2.7.53", "decamelize": "^6.0.0", "edge-paths": "^3.0.5", - "fast-xml-parser": "^4.5.0", + "fast-xml-parser": "^5.0.8", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.5", "node-fetch": "^3.3.2", @@ -14321,9 +14588,9 @@ } }, "node_modules/edgedriver/node_modules/decamelize": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", - "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.1.tgz", + "integrity": "sha512-G7Cqgaelq68XHJNGlZ7lrNQyhZGsFqpwtGFexqUv4IQdjKoSYF7ipZ9UuTJZUSQXFj/XaoBLuEVIVqr8EJngEQ==", "dev": true, "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -14333,9 +14600,9 @@ } }, "node_modules/edgedriver/node_modules/fast-xml-parser": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz", - "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.0.tgz", + "integrity": "sha512-gkWGshjYcQCF+6qtlrqBqELqNqnt4CxruY6UVAWWnqb3DQ6qaNFEIKqzYep1XzHLM/QtrHVCxyPOtTk4LTQ7Aw==", "dev": true, "funding": [ { @@ -14344,7 +14611,7 @@ } ], "dependencies": { - "strnum": "^1.1.1" + "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" @@ -14359,6 +14626,18 @@ "node": ">=16" } }, + "node_modules/edgedriver/node_modules/strnum": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", + "integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ] + }, "node_modules/edgedriver/node_modules/which": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", @@ -14395,9 +14674,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.177", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.177.tgz", - "integrity": "sha512-7EH2G59nLsEMj97fpDuvVcYi6lwTcM1xuWw3PssD8xzboAW7zj7iB3COEEEATUfjLHrs5uKBLQT03V/8URx06g==", + "version": "1.5.232", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.232.tgz", + "integrity": "sha512-ENirSe7wf8WzyPCibqKUG1Cg43cPaxH4wRR7AJsX7MCABCHBIOFqvaYODSLKUuZdraxUTHRE/0A2Aq8BYKEHOg==", "devOptional": true }, "node_modules/elliptic": { @@ -14432,9 +14711,9 @@ } }, "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/emojis-list": { "version": "3.0.0", @@ -14457,7 +14736,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/encoding-japanese/-/encoding-japanese-2.2.0.tgz", "integrity": "sha512-EuJWwlHPZ1LbADuKTClvHtwbaFn4rOD+dRAbWysqEOXRc2Uui0hJInNJrsdH0c+OhJA4nrCBdSkW4DD5YxAo6A==", - "license": "MIT", "engines": { "node": ">=8.10.0" } @@ -14493,9 +14771,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.18.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz", - "integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==", + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", "devOptional": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -14526,9 +14804,9 @@ } }, "node_modules/envinfo": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", - "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.17.0.tgz", + "integrity": "sha512-GpfViocsFM7viwClFgxK26OtjMlKN67GCR5v6ASFkotxtpBWd9d+vNy+AH7F2E1TUkMDZ8P/dDPZX71/NG8xnQ==", "dev": true, "bin": { "envinfo": "dist/cli.js" @@ -14538,9 +14816,9 @@ } }, "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "dev": true, "dependencies": { "is-arrayish": "^0.2.1" @@ -14691,9 +14969,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", - "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", + "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", "dev": true, "hasInstallScript": true, "bin": { @@ -14703,31 +14981,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.5", - "@esbuild/android-arm": "0.25.5", - "@esbuild/android-arm64": "0.25.5", - "@esbuild/android-x64": "0.25.5", - "@esbuild/darwin-arm64": "0.25.5", - "@esbuild/darwin-x64": "0.25.5", - "@esbuild/freebsd-arm64": "0.25.5", - "@esbuild/freebsd-x64": "0.25.5", - "@esbuild/linux-arm": "0.25.5", - "@esbuild/linux-arm64": "0.25.5", - "@esbuild/linux-ia32": "0.25.5", - "@esbuild/linux-loong64": "0.25.5", - "@esbuild/linux-mips64el": "0.25.5", - "@esbuild/linux-ppc64": "0.25.5", - "@esbuild/linux-riscv64": "0.25.5", - "@esbuild/linux-s390x": "0.25.5", - "@esbuild/linux-x64": "0.25.5", - "@esbuild/netbsd-arm64": "0.25.5", - "@esbuild/netbsd-x64": "0.25.5", - "@esbuild/openbsd-arm64": "0.25.5", - "@esbuild/openbsd-x64": "0.25.5", - "@esbuild/sunos-x64": "0.25.5", - "@esbuild/win32-arm64": "0.25.5", - "@esbuild/win32-ia32": "0.25.5", - "@esbuild/win32-x64": "0.25.5" + "@esbuild/aix-ppc64": "0.25.10", + "@esbuild/android-arm": "0.25.10", + "@esbuild/android-arm64": "0.25.10", + "@esbuild/android-x64": "0.25.10", + "@esbuild/darwin-arm64": "0.25.10", + "@esbuild/darwin-x64": "0.25.10", + "@esbuild/freebsd-arm64": "0.25.10", + "@esbuild/freebsd-x64": "0.25.10", + "@esbuild/linux-arm": "0.25.10", + "@esbuild/linux-arm64": "0.25.10", + "@esbuild/linux-ia32": "0.25.10", + "@esbuild/linux-loong64": "0.25.10", + "@esbuild/linux-mips64el": "0.25.10", + "@esbuild/linux-ppc64": "0.25.10", + "@esbuild/linux-riscv64": "0.25.10", + "@esbuild/linux-s390x": "0.25.10", + "@esbuild/linux-x64": "0.25.10", + "@esbuild/netbsd-arm64": "0.25.10", + "@esbuild/netbsd-x64": "0.25.10", + "@esbuild/openbsd-arm64": "0.25.10", + "@esbuild/openbsd-x64": "0.25.10", + "@esbuild/openharmony-arm64": "0.25.10", + "@esbuild/sunos-x64": "0.25.10", + "@esbuild/win32-arm64": "0.25.10", + "@esbuild/win32-ia32": "0.25.10", + "@esbuild/win32-x64": "0.25.10" } }, "node_modules/escalade": { @@ -14941,18 +15220,6 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, "node_modules/eslint-plugin-import/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -14965,31 +15232,19 @@ "node": "*" } }, - "node_modules/eslint-plugin-import/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-import/node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" + "bin": { + "semver": "bin/semver.js" } }, "node_modules/eslint-plugin-unused-imports": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz", - "integrity": "sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.2.0.tgz", + "integrity": "sha512-hLbJ2/wnjKq4kGA9AUaExVFIbNzyxYdVo49QZmKCnhk5pc9wcYRbfgLHvWJ8tnsdcseGhoUAddm9gn/lt+d74w==", "dev": true, "peerDependencies": { "@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0", @@ -15045,21 +15300,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -15102,21 +15342,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -15159,6 +15384,21 @@ "node": "*" } }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint/node_modules/p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", @@ -15183,10 +15423,10 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/eslint/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "engines": { "node": ">=10" @@ -15288,11 +15528,19 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, "node_modules/events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "engines": { - "node": ">=0.4.x" + "node": ">=0.8.x" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "dependencies": { + "bare-events": "^2.7.0" } }, "node_modules/eventsource": { @@ -15307,11 +15555,11 @@ } }, "node_modules/eventsource-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.3.tgz", - "integrity": "sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", "engines": { - "node": ">=20.0.0" + "node": ">=18.0.0" } }, "node_modules/evp_bytestokey": { @@ -15324,45 +15572,54 @@ } }, "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.0.tgz", + "integrity": "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" }, "engines": { - "node": ">=10" + "node": "^18.19.0 || >=20.5.0" }, "funding": { "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/execa/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/execa/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/execa/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "node_modules/execa/node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/exit": { "version": "0.1.2", @@ -15389,7 +15646,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "license": "(MIT OR WTFPL)", "engines": { "node": ">=6" } @@ -15411,15 +15667,15 @@ } }, "node_modules/expect-webdriverio": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-5.3.4.tgz", - "integrity": "sha512-FU+96C0nqeYTXrJcGLUDB6hPKKaSm1/tVHjFDE4EDHGCYvajAHCC2MBQJ5MomjCmp6lGMz36lDHeZj52LHylyA==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/expect-webdriverio/-/expect-webdriverio-5.4.3.tgz", + "integrity": "sha512-/XxRRR90gNSuNf++w1jOQjhC5LE9Ixf/iAQctVb/miEI3dwzPZTuG27/omoh5REfSLDoPXofM84vAH/ULtz35g==", "dev": true, "dependencies": { "@vitest/snapshot": "^3.2.4", + "deep-eql": "^5.0.2", "expect": "^30.0.0", - "jest-matcher-utils": "^30.0.0", - "lodash.isequal": "^4.5.0" + "jest-matcher-utils": "^30.0.0" }, "engines": { "node": ">=18 || >=20 || >=22" @@ -15442,21 +15698,21 @@ } }, "node_modules/expect-webdriverio/node_modules/@jest/expect-utils": { - "version": "30.0.3", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.0.3.tgz", - "integrity": "sha512-SMtBvf2sfX2agcT0dA9pXwcUrKvOSDqBY4e4iRfT+Hya33XzV35YVg+98YQFErVGA/VR1Gto5Y2+A6G9LSQ3Yg==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", "dev": true, "dependencies": { - "@jest/get-type": "30.0.1" + "@jest/get-type": "30.1.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/expect-webdriverio/node_modules/@jest/schemas": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.1.tgz", - "integrity": "sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==", + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", "dev": true, "dependencies": { "@sinclair/typebox": "^0.34.0" @@ -15466,13 +15722,13 @@ } }, "node_modules/expect-webdriverio/node_modules/@jest/types": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.1.tgz", - "integrity": "sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", "dev": true, "dependencies": { "@jest/pattern": "30.0.1", - "@jest/schemas": "30.0.1", + "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", @@ -15484,9 +15740,9 @@ } }, "node_modules/expect-webdriverio/node_modules/@sinclair/typebox": { - "version": "0.34.37", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.37.tgz", - "integrity": "sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==", + "version": "0.34.41", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", "dev": true }, "node_modules/expect-webdriverio/node_modules/@vitest/pretty-format": { @@ -15531,25 +15787,10 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/expect-webdriverio/node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/expect-webdriverio/node_modules/ci-info": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz", - "integrity": "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", "dev": true, "funding": [ { @@ -15561,66 +15802,75 @@ "node": ">=8" } }, + "node_modules/expect-webdriverio/node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/expect-webdriverio/node_modules/expect": { - "version": "30.0.3", - "resolved": "https://registry.npmjs.org/expect/-/expect-30.0.3.tgz", - "integrity": "sha512-HXg6NvK35/cSYZCUKAtmlgCFyqKM4frEPbzrav5hRqb0GMz0E0lS5hfzYjSaiaE5ysnp/qI2aeZkeyeIAOeXzQ==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", "dev": true, "dependencies": { - "@jest/expect-utils": "30.0.3", - "@jest/get-type": "30.0.1", - "jest-matcher-utils": "30.0.3", - "jest-message-util": "30.0.2", - "jest-mock": "30.0.2", - "jest-util": "30.0.2" + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/expect-webdriverio/node_modules/jest-diff": { - "version": "30.0.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.0.3.tgz", - "integrity": "sha512-Q1TAV0cUcBTic57SVnk/mug0/ASyAqtSIOkr7RAlxx97llRYsM74+E8N5WdGJUlwCKwgxPAkVjKh653h1+HA9A==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", "dev": true, "dependencies": { "@jest/diff-sequences": "30.0.1", - "@jest/get-type": "30.0.1", + "@jest/get-type": "30.1.0", "chalk": "^4.1.2", - "pretty-format": "30.0.2" + "pretty-format": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/expect-webdriverio/node_modules/jest-matcher-utils": { - "version": "30.0.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.0.3.tgz", - "integrity": "sha512-hMpVFGFOhYmIIRGJ0HgM9htC5qUiJ00famcc9sRFchJJiLZbbVKrAztcgE6VnXLRxA3XZ0bvNA7hQWh3oHXo/A==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", "dev": true, "dependencies": { - "@jest/get-type": "30.0.1", + "@jest/get-type": "30.1.0", "chalk": "^4.1.2", - "jest-diff": "30.0.3", - "pretty-format": "30.0.2" + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/expect-webdriverio/node_modules/jest-message-util": { - "version": "30.0.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.2.tgz", - "integrity": "sha512-vXywcxmr0SsKXF/bAD7t7nMamRvPuJkras00gqYeB1V0WllxZrbZ0paRr3XqpFU2sYYjD0qAaG2fRyn/CGZ0aw==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.0.1", + "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", - "pretty-format": "30.0.2", + "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -15629,26 +15879,26 @@ } }, "node_modules/expect-webdriverio/node_modules/jest-mock": { - "version": "30.0.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.0.2.tgz", - "integrity": "sha512-PnZOHmqup/9cT/y+pXIVbbi8ID6U1XHRmbvR7MvUy4SLqhCbwpkmXhLbsWbGewHrV5x/1bF7YDjs+x24/QSvFA==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", "dev": true, "dependencies": { - "@jest/types": "30.0.1", + "@jest/types": "30.2.0", "@types/node": "*", - "jest-util": "30.0.2" + "jest-util": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/expect-webdriverio/node_modules/jest-util": { - "version": "30.0.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.2.tgz", - "integrity": "sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "dependencies": { - "@jest/types": "30.0.1", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -15665,13 +15915,25 @@ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true }, + "node_modules/expect-webdriverio/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/expect-webdriverio/node_modules/pretty-format": { - "version": "30.0.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.2.tgz", - "integrity": "sha512-yC5/EBSOrTtqhCKfLHqoUIAXVRZnukHPwWBJWR7h84Q3Be1DRQZLncwcfLoPA5RPQ65qfiCMqgYwdUuQ//eVpg==", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "dependencies": { - "@jest/schemas": "30.0.1", + "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" }, @@ -15679,6 +15941,18 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/expect-webdriverio/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/expect-webdriverio/node_modules/tinyrainbow": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", @@ -15743,39 +16017,24 @@ "express": ">= 4.11" } }, - "node_modules/ext-list": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", - "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", - "dev": true, - "dependencies": { - "mime-db": "^1.28.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, + "node_modules/express/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" + "mime-db": "^1.54.0" }, "engines": { - "node": ">=4" + "node": ">= 0.6" } }, - "node_modules/external-editor/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", "dev": true, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "mime-db": "^1.28.0" }, "engines": { "node": ">=0.10.0" @@ -15801,11 +16060,26 @@ "@types/yauzl": "^2.9.1" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, "node_modules/fast-fifo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", @@ -15864,9 +16138,9 @@ "dev": true }, "node_modules/fast-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "funding": [ { "type": "github", @@ -15944,19 +16218,6 @@ "pend": "~1.2.0" } }, - "node_modules/fdir": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", - "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, "node_modules/fetch-blob": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", @@ -15995,18 +16256,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/figures/node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -16114,9 +16363,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "funding": [ { "type": "individual", @@ -16165,7 +16414,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", - "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -16177,25 +16425,6 @@ "node": ">= 6" } }, - "node_modules/form-data/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/form-data/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", @@ -16227,8 +16456,7 @@ "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT" + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "node_modules/fs-jetpack": { "version": "0.12.0", @@ -16252,27 +16480,6 @@ "concat-map": "0.0.1" } }, - "node_modules/fs-jetpack/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/fs-jetpack/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -16285,18 +16492,6 @@ "node": "*" } }, - "node_modules/fs-jetpack/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/fs-jetpack/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -16378,7 +16573,6 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", "deprecated": "This package is no longer supported.", - "license": "ISC", "dependencies": { "aproba": "^1.0.3", "console-control-strings": "^1.0.0", @@ -16394,19 +16588,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", - "license": "MIT", - "dependencies": { - "number-is-nan": "^1.0.0" - }, "engines": { "node": ">=0.10.0" } @@ -16414,28 +16595,12 @@ "node_modules/gauge/node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, - "node_modules/gauge/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", - "license": "MIT", - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/gauge/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, @@ -16467,9 +16632,9 @@ } }, "node_modules/geckodriver/node_modules/decamelize": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", - "integrity": "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.1.tgz", + "integrity": "sha512-G7Cqgaelq68XHJNGlZ7lrNQyhZGsFqpwtGFexqUv4IQdjKoSYF7ipZ9UuTJZUSQXFj/XaoBLuEVIVqr8EJngEQ==", "dev": true, "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -16488,9 +16653,9 @@ } }, "node_modules/geckodriver/node_modules/tar-fs": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.10.tgz", - "integrity": "sha512-C1SwlQGNLe/jPNqapK8epDsXME7CAJR5RL3GcE6KWx1d9OUByzoHVcbu1VPI8tevg9H8Alae0AApHHFGzrD5zA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz", + "integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==", "dev": true, "dependencies": { "pump": "^3.0.0", @@ -16501,6 +16666,17 @@ "bare-path": "^3.0.0" } }, + "node_modules/geckodriver/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "node_modules/geckodriver/node_modules/which": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", @@ -16516,6 +16692,15 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -16599,14 +16784,28 @@ } }, "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, "dependencies": { - "pump": "^3.0.0" + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream/node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "engines": { + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -16630,9 +16829,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", - "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.11.0.tgz", + "integrity": "sha512-sNsqf7XKQ38IawiVGPOoAlqZo1DMrO7TU+ZcZwi7yLl7/7S0JwmoBMKz/IkUPhSoXM0Ng3vT0yB1iCe5XavDeQ==", "dev": true, "dependencies": { "resolve-pkg-maps": "^1.0.0" @@ -16642,9 +16841,9 @@ } }, "node_modules/get-uri": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz", - "integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", + "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", "dev": true, "dependencies": { "basic-ftp": "^5.0.2", @@ -16684,23 +16883,23 @@ "node_modules/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "license": "MIT" + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" }, "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, - "bin": { - "glob": "dist/esm/bin.mjs" + "engines": { + "node": "*" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -16718,12 +16917,47 @@ "node": ">=10.13.0" } }, + "node_modules/glob-to-regex.js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz", + "integrity": "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "devOptional": true }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/global-directory": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", @@ -16740,12 +16974,18 @@ } }, "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globalthis": { @@ -16799,6 +17039,31 @@ "url": "https://github.com/sindresorhus/got?sponsor=1" } }, + "node_modules/got/node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/got/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -16821,13 +17086,34 @@ "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" }, - "node_modules/has-ansi": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", - "integrity": "sha512-1YsTg1fk2/6JToQhtZkArMkurq8UoWU1Qe0aR3VUHjgij4nOylSWLWAtBXoZ4/dXOmugfLGm1c+QhuD0JyedFA==", + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "dev": true, "dependencies": { - "ansi-regex": "^0.2.0" + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-ansi": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", + "integrity": "sha512-1YsTg1fk2/6JToQhtZkArMkurq8UoWU1Qe0aR3VUHjgij4nOylSWLWAtBXoZ4/dXOmugfLGm1c+QhuD0JyedFA==", + "dev": true, + "dependencies": { + "ansi-regex": "^0.2.0" }, "bin": { "has-ansi": "cli.js" @@ -16919,8 +17205,7 @@ "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "license": "ISC" + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, "node_modules/hash-base": { "version": "3.0.5", @@ -16934,6 +17219,25 @@ "node": ">= 0.10" } }, + "node_modules/hash-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/hash.js": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", @@ -16982,21 +17286,9 @@ } }, "node_modules/hosted-git-info": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", - "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", - "dev": true, - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "node_modules/hpack.js": { @@ -17010,33 +17302,6 @@ "wbuf": "^1.1.0" } }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/hpagent": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", @@ -17114,9 +17379,9 @@ } }, "node_modules/html-webpack-plugin": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", - "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.4.tgz", + "integrity": "sha512-V/PZeWsqhfpE27nKeX9EO2sbR+D17A+tLf6qU+ht66jdUsN0QLKJN27Z+1+gHrVMKgndBahes0PU6rRihDgHTw==", "dev": true, "dependencies": { "@types/html-minifier-terser": "^6.0.0", @@ -17176,9 +17441,9 @@ } }, "node_modules/htmlfy": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/htmlfy/-/htmlfy-0.6.7.tgz", - "integrity": "sha512-r8hRd+oIM10lufovN+zr3VKPTYEIvIwqXGucidh2XQufmiw6sbUXFUFjWlfjo3AnefIDTyzykVzQ8IUVuT1peQ==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/htmlfy/-/htmlfy-0.8.1.tgz", + "integrity": "sha512-xWROBw9+MEGwxpotll0h672KCaLrKKiCYzsyN8ZgL9cQbVumFnyvsk2JqiB9ELAV1GLj1GG/jxZUjV9OZZi/yQ==", "dev": true }, "node_modules/htmlparser2": { @@ -17337,12 +17602,12 @@ } }, "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", "dev": true, "engines": { - "node": ">=10.17.0" + "node": ">=18.18.0" } }, "node_modules/husky": { @@ -17380,9 +17645,23 @@ } }, "node_modules/ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/ignore": { "version": "7.0.5", @@ -17453,9 +17732,9 @@ } }, "node_modules/import-meta-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", - "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", "dev": true, "funding": { "type": "github", @@ -17496,22 +17775,29 @@ } }, "node_modules/inquirer": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-11.1.0.tgz", - "integrity": "sha512-CmLAZT65GG/v30c+D2Fk8+ceP6pxD6RL+hIUOWAltCmeyEqWYwqu9v76q03OvjyZ3AB0C1Ala2stn1z/rMqGEw==", + "version": "12.9.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.9.6.tgz", + "integrity": "sha512-603xXOgyfxhuis4nfnWaZrMaotNT0Km9XwwBNWUKbIDqeCY89jGr2F9YPEMiNhU6XjIP4VoWISMBFfcc5NgrTw==", "dev": true, "dependencies": { - "@inquirer/core": "^9.2.1", - "@inquirer/prompts": "^6.0.1", - "@inquirer/type": "^2.0.0", - "@types/mute-stream": "^0.0.4", - "ansi-escapes": "^4.3.2", - "mute-stream": "^1.0.0", - "run-async": "^3.0.0", - "rxjs": "^7.8.1" + "@inquirer/ansi": "^1.0.0", + "@inquirer/core": "^10.2.2", + "@inquirer/prompts": "^7.8.6", + "@inquirer/type": "^3.0.8", + "mute-stream": "^2.0.0", + "run-async": "^4.0.5", + "rxjs": "^7.8.2" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/internal-slot": { @@ -17553,24 +17839,14 @@ } }, "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", "dev": true, - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, "engines": { "node": ">= 12" } }, - "node_modules/ip-address/node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true - }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -17583,6 +17859,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "dev": true, "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" @@ -17780,11 +18057,14 @@ } }, "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dependencies": { + "number-is-nan": "^1.0.0" + }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, "node_modules/is-generator-fn": { @@ -17797,12 +18077,14 @@ } }, "node_modules/is-generator-function": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", - "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, "dependencies": { - "call-bound": "^1.0.3", - "get-proto": "^1.0.0", + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" }, @@ -17842,13 +18124,11 @@ } }, "node_modules/is-it-type": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/is-it-type/-/is-it-type-5.1.2.tgz", - "integrity": "sha512-q/gOZQTNYABAxaXWnBKZjTFH4yACvWEFtgVOj+LbgxYIgAJG1xVmUZOsECSrZPIemYUQvaQWVilSFVbh4Eyt8A==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/is-it-type/-/is-it-type-5.1.3.tgz", + "integrity": "sha512-AX2uU0HW+TxagTgQXOJY7+2fbFHemC7YFBwN1XqD8qQMKdtfbOC8OC3fUb4s5NU59a3662Dzwto8tWDdZYRXxg==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/runtime": "^7.16.7", "globalthis": "^1.0.2" }, "engines": { @@ -17896,9 +18176,9 @@ } }, "node_modules/is-network-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", - "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.0.tgz", + "integrity": "sha512-6oIwpsgRfnDiyEDLMay/GqCl3HoAtH5+RUKW29gYkL0QA+ipzpDLA16yQs7/RHCSu+BwgbJaOUqa4A99qNVQVw==", "engines": { "node": ">=16" }, @@ -17949,22 +18229,18 @@ } }, "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "engines": { "node": ">=0.10.0" } @@ -17984,6 +18260,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", @@ -18095,12 +18372,12 @@ } }, "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", "dev": true, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -18231,18 +18508,6 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", @@ -18272,9 +18537,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -18299,15 +18564,14 @@ } }, "node_modules/jake": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", - "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", "dev": true, "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", + "async": "^3.2.6", "filelist": "^1.0.4", - "minimatch": "^3.1.2" + "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" @@ -18316,58 +18580,11 @@ "node": ">=10" } }, - "node_modules/jake/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jake/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/jake/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jake/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } + "node_modules/jake/node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true }, "node_modules/jest": { "version": "29.7.0", @@ -18409,50 +18626,133 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-circus": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", - "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "node_modules/jest-changed-files/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^1.0.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.7.0", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.7.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/jest-circus/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/jest-changed-files/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-changed-files/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/jest-changed-files/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "path-key": "^3.0.0" }, "engines": { "node": ">=8" + } + }, + "node_modules/jest-changed-files/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-changed-files/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/jest-changed-files/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-changed-files/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-circus/node_modules/chalk": { @@ -18471,6 +18771,33 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/jest-circus/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-circus/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/jest-cli": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", @@ -18504,21 +18831,6 @@ } } }, - "node_modules/jest-cli/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/jest-cli/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -18580,31 +18892,6 @@ } } }, - "node_modules/jest-config/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/jest-config/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -18621,39 +18908,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-config/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/jest-config/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/jest-diff": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", @@ -18669,21 +18923,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/jest-diff/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -18728,21 +18967,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-each/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/jest-each/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -18810,47 +19034,62 @@ "fsevents": "^2.3.2" } }, - "node_modules/jest-leak-detector": { + "node_modules/jest-haste-map/node_modules/jest-worker": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", - "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "node_modules/jest-haste-map/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "has-flag": "^4.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-matcher-utils/node_modules/chalk": { @@ -18889,21 +19128,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/jest-message-util/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -18993,21 +19217,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-resolve/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/jest-resolve/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -19056,35 +19265,87 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runner/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-runner/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-runner/node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/jest-runner/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/jest-runtime": { @@ -19120,31 +19381,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runtime/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/jest-runtime/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -19161,37 +19397,13 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-runtime/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/jest-runtime/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/jest-runtime/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, "engines": { - "node": "*" + "node": ">=8" } }, "node_modules/jest-snapshot": { @@ -19225,21 +19437,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-snapshot/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/jest-snapshot/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -19256,18 +19453,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/jest-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", @@ -19285,21 +19470,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/jest-util/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -19316,18 +19486,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-util/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/jest-validate": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", @@ -19345,21 +19503,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-validate/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/jest-validate/node_modules/camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -19407,21 +19550,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-watcher/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/jest-watcher/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -19439,25 +19567,24 @@ } }, "node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "devOptional": true, "dependencies": { "@types/node": "*", - "jest-util": "^29.7.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 10.13.0" } }, "node_modules/jest-worker/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, + "devOptional": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -19469,18 +19596,19 @@ } }, "node_modules/jiti": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", - "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "dev": true, "bin": { "jiti": "lib/jiti-cli.mjs" } }, "node_modules/jmespath": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", - "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", + "integrity": "sha512-+kHj8HXArPfpPEKGLZ+kB5ONRTCiGQXo8RQYL0hH8t6pWXUBBK5KkkQmTNOwKK4LEsd0yTsgtjJVm4UBSZea4w==", + "dev": true, "engines": { "node": ">= 0.6.0" } @@ -19489,7 +19617,6 @@ "version": "5.10.0", "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", - "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" } @@ -19526,12 +19653,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true - }, "node_modules/jsdom": { "version": "24.1.3", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.3.tgz", @@ -19599,8 +19720,7 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/json-rpc-2.0/-/json-rpc-2.0-1.7.1.tgz", "integrity": "sha512-JqZjhjAanbpkXIzFE7u8mE/iFblawwlXtONaCvRqI+pyABVz7B4M1EUNpyVW+dZjqgQ2L5HFmZCmOCgUKm00hg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json-schema-traverse": { "version": "1.0.0", @@ -19666,33 +19786,6 @@ "setimmediate": "^1.0.5" } }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/just-clone": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-6.2.0.tgz", @@ -19731,12 +19824,12 @@ } }, "node_modules/launch-editor": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.10.0.tgz", - "integrity": "sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.11.1.tgz", + "integrity": "sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg==", "dependencies": { - "picocolors": "^1.0.0", - "shell-quote": "^1.8.1" + "picocolors": "^1.1.1", + "shell-quote": "^1.8.3" } }, "node_modules/lazystream": { @@ -19750,33 +19843,6 @@ "node": ">= 0.6.3" } }, - "node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/lazystream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/lazystream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -19900,18 +19966,6 @@ "node": ">=4" } }, - "node_modules/license-checker/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/license-checker/node_modules/semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", @@ -19975,15 +20029,6 @@ "node": ">=0.10.0" } }, - "node_modules/load-json-file/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/load-json-file/node_modules/strip-bom": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", @@ -20097,13 +20142,6 @@ "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", "dev": true }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", - "dev": true - }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", @@ -20192,21 +20230,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/log-symbols/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -20223,6 +20246,18 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/loglevel": { "version": "1.9.2", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz", @@ -20279,13 +20314,9 @@ } }, "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" }, "node_modules/mac-ca": { "version": "3.1.3", @@ -20297,12 +20328,12 @@ } }, "node_modules/magic-string": { - "version": "0.30.17", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", "dev": true, "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, "node_modules/make-array": { @@ -20328,18 +20359,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -20393,18 +20412,17 @@ } }, "node_modules/memfs": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.17.2.tgz", - "integrity": "sha512-NgYhCOWgovOXSzvYgUW0LQ7Qy72rWQMGGFJDoWg4G30RHd3z77VbYdtJ4fembJXBy8pMIUA31XNAupobOQlwdg==", - "dependencies": { - "@jsonjoy.com/json-pack": "^1.0.3", - "@jsonjoy.com/util": "^1.3.0", - "tree-dump": "^1.0.1", + "version": "4.49.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.49.0.tgz", + "integrity": "sha512-L9uC9vGuc4xFybbdOpRLoOAOq1YEBBsocCs5NVW32DfU+CZWWIn3OVF+lB8Gp4ttBVSMazwrTrjv8ussX/e3VQ==", + "dependencies": { + "@jsonjoy.com/json-pack": "^1.11.0", + "@jsonjoy.com/util": "^1.9.0", + "glob-to-regex.js": "^1.0.1", + "thingies": "^2.5.0", + "tree-dump": "^1.0.3", "tslib": "^2.0.0" }, - "engines": { - "node": ">= 4.0.0" - }, "funding": { "type": "github", "url": "https://github.com/sponsors/streamich" @@ -20467,17 +20485,6 @@ "node": ">=8.6" } }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", @@ -20515,16 +20522,24 @@ } }, "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "mime-db": "^1.54.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" } }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -20535,11 +20550,14 @@ } }, "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/minimalistic-assert": { @@ -20582,6 +20600,12 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true + }, "node_modules/mix2": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/mix2/-/mix2-1.0.5.tgz", @@ -20591,26 +20615,26 @@ } }, "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, "bin": { "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" } }, "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "license": "MIT" + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" }, "node_modules/mocha": { - "version": "11.7.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.1.tgz", - "integrity": "sha512-5EK+Cty6KheMS/YLPPMJC64g5V61gIR25KsRItHw6x4hEKT6Njp1n9LOlH4gpevuwMVS66SXaBBpg+RWZkza4A==", + "version": "11.7.4", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.4.tgz", + "integrity": "sha512-1jYAaY8x0kAZ0XszLWu14pzsf4KV740Gld4HXkhNTXwcHx4AUEDkPzgEHg9CM5dVcW+zv036tjpsEbLraPJj4w==", "dev": true, "dependencies": { "browser-stdout": "^1.3.1", @@ -20621,6 +20645,7 @@ "find-up": "^5.0.0", "glob": "^10.4.5", "he": "^1.2.0", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", "minimatch": "^9.0.5", @@ -20642,6 +20667,15 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/mocha/node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/mocha/node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -20658,6 +20692,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mocha/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/mocha/node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -20673,6 +20727,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mocha/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mocha/node_modules/p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", @@ -20712,13 +20781,25 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/mock-fs": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.5.0.tgz", - "integrity": "sha512-d/P1M/RacgM3dB0sJ8rjeRNXxtapkPCUnMGmIN0ixJ16F/E4GUZCvWcSGfWGz8eaXYvn1s9baUwNjI4LOPEjiA==", + "node_modules/mocha/node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "engines": { - "node": ">=12.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mock-fs": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.5.0.tgz", + "integrity": "sha512-d/P1M/RacgM3dB0sJ8rjeRNXxtapkPCUnMGmIN0ixJ16F/E4GUZCvWcSGfWGz8eaXYvn1s9baUwNjI4LOPEjiA==", + "dev": true, + "engines": { + "node": ">=12.0.0" } }, "node_modules/mri": { @@ -20748,12 +20829,12 @@ } }, "node_modules/mute-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", "dev": true, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/nanoid": { @@ -20776,8 +20857,7 @@ "node_modules/napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "license": "MIT" + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" }, "node_modules/natural-compare": { "version": "1.4.0", @@ -20844,7 +20924,6 @@ "version": "2.30.1", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", - "license": "MIT", "dependencies": { "semver": "^5.4.1" } @@ -20853,7 +20932,6 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "license": "ISC", "bin": { "semver": "bin/semver" } @@ -20861,8 +20939,7 @@ "node_modules/node-addon-api": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "license": "MIT" + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" }, "node_modules/node-domexception": { "version": "1.0.0", @@ -20936,9 +21013,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", + "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", "devOptional": true }, "node_modules/noms": { @@ -20974,8 +21051,7 @@ "node_modules/noop-logger": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", - "integrity": "sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ==", - "license": "MIT" + "integrity": "sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ==" }, "node_modules/nopt": { "version": "4.0.3", @@ -20997,29 +21073,24 @@ "dev": true }, "node_modules/normalize-package-data": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", - "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "dependencies": { - "hosted-git-info": "^7.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "semver": "bin/semver" } }, "node_modules/normalize-path": { @@ -21060,18 +21131,6 @@ "npm-license": "bin/npm-license" } }, - "node_modules/npm-license/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/npm-license/node_modules/nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -21106,15 +21165,43 @@ "dev": true }, "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", "dev": true, "dependencies": { - "path-key": "^3.0.0" + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/npmlog": { @@ -21122,7 +21209,6 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "deprecated": "This package is no longer supported.", - "license": "ISC", "dependencies": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -21146,15 +21232,14 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/nwsapi": { - "version": "2.2.20", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz", - "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==", + "version": "2.2.22", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.22.tgz", + "integrity": "sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ==", "dev": true }, "node_modules/object-assign": { @@ -21297,7 +21382,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -21326,14 +21410,14 @@ } }, "node_modules/open": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/open/-/open-10.1.2.tgz", - "integrity": "sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", - "is-wsl": "^3.1.0" + "wsl-utils": "^0.1.0" }, "engines": { "node": ">=18" @@ -21444,15 +21528,6 @@ "node": ">=0.10.0" } }, - "node_modules/oss-attribution-generator/node_modules/camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/oss-attribution-generator/node_modules/chalk": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", @@ -21510,15 +21585,6 @@ "ms": "2.0.0" } }, - "node_modules/oss-attribution-generator/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/oss-attribution-generator/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -21528,43 +21594,12 @@ "node": ">=0.8.0" } }, - "node_modules/oss-attribution-generator/node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", - "dev": true, - "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/oss-attribution-generator/node_modules/get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, - "node_modules/oss-attribution-generator/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/oss-attribution-generator/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", - "dev": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/oss-attribution-generator/node_modules/license-checker": { "version": "13.1.0", "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-13.1.0.tgz", @@ -21611,57 +21646,6 @@ "nopt": "bin/nopt.js" } }, - "node_modules/oss-attribution-generator/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/oss-attribution-generator/node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", - "dev": true, - "dependencies": { - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/oss-attribution-generator/node_modules/read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", - "dev": true, - "dependencies": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/oss-attribution-generator/node_modules/read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", - "dev": true, - "dependencies": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/oss-attribution-generator/node_modules/semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", @@ -21735,41 +21719,6 @@ "integrity": "sha512-xMXXC4eLKaIskvZm89nZi/MstVv1UtGk3nJz9BBKjreMVyoWisWFKfboH+kJS97+wUyBLpO/8ghV9M5VvrwwrA==", "dev": true }, - "node_modules/oss-attribution-generator/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", - "dev": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/oss-attribution-generator/node_modules/string-width/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/oss-attribution-generator/node_modules/string-width/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/oss-attribution-generator/node_modules/strip-ansi": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", @@ -21894,15 +21843,15 @@ } }, "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, "dependencies": { - "yocto-queue": "^0.1.0" + "yocto-queue": "^1.0.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -21923,33 +21872,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate/node_modules/yocto-queue": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", - "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-retry": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", @@ -22046,23 +21968,41 @@ } }, "node_modules/parse-asn1": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", - "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", + "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", "dependencies": { "asn1.js": "^4.10.1", "browserify-aes": "^1.2.0", "evp_bytestokey": "^1.0.3", - "hash-base": "~3.0", - "pbkdf2": "^3.1.2", + "pbkdf2": "^3.1.5", "safe-buffer": "^5.2.1" }, "engines": { "node": ">= 0.10" } }, - "node_modules/parse-json": { - "version": "5.2.0", + "node_modules/parse-asn1/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/parse-json": { + "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, @@ -22239,17 +22179,13 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" - }, "node_modules/path-to-regexp": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", - "engines": { - "node": ">=16" + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/path-type": { @@ -22266,15 +22202,6 @@ "node": ">=0.10.0" } }, - "node_modules/path-type/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path/node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -22306,48 +22233,39 @@ } }, "node_modules/pbkdf2": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.3.tgz", - "integrity": "sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", + "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", "dependencies": { - "create-hash": "~1.1.3", + "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "ripemd160": "=2.0.1", + "ripemd160": "^2.0.3", "safe-buffer": "^5.2.1", - "sha.js": "^2.4.11", - "to-buffer": "^1.2.0" + "sha.js": "^2.4.12", + "to-buffer": "^1.2.1" }, "engines": { - "node": ">=0.12" - } - }, - "node_modules/pbkdf2/node_modules/create-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", - "integrity": "sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "sha.js": "^2.4.0" - } - }, - "node_modules/pbkdf2/node_modules/hash-base": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", - "integrity": "sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==", - "dependencies": { - "inherits": "^2.0.1" + "node": ">= 0.10" } }, - "node_modules/pbkdf2/node_modules/ripemd160": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", - "integrity": "sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==", - "dependencies": { - "hash-base": "^2.0.0", - "inherits": "^2.0.1" - } + "node_modules/pbkdf2/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/pend": { "version": "1.2.0", @@ -22361,22 +22279,23 @@ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "engines": { - "node": ">=12" + "node": ">=8.6" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, "node_modules/pinkie": { @@ -22455,21 +22374,6 @@ "pino-pretty": "bin.js" } }, - "node_modules/pino-pretty/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/pino-pretty/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -22486,15 +22390,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/pino-pretty/node_modules/jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha512-+kHj8HXArPfpPEKGLZ+kB5ONRTCiGQXo8RQYL0hH8t6pWXUBBK5KkkQmTNOwKK4LEsd0yTsgtjJVm4UBSZea4w==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/pino-pretty/node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -22662,7 +22557,6 @@ "version": "5.3.6", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.6.tgz", "integrity": "sha512-s8Aai8++QQGi4sSbs/M1Qku62PFK49Jm1CbgXklGz4nmHveDq0wzJkg7Na5QbnO1uNH8K7iqx2EQ/mV0MZEmOg==", - "license": "MIT", "dependencies": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", @@ -22735,6 +22629,18 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", @@ -22745,9 +22651,9 @@ } }, "node_modules/pretty-ms": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz", - "integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", + "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", "dev": true, "dependencies": { "parse-ms": "^4.0.0" @@ -22786,6 +22692,18 @@ "prettier": "^3.0.0" } }, + "node_modules/pretty-quick/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pretty-quick/node_modules/tinyexec": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", @@ -22843,9 +22761,9 @@ } }, "node_modules/protobufjs": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.3.tgz", - "integrity": "sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", + "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", "hasInstallScript": true, "dependencies": { "@protobufjs/aspromise": "^1.1.2", @@ -22922,15 +22840,6 @@ "url": "https://github.com/sponsors/lupomontero" } }, - "node_modules/psl/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", @@ -22959,9 +22868,12 @@ } }, "node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } }, "node_modules/pure-rand": { "version": "6.1.0", @@ -23010,15 +22922,6 @@ "integrity": "sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==", "dev": true }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "engines": { - "node": ">=0.4.x" - } - }, "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -23099,24 +23002,38 @@ "dev": true }, "node_modules/raw-body": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", - "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", + "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", - "iconv-lite": "0.6.3", + "iconv-lite": "0.7.0", "unpipe": "1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.10" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -23127,17 +23044,23 @@ "rc": "cli.js" } }, + "node_modules/rc/node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/rc/node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -23188,265 +23111,72 @@ "npm-normalize-package-bin": "^1.0.0" } }, - "node_modules/read-package-json/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/read-package-json/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=0.10.0" } }, - "node_modules/read-package-json/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/read-package-json/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/read-package-json/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", "dev": true, "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/read-package-json/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/read-pkg": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.1.0.tgz", - "integrity": "sha512-PORM8AgzXeskHO/WEv312k9U03B8K9JSiWF/8N9sUuFjBa+9SF2u6K7VClzXwDXab51jCd8Nd36CNM+zR97ScQ==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.1", - "normalize-package-data": "^6.0.0", - "parse-json": "^7.0.0", - "type-fest": "^4.2.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-10.1.0.tgz", - "integrity": "sha512-aNtBq4jR8NawpKJQldrQcSW9y/d+KWH4v24HWkHljOZ7H0av+YTGANBzRh9A5pw7v/bLVsLVPpOhJ7gHNVy8lA==", - "dev": true, - "dependencies": { - "find-up": "^6.3.0", - "read-pkg": "^8.1.0", - "type-fest": "^4.2.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", - "dev": true, - "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg/node_modules/json-parse-even-better-errors": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", - "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/read-pkg/node_modules/lines-and-columns": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", - "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/read-pkg/node_modules/parse-json": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.1.1.tgz", - "integrity": "sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.21.4", - "error-ex": "^1.3.2", - "json-parse-even-better-errors": "^3.0.0", - "lines-and-columns": "^2.0.3", - "type-fest": "^3.8.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg/node_modules/parse-json/node_modules/type-fest": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", - "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/readable-stream": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", - "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", - "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/readable-stream/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/readable-stream/node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/readable-stream/node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/readdir-glob": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", @@ -23639,7 +23369,6 @@ "resolved": "https://registry.npmjs.org/registry-js/-/registry-js-1.16.1.tgz", "integrity": "sha512-pQ2kD36lh+YNtpaXm6HCCb0QZtV/zQEeKnkfEIj5FDSpF/oFts7pwizEUkWSvP8IbGb4A4a5iBhhS9eUearMmQ==", "hasInstallScript": true, - "license": "MIT", "dependencies": { "node-addon-api": "^3.2.1", "prebuild-install": "^5.3.5" @@ -23789,6 +23518,15 @@ "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==", "dev": true }, + "node_modules/ret": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz", + "integrity": "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/retry": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", @@ -23834,57 +23572,50 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, + "node_modules/ripemd160": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "hash-base": "^3.1.2", + "inherits": "^2.0.4" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 0.8" } }, - "node_modules/rimraf/node_modules/minimatch": { + "node_modules/ripemd160/node_modules/hash-base": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", "dependencies": { - "brace-expansion": "^1.1.7" + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" }, "engines": { - "node": "*" + "node": ">= 0.8" } }, - "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } + "node_modules/ripemd160/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/router": { "version": "2.2.0", @@ -23908,9 +23639,9 @@ "dev": true }, "node_modules/run-applescript": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", - "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", "engines": { "node": ">=18" }, @@ -23919,9 +23650,9 @@ } }, "node_modules/run-async": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", - "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz", + "integrity": "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ==", "dev": true, "engines": { "node": ">=0.12.0" @@ -23992,23 +23723,9 @@ "dev": true }, "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/safe-push-apply": { "version": "1.0.0", @@ -24036,6 +23753,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -24048,6 +23766,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-regex2": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.0.0.tgz", + "integrity": "sha512-YwJwe5a51WlK7KbOJREPdjNrpViQBI3p4T50lfwPuDhZnE3XGVTlGvi+aolc5+RvxDD6bnUmjVsU9n1eboLUYw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "dependencies": { + "ret": "~0.5.0" + } + }, "node_modules/safe-stable-stringify": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", @@ -24133,18 +23870,10 @@ "entities": "^4.4.0" } }, - "node_modules/sanitize-html/node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" }, "node_modules/saxes": { "version": "6.0.0", @@ -24159,9 +23888,9 @@ } }, "node_modules/schema-utils": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", - "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", @@ -24194,12 +23923,14 @@ } }, "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/send": { @@ -24223,28 +23954,39 @@ "node": ">= 18" } }, + "node_modules/send/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/serialize-error": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-11.0.3.tgz", - "integrity": "sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-12.0.0.tgz", + "integrity": "sha512-ZYkZLAvKTKQXWuh5XpBw7CdbSzagarX39WyZ2H07CDLC5/KfsRGlIXV8d4+tfqX1M7916mRqR1QfNHSij+c9Pw==", "dev": true, "dependencies": { - "type-fest": "^2.12.2" + "type-fest": "^4.31.0" }, "engines": { - "node": ">=14.16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/serialize-error/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "dev": true, "engines": { - "node": ">=12.20" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -24323,25 +24065,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" }, - "node_modules/serve-index/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -24385,8 +24108,7 @@ "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "license": "ISC" + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, "node_modules/set-function-length": { "version": "1.2.2", @@ -24444,17 +24166,43 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" }, "bin": { "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sha.js/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -24514,49 +24262,6 @@ "node": ">=4" } }, - "node_modules/shelljs/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/shelljs/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/shelljs/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/shlex": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/shlex/-/shlex-2.1.2.tgz", @@ -24674,50 +24379,23 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/simple-get": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", - "license": "MIT", "dependencies": { "decompress-response": "^4.2.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, - "node_modules/simple-get/node_modules/decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "license": "MIT", - "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/simple-get/node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/simple-invariant": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/simple-invariant/-/simple-invariant-2.0.1.tgz", "integrity": "sha512-1sbhsxqI+I2tqlmjbz99GXNmZtr6tKIyEgGGnJw/MKGblalqk/XoOYYFJlBzTKZCxx8kLaD3FD5s9BEEjx5Pyg==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" } @@ -24749,6 +24427,15 @@ "@sinonjs/commons": "^3.0.1" } }, + "node_modules/sinon/node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -24765,11 +24452,6 @@ "mix2": "^1.0.0" } }, - "node_modules/skema/node_modules/async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==" - }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -24817,12 +24499,12 @@ } }, "node_modules/socks": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.5.tgz", - "integrity": "sha512-iF+tNDQla22geJdTyJB1wM/qrX9DMRwWrciEPwWLPRWAUEM8sQiyxgckLxWT1f7+9VabJS0jTGGr4QgBuvi6Ww==", + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", "dev": true, "dependencies": { - "ip-address": "^9.0.5", + "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" }, "engines": { @@ -24877,15 +24559,6 @@ "node": ">=0.10.0" } }, - "node_modules/sort-keys/node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -24904,10 +24577,10 @@ } }, "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "devOptional": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -24978,9 +24651,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", - "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", "dev": true }, "node_modules/spdx-licenses": { @@ -25201,23 +24874,21 @@ "dev": true }, "node_modules/streamx": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.1.tgz", - "integrity": "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==", + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", + "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", "dependencies": { + "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" - }, - "optionalDependencies": { - "bare-events": "^2.2.0" } }, "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dependencies": { - "safe-buffer": "~5.2.0" + "safe-buffer": "~5.1.0" } }, "node_modules/string-length": { @@ -25234,19 +24905,16 @@ } }, "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, "node_modules/string-width-cjs": { @@ -25263,34 +24931,31 @@ "node": ">=8" } }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } }, "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": ">=0.10.0" } }, "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dependencies": { - "ansi-regex": "^6.0.1" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dependencies": { + "ansi-regex": "^2.0.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=0.10.0" } }, "node_modules/string.prototype.trim": { @@ -25373,21 +25038,24 @@ } }, "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", "dev": true, "engines": { - "node": ">=6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/strip-json-comments": { @@ -25530,19 +25198,22 @@ } }, "node_modules/tapable": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", - "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", "devOptional": true, "engines": { "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/tar-fs": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz", - "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==", - "license": "MIT", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -25550,25 +25221,10 @@ "tar-stream": "^2.1.4" } }, - "node_modules/tar-fs/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/tar-fs/node_modules/tar-stream": { + "node_modules/tar-stream": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "license": "MIT", "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -25580,24 +25236,27 @@ "node": ">=6" } }, - "node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/terser": { - "version": "5.43.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", - "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", + "version": "5.44.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", + "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", "devOptional": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.14.0", + "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -25642,43 +25301,14 @@ } } }, - "node_modules/terser-webpack-plugin/node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "devOptional": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/terser-webpack-plugin/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "devOptional": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/terser/node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "node_modules/terser-webpack-plugin/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "devOptional": true, "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/test-exclude": { @@ -25695,6 +25325,26 @@ "node": ">=18" } }, + "node_modules/test-exclude/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/text-decoder": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", @@ -25722,12 +25372,16 @@ "dev": true }, "node_modules/thingies": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", - "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz", + "integrity": "sha512-s+2Bwztg6PhWUD7XMfeYm5qliDdSiZm7M7n8KjTkIsm3l/2lgVRc2/Gx/v+ZX8lT4FMA+i8aQvhcWylldc+ZNw==", "engines": { "node": ">=10.18" }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, "peerDependencies": { "tslib": "^2" } @@ -25755,33 +25409,6 @@ "xtend": "~4.0.1" } }, - "node_modules/through2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/through2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/through2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -25802,18 +25429,6 @@ "node": ">=14.0.0" } }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -25821,9 +25436,9 @@ "dev": true }, "node_modules/to-buffer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz", - "integrity": "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", "dependencies": { "isarray": "^2.0.5", "safe-buffer": "^5.2.1", @@ -25838,6 +25453,25 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" }, + "node_modules/to-buffer/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -25872,15 +25506,6 @@ "node": ">=6" } }, - "node_modules/tough-cookie/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/tr46": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", @@ -25893,19 +25518,10 @@ "node": ">=18" } }, - "node_modules/tr46/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/tree-dump": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.3.tgz", - "integrity": "sha512-il+Cv80yVHFBwokQSfd4bldvr1Md951DpgAGfmhydt04L+YzHgubm2tQ7zueWDcGENKHq0ZvGFR/hjvNXilHEg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", + "integrity": "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==", "engines": { "node": ">=10.0" }, @@ -25939,14 +25555,14 @@ } }, "node_modules/ts-jest": { - "version": "29.4.0", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.0.tgz", - "integrity": "sha512-d423TJMnJGu80/eSgfQ5w/R+0zFJvdtTxwtF9KzFFunOpSeD+79lHJQIiAhluJoyGRbvj9NZJsl9WjCUo0ND7Q==", + "version": "29.4.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.4.tgz", + "integrity": "sha512-ccVcRABct5ZELCT5U0+DZwkXMCcOCLi2doHRrKy1nK/s7J7bch6TzJMsrY09WxgUUIP/ITfmcDS8D2yl63rnXw==", "dev": true, "dependencies": { "bs-logger": "^0.2.6", - "ejs": "^3.1.10", "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.8", "json5": "^2.2.3", "lodash.memoize": "^4.1.2", "make-error": "^1.3.6", @@ -25990,18 +25606,6 @@ } } }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/ts-jest/node_modules/type-fest": { "version": "4.41.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", @@ -26015,9 +25619,9 @@ } }, "node_modules/ts-loader": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.2.tgz", - "integrity": "sha512-Qo4piXvOTWcMGIgRiuFa6nHNm+54HbYaZCKqc9eeZCLRy3XqafQgwX2F7mofrbJG3g7EEb+lkiR+z2Lic2s3Zw==", + "version": "9.5.4", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.4.tgz", + "integrity": "sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ==", "dev": true, "dependencies": { "chalk": "^4.1.0", @@ -26034,21 +25638,6 @@ "webpack": "^5.0.0" } }, - "node_modules/ts-loader/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/ts-loader/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -26065,25 +25654,13 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/ts-loader/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/ts-loader/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", "dev": true, "engines": { - "node": ">= 8" + "node": ">= 12" } }, "node_modules/ts-lsp-client": { @@ -26108,28 +25685,6 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "dev": true }, - "node_modules/ts-mocha": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-11.1.0.tgz", - "integrity": "sha512-yT7FfzNRCu8ZKkYvAOiH01xNma/vLq6Vit7yINKYFNVP8e5UyrYXSOMIipERTpzVKJQ4Qcos5bQo1tNERNZevQ==", - "dev": true, - "bin": { - "ts-mocha": "bin/ts-mocha" - }, - "engines": { - "node": ">= 6.X.X" - }, - "peerDependencies": { - "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X || ^11.X.X", - "ts-node": "^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X", - "tsconfig-paths": "^4.X.X" - }, - "peerDependenciesMeta": { - "tsconfig-paths": { - "optional": true - } - } - }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", @@ -26173,15 +25728,6 @@ } } }, - "node_modules/ts-node/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/ts-sinon": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ts-sinon/-/ts-sinon-2.0.2.tgz", @@ -26238,15 +25784,6 @@ "@types/sinonjs__fake-timers": "*" } }, - "node_modules/ts-sinon/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/ts-sinon/node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -26310,30 +25847,27 @@ } }, "node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, - "optional": true, - "peer": true, "dependencies": { - "json5": "^2.2.2", + "@types/json5": "^0.0.29", + "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" } }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=4" + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" } }, "node_modules/tslib": { @@ -26342,9 +25876,9 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, "node_modules/tsx": { - "version": "4.20.3", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.3.tgz", - "integrity": "sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==", + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", "dev": true, "dependencies": { "esbuild": "~0.25.0", @@ -26364,7 +25898,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" }, @@ -26394,9 +25927,9 @@ } }, "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "engines": { "node": ">=10" @@ -26418,6 +25951,17 @@ "node": ">= 0.6" } }, + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", @@ -26492,9 +26036,9 @@ } }, "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -26508,6 +26052,19 @@ "resolved": "https://registry.npmjs.org/typescript-collections/-/typescript-collections-1.3.3.tgz", "integrity": "sha512-7sI4e/bZijOzyURng88oOFZCISQPTHozfE2sUu5AviFYk5QV7fYGb6YiDl+vKjF/pICA354JImBImL9XJWUvdQ==" }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/umd-compat-loader": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/umd-compat-loader/-/umd-compat-loader-2.1.2.tgz", @@ -26579,9 +26136,9 @@ "dev": true }, "node_modules/undici": { - "version": "6.21.3", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz", - "integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==", + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.22.0.tgz", + "integrity": "sha512-hU/10obOIu62MGYjdskASR3CUAiYaFTtC9Pa6vHyf//mAipSvSQg6od2CnJswq7fvzNS3zJhxoRkgNVaHurWKw==", "engines": { "node": ">=18.17" } @@ -26671,23 +26228,6 @@ "punycode": "^2.1.0" } }, - "node_modules/uri-js/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, "node_modules/url-parse": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", @@ -26717,6 +26257,7 @@ "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", @@ -26782,6 +26323,16 @@ "node": ">=10.12.0" } }, + "node_modules/v8-to-istanbul/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -26849,18 +26400,6 @@ "node": ">=10" } }, - "node_modules/vscode-languageclient/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/vscode-languageserver": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", @@ -26930,21 +26469,6 @@ "node": ">=10" } }, - "node_modules/wait-port/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/wait-port/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -27025,20 +26549,6 @@ "wdio": "bin/wdio.js" } }, - "node_modules/wdio/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/wdio/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -27062,17 +26572,6 @@ "node": ">= 12" } }, - "node_modules/wdio/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", @@ -27088,20 +26587,21 @@ "integrity": "sha512-hS87TH71Zd6mGAmYCvlgxeGDjqd9GTeqXNqTT+u0Gs51uIozNIaaq/kUAbV/Zf56jb2ZOyG8BxZs2GG9wbLi6Q==" }, "node_modules/webdriver": { - "version": "9.16.2", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.16.2.tgz", - "integrity": "sha512-T7QKqD+N0hfvrxq/am5wqdOuyOy7F2tGS7X2f/7jyhrxSPG6Q0cNkSt4gCwla+q3nDMivCP0QIPc7mAVSx5AYQ==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.20.0.tgz", + "integrity": "sha512-Kk+AGV1xWLNHVpzUynQJDULMzbcO3IjXo3s0BzfC30OpGxhpaNmoazMQodhtv0Lp242Mb1VYXD89dCb4oAHc4w==", "dev": true, "dependencies": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "9.16.2", - "@wdio/logger": "9.16.2", + "@wdio/config": "9.20.0", + "@wdio/logger": "9.18.0", "@wdio/protocols": "9.16.2", - "@wdio/types": "9.16.2", - "@wdio/utils": "9.16.2", + "@wdio/types": "9.20.0", + "@wdio/utils": "9.20.0", "deepmerge-ts": "^7.0.3", - "undici": "^6.20.1", + "https-proxy-agent": "^7.0.6", + "undici": "^6.21.3", "ws": "^8.8.0" }, "engines": { @@ -27109,35 +26609,35 @@ } }, "node_modules/webdriver/node_modules/@types/node": { - "version": "20.19.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.2.tgz", - "integrity": "sha512-9pLGGwdzOUBDYi0GNjM97FIA+f92fqSke6joWeBjWXllfNxZBs7qeMF7tvtOIsbY45xkWkxrdwUfUf3MnQa9gA==", + "version": "20.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.19.tgz", + "integrity": "sha512-pb1Uqj5WJP7wrcbLU7Ru4QtA0+3kAXrkutGiD26wUKzSMgNNaPARTUDQmElUXp64kh3cWdou3Q0C7qwwxqSFmg==", "dev": true, "dependencies": { "undici-types": "~6.21.0" } }, "node_modules/webdriverio": { - "version": "9.16.2", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.16.2.tgz", - "integrity": "sha512-aRcfBZyY+OFqz2DI0ZYmMahGlH3h/clAXXOQSFN5QfrHG4Cjuo5xy3lq4tVfszjEJ813+wwC4HJLbgDmMrPXkA==", + "version": "9.20.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.20.0.tgz", + "integrity": "sha512-cqaXfahTzCFaQLlk++feZaze6tAsW8OSdaVRgmOGJRII1z2A4uh4YGHtusTpqOiZAST7OBPqycOwfh01G/Ktbg==", "dev": true, "dependencies": { "@types/node": "^20.11.30", "@types/sinonjs__fake-timers": "^8.1.5", - "@wdio/config": "9.16.2", - "@wdio/logger": "9.16.2", + "@wdio/config": "9.20.0", + "@wdio/logger": "9.18.0", "@wdio/protocols": "9.16.2", "@wdio/repl": "9.16.2", - "@wdio/types": "9.16.2", - "@wdio/utils": "9.16.2", + "@wdio/types": "9.20.0", + "@wdio/utils": "9.20.0", "archiver": "^7.0.1", "aria-query": "^5.3.0", "cheerio": "^1.0.0-rc.12", "css-shorthand-properties": "^1.1.1", "css-value": "^0.0.1", "grapheme-splitter": "^1.0.4", - "htmlfy": "^0.6.0", + "htmlfy": "^0.8.1", "is-plain-obj": "^4.1.0", "jszip": "^3.10.1", "lodash.clonedeep": "^4.5.0", @@ -27145,9 +26645,9 @@ "query-selector-shadow-dom": "^1.0.1", "resq": "^1.11.0", "rgb2hex": "0.2.5", - "serialize-error": "^11.0.3", + "serialize-error": "^12.0.0", "urlpattern-polyfill": "^10.0.0", - "webdriver": "9.16.2" + "webdriver": "9.20.0" }, "engines": { "node": ">=18.20.0" @@ -27162,9 +26662,9 @@ } }, "node_modules/webdriverio/node_modules/@types/node": { - "version": "20.19.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.2.tgz", - "integrity": "sha512-9pLGGwdzOUBDYi0GNjM97FIA+f92fqSke6joWeBjWXllfNxZBs7qeMF7tvtOIsbY45xkWkxrdwUfUf3MnQa9gA==", + "version": "20.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.19.tgz", + "integrity": "sha512-pb1Uqj5WJP7wrcbLU7Ru4QtA0+3kAXrkutGiD26wUKzSMgNNaPARTUDQmElUXp64kh3cWdou3Q0C7qwwxqSFmg==", "dev": true, "dependencies": { "undici-types": "~6.21.0" @@ -27192,21 +26692,22 @@ } }, "node_modules/webpack": { - "version": "5.99.9", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz", - "integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==", + "version": "5.102.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.102.1.tgz", + "integrity": "sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==", "devOptional": true, "dependencies": { "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.6", + "@types/estree": "^1.0.8", "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.14.0", - "browserslist": "^4.24.0", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.26.3", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", + "enhanced-resolve": "^5.17.3", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -27216,11 +26717,11 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^4.3.2", - "tapable": "^2.1.1", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", "terser-webpack-plugin": "^5.3.11", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "watchpack": "^2.4.4", + "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" @@ -27311,13 +26812,13 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", - "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.5.tgz", + "integrity": "sha512-uxQ6YqGdE4hgDKNf7hUiPXOdtkXvBJXrfEGYSx7P7LC8hnUYGK70X6xQXUvXeNyBDDcsiQXpG2m3G9vxowaEuA==", "dependencies": { "colorette": "^2.0.10", - "memfs": "^4.6.0", - "mime-types": "^2.1.31", + "memfs": "^4.43.1", + "mime-types": "^3.0.1", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" @@ -27338,20 +26839,12 @@ } } }, - "node_modules/webpack-dev-middleware/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/webpack-dev-middleware/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "dependencies": { - "mime-db": "1.52.0" + "mime-db": "^1.54.0" }, "engines": { "node": ">= 0.6" @@ -27624,25 +27117,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack-dev-server/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack-dev-server/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/webpack-dev-server/node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -27656,17 +27130,6 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, - "node_modules/webpack-dev-server/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/webpack-dev-server/node_modules/qs": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", @@ -27706,6 +27169,25 @@ "node": ">=8.10.0" } }, + "node_modules/webpack-dev-server/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/webpack-dev-server/node_modules/send": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", @@ -27816,36 +27298,6 @@ "node": ">=4.0" } }, - "node_modules/webpack/node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "devOptional": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/webpack/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "devOptional": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/webpack/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "devOptional": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", @@ -27995,7 +27447,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", - "license": "MIT", "engines": { "node": ">=4" } @@ -28024,31 +27475,10 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "license": "ISC", "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, - "node_modules/wide-align/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/wide-align/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", @@ -28078,6 +27508,14 @@ "node": ">=4" } }, + "node_modules/win-ca/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "engines": { + "node": ">=4" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -28087,23 +27525,29 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, "node_modules/workerpool": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.3.tgz", - "integrity": "sha512-slxCaKbYjEdFT/o2rH9xS1hf4uRDch1w7Uo+apxhZ+sf/1d9e0ZVkn42kPNGP2dgjIx6YFvSevj0zHvbWe2jdw==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", "dev": true }, "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -28126,25 +27570,14 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, + "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -28158,40 +27591,25 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dependencies": { - "ansi-regex": "^6.0.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=8" } }, "node_modules/wrappy": { @@ -28238,6 +27656,20 @@ } } }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", @@ -28467,11 +27899,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "node_modules/yargs-unparser/node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs-unparser/node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } }, "node_modules/yargs/node_modules/string-width": { "version": "4.2.3", @@ -28502,7 +27958,6 @@ "resolved": "https://registry.npmjs.org/yauzl-promise/-/yauzl-promise-4.0.0.tgz", "integrity": "sha512-/HCXpyHXJQQHvFq9noqrjfa/WpQC2XYs3vI7tBiAi4QiIU1knvYhZGaO1QPjwIVMdqflxbmwgMXtYeaRiAE0CA==", "dev": true, - "license": "MIT", "dependencies": { "@node-rs/crc32": "^1.7.0", "is-it-type": "^5.1.2", @@ -28531,21 +27986,21 @@ } }, "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/yoctocolors": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.1.tgz", - "integrity": "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", "dev": true, "engines": { "node": ">=18" @@ -28555,9 +28010,9 @@ } }, "node_modules/yoctocolors-cjs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", - "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", "dev": true, "engines": { "node": ">=18" @@ -28579,10 +28034,75 @@ "node": ">= 14" } }, + "node_modules/zip-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/zip-stream/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/zip-stream/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/zip-stream/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/zod": { - "version": "3.25.67", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.67.tgz", - "integrity": "sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw==", + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -28596,9 +28116,9 @@ } }, "node_modules/zx": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/zx/-/zx-8.6.0.tgz", - "integrity": "sha512-CpOskNj7nNW19z5DkOTHX24Yh1qnnx1oANn8EnD3QbCUBnZpuennJaYkb4zea5GJCxT6/IdxeiA5nweQ1S2YtA==", + "version": "8.8.4", + "resolved": "https://registry.npmjs.org/zx/-/zx-8.8.4.tgz", + "integrity": "sha512-44GcD+ZlM/v1OQtbwnSxLPcoE1ZEUICmR+RSbJZLAqfIixNLuMjLyh0DcS75OyfJ/sWYAwCWDmDvJ4hdnANAPQ==", "dev": true, "bin": { "zx": "build/cli.js" @@ -28612,14 +28132,14 @@ "version": "0.1.20", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-core": "^0.0.16" }, "devDependencies": { "@babel/plugin-transform-modules-commonjs": "^7.24.1", "@types/jest": "29.5.14", - "antlr4-c3": "3.4.2", - "antlr4ng": "3.0.14", + "antlr4-c3": "3.4.4", + "antlr4ng": "3.0.16", "antlr4ng-cli": "^2.0.0", "babel-plugin-transform-import-meta": "^2.3.2", "jest": "^29.7.0", @@ -28637,9 +28157,8 @@ }, "server/aws-lsp-antlr4/node_modules/prettier": { "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, + "license": "MIT", "bin": { "prettier": "bin-prettier.js" }, @@ -28654,7 +28173,7 @@ "name": "@aws/lsp-buildspec", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", @@ -28665,7 +28184,7 @@ "name": "@aws/lsp-cloudformation", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", @@ -28676,6 +28195,8 @@ "name": "@aws/lsp-codewhisperer", "version": "0.0.84", "bundleDependencies": [ + "@amzn/codewhisperer", + "@amzn/codewhisperer-runtime", "@amzn/codewhisperer-streaming", "@amzn/amazon-q-developer-streaming-client" ], @@ -28683,18 +28204,20 @@ "license": "Apache-2.0", "dependencies": { "@amzn/amazon-q-developer-streaming-client": "file:../../core/q-developer-streaming-client/amzn-amazon-q-developer-streaming-client-1.0.0.tgz", + "@amzn/codewhisperer": "file:../../core/codewhisperer/amzn-codewhisperer-1.0.0.tgz", + "@amzn/codewhisperer-runtime": "file:../../core/codewhisperer-runtime/amzn-codewhisperer-runtime-1.0.0.tgz", "@amzn/codewhisperer-streaming": "file:../../core/codewhisperer-streaming/amzn-codewhisperer-streaming-1.0.0.tgz", + "@aws-sdk/types": "^3.734.0", "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.57", - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-core": "^0.0.16", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", "adm-zip": "^0.5.10", "archiver": "^7.0.1", "async-mutex": "^0.5.0", - "aws-sdk": "^2.1403.0", "axios": "^1.8.4", "chokidar": "^4.0.3", "deepmerge": "^4.3.1", @@ -28749,8 +28272,7 @@ }, "server/aws-lsp-codewhisperer/node_modules/@smithy/abort-controller": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.2.0.tgz", - "integrity": "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==", + "license": "Apache-2.0", "dependencies": { "@smithy/types": "^2.12.0", "tslib": "^2.6.2" @@ -28761,8 +28283,7 @@ }, "server/aws-lsp-codewhisperer/node_modules/@smithy/node-http-handler": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.5.0.tgz", - "integrity": "sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==", + "license": "Apache-2.0", "dependencies": { "@smithy/abort-controller": "^2.2.0", "@smithy/protocol-http": "^3.3.0", @@ -28771,121 +28292,647 @@ "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=14.0.0" + } + }, + "server/aws-lsp-codewhisperer/node_modules/@smithy/protocol-http": { + "version": "3.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "server/aws-lsp-codewhisperer/node_modules/@smithy/querystring-builder": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.12.0", + "@smithy/util-uri-escape": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "server/aws-lsp-codewhisperer/node_modules/@smithy/types": { + "version": "2.12.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "server/aws-lsp-codewhisperer/node_modules/@smithy/util-uri-escape": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "server/aws-lsp-codewhisperer/node_modules/diff": { + "version": "7.0.0", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "server/aws-lsp-codewhisperer/node_modules/fdir": { + "version": "6.5.0", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "server/aws-lsp-codewhisperer/node_modules/picomatch": { + "version": "4.0.3", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "server/aws-lsp-codewhisperer/node_modules/ts-mocha": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "bin": { + "ts-mocha": "bin/ts-mocha" + }, + "engines": { + "node": ">= 6.X.X" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X || ^11.X.X", + "ts-node": "^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X", + "tsconfig-paths": "^4.X.X" + }, + "peerDependenciesMeta": { + "tsconfig-paths": { + "optional": true + } + } + }, + "server/aws-lsp-codewhisperer/node_modules/tsconfig-paths": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "server/aws-lsp-identity": { + "name": "@aws/lsp-identity", + "version": "0.0.1", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso-oidc": "^3.616.0", + "@aws-sdk/token-providers": "^3.744.0", + "@aws/language-server-runtimes": "^0.3.0", + "@aws/lsp-core": "^0.0.16", + "@smithy/node-http-handler": "^3.2.5", + "@smithy/shared-ini-file-loader": "^4.0.1", + "https-proxy-agent": "^7.0.5", + "vscode-languageserver": "^9.0.1" + }, + "devDependencies": { + "@aws-sdk/types": "^3.734.0", + "@smithy/types": "^3.4.1", + "@types/chai": "^4.3.5", + "@types/chai-as-promised": "^7.1.5", + "@types/mocha": "^10.0.9", + "@types/mock-fs": "^4.13.4", + "@types/sinon": "^17.0.3", + "c8": "^10.1.2", + "chai": "^4.3.7", + "chai-as-promised": "^7.1.1", + "copyfiles": "^2.4.1", + "mock-fs": "^5.2.0", + "sinon": "^19.0.2", + "ts-loader": "^9.5.1", + "ts-mocha": "^11.1.0", + "ts-sinon": "^2.0.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/core": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@aws-sdk/xml-builder": "3.901.0", + "@smithy/core": "^3.14.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/signature-v4": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/core/node_modules/@smithy/protocol-http": { + "version": "5.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/core/node_modules/@smithy/types": { + "version": "4.6.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/middleware-host-header/node_modules/@smithy/protocol-http": { + "version": "5.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/middleware-host-header/node_modules/@smithy/types": { + "version": "4.6.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/middleware-logger": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/middleware-logger/node_modules/@smithy/types": { + "version": "4.6.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@aws/lambda-invoke-store": "^0.0.1", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/middleware-recursion-detection/node_modules/@smithy/protocol-http": { + "version": "5.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/middleware-recursion-detection/node_modules/@smithy/types": { + "version": "4.6.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@smithy/core": "^3.14.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/protocol-http": { + "version": "5.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/types": { + "version": "4.6.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/nested-clients": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.901.0", + "@aws-sdk/middleware-host-header": "3.901.0", + "@aws-sdk/middleware-logger": "3.901.0", + "@aws-sdk/middleware-recursion-detection": "3.901.0", + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/region-config-resolver": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@aws-sdk/util-user-agent-browser": "3.901.0", + "@aws-sdk/util-user-agent-node": "3.901.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.14.0", + "@smithy/fetch-http-handler": "^5.3.0", + "@smithy/hash-node": "^4.2.0", + "@smithy/invalid-dependency": "^4.2.0", + "@smithy/middleware-content-length": "^4.2.0", + "@smithy/middleware-endpoint": "^4.3.0", + "@smithy/middleware-retry": "^4.4.0", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-base64": "^4.2.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.0", + "@smithy/util-defaults-mode-browser": "^4.2.0", + "@smithy/util-defaults-mode-node": "^4.2.0", + "@smithy/util-endpoints": "^3.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/nested-clients/node_modules/@smithy/abort-controller": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler": { + "version": "4.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/querystring-builder": "^4.2.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/nested-clients/node_modules/@smithy/protocol-http": { + "version": "5.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/nested-clients/node_modules/@smithy/querystring-builder": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "@smithy/util-uri-escape": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/nested-clients/node_modules/@smithy/types": { + "version": "4.6.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/nested-clients/node_modules/@smithy/util-uri-escape": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/region-config-resolver/node_modules/@smithy/types": { + "version": "4.6.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/token-providers": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.901.0", + "@aws-sdk/nested-clients": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/token-providers/node_modules/@smithy/types": { + "version": "4.6.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/util-user-agent-browser/node_modules/@smithy/types": { + "version": "4.6.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "server/aws-lsp-identity/node_modules/@aws-sdk/util-user-agent-node/node_modules/@smithy/types": { + "version": "4.6.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "server/aws-lsp-identity/node_modules/@smithy/abort-controller": { + "version": "3.1.9", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^3.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "server/aws-lsp-codewhisperer/node_modules/@smithy/protocol-http": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.3.0.tgz", - "integrity": "sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==", + "server/aws-lsp-identity/node_modules/@smithy/node-http-handler": { + "version": "3.3.3", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", + "@smithy/abort-controller": "^3.1.9", + "@smithy/protocol-http": "^4.1.8", + "@smithy/querystring-builder": "^3.0.11", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "server/aws-lsp-codewhisperer/node_modules/@smithy/querystring-builder": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.2.0.tgz", - "integrity": "sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==", + "server/aws-lsp-identity/node_modules/@smithy/protocol-http": { + "version": "4.1.8", + "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^2.12.0", - "@smithy/util-uri-escape": "^2.2.0", + "@smithy/types": "^3.7.2", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "server/aws-lsp-codewhisperer/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", + "server/aws-lsp-identity/node_modules/@smithy/querystring-builder": { + "version": "3.0.11", + "license": "Apache-2.0", "dependencies": { + "@smithy/types": "^3.7.2", + "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "server/aws-lsp-codewhisperer/node_modules/@smithy/util-uri-escape": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.2.0.tgz", - "integrity": "sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==", + "server/aws-lsp-identity/node_modules/@smithy/types": { + "version": "3.7.2", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "server/aws-lsp-identity": { - "name": "@aws/lsp-identity", - "version": "0.0.1", + "server/aws-lsp-identity/node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-sso-oidc": "^3.616.0", - "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.2.129", - "@aws/lsp-core": "^0.0.12", - "@smithy/node-http-handler": "^3.2.5", - "@smithy/shared-ini-file-loader": "^4.0.1", - "https-proxy-agent": "^7.0.5", - "vscode-languageserver": "^9.0.1" - }, - "devDependencies": { - "@aws-sdk/types": "^3.734.0", - "@smithy/types": "^3.4.1", - "@types/chai": "^4.3.5", - "@types/chai-as-promised": "^7.1.5", - "@types/mocha": "^10.0.9", - "@types/mock-fs": "^4.13.4", - "@types/sinon": "^17.0.3", - "c8": "^10.1.2", - "chai": "^4.3.7", - "chai-as-promised": "^7.1.1", - "copyfiles": "^2.4.1", - "mock-fs": "^5.2.0", - "sinon": "^19.0.2", - "ts-loader": "^9.5.1", - "ts-mocha": "^11.1.0", - "ts-sinon": "^2.0.2" + "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=16.0.0" } }, - "server/aws-lsp-identity/node_modules/@aws/lsp-core": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/@aws/lsp-core/-/lsp-core-0.0.12.tgz", - "integrity": "sha512-FNbbvzUZQKtUE/LHGsI8b05+M44h47f7ExlET1WeOnhfjDWu7n+wlHRkPZkdsEe1z5pbluGNBaiTO/cV9A2qQQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws/language-server-runtimes": "^0.2.109", - "@gerhobbelt/gitignore-parser": "^0.2.0-9", - "cross-spawn": "7.0.6", - "jose": "^5.2.4", - "request-light": "^0.8.0", - "vscode-languageserver-textdocument": "^1.0.8", - "vscode-languageserver-types": "^3.17.3", - "vscode-uri": "^3.1.0" + "server/aws-lsp-identity/node_modules/ts-mocha": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "bin": { + "ts-mocha": "bin/ts-mocha" }, "engines": { - "node": ">=18.0.0" + "node": ">= 6.X.X" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X || ^11.X.X", + "ts-node": "^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X", + "tsconfig-paths": "^4.X.X" + }, + "peerDependenciesMeta": { + "tsconfig-paths": { + "optional": true + } } }, - "server/aws-lsp-identity/node_modules/@smithy/types": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.7.2.tgz", - "integrity": "sha512-bNwBYYmN8Eh9RyjS1p2gW6MIhSO2rl7X9QeLM8iTdcGRP+eDiIWDt66c9IysCc22gefKszZv+ubV9qZc7hdESg==", + "server/aws-lsp-identity/node_modules/tsconfig-paths": { + "version": "4.2.0", "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "tslib": "^2.6.2" + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=6" } }, "server/aws-lsp-json": { @@ -28893,25 +28940,64 @@ "version": "0.1.20", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" }, "devDependencies": { - "c8": "^10.1.2" + "c8": "^10.1.2", + "ts-mocha": "^11.1.0" }, "engines": { "node": ">=18.0.0" } }, + "server/aws-lsp-json/node_modules/ts-mocha": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-11.1.0.tgz", + "integrity": "sha512-yT7FfzNRCu8ZKkYvAOiH01xNma/vLq6Vit7yINKYFNVP8e5UyrYXSOMIipERTpzVKJQ4Qcos5bQo1tNERNZevQ==", + "dev": true, + "bin": { + "ts-mocha": "bin/ts-mocha" + }, + "engines": { + "node": ">= 6.X.X" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X || ^11.X.X", + "ts-node": "^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X", + "tsconfig-paths": "^4.X.X" + }, + "peerDependenciesMeta": { + "tsconfig-paths": { + "optional": true + } + } + }, + "server/aws-lsp-json/node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "server/aws-lsp-notification": { "name": "@aws/lsp-notification", "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", - "@aws/lsp-core": "^0.0.12", + "@aws/language-server-runtimes": "^0.3.0", + "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1" }, "devDependencies": { @@ -28935,35 +29021,51 @@ "node": ">=18.0.0" } }, - "server/aws-lsp-notification/node_modules/@aws/lsp-core": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/@aws/lsp-core/-/lsp-core-0.0.12.tgz", - "integrity": "sha512-FNbbvzUZQKtUE/LHGsI8b05+M44h47f7ExlET1WeOnhfjDWu7n+wlHRkPZkdsEe1z5pbluGNBaiTO/cV9A2qQQ==", + "server/aws-lsp-notification/node_modules/@smithy/types": { + "version": "3.7.2", + "dev": true, "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.109", - "@gerhobbelt/gitignore-parser": "^0.2.0-9", - "cross-spawn": "7.0.6", - "jose": "^5.2.4", - "request-light": "^0.8.0", - "vscode-languageserver-textdocument": "^1.0.8", - "vscode-languageserver-types": "^3.17.3", - "vscode-uri": "^3.1.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=16.0.0" } }, - "server/aws-lsp-notification/node_modules/@smithy/types": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.7.2.tgz", - "integrity": "sha512-bNwBYYmN8Eh9RyjS1p2gW6MIhSO2rl7X9QeLM8iTdcGRP+eDiIWDt66c9IysCc22gefKszZv+ubV9qZc7hdESg==", + "server/aws-lsp-notification/node_modules/ts-mocha": { + "version": "11.1.0", "dev": true, + "license": "MIT", + "bin": { + "ts-mocha": "bin/ts-mocha" + }, + "engines": { + "node": ">= 6.X.X" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X || ^11.X.X", + "ts-node": "^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X", + "tsconfig-paths": "^4.X.X" + }, + "peerDependenciesMeta": { + "tsconfig-paths": { + "optional": true + } + } + }, + "server/aws-lsp-notification/node_modules/tsconfig-paths": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "tslib": "^2.6.2" + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=6" } }, "server/aws-lsp-partiql": { @@ -28971,9 +29073,9 @@ "version": "0.0.18", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", - "antlr4-c3": "3.4.2", - "antlr4ng": "3.0.14", + "@aws/language-server-runtimes": "^0.3.0", + "antlr4-c3": "3.4.4", + "antlr4ng": "3.0.16", "web-tree-sitter": "0.22.6" }, "devDependencies": { @@ -28993,19 +29095,17 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.2.129", - "@aws/lsp-core": "^0.0.12", + "@aws/language-server-runtimes": "^0.3.0", + "@aws/lsp-core": "^0.0.15", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" } }, "server/aws-lsp-s3/node_modules/@aws/lsp-core": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/@aws/lsp-core/-/lsp-core-0.0.12.tgz", - "integrity": "sha512-FNbbvzUZQKtUE/LHGsI8b05+M44h47f7ExlET1WeOnhfjDWu7n+wlHRkPZkdsEe1z5pbluGNBaiTO/cV9A2qQQ==", + "version": "0.0.15", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.109", + "@aws/language-server-runtimes": "^0.2.128", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", @@ -29018,13 +29118,43 @@ "node": ">=18.0.0" } }, + "server/aws-lsp-s3/node_modules/@aws/lsp-core/node_modules/@aws/language-server-runtimes": { + "version": "0.2.129", + "license": "Apache-2.0", + "dependencies": { + "@aws/language-server-runtimes-types": "^0.1.56", + "@opentelemetry/api": "^1.9.0", + "@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.1", + "@opentelemetry/sdk-logs": "^0.200.0", + "@opentelemetry/sdk-metrics": "^2.0.1", + "@smithy/node-http-handler": "^4.0.4", + "ajv": "^8.17.1", + "aws-sdk": "^2.1692.0", + "hpagent": "^1.2.0", + "jose": "^5.9.6", + "mac-ca": "^3.1.1", + "registry-js": "^1.16.1", + "rxjs": "^7.8.2", + "vscode-languageserver": "^9.0.1", + "vscode-languageserver-protocol": "^3.17.5", + "vscode-uri": "^3.1.0", + "win-ca": "^3.5.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, "server/aws-lsp-yaml": { "name": "@aws/lsp-yaml", "version": "0.1.20", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", @@ -29038,7 +29168,7 @@ "name": "@amzn/device-sso-auth-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "vscode-languageserver": "^9.0.1" }, "devDependencies": { @@ -29049,15 +29179,54 @@ "name": "@aws/hello-world-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "vscode-languageserver": "^9.0.1" }, "devDependencies": { "c8": "^10.1.2", "ts-loader": "^9.4.4", + "ts-mocha": "^11.1.0", "webpack": "^5.94.0", "webpack-cli": "^6.0.1" } + }, + "server/hello-world-lsp/node_modules/ts-mocha": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-11.1.0.tgz", + "integrity": "sha512-yT7FfzNRCu8ZKkYvAOiH01xNma/vLq6Vit7yINKYFNVP8e5UyrYXSOMIipERTpzVKJQ4Qcos5bQo1tNERNZevQ==", + "dev": true, + "bin": { + "ts-mocha": "bin/ts-mocha" + }, + "engines": { + "node": ">= 6.X.X" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X || ^11.X.X", + "ts-node": "^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X", + "tsconfig-paths": "^4.X.X" + }, + "peerDependenciesMeta": { + "tsconfig-paths": { + "optional": true + } + } + }, + "server/hello-world-lsp/node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } } } } diff --git a/package.json b/package.json index 82468102ab..4e7f440ac4 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "ci:generate:agentic:attribution": "ts-node ./script/prepare-agentic-attribution-dependencies.ts && ./script/generate-agentic-attribution.sh && git restore package.json" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.116", + "@aws/language-server-runtimes": "^0.3.0", "@smithy/types": "4.2.0", "clean": "^4.0.2", "typescript": "^5.8.2" diff --git a/server/aws-lsp-antlr4/package.json b/server/aws-lsp-antlr4/package.json index 38758b8335..565a3732e1 100644 --- a/server/aws-lsp-antlr4/package.json +++ b/server/aws-lsp-antlr4/package.json @@ -28,7 +28,7 @@ "clean": "rm -rf node_modules" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-core": "^0.0.16" }, "peerDependencies": { @@ -38,8 +38,8 @@ "devDependencies": { "@babel/plugin-transform-modules-commonjs": "^7.24.1", "@types/jest": "29.5.14", - "antlr4-c3": "3.4.2", - "antlr4ng": "3.0.14", + "antlr4-c3": "3.4.4", + "antlr4ng": "3.0.16", "antlr4ng-cli": "^2.0.0", "babel-plugin-transform-import-meta": "^2.3.2", "jest": "^29.7.0", diff --git a/server/aws-lsp-buildspec/package.json b/server/aws-lsp-buildspec/package.json index 3d8bdc4671..32da0c8306 100644 --- a/server/aws-lsp-buildspec/package.json +++ b/server/aws-lsp-buildspec/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-cloudformation/package.json b/server/aws-lsp-cloudformation/package.json index 14860f5ea9..4b5087c74a 100644 --- a/server/aws-lsp-cloudformation/package.json +++ b/server/aws-lsp-cloudformation/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-codewhisperer/.prettierignore b/server/aws-lsp-codewhisperer/.prettierignore index f1287fa3c5..0dbb1b11cb 100644 --- a/server/aws-lsp-codewhisperer/.prettierignore +++ b/server/aws-lsp-codewhisperer/.prettierignore @@ -5,5 +5,4 @@ out/ **/bin/ **/obj/ src/client/sigv4/codewhisperersigv4client.d.ts -src/client/token/codewhispererbearertokenclient.d.ts **/*.md diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index baa5f2e253..9656bbe1e1 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -14,8 +14,6 @@ }, "scripts": { "compile": "tsc --build", - "postcompile": "npm run copyServiceClient", - "copyServiceClient": "copyfiles -u 1 --error ./src/client/sigv4/*.json out && copyfiles -u 1 --error ./src/client/token/*.json out", "fix": "npm run fix:prettier", "fix:prettier": "prettier . --write", "lint": "npm run lint:src", @@ -32,18 +30,20 @@ }, "dependencies": { "@amzn/amazon-q-developer-streaming-client": "file:../../core/q-developer-streaming-client/amzn-amazon-q-developer-streaming-client-1.0.0.tgz", + "@amzn/codewhisperer": "file:../../core/codewhisperer/amzn-codewhisperer-1.0.0.tgz", + "@amzn/codewhisperer-runtime": "file:../../core/codewhisperer-runtime/amzn-codewhisperer-runtime-1.0.0.tgz", "@amzn/codewhisperer-streaming": "file:../../core/codewhisperer-streaming/amzn-codewhisperer-streaming-1.0.0.tgz", "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", "@aws/chat-client-ui-types": "^0.1.57", - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-core": "^0.0.16", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", "adm-zip": "^0.5.10", "archiver": "^7.0.1", "async-mutex": "^0.5.0", - "aws-sdk": "^2.1403.0", + "@aws-sdk/types": "^3.734.0", "axios": "^1.8.4", "chokidar": "^4.0.3", "deepmerge": "^4.3.1", @@ -103,6 +103,8 @@ "endOfLine": "lf" }, "bundleDependencies": [ + "@amzn/codewhisperer", + "@amzn/codewhisperer-runtime", "@amzn/codewhisperer-streaming", "@amzn/amazon-q-developer-streaming-client" ] diff --git a/server/aws-lsp-codewhisperer/src/client/sigv4/codewhisperer.ts b/server/aws-lsp-codewhisperer/src/client/sigv4/codewhisperer.ts index 0395a639f6..22bb8a5641 100644 --- a/server/aws-lsp-codewhisperer/src/client/sigv4/codewhisperer.ts +++ b/server/aws-lsp-codewhisperer/src/client/sigv4/codewhisperer.ts @@ -1,25 +1,68 @@ -import { Service } from 'aws-sdk' -import { ServiceConfigurationOptions } from 'aws-sdk/lib/service' -const apiConfig = require('./service.json') -import CodeWhispererClient = require('./codewhisperersigv4client') +import { CodeWhispererClient, CodeWhispererClientConfig } from '@amzn/codewhisperer' import { SDKInitializator, Logging } from '@aws/language-server-runtimes/server-interface' +import { HttpResponse } from '@smithy/types' -export type CodeWhispererSigv4ClientConfigurationOptions = ServiceConfigurationOptions +export type CodeWhispererSigv4ClientConfigurationOptions = CodeWhispererClientConfig export function createCodeWhispererSigv4Client( - options: ServiceConfigurationOptions, + options: CodeWhispererClientConfig, sdkInitializator: SDKInitializator, - logging: Logging + logging: Logging, + shareCodeWhispererContentWithAWS: boolean = false ): CodeWhispererClient { - return createService(options, sdkInitializator, logging) as CodeWhispererClient -} + logging.log( + `Passing client for class CodeWhispererClient to sdkInitializator (v3) for additional setup (e.g. proxy)` + ) + + const client = sdkInitializator(CodeWhispererClient, { + ...options, + }) + + // Add middleware to set opt-out header + client.middlewareStack.add( + next => async args => { + if ( + args.request && + typeof args.request === 'object' && + args.request !== null && + 'headers' in args.request + ) { + ;(args.request as any).headers['x-amzn-codewhisperer-optout'] = `${!shareCodeWhispererContentWithAWS}` + } + return next(args) + }, + { + step: 'build', + name: 'addOptOutHeader', + priority: 'high', + } + ) + + // Add middleware to capture HTTP headers + client.middlewareStack.add( + next => async args => { + const result = await next(args) + + // Store headers on the response metadata + if (result.response) { + const httpResponse = result.response as HttpResponse + if (httpResponse.headers && result.output?.$metadata) { + // Extend metadata to include headers + ;(result.output.$metadata as any).httpHeaders = httpResponse.headers + } + } + + return result + }, + { + step: 'deserialize', + name: 'captureHeaders', + priority: 'high', + } + ) -function createService( - options: ServiceConfigurationOptions, - sdkInitializator: SDKInitializator, - logging: Logging -): Service { - logging.log(`Passing client for class Service to sdkInitializator (v2) for additional setup (e.g. proxy)`) - const client = sdkInitializator.v2(Service, { apiConfig, ...options } as any) return client } + +// Export the V3 client type for compatibility +export type CodeWhispererSigv4Client = CodeWhispererClient diff --git a/server/aws-lsp-codewhisperer/src/client/sigv4/codewhisperersigv4client.d.ts b/server/aws-lsp-codewhisperer/src/client/sigv4/codewhisperersigv4client.d.ts deleted file mode 100644 index 6cb67d3ef8..0000000000 --- a/server/aws-lsp-codewhisperer/src/client/sigv4/codewhisperersigv4client.d.ts +++ /dev/null @@ -1,605 +0,0 @@ - -/** - * THIS FILE IS AUTOGENERATED BY 'generateServiceClient.ts'. - * DO NOT EDIT BY HAND. - */ - -import {Request} from 'aws-sdk/lib/request'; -import {Response} from 'aws-sdk/lib/response'; -import {AWSError} from 'aws-sdk/lib/error'; -import {Service} from 'aws-sdk/lib/service'; -import {ServiceConfigurationOptions} from 'aws-sdk/lib/service'; -import {ConfigBase as Config} from 'aws-sdk/lib/config-base'; -interface Blob {} -declare class CodeWhispererSigV4Client extends Service { - /** - * Constructs a service object. This object has one method for each API operation. - */ - constructor(options?: CodeWhispererSigV4Client.Types.ClientConfiguration) - config: Config & CodeWhispererSigV4Client.Types.ClientConfiguration; - /** - * Internal API to authorize a CodeWhisperer resource for vended log delivery. - */ - allowVendedLogDeliveryForResource(params: CodeWhispererSigV4Client.Types.AllowVendedLogDeliveryForResourceRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.AllowVendedLogDeliveryForResourceResponse) => void): Request; - /** - * Internal API to authorize a CodeWhisperer resource for vended log delivery. - */ - allowVendedLogDeliveryForResource(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.AllowVendedLogDeliveryForResourceResponse) => void): Request; - /** - * Add permission for an Identity Center User/Group to use the Customization. - */ - associateCustomizationPermission(params: CodeWhispererSigV4Client.Types.AssociateCustomizationPermissionRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.AssociateCustomizationPermissionResponse) => void): Request; - /** - * Add permission for an Identity Center User/Group to use the Customization. - */ - associateCustomizationPermission(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.AssociateCustomizationPermissionResponse) => void): Request; - /** - * - */ - createCustomization(params: CodeWhispererSigV4Client.Types.CreateCustomizationRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.CreateCustomizationResponse) => void): Request; - /** - * - */ - createCustomization(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.CreateCustomizationResponse) => void): Request; - /** - * Creates a CodeWhisperer profile which can then be associated to users/groups of an identity source - */ - createProfile(params: CodeWhispererSigV4Client.Types.CreateProfileRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.CreateProfileResponse) => void): Request; - /** - * Creates a CodeWhisperer profile which can then be associated to users/groups of an identity source - */ - createProfile(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.CreateProfileResponse) => void): Request; - /** - * Deletes CodeWhisperer Customization and associated resources - */ - deleteCustomization(params: CodeWhispererSigV4Client.Types.DeleteCustomizationRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.DeleteCustomizationResponse) => void): Request; - /** - * Deletes CodeWhisperer Customization and associated resources - */ - deleteCustomization(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.DeleteCustomizationResponse) => void): Request; - /** - * Deletes CodeWhisperer profile and associated resources - */ - deleteProfile(params: CodeWhispererSigV4Client.Types.DeleteProfileRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.DeleteProfileResponse) => void): Request; - /** - * Deletes CodeWhisperer profile and associated resources - */ - deleteProfile(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.DeleteProfileResponse) => void): Request; - /** - * Disassociate the permission for a Customization from an Identity Center User/Group. - */ - disassociateCustomizationPermission(params: CodeWhispererSigV4Client.Types.DisassociateCustomizationPermissionRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.DisassociateCustomizationPermissionResponse) => void): Request; - /** - * Disassociate the permission for a Customization from an Identity Center User/Group. - */ - disassociateCustomizationPermission(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.DisassociateCustomizationPermissionResponse) => void): Request; - /** - * Generates recommendations based on the provided file context. - */ - generateRecommendations(params: CodeWhispererSigV4Client.Types.GenerateRecommendationsRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.GenerateRecommendationsResponse) => void): Request; - /** - * Generates recommendations based on the provided file context. - */ - generateRecommendations(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.GenerateRecommendationsResponse) => void): Request; - /** - * - */ - getCustomization(params: CodeWhispererSigV4Client.Types.GetCustomizationRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.GetCustomizationResponse) => void): Request; - /** - * - */ - getCustomization(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.GetCustomizationResponse) => void): Request; - /** - * List User(s)/Group(s) who have permissions to use a Customization. - */ - listCustomizationPermissions(params: CodeWhispererSigV4Client.Types.ListCustomizationPermissionsRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.ListCustomizationPermissionsResponse) => void): Request; - /** - * List User(s)/Group(s) who have permissions to use a Customization. - */ - listCustomizationPermissions(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.ListCustomizationPermissionsResponse) => void): Request; - /** - * List actionable versions associated with a Customization. - */ - listCustomizationVersions(params: CodeWhispererSigV4Client.Types.ListCustomizationVersionsRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.ListCustomizationVersionsResponse) => void): Request; - /** - * List actionable versions associated with a Customization. - */ - listCustomizationVersions(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.ListCustomizationVersionsResponse) => void): Request; - /** - * - */ - listCustomizations(params: CodeWhispererSigV4Client.Types.ListCustomizationsRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.ListCustomizationsResponse) => void): Request; - /** - * - */ - listCustomizations(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.ListCustomizationsResponse) => void): Request; - /** - * Lists one or more CodeWhisperer profiles that you have created. - */ - listProfiles(params: CodeWhispererSigV4Client.Types.ListProfilesRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.ListProfilesResponse) => void): Request; - /** - * Lists one or more CodeWhisperer profiles that you have created. - */ - listProfiles(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.ListProfilesResponse) => void): Request; - /** - * List tags of an existing CodeWhisperer profile. - */ - listTagsForResource(params: CodeWhispererSigV4Client.Types.ListTagsForResourceRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.ListTagsForResourceResponse) => void): Request; - /** - * List tags of an existing CodeWhisperer profile. - */ - listTagsForResource(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.ListTagsForResourceResponse) => void): Request; - /** - * Add tags to an existing CodeWhisperer profile. - */ - tagResource(params: CodeWhispererSigV4Client.Types.TagResourceRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.TagResourceResponse) => void): Request; - /** - * Add tags to an existing CodeWhisperer profile. - */ - tagResource(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.TagResourceResponse) => void): Request; - /** - * Remove tags from an existing CodeWhisperer profile. - */ - untagResource(params: CodeWhispererSigV4Client.Types.UntagResourceRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.UntagResourceResponse) => void): Request; - /** - * Remove tags from an existing CodeWhisperer profile. - */ - untagResource(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.UntagResourceResponse) => void): Request; - /** - * - */ - updateCustomization(params: CodeWhispererSigV4Client.Types.UpdateCustomizationRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.UpdateCustomizationResponse) => void): Request; - /** - * - */ - updateCustomization(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.UpdateCustomizationResponse) => void): Request; - /** - * Updates an existing CodeWhisperer profile. - */ - updateProfile(params: CodeWhispererSigV4Client.Types.UpdateProfileRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.UpdateProfileResponse) => void): Request; - /** - * Updates an existing CodeWhisperer profile. - */ - updateProfile(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.UpdateProfileResponse) => void): Request; - /** - * Returns grant details associated with the profile under the input account Id Output includes cmk arn, grant token, and grant id - */ - vendKeyGrant(params: CodeWhispererSigV4Client.Types.VendKeyGrantRequest, callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.VendKeyGrantResponse) => void): Request; - /** - * Returns grant details associated with the profile under the input account Id Output includes cmk arn, grant token, and grant id - */ - vendKeyGrant(callback?: (err: AWSError, data: CodeWhispererSigV4Client.Types.VendKeyGrantResponse) => void): Request; -} -declare namespace CodeWhispererSigV4Client { - export type AWSAccountId = string; - export type ActiveFunctionalityList = FunctionalityName[]; - export interface AllowVendedLogDeliveryForResourceRequest { - resourceArnBeingAuthorized: ResourceArn; - deliverySourceArn: ResourceArn; - } - export interface AllowVendedLogDeliveryForResourceResponse { - message?: String; - } - export interface ApplicationProperties { - tenantId: TenantId; - applicationArn: ResourceArn; - tenantUrl: Url; - applicationType: FunctionalityName; - } - export type ApplicationPropertiesList = ApplicationProperties[]; - export interface AssociateCustomizationPermissionRequest { - identifier: CustomizationIdentifier; - permission: CustomizationPermission; - } - export interface AssociateCustomizationPermissionResponse { - } - export type Base64EncodedPaginationToken = string; - export type Boolean = boolean; - export interface ByUserAnalytics { - s3Uri?: S3Uri; - toggle: OptInFeatureToggle; - } - export type ClientId = string; - export interface CodeStarReference { - connectionArn: ResourceArn; - } - export interface CreateCustomizationRequest { - dataReference: DataReference; - customizationName: CustomizationName; - description?: Description; - profileArn: ProfileArn; - tags?: TagList; - clientToken?: IdempotencyToken; - includeRepos?: RepositoryList; - } - export interface CreateCustomizationResponse { - customizationArn: CustomizationArn; - } - export interface CreateProfileRequest { - identitySource?: IdentitySource; - profileName: ProfileName; - description?: ProfileDescription; - referenceTrackerConfiguration: ReferenceTrackerConfiguration; - activeFunctionalities?: ActiveFunctionalityList; - clientToken?: IdempotencyToken; - kmsKeyArn?: ResourceArn; - tags?: TagList; - resourcePolicy?: ResourcePolicy; - optInFeatures?: OptInFeatures; - } - export interface CreateProfileResponse { - profileArn: ProfileArn; - } - export type CustomizationArn = string; - export type CustomizationIdentifier = string; - export type CustomizationName = string; - export interface CustomizationPermission { - user?: IdentityCenterIdentifier; - group?: IdentityCenterIdentifier; - } - export type CustomizationStatus = "CREATED"|"UPDATED"|"CREATING"|"UPDATING"|"DELETING"|"ACTIVATING"|"DEACTIVATING"|"ACTIVATED"|"CREATION_FAILED"|"UPDATE_FAILED"|"DELETION_FAILED"|"ACTIVATION_FAILED"|"DEACTIVATION_FAILED"|string; - export interface CustomizationSummary { - arn: CustomizationArn; - version?: Version; - customizationName: CustomizationName; - description?: Description; - status: CustomizationStatus; - updatedAt: Timestamp; - } - export type CustomizationSummaryList = CustomizationSummary[]; - export interface CustomizationVersionSummary { - version: Version; - baseVersion?: Version; - status: CustomizationStatus; - dataReference: DataReference; - updatedAt: Timestamp; - evaluationMetrics?: EvaluationMetrics; - } - export type CustomizationVersionSummaryList = CustomizationVersionSummary[]; - export interface DashboardAnalytics { - toggle: OptInFeatureToggle; - } - export interface DataReference { - codeStarReference?: CodeStarReference; - s3Reference?: S3Reference; - } - export interface DeleteCustomizationRequest { - identifier: CustomizationIdentifier; - clientToken?: IdempotencyToken; - } - export interface DeleteCustomizationResponse { - } - export interface DeleteProfileRequest { - profileArn: ProfileArn; - } - export interface DeleteProfileResponse { - } - export type Description = string; - export interface DisassociateCustomizationPermissionRequest { - identifier: CustomizationIdentifier; - permission: CustomizationPermission; - } - export interface DisassociateCustomizationPermissionResponse { - } - export type ErrorDetails = string; - export interface EvaluationMetrics { - compositeScore: Integer; - } - export interface ExternalIdentityDetails { - issuerUrl?: IssuerUrl; - clientId?: ClientId; - scimEndpoint?: String; - } - export interface ExternalIdentitySource { - issuerUrl: IssuerUrl; - clientId: ClientId; - } - export type FeatureName = string; - export interface FileContext { - leftFileContent: FileContextLeftFileContentString; - rightFileContent: FileContextRightFileContentString; - filename: FileContextFilenameString; - fileUri?: FileContextFileUriString; - programmingLanguage: ProgrammingLanguage; - } - export type FileContextFileUriString = string; - export type FileContextFilenameString = string; - export type FileContextLeftFileContentString = string; - export type FileContextRightFileContentString = string; - export type FunctionalityName = "COMPLETIONS"|"ANALYSIS"|"CONVERSATIONS"|"TASK_ASSIST"|"TRANSFORMATIONS"|"CHAT_CUSTOMIZATION"|"TRANSFORMATIONS_WEBAPP"|"FEATURE_DEVELOPMENT"|string; - export interface GenerateRecommendationsRequest { - fileContext: FileContext; - maxResults?: GenerateRecommendationsRequestMaxResultsInteger; - nextToken?: GenerateRecommendationsRequestNextTokenString; - referenceTrackerConfiguration?: ReferenceTrackerConfiguration; - supplementalContexts?: SupplementalContextList; - } - export type GenerateRecommendationsRequestMaxResultsInteger = number; - export type GenerateRecommendationsRequestNextTokenString = string; - export interface GenerateRecommendationsResponse { - recommendations?: RecommendationsList; - nextToken?: String; - } - export interface GetCustomizationRequest { - identifier: CustomizationIdentifier; - } - export interface GetCustomizationResponse { - arn: CustomizationArn; - version?: Version; - status: CustomizationStatus; - errorDetails?: ErrorDetails; - dataReference: DataReference; - customizationName: CustomizationName; - description?: Description; - profileArn: ProfileArn; - updatedAt: Timestamp; - evaluationMetrics?: EvaluationMetrics; - includeRepos?: RepositoryList; - } - export type GrantId = string; - export type GrantToken = string; - export type IdempotencyToken = string; - export type IdentityCenterIdentifier = string; - export type IdentityCenterPermissions = CustomizationPermission[]; - export interface IdentityDetails { - ssoIdentityDetails?: SSOIdentityDetails; - externalIdentityDetails?: ExternalIdentityDetails; - } - export interface IdentitySource { - ssoIdentitySource?: SSOIdentitySource; - externalIdentitySource?: ExternalIdentitySource; - } - export interface Import { - statement?: ImportStatementString; - } - export type ImportStatementString = string; - export type Imports = Import[]; - export type Integer = number; - export type IssuerUrl = string; - export interface ListCustomizationPermissionsRequest { - identifier: CustomizationIdentifier; - maxResults?: ListCustomizationPermissionsRequestMaxResultsInteger; - nextToken?: Base64EncodedPaginationToken; - } - export type ListCustomizationPermissionsRequestMaxResultsInteger = number; - export interface ListCustomizationPermissionsResponse { - permissions: IdentityCenterPermissions; - nextToken?: Base64EncodedPaginationToken; - } - export interface ListCustomizationVersionsRequest { - identifier: CustomizationIdentifier; - maxResults?: ListCustomizationVersionsRequestMaxResultsInteger; - nextToken?: Base64EncodedPaginationToken; - } - export type ListCustomizationVersionsRequestMaxResultsInteger = number; - export interface ListCustomizationVersionsResponse { - versions: CustomizationVersionSummaryList; - nextToken?: Base64EncodedPaginationToken; - } - export interface ListCustomizationsRequest { - maxResults?: ListCustomizationsRequestMaxResultsInteger; - nextToken?: Base64EncodedPaginationToken; - } - export type ListCustomizationsRequestMaxResultsInteger = number; - export interface ListCustomizationsResponse { - customizations: CustomizationSummaryList; - nextToken?: Base64EncodedPaginationToken; - } - export interface ListProfilesRequest { - maxResults?: ListProfilesRequestMaxResultsInteger; - includeManagementAccount?: Boolean; - nextToken?: Base64EncodedPaginationToken; - } - export type ListProfilesRequestMaxResultsInteger = number; - export interface ListProfilesResponse { - profiles: ProfileList; - nextToken?: Base64EncodedPaginationToken; - } - export interface ListTagsForResourceRequest { - resourceArn: ResourceArn; - } - export interface ListTagsForResourceResponse { - tags?: TagList; - } - export type Notifications = NotificationsFeature[]; - export interface NotificationsFeature { - feature: FeatureName; - toggle: OptInFeatureToggle; - } - export type OptInFeatureToggle = "ON"|"OFF"|string; - export interface OptInFeatures { - promptLogging?: PromptLogging; - byUserAnalytics?: ByUserAnalytics; - dashboardAnalytics?: DashboardAnalytics; - notifications?: Notifications; - workspaceContext?: WorkspaceContext; - } - export interface PreviousEditorStateMetadata { - timeOffset: Integer; - } - export interface Profile { - arn: ProfileArn; - identityDetails?: IdentityDetails; - profileName: ProfileName; - description?: ProfileDescription; - referenceTrackerConfiguration?: ReferenceTrackerConfiguration; - kmsKeyArn?: ResourceArn; - activeFunctionalities?: ActiveFunctionalityList; - status?: ProfileStatus; - errorDetails?: ErrorDetails; - resourcePolicy?: ResourcePolicy; - profileType?: ProfileType; - optInFeatures?: OptInFeatures; - permissionUpdateRequired?: Boolean; - applicationProperties?: ApplicationPropertiesList; - } - export type ProfileArn = string; - export type ProfileDescription = string; - export type ProfileList = Profile[]; - export type ProfileName = string; - export type ProfileStatus = "ACTIVE"|"CREATING"|"CREATE_FAILED"|"UPDATING"|"UPDATE_FAILED"|"DELETING"|"DELETE_FAILED"|string; - export type ProfileType = "Q_DEVELOPER"|"CODEWHISPERER"|string; - export interface ProgrammingLanguage { - languageName: ProgrammingLanguageLanguageNameString; - } - export type ProgrammingLanguageLanguageNameString = string; - export interface PromptLogging { - s3Uri: S3Uri; - toggle: OptInFeatureToggle; - } - export interface Recommendation { - content: RecommendationContentString; - references?: References; - mostRelevantMissingImports?: Imports; - } - export type RecommendationContentString = string; - export type RecommendationsList = Recommendation[]; - export type RecommendationsWithReferencesPreference = "BLOCK"|"ALLOW"|string; - export interface Reference { - /** - * License name - */ - licenseName?: ReferenceLicenseNameString; - /** - * Code Repsitory for the associated reference - */ - repository?: ReferenceRepositoryString; - /** - * Respository URL - */ - url?: ReferenceUrlString; - /** - * Span / Range for the Reference - */ - recommendationContentSpan?: Span; - } - export type ReferenceLicenseNameString = string; - export type ReferenceRepositoryString = string; - export interface ReferenceTrackerConfiguration { - recommendationsWithReferences: RecommendationsWithReferencesPreference; - } - export type ReferenceUrlString = string; - export type References = Reference[]; - export type RepositoryId = string; - export type RepositoryList = RepositoryId[]; - export type ResourceArn = string; - export interface ResourcePolicy { - effect: ResourcePolicyEffect; - } - export type ResourcePolicyEffect = "ALLOW"|"DENY"|string; - export interface S3Reference { - uri: S3Uri; - } - export type S3Uri = string; - export interface SSOIdentityDetails { - instanceArn: ResourceArn; - oidcClientId: String; - ssoRegion?: SSORegion; - } - export interface SSOIdentitySource { - instanceArn: ResourceArn; - ssoRegion?: SSORegion; - } - export type SSORegion = string; - export interface Span { - start?: SpanStartInteger; - end?: SpanEndInteger; - } - export type SpanEndInteger = number; - export type SpanStartInteger = number; - export type String = string; - export interface SupplementalContext { - filePath: SupplementalContextFilePathString; - content: SupplementalContextContentString; - type?: SupplementalContextType; - metadata?: SupplementalContextMetadata; - } - export type SupplementalContextContentString = string; - export type SupplementalContextFilePathString = string; - export type SupplementalContextList = SupplementalContext[]; - export interface SupplementalContextMetadata { - previousEditorStateMetadata?: PreviousEditorStateMetadata; - } - export type SupplementalContextType = "PreviousEditorState"|"WorkspaceContext"|string; - export interface Tag { - key: TagKey; - value: TagValue; - } - export type TagKey = string; - export type TagKeyList = TagKey[]; - export type TagList = Tag[]; - export interface TagResourceRequest { - resourceArn: ResourceArn; - tags: TagList; - } - export interface TagResourceResponse { - } - export type TagValue = string; - export type TenantId = string; - export type Timestamp = Date; - export interface UntagResourceRequest { - resourceArn: ResourceArn; - tagKeys: TagKeyList; - } - export interface UntagResourceResponse { - } - export interface UpdateCustomizationRequest { - identifier: CustomizationIdentifier; - operation: UpdateOperation; - clientToken?: IdempotencyToken; - dataReference?: DataReference; - version?: Version; - includeRepos?: RepositoryList; - } - export interface UpdateCustomizationResponse { - } - export type UpdateOperation = "ACTIVATE"|"DEACTIVATE"|"UPDATE"|string; - export interface UpdateProfileRequest { - profileArn: ProfileArn; - identitySource?: IdentitySource; - profileName?: ProfileName; - description?: ProfileDescription; - referenceTrackerConfiguration?: ReferenceTrackerConfiguration; - activeFunctionalities?: ActiveFunctionalityList; - kmsKeyArn?: ResourceArn; - resourcePolicy?: ResourcePolicy; - targetProfileType?: ProfileType; - optInFeatures?: OptInFeatures; - } - export interface UpdateProfileResponse { - profileArn: ProfileArn; - } - export type Url = string; - export interface VendKeyGrantRequest { - accountId: AWSAccountId; - usecase: VendKeyGrantUseCase; - } - export interface VendKeyGrantResponse { - cmkArn?: ResourceArn; - grantId?: GrantToken; - grantToken?: GrantId; - } - export type VendKeyGrantUseCase = "TEST"|"WEAVER_BIRD"|"ELASTIC_GUMBY"|"LOCHNESS"|"BOWER_BIRD"|"ELASTIC_GUMBY_V2_JOB"|"ELASTIC_GUMBY_V2_CHAT"|string; - export type Version = number; - export interface WorkspaceContext { - toggle: OptInFeatureToggle; - } - /** - * A string in YYYY-MM-DD format that represents the latest possible API version that can be used in this service. Specify 'latest' to use the latest possible version. - */ - export type apiVersion = "2024-10-25"|"latest"|string; - export interface ClientApiVersions { - /** - * A string in YYYY-MM-DD format that represents the latest possible API version that can be used in this service. Specify 'latest' to use the latest possible version. - */ - apiVersion?: apiVersion; - } - export type ClientConfiguration = ServiceConfigurationOptions & ClientApiVersions; - /** - * Contains interfaces for use with the CodeWhispererSigV4Client client. - */ - export import Types = CodeWhispererSigV4Client; -} -export = CodeWhispererSigV4Client; - - \ No newline at end of file diff --git a/server/aws-lsp-codewhisperer/src/client/sigv4/service.json b/server/aws-lsp-codewhisperer/src/client/sigv4/service.json deleted file mode 100644 index 26220aa7a0..0000000000 --- a/server/aws-lsp-codewhisperer/src/client/sigv4/service.json +++ /dev/null @@ -1,2145 +0,0 @@ -{ - "version": "2.0", - "metadata": { - "apiVersion": "2024-10-25", - "auth": ["aws.auth#sigv4"], - "endpointPrefix": "codewhisperer", - "jsonVersion": "1.0", - "protocol": "json", - "protocols": ["json"], - "serviceFullName": "AWS CodeWhisperer", - "serviceId": "CodeWhisperer", - "signatureVersion": "v4", - "signingName": "codewhisperer", - "targetPrefix": "AWSCodeWhispererService", - "uid": "codewhisperer-2024-10-25" - }, - "operations": { - "AllowVendedLogDeliveryForResource": { - "name": "AllowVendedLogDeliveryForResource", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "AllowVendedLogDeliveryForResourceRequest" - }, - "output": { - "shape": "AllowVendedLogDeliveryForResourceResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Internal API to authorize a CodeWhisperer resource for vended log delivery.

" - }, - "AssociateCustomizationPermission": { - "name": "AssociateCustomizationPermission", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "AssociateCustomizationPermissionRequest" - }, - "output": { - "shape": "AssociateCustomizationPermissionResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Add permission for an Identity Center User/Group to use the Customization.

" - }, - "CreateCustomization": { - "name": "CreateCustomization", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "CreateCustomizationRequest" - }, - "output": { - "shape": "CreateCustomizationResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ] - }, - "CreateProfile": { - "name": "CreateProfile", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "CreateProfileRequest" - }, - "output": { - "shape": "CreateProfileResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Creates a CodeWhisperer profile which can then be associated to users/groups of an identity source

" - }, - "DeleteCustomization": { - "name": "DeleteCustomization", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "DeleteCustomizationRequest" - }, - "output": { - "shape": "DeleteCustomizationResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Deletes CodeWhisperer Customization and associated resources

" - }, - "DeleteProfile": { - "name": "DeleteProfile", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "DeleteProfileRequest" - }, - "output": { - "shape": "DeleteProfileResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Deletes CodeWhisperer profile and associated resources

" - }, - "DisassociateCustomizationPermission": { - "name": "DisassociateCustomizationPermission", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "DisassociateCustomizationPermissionRequest" - }, - "output": { - "shape": "DisassociateCustomizationPermissionResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Disassociate the permission for a Customization from an Identity Center User/Group.

" - }, - "GenerateRecommendations": { - "name": "GenerateRecommendations", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "GenerateRecommendationsRequest" - }, - "output": { - "shape": "GenerateRecommendationsResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Generates recommendations based on the provided file context.

" - }, - "GetCustomization": { - "name": "GetCustomization", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "GetCustomizationRequest" - }, - "output": { - "shape": "GetCustomizationResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ] - }, - "ListCustomizationPermissions": { - "name": "ListCustomizationPermissions", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "ListCustomizationPermissionsRequest" - }, - "output": { - "shape": "ListCustomizationPermissionsResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

List User(s)/Group(s) who have permissions to use a Customization.

" - }, - "ListCustomizationVersions": { - "name": "ListCustomizationVersions", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "ListCustomizationVersionsRequest" - }, - "output": { - "shape": "ListCustomizationVersionsResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

List actionable versions associated with a Customization.

" - }, - "ListCustomizations": { - "name": "ListCustomizations", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "ListCustomizationsRequest" - }, - "output": { - "shape": "ListCustomizationsResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ] - }, - "ListProfiles": { - "name": "ListProfiles", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "ListProfilesRequest" - }, - "output": { - "shape": "ListProfilesResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Lists one or more CodeWhisperer profiles that you have created.

" - }, - "ListTagsForResource": { - "name": "ListTagsForResource", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "ListTagsForResourceRequest" - }, - "output": { - "shape": "ListTagsForResourceResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

List tags of an existing CodeWhisperer profile.

" - }, - "TagResource": { - "name": "TagResource", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "TagResourceRequest" - }, - "output": { - "shape": "TagResourceResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Add tags to an existing CodeWhisperer profile.

" - }, - "UntagResource": { - "name": "UntagResource", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "UntagResourceRequest" - }, - "output": { - "shape": "UntagResourceResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Remove tags from an existing CodeWhisperer profile.

" - }, - "UpdateCustomization": { - "name": "UpdateCustomization", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "UpdateCustomizationRequest" - }, - "output": { - "shape": "UpdateCustomizationResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ] - }, - "UpdateProfile": { - "name": "UpdateProfile", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "UpdateProfileRequest" - }, - "output": { - "shape": "UpdateProfileResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Updates an existing CodeWhisperer profile.

" - }, - "VendKeyGrant": { - "name": "VendKeyGrant", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "VendKeyGrantRequest" - }, - "output": { - "shape": "VendKeyGrantResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Returns grant details associated with the profile under the input account Id Output includes cmk arn, grant token, and grant id

" - } - }, - "shapes": { - "AWSAccountId": { - "type": "string", - "documentation": "

Represents the AWS account ID of the customer

", - "pattern": "[0-9]{12}" - }, - "AccessDeniedException": { - "type": "structure", - "required": ["message"], - "members": { - "message": { - "shape": "String" - }, - "reason": { - "shape": "AccessDeniedExceptionReason" - } - }, - "documentation": "

This exception is thrown when the user does not have sufficient access to perform this action.

", - "exception": true - }, - "AccessDeniedExceptionReason": { - "type": "string", - "documentation": "

Reason for AccessDeniedException

", - "enum": ["UNAUTHORIZED_CUSTOMIZATION_RESOURCE_ACCESS", "UNAUTHORIZED_WORKSPACE_CONTEXT_FEATURE_ACCESS"] - }, - "ActiveFunctionalityList": { - "type": "list", - "member": { - "shape": "FunctionalityName" - }, - "max": 10, - "min": 0 - }, - "AllowVendedLogDeliveryForResourceRequest": { - "type": "structure", - "required": ["resourceArnBeingAuthorized", "deliverySourceArn"], - "members": { - "resourceArnBeingAuthorized": { - "shape": "ResourceArn" - }, - "deliverySourceArn": { - "shape": "ResourceArn" - } - } - }, - "AllowVendedLogDeliveryForResourceResponse": { - "type": "structure", - "members": { - "message": { - "shape": "String" - } - } - }, - "ApplicationProperties": { - "type": "structure", - "required": ["tenantId", "applicationArn", "tenantUrl", "applicationType"], - "members": { - "tenantId": { - "shape": "TenantId" - }, - "applicationArn": { - "shape": "ResourceArn" - }, - "tenantUrl": { - "shape": "Url" - }, - "applicationType": { - "shape": "FunctionalityName" - } - } - }, - "ApplicationPropertiesList": { - "type": "list", - "member": { - "shape": "ApplicationProperties" - } - }, - "AssociateCustomizationPermissionRequest": { - "type": "structure", - "required": ["identifier", "permission"], - "members": { - "identifier": { - "shape": "CustomizationIdentifier" - }, - "permission": { - "shape": "CustomizationPermission" - } - } - }, - "AssociateCustomizationPermissionResponse": { - "type": "structure", - "members": {} - }, - "Base64EncodedPaginationToken": { - "type": "string", - "max": 2048, - "min": 1, - "pattern": "(?:[A-Za-z0-9\\+/]{4})*(?:[A-Za-z0-9\\+/]{2}\\=\\=|[A-Za-z0-9\\+/]{3}\\=)?" - }, - "Boolean": { - "type": "boolean", - "box": true - }, - "ByUserAnalytics": { - "type": "structure", - "required": ["toggle"], - "members": { - "s3Uri": { - "shape": "S3Uri" - }, - "toggle": { - "shape": "OptInFeatureToggle" - } - } - }, - "ClientId": { - "type": "string", - "max": 255, - "min": 1 - }, - "CodeStarReference": { - "type": "structure", - "required": ["connectionArn"], - "members": { - "connectionArn": { - "shape": "ResourceArn" - } - } - }, - "ConflictException": { - "type": "structure", - "required": ["message"], - "members": { - "message": { - "shape": "String" - }, - "reason": { - "shape": "ConflictExceptionReason" - } - }, - "documentation": "

This exception is thrown when the action to perform could not be completed because the resource is in a conflicting state.

", - "exception": true - }, - "ConflictExceptionReason": { - "type": "string", - "documentation": "

Reason for ConflictException

", - "enum": ["CUSTOMER_KMS_KEY_INVALID_KEY_POLICY", "CUSTOMER_KMS_KEY_DISABLED", "MISMATCHED_KMS_KEY"] - }, - "CreateCustomizationRequest": { - "type": "structure", - "required": ["dataReference", "customizationName", "profileArn"], - "members": { - "dataReference": { - "shape": "DataReference" - }, - "customizationName": { - "shape": "CustomizationName" - }, - "description": { - "shape": "Description" - }, - "profileArn": { - "shape": "ProfileArn" - }, - "tags": { - "shape": "TagList" - }, - "clientToken": { - "shape": "IdempotencyToken" - }, - "includeRepos": { - "shape": "RepositoryList" - } - } - }, - "CreateCustomizationResponse": { - "type": "structure", - "required": ["customizationArn"], - "members": { - "customizationArn": { - "shape": "CustomizationArn" - } - } - }, - "CreateProfileRequest": { - "type": "structure", - "required": ["profileName", "referenceTrackerConfiguration"], - "members": { - "identitySource": { - "shape": "IdentitySource" - }, - "profileName": { - "shape": "ProfileName" - }, - "description": { - "shape": "ProfileDescription" - }, - "referenceTrackerConfiguration": { - "shape": "ReferenceTrackerConfiguration" - }, - "activeFunctionalities": { - "shape": "ActiveFunctionalityList" - }, - "clientToken": { - "shape": "IdempotencyToken", - "idempotencyToken": true - }, - "kmsKeyArn": { - "shape": "ResourceArn" - }, - "tags": { - "shape": "TagList" - }, - "resourcePolicy": { - "shape": "ResourcePolicy" - }, - "optInFeatures": { - "shape": "OptInFeatures" - } - } - }, - "CreateProfileResponse": { - "type": "structure", - "required": ["profileArn"], - "members": { - "profileArn": { - "shape": "ProfileArn" - } - } - }, - "CustomizationArn": { - "type": "string", - "max": 950, - "min": 0, - "pattern": "arn:[-.a-z0-9]{1,63}:codewhisperer:([-.a-z0-9]{0,63}:){2}([a-zA-Z0-9-_:/]){1,1023}" - }, - "CustomizationIdentifier": { - "type": "string", - "max": 950, - "min": 1, - "pattern": ".*[a-zA-Z0-9-:/]*.*" - }, - "CustomizationName": { - "type": "string", - "max": 100, - "min": 1, - "pattern": "[a-zA-Z][a-zA-Z0-9_-]*" - }, - "CustomizationPermission": { - "type": "structure", - "members": { - "user": { - "shape": "IdentityCenterIdentifier" - }, - "group": { - "shape": "IdentityCenterIdentifier" - } - }, - "union": true - }, - "CustomizationStatus": { - "type": "string", - "enum": [ - "CREATED", - "UPDATED", - "CREATING", - "UPDATING", - "DELETING", - "ACTIVATING", - "DEACTIVATING", - "ACTIVATED", - "CREATION_FAILED", - "UPDATE_FAILED", - "DELETION_FAILED", - "ACTIVATION_FAILED", - "DEACTIVATION_FAILED" - ] - }, - "CustomizationSummary": { - "type": "structure", - "required": ["arn", "customizationName", "status", "updatedAt"], - "members": { - "arn": { - "shape": "CustomizationArn" - }, - "version": { - "shape": "Version" - }, - "customizationName": { - "shape": "CustomizationName" - }, - "description": { - "shape": "Description" - }, - "status": { - "shape": "CustomizationStatus" - }, - "updatedAt": { - "shape": "Timestamp" - } - } - }, - "CustomizationSummaryList": { - "type": "list", - "member": { - "shape": "CustomizationSummary" - } - }, - "CustomizationVersionSummary": { - "type": "structure", - "required": ["version", "status", "dataReference", "updatedAt"], - "members": { - "version": { - "shape": "Version" - }, - "baseVersion": { - "shape": "Version" - }, - "status": { - "shape": "CustomizationStatus" - }, - "dataReference": { - "shape": "DataReference" - }, - "updatedAt": { - "shape": "Timestamp" - }, - "evaluationMetrics": { - "shape": "EvaluationMetrics" - } - } - }, - "CustomizationVersionSummaryList": { - "type": "list", - "member": { - "shape": "CustomizationVersionSummary" - } - }, - "DashboardAnalytics": { - "type": "structure", - "required": ["toggle"], - "members": { - "toggle": { - "shape": "OptInFeatureToggle" - } - } - }, - "DataReference": { - "type": "structure", - "members": { - "codeStarReference": { - "shape": "CodeStarReference" - }, - "s3Reference": { - "shape": "S3Reference" - } - }, - "union": true - }, - "DeleteCustomizationRequest": { - "type": "structure", - "required": ["identifier"], - "members": { - "identifier": { - "shape": "CustomizationIdentifier" - }, - "clientToken": { - "shape": "IdempotencyToken" - } - } - }, - "DeleteCustomizationResponse": { - "type": "structure", - "members": {} - }, - "DeleteProfileRequest": { - "type": "structure", - "required": ["profileArn"], - "members": { - "profileArn": { - "shape": "ProfileArn" - } - } - }, - "DeleteProfileResponse": { - "type": "structure", - "members": {} - }, - "Description": { - "type": "string", - "max": 256, - "min": 0, - "pattern": "[\\sa-zA-Z0-9_-]*" - }, - "DisassociateCustomizationPermissionRequest": { - "type": "structure", - "required": ["identifier", "permission"], - "members": { - "identifier": { - "shape": "CustomizationIdentifier" - }, - "permission": { - "shape": "CustomizationPermission" - } - } - }, - "DisassociateCustomizationPermissionResponse": { - "type": "structure", - "members": {} - }, - "ErrorDetails": { - "type": "string", - "max": 2048, - "min": 0 - }, - "EvaluationMetrics": { - "type": "structure", - "required": ["compositeScore"], - "members": { - "compositeScore": { - "shape": "Integer" - } - } - }, - "ExternalIdentityDetails": { - "type": "structure", - "members": { - "issuerUrl": { - "shape": "IssuerUrl" - }, - "clientId": { - "shape": "ClientId" - }, - "scimEndpoint": { - "shape": "String" - } - } - }, - "ExternalIdentitySource": { - "type": "structure", - "required": ["issuerUrl", "clientId"], - "members": { - "issuerUrl": { - "shape": "IssuerUrl" - }, - "clientId": { - "shape": "ClientId" - } - } - }, - "FeatureName": { - "type": "string", - "max": 128, - "min": 1, - "pattern": "[-a-zA-Z0-9._]*" - }, - "FileContext": { - "type": "structure", - "required": ["leftFileContent", "rightFileContent", "filename", "programmingLanguage"], - "members": { - "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, - "min": 1, - "sensitive": true - }, - "FileContextLeftFileContentString": { - "type": "string", - "max": 10240, - "min": 0, - "sensitive": true - }, - "FileContextRightFileContentString": { - "type": "string", - "max": 10240, - "min": 0, - "sensitive": true - }, - "FunctionalityName": { - "type": "string", - "enum": [ - "COMPLETIONS", - "ANALYSIS", - "CONVERSATIONS", - "TASK_ASSIST", - "TRANSFORMATIONS", - "CHAT_CUSTOMIZATION", - "TRANSFORMATIONS_WEBAPP", - "FEATURE_DEVELOPMENT" - ], - "max": 64, - "min": 1 - }, - "GenerateRecommendationsRequest": { - "type": "structure", - "required": ["fileContext"], - "members": { - "fileContext": { - "shape": "FileContext" - }, - "maxResults": { - "shape": "GenerateRecommendationsRequestMaxResultsInteger" - }, - "nextToken": { - "shape": "GenerateRecommendationsRequestNextTokenString" - }, - "referenceTrackerConfiguration": { - "shape": "ReferenceTrackerConfiguration" - }, - "supplementalContexts": { - "shape": "SupplementalContextList" - } - } - }, - "GenerateRecommendationsRequestMaxResultsInteger": { - "type": "integer", - "box": true, - "max": 10, - "min": 1 - }, - "GenerateRecommendationsRequestNextTokenString": { - "type": "string", - "max": 2048, - "min": 0, - "pattern": "(?:[A-Za-z0-9\\+/]{4})*(?:[A-Za-z0-9\\+/]{2}\\=\\=|[A-Za-z0-9\\+/]{3}\\=)?" - }, - "GenerateRecommendationsResponse": { - "type": "structure", - "members": { - "recommendations": { - "shape": "RecommendationsList" - }, - "nextToken": { - "shape": "String" - } - } - }, - "GetCustomizationRequest": { - "type": "structure", - "required": ["identifier"], - "members": { - "identifier": { - "shape": "CustomizationIdentifier" - } - } - }, - "GetCustomizationResponse": { - "type": "structure", - "required": ["arn", "status", "dataReference", "customizationName", "profileArn", "updatedAt"], - "members": { - "arn": { - "shape": "CustomizationArn" - }, - "version": { - "shape": "Version" - }, - "status": { - "shape": "CustomizationStatus" - }, - "errorDetails": { - "shape": "ErrorDetails" - }, - "dataReference": { - "shape": "DataReference" - }, - "customizationName": { - "shape": "CustomizationName" - }, - "description": { - "shape": "Description" - }, - "profileArn": { - "shape": "ProfileArn" - }, - "updatedAt": { - "shape": "Timestamp" - }, - "evaluationMetrics": { - "shape": "EvaluationMetrics" - }, - "includeRepos": { - "shape": "RepositoryList" - } - } - }, - "GrantId": { - "type": "string", - "max": 128, - "min": 1 - }, - "GrantToken": { - "type": "string", - "max": 8192, - "min": 1 - }, - "IdempotencyToken": { - "type": "string", - "max": 256, - "min": 1 - }, - "IdentityCenterIdentifier": { - "type": "string", - "max": 64, - "min": 1, - "pattern": "([0-9a-f]{10}-|)[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}" - }, - "IdentityCenterPermissions": { - "type": "list", - "member": { - "shape": "CustomizationPermission" - } - }, - "IdentityDetails": { - "type": "structure", - "members": { - "ssoIdentityDetails": { - "shape": "SSOIdentityDetails" - }, - "externalIdentityDetails": { - "shape": "ExternalIdentityDetails" - } - }, - "union": true - }, - "IdentitySource": { - "type": "structure", - "members": { - "ssoIdentitySource": { - "shape": "SSOIdentitySource" - }, - "externalIdentitySource": { - "shape": "ExternalIdentitySource" - } - }, - "union": true - }, - "Import": { - "type": "structure", - "members": { - "statement": { - "shape": "ImportStatementString" - } - } - }, - "ImportStatementString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "Imports": { - "type": "list", - "member": { - "shape": "Import" - }, - "max": 10, - "min": 0 - }, - "Integer": { - "type": "integer", - "box": true - }, - "InternalServerException": { - "type": "structure", - "required": ["message"], - "members": { - "message": { - "shape": "String" - }, - "reason": { - "shape": "InternalServerExceptionReason" - } - }, - "documentation": "

This exception is thrown when an unexpected error occurred during the processing of a request.

", - "exception": true, - "fault": true, - "retryable": { - "throttling": false - } - }, - "InternalServerExceptionReason": { - "type": "string", - "documentation": "

Reason for InternalServerException

", - "enum": ["MODEL_TEMPORARILY_UNAVAILABLE"] - }, - "IssuerUrl": { - "type": "string", - "max": 255, - "min": 1 - }, - "ListCustomizationPermissionsRequest": { - "type": "structure", - "required": ["identifier"], - "members": { - "identifier": { - "shape": "CustomizationIdentifier" - }, - "maxResults": { - "shape": "ListCustomizationPermissionsRequestMaxResultsInteger" - }, - "nextToken": { - "shape": "Base64EncodedPaginationToken" - } - } - }, - "ListCustomizationPermissionsRequestMaxResultsInteger": { - "type": "integer", - "box": true, - "max": 50, - "min": 1 - }, - "ListCustomizationPermissionsResponse": { - "type": "structure", - "required": ["permissions"], - "members": { - "permissions": { - "shape": "IdentityCenterPermissions" - }, - "nextToken": { - "shape": "Base64EncodedPaginationToken" - } - } - }, - "ListCustomizationVersionsRequest": { - "type": "structure", - "required": ["identifier"], - "members": { - "identifier": { - "shape": "CustomizationIdentifier" - }, - "maxResults": { - "shape": "ListCustomizationVersionsRequestMaxResultsInteger" - }, - "nextToken": { - "shape": "Base64EncodedPaginationToken" - } - } - }, - "ListCustomizationVersionsRequestMaxResultsInteger": { - "type": "integer", - "box": true, - "max": 100, - "min": 1 - }, - "ListCustomizationVersionsResponse": { - "type": "structure", - "required": ["versions"], - "members": { - "versions": { - "shape": "CustomizationVersionSummaryList" - }, - "nextToken": { - "shape": "Base64EncodedPaginationToken" - } - } - }, - "ListCustomizationsRequest": { - "type": "structure", - "members": { - "maxResults": { - "shape": "ListCustomizationsRequestMaxResultsInteger" - }, - "nextToken": { - "shape": "Base64EncodedPaginationToken" - } - } - }, - "ListCustomizationsRequestMaxResultsInteger": { - "type": "integer", - "box": true, - "max": 100, - "min": 1 - }, - "ListCustomizationsResponse": { - "type": "structure", - "required": ["customizations"], - "members": { - "customizations": { - "shape": "CustomizationSummaryList" - }, - "nextToken": { - "shape": "Base64EncodedPaginationToken" - } - } - }, - "ListProfilesRequest": { - "type": "structure", - "members": { - "maxResults": { - "shape": "ListProfilesRequestMaxResultsInteger" - }, - "includeManagementAccount": { - "shape": "Boolean" - }, - "nextToken": { - "shape": "Base64EncodedPaginationToken" - } - } - }, - "ListProfilesRequestMaxResultsInteger": { - "type": "integer", - "box": true, - "max": 100, - "min": 1 - }, - "ListProfilesResponse": { - "type": "structure", - "required": ["profiles"], - "members": { - "profiles": { - "shape": "ProfileList" - }, - "nextToken": { - "shape": "Base64EncodedPaginationToken" - } - } - }, - "ListTagsForResourceRequest": { - "type": "structure", - "required": ["resourceArn"], - "members": { - "resourceArn": { - "shape": "ResourceArn" - } - } - }, - "ListTagsForResourceResponse": { - "type": "structure", - "members": { - "tags": { - "shape": "TagList" - } - } - }, - "Notifications": { - "type": "list", - "member": { - "shape": "NotificationsFeature" - }, - "max": 10, - "min": 0 - }, - "NotificationsFeature": { - "type": "structure", - "required": ["feature", "toggle"], - "members": { - "feature": { - "shape": "FeatureName" - }, - "toggle": { - "shape": "OptInFeatureToggle" - } - } - }, - "OptInFeatureToggle": { - "type": "string", - "enum": ["ON", "OFF"] - }, - "OptInFeatures": { - "type": "structure", - "members": { - "promptLogging": { - "shape": "PromptLogging" - }, - "byUserAnalytics": { - "shape": "ByUserAnalytics" - }, - "dashboardAnalytics": { - "shape": "DashboardAnalytics" - }, - "notifications": { - "shape": "Notifications" - }, - "workspaceContext": { - "shape": "WorkspaceContext" - } - } - }, - "PreviousEditorStateMetadata": { - "type": "structure", - "required": ["timeOffset"], - "members": { - "timeOffset": { - "shape": "Integer" - } - } - }, - "Profile": { - "type": "structure", - "required": ["arn", "profileName"], - "members": { - "arn": { - "shape": "ProfileArn" - }, - "identityDetails": { - "shape": "IdentityDetails" - }, - "profileName": { - "shape": "ProfileName" - }, - "description": { - "shape": "ProfileDescription" - }, - "referenceTrackerConfiguration": { - "shape": "ReferenceTrackerConfiguration" - }, - "kmsKeyArn": { - "shape": "ResourceArn" - }, - "activeFunctionalities": { - "shape": "ActiveFunctionalityList" - }, - "status": { - "shape": "ProfileStatus" - }, - "errorDetails": { - "shape": "ErrorDetails" - }, - "resourcePolicy": { - "shape": "ResourcePolicy" - }, - "profileType": { - "shape": "ProfileType" - }, - "optInFeatures": { - "shape": "OptInFeatures" - }, - "permissionUpdateRequired": { - "shape": "Boolean" - }, - "applicationProperties": { - "shape": "ApplicationPropertiesList" - } - } - }, - "ProfileArn": { - "type": "string", - "max": 950, - "min": 0, - "pattern": "arn:aws:(codewhisperer|transform):[-.a-z0-9]{1,63}:\\d{12}:profile/([a-zA-Z0-9]){12}" - }, - "ProfileDescription": { - "type": "string", - "max": 256, - "min": 1, - "pattern": "[\\sa-zA-Z0-9_-]*" - }, - "ProfileList": { - "type": "list", - "member": { - "shape": "Profile" - } - }, - "ProfileName": { - "type": "string", - "max": 100, - "min": 1, - "pattern": "[a-zA-Z][a-zA-Z0-9_-]*" - }, - "ProfileStatus": { - "type": "string", - "enum": ["ACTIVE", "CREATING", "CREATE_FAILED", "UPDATING", "UPDATE_FAILED", "DELETING", "DELETE_FAILED"] - }, - "ProfileType": { - "type": "string", - "enum": ["Q_DEVELOPER", "CODEWHISPERER"] - }, - "ProgrammingLanguage": { - "type": "structure", - "required": ["languageName"], - "members": { - "languageName": { - "shape": "ProgrammingLanguageLanguageNameString" - } - }, - "documentation": "

Programming Languages supported by CodeWhisperer

" - }, - "ProgrammingLanguageLanguageNameString": { - "type": "string", - "max": 128, - "min": 1, - "pattern": "(python|javascript|java|csharp|typescript|c|cpp|go|kotlin|php|ruby|rust|scala|shell|sql|json|yaml|vue|tf|tsx|jsx|plaintext|systemverilog|dart|lua|swift|hcl|powershell|r|abap)" - }, - "PromptLogging": { - "type": "structure", - "required": ["s3Uri", "toggle"], - "members": { - "s3Uri": { - "shape": "S3Uri" - }, - "toggle": { - "shape": "OptInFeatureToggle" - } - } - }, - "Recommendation": { - "type": "structure", - "required": ["content"], - "members": { - "content": { - "shape": "RecommendationContentString" - }, - "references": { - "shape": "References" - }, - "mostRelevantMissingImports": { - "shape": "Imports" - } - } - }, - "RecommendationContentString": { - "type": "string", - "max": 5120, - "min": 1, - "sensitive": true - }, - "RecommendationsList": { - "type": "list", - "member": { - "shape": "Recommendation" - }, - "max": 10, - "min": 0 - }, - "RecommendationsWithReferencesPreference": { - "type": "string", - "documentation": "

Recommendations with references setting for CodeWhisperer

", - "enum": ["BLOCK", "ALLOW"] - }, - "Reference": { - "type": "structure", - "members": { - "licenseName": { - "shape": "ReferenceLicenseNameString", - "documentation": "

License name

" - }, - "repository": { - "shape": "ReferenceRepositoryString", - "documentation": "

Code Repsitory for the associated reference

" - }, - "url": { - "shape": "ReferenceUrlString", - "documentation": "

Respository URL

" - }, - "recommendationContentSpan": { - "shape": "Span", - "documentation": "

Span / Range for the Reference

" - } - }, - "documentation": "

Code Reference / Repository details

" - }, - "ReferenceLicenseNameString": { - "type": "string", - "max": 1024, - "min": 1 - }, - "ReferenceRepositoryString": { - "type": "string", - "max": 1024, - "min": 1 - }, - "ReferenceTrackerConfiguration": { - "type": "structure", - "required": ["recommendationsWithReferences"], - "members": { - "recommendationsWithReferences": { - "shape": "RecommendationsWithReferencesPreference" - } - } - }, - "ReferenceUrlString": { - "type": "string", - "max": 1024, - "min": 1 - }, - "References": { - "type": "list", - "member": { - "shape": "Reference" - }, - "max": 10, - "min": 0 - }, - "RepositoryId": { - "type": "string", - "max": 255, - "min": 1, - "pattern": ".*(?x)^([a-zA-Z0-9-_\\.\\s()]+/)+[\\w-\\.\\+_\\s]+", - "sensitive": true - }, - "RepositoryList": { - "type": "list", - "member": { - "shape": "RepositoryId" - }, - "max": 100, - "min": 1, - "sensitive": true - }, - "ResourceArn": { - "type": "string", - "max": 1224, - "min": 0, - "pattern": "arn:([-.a-z0-9]{1,63}:){2}([-.a-z0-9]{0,63}:){2}([a-zA-Z0-9-_:/]){1,1023}" - }, - "ResourceNotFoundException": { - "type": "structure", - "required": ["message"], - "members": { - "message": { - "shape": "String" - } - }, - "documentation": "

This exception is thrown when describing a resource that does not exist.

", - "exception": true - }, - "ResourcePolicy": { - "type": "structure", - "required": ["effect"], - "members": { - "effect": { - "shape": "ResourcePolicyEffect" - } - } - }, - "ResourcePolicyEffect": { - "type": "string", - "enum": ["ALLOW", "DENY"] - }, - "S3Reference": { - "type": "structure", - "required": ["uri"], - "members": { - "uri": { - "shape": "S3Uri" - } - } - }, - "S3Uri": { - "type": "string", - "max": 1024, - "min": 1, - "pattern": "s3://((?!xn--)[a-z0-9](?![^/]*[.]{2})[a-z0-9-.]{1,61}[a-z0-9](?Represents span in a text.

" - }, - "SpanEndInteger": { - "type": "integer", - "box": true, - "min": 0 - }, - "SpanStartInteger": { - "type": "integer", - "box": true, - "min": 0 - }, - "String": { - "type": "string" - }, - "SupplementalContext": { - "type": "structure", - "required": ["filePath", "content"], - "members": { - "filePath": { - "shape": "SupplementalContextFilePathString" - }, - "content": { - "shape": "SupplementalContextContentString" - }, - "type": { - "shape": "SupplementalContextType" - }, - "metadata": { - "shape": "SupplementalContextMetadata" - } - } - }, - "SupplementalContextContentString": { - "type": "string", - "max": 10240, - "min": 1, - "sensitive": true - }, - "SupplementalContextFilePathString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "SupplementalContextList": { - "type": "list", - "member": { - "shape": "SupplementalContext" - }, - "max": 20, - "min": 0 - }, - "SupplementalContextMetadata": { - "type": "structure", - "members": { - "previousEditorStateMetadata": { - "shape": "PreviousEditorStateMetadata" - } - }, - "union": true - }, - "SupplementalContextType": { - "type": "string", - "enum": ["PreviousEditorState", "WorkspaceContext"] - }, - "Tag": { - "type": "structure", - "required": ["key", "value"], - "members": { - "key": { - "shape": "TagKey" - }, - "value": { - "shape": "TagValue" - } - } - }, - "TagKey": { - "type": "string", - "max": 128, - "min": 1 - }, - "TagKeyList": { - "type": "list", - "member": { - "shape": "TagKey" - }, - "max": 50, - "min": 0 - }, - "TagList": { - "type": "list", - "member": { - "shape": "Tag" - }, - "max": 50, - "min": 0 - }, - "TagResourceRequest": { - "type": "structure", - "required": ["resourceArn", "tags"], - "members": { - "resourceArn": { - "shape": "ResourceArn" - }, - "tags": { - "shape": "TagList" - } - } - }, - "TagResourceResponse": { - "type": "structure", - "members": {} - }, - "TagValue": { - "type": "string", - "max": 256, - "min": 0 - }, - "TenantId": { - "type": "string", - "max": 1024, - "min": 1 - }, - "ThrottlingException": { - "type": "structure", - "required": ["message"], - "members": { - "message": { - "shape": "String" - }, - "reason": { - "shape": "ThrottlingExceptionReason" - } - }, - "documentation": "

This exception is thrown when request was denied due to request throttling.

", - "exception": true, - "retryable": { - "throttling": true - } - }, - "ThrottlingExceptionReason": { - "type": "string", - "documentation": "

Reason for ThrottlingException

", - "enum": ["MONTHLY_REQUEST_COUNT"] - }, - "Timestamp": { - "type": "timestamp" - }, - "UntagResourceRequest": { - "type": "structure", - "required": ["resourceArn", "tagKeys"], - "members": { - "resourceArn": { - "shape": "ResourceArn" - }, - "tagKeys": { - "shape": "TagKeyList" - } - } - }, - "UntagResourceResponse": { - "type": "structure", - "members": {} - }, - "UpdateCustomizationRequest": { - "type": "structure", - "required": ["identifier", "operation"], - "members": { - "identifier": { - "shape": "CustomizationIdentifier" - }, - "operation": { - "shape": "UpdateOperation" - }, - "clientToken": { - "shape": "IdempotencyToken" - }, - "dataReference": { - "shape": "DataReference" - }, - "version": { - "shape": "Version" - }, - "includeRepos": { - "shape": "RepositoryList" - } - } - }, - "UpdateCustomizationResponse": { - "type": "structure", - "members": {} - }, - "UpdateOperation": { - "type": "string", - "enum": ["ACTIVATE", "DEACTIVATE", "UPDATE"] - }, - "UpdateProfileRequest": { - "type": "structure", - "required": ["profileArn"], - "members": { - "profileArn": { - "shape": "ProfileArn" - }, - "identitySource": { - "shape": "IdentitySource" - }, - "profileName": { - "shape": "ProfileName" - }, - "description": { - "shape": "ProfileDescription" - }, - "referenceTrackerConfiguration": { - "shape": "ReferenceTrackerConfiguration" - }, - "activeFunctionalities": { - "shape": "ActiveFunctionalityList" - }, - "kmsKeyArn": { - "shape": "ResourceArn" - }, - "resourcePolicy": { - "shape": "ResourcePolicy" - }, - "targetProfileType": { - "shape": "ProfileType" - }, - "optInFeatures": { - "shape": "OptInFeatures" - } - } - }, - "UpdateProfileResponse": { - "type": "structure", - "required": ["profileArn"], - "members": { - "profileArn": { - "shape": "ProfileArn" - } - } - }, - "Url": { - "type": "string", - "max": 1024, - "min": 1 - }, - "ValidationException": { - "type": "structure", - "required": ["message"], - "members": { - "message": { - "shape": "String" - }, - "reason": { - "shape": "ValidationExceptionReason" - } - }, - "documentation": "

This exception is thrown when the input fails to satisfy the constraints specified by the service.

", - "exception": true - }, - "ValidationExceptionReason": { - "type": "string", - "documentation": "

Reason for ValidationException

", - "enum": ["INVALID_CONVERSATION_ID", "CONTENT_LENGTH_EXCEEDS_THRESHOLD", "INVALID_KMS_GRANT"] - }, - "VendKeyGrantRequest": { - "type": "structure", - "required": ["accountId", "usecase"], - "members": { - "accountId": { - "shape": "AWSAccountId" - }, - "usecase": { - "shape": "VendKeyGrantUseCase" - } - } - }, - "VendKeyGrantResponse": { - "type": "structure", - "members": { - "cmkArn": { - "shape": "ResourceArn" - }, - "grantId": { - "shape": "GrantToken" - }, - "grantToken": { - "shape": "GrantId" - } - } - }, - "VendKeyGrantUseCase": { - "type": "string", - "enum": [ - "TEST", - "WEAVER_BIRD", - "ELASTIC_GUMBY", - "LOCHNESS", - "BOWER_BIRD", - "ELASTIC_GUMBY_V2_JOB", - "ELASTIC_GUMBY_V2_CHAT" - ] - }, - "Version": { - "type": "long", - "box": true - }, - "WorkspaceContext": { - "type": "structure", - "required": ["toggle"], - "members": { - "toggle": { - "shape": "OptInFeatureToggle" - } - } - } - } -} diff --git a/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json b/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json deleted file mode 100644 index f54c13cbdd..0000000000 --- a/server/aws-lsp-codewhisperer/src/client/token/bearer-token-service.json +++ /dev/null @@ -1,6690 +0,0 @@ -{ - "version": "2.0", - "metadata": { - "apiVersion": "2022-11-11", - "auth": ["smithy.api#httpBearerAuth"], - "endpointPrefix": "amazoncodewhispererservice", - "jsonVersion": "1.0", - "protocol": "json", - "protocols": ["json"], - "serviceFullName": "Amazon CodeWhisperer", - "serviceId": "CodeWhispererRuntime", - "signingName": "amazoncodewhispererservice", - "targetPrefix": "AmazonCodeWhispererService", - "uid": "codewhispererruntime-2022-11-11" - }, - "operations": { - "CreateArtifactUploadUrl": { - "name": "CreateArtifactUploadUrl", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "CreateUploadUrlRequest" - }, - "output": { - "shape": "CreateUploadUrlResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Creates a pre-signed, S3 write URL for uploading a repository zip archive.

", - "idempotent": true - }, - "CreateSubscriptionToken": { - "name": "CreateSubscriptionToken", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "CreateSubscriptionTokenRequest" - }, - "output": { - "shape": "CreateSubscriptionTokenResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "idempotent": true - }, - "CreateTaskAssistConversation": { - "name": "CreateTaskAssistConversation", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "CreateTaskAssistConversationRequest" - }, - "output": { - "shape": "CreateTaskAssistConversationResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ServiceQuotaExceededException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to create task assist conversation.

" - }, - "CreateUploadUrl": { - "name": "CreateUploadUrl", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "CreateUploadUrlRequest" - }, - "output": { - "shape": "CreateUploadUrlResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "ServiceQuotaExceededException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Creates a pre-signed, S3 write URL for uploading a repository zip archive.

", - "idempotent": true - }, - "CreateUserMemoryEntry": { - "name": "CreateUserMemoryEntry", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "CreateUserMemoryEntryInput" - }, - "output": { - "shape": "CreateUserMemoryEntryOutput" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ServiceQuotaExceededException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to create a single user memory entry

", - "idempotent": true - }, - "CreateWorkspace": { - "name": "CreateWorkspace", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "CreateWorkspaceRequest" - }, - "output": { - "shape": "CreateWorkspaceResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "ServiceQuotaExceededException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Create a workspace based on a workspace root

" - }, - "DeleteTaskAssistConversation": { - "name": "DeleteTaskAssistConversation", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "DeleteTaskAssistConversationRequest" - }, - "output": { - "shape": "DeleteTaskAssistConversationResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to delete task assist conversation.

" - }, - "DeleteUserMemoryEntry": { - "name": "DeleteUserMemoryEntry", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "DeleteUserMemoryEntryInput" - }, - "output": { - "shape": "DeleteUserMemoryEntryOutput" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to delete a single user memory entry

", - "idempotent": true - }, - "DeleteWorkspace": { - "name": "DeleteWorkspace", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "DeleteWorkspaceRequest" - }, - "output": { - "shape": "DeleteWorkspaceResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Delete a workspace based on a workspaceId

" - }, - "GenerateCompletions": { - "name": "GenerateCompletions", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "GenerateCompletionsRequest" - }, - "output": { - "shape": "GenerateCompletionsResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Generate completions based on the provided file context in a paginated response.

" - }, - "GetCodeAnalysis": { - "name": "GetCodeAnalysis", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "GetCodeAnalysisRequest" - }, - "output": { - "shape": "GetCodeAnalysisResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Gets the metadata of a code analysis job.

" - }, - "GetCodeFixJob": { - "name": "GetCodeFixJob", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "GetCodeFixJobRequest" - }, - "output": { - "shape": "GetCodeFixJobResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ] - }, - "GetTaskAssistCodeGeneration": { - "name": "GetTaskAssistCodeGeneration", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "GetTaskAssistCodeGenerationRequest" - }, - "output": { - "shape": "GetTaskAssistCodeGenerationResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to get status of task assist code generation.

" - }, - "GetTestGeneration": { - "name": "GetTestGeneration", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "GetTestGenerationRequest" - }, - "output": { - "shape": "GetTestGenerationResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to get test generation job.

" - }, - "GetTransformation": { - "name": "GetTransformation", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "GetTransformationRequest" - }, - "output": { - "shape": "GetTransformationResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to get code transformation status.

" - }, - "GetTransformationPlan": { - "name": "GetTransformationPlan", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "GetTransformationPlanRequest" - }, - "output": { - "shape": "GetTransformationPlanResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to get code transformation status.

" - }, - "GetProfile": { - "name": "GetProfile", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "GetProfileRequest" - }, - "output": { - "shape": "GetProfileResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Get the requested CodeWhisperer profile.

" - }, - "GetUsageLimits": { - "name": "GetUsageLimits", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "GetUsageLimitsRequest" - }, - "output": { - "shape": "GetUsageLimitsResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to get current usage limits

" - }, - "ListAvailableCustomizations": { - "name": "ListAvailableCustomizations", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "ListAvailableCustomizationsRequest" - }, - "output": { - "shape": "ListAvailableCustomizationsResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ] - }, - "ListAvailableModels": { - "name": "ListAvailableModels", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "ListAvailableModelsRequest" - }, - "output": { - "shape": "ListAvailableModelsResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ] - }, - "ListAvailableProfiles": { - "name": "ListAvailableProfiles", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "ListAvailableProfilesRequest" - }, - "output": { - "shape": "ListAvailableProfilesResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ] - }, - "ListCodeAnalysisFindings": { - "name": "ListCodeAnalysisFindings", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "ListCodeAnalysisFindingsRequest" - }, - "output": { - "shape": "ListCodeAnalysisFindingsResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Lists the findings from a particular code analysis job.

" - }, - "ListEvents": { - "name": "ListEvents", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "ListEventsRequest" - }, - "output": { - "shape": "ListEventsResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

List events for agent activity

" - }, - "ListFeatureEvaluations": { - "name": "ListFeatureEvaluations", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "ListFeatureEvaluationsRequest" - }, - "output": { - "shape": "ListFeatureEvaluationsResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Return configruations for each feature that has been setup for A/B testing.

" - }, - "ListUserMemoryEntries": { - "name": "ListUserMemoryEntries", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "ListUserMemoryEntriesInput" - }, - "output": { - "shape": "ListUserMemoryEntriesOutput" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to list user memories

" - }, - "ListWorkspaceMetadata": { - "name": "ListWorkspaceMetadata", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "ListWorkspaceMetadataRequest" - }, - "output": { - "shape": "ListWorkspaceMetadataResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

List workspace metadata based on a workspace root

" - }, - "PushTelemetryEvent": { - "name": "PushTelemetryEvent", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "PushTelemetryEventRequest" - }, - "output": { - "shape": "PushTelemetryEventResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to push telemetry events to CloudWatch, DataHub and EventBridge.

", - "idempotent": true - }, - "ResumeTransformation": { - "name": "ResumeTransformation", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "ResumeTransformationRequest" - }, - "output": { - "shape": "ResumeTransformationResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to resume transformation job.

" - }, - "SendTelemetryEvent": { - "name": "SendTelemetryEvent", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "SendTelemetryEventRequest" - }, - "output": { - "shape": "SendTelemetryEventResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to record telemetry events.

", - "idempotent": true - }, - "StartCodeAnalysis": { - "name": "StartCodeAnalysis", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "StartCodeAnalysisRequest" - }, - "output": { - "shape": "StartCodeAnalysisResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

Starts a code analysis job

", - "idempotent": true - }, - "StartCodeFixJob": { - "name": "StartCodeFixJob", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "StartCodeFixJobRequest" - }, - "output": { - "shape": "StartCodeFixJobResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ] - }, - "StartTaskAssistCodeGeneration": { - "name": "StartTaskAssistCodeGeneration", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "StartTaskAssistCodeGenerationRequest" - }, - "output": { - "shape": "StartTaskAssistCodeGenerationResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "ServiceQuotaExceededException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to start task assist code generation.

" - }, - "StartTestGeneration": { - "name": "StartTestGeneration", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "StartTestGenerationRequest" - }, - "output": { - "shape": "StartTestGenerationResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to start test generation.

", - "idempotent": true - }, - "StartTransformation": { - "name": "StartTransformation", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "StartTransformationRequest" - }, - "output": { - "shape": "StartTransformationResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ConflictException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to start code translation.

" - }, - "StopTransformation": { - "name": "StopTransformation", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "StopTransformationRequest" - }, - "output": { - "shape": "StopTransformationResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "ResourceNotFoundException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - } - ], - "documentation": "

API to stop code transformation status.

" - }, - "UpdateUsageLimits": { - "name": "UpdateUsageLimits", - "http": { - "method": "POST", - "requestUri": "/" - }, - "input": { - "shape": "UpdateUsageLimitsRequest" - }, - "output": { - "shape": "UpdateUsageLimitsResponse" - }, - "errors": [ - { - "shape": "ThrottlingException" - }, - { - "shape": "InternalServerException" - }, - { - "shape": "ValidationException" - }, - { - "shape": "AccessDeniedException" - }, - { - "shape": "UpdateUsageLimitQuotaExceededException" - } - ], - "documentation": "

API to update usage limits for enterprise customers

" - } - }, - "shapes": { - "AccessDeniedException": { - "type": "structure", - "required": ["message"], - "members": { - "message": { - "shape": "String" - }, - "reason": { - "shape": "AccessDeniedExceptionReason" - } - }, - "documentation": "

This exception is thrown when the user does not have sufficient access to perform this action.

", - "exception": true - }, - "AccessDeniedExceptionReason": { - "type": "string", - "documentation": "

Reason for AccessDeniedException

", - "enum": ["UNAUTHORIZED_CUSTOMIZATION_RESOURCE_ACCESS", "UNAUTHORIZED_WORKSPACE_CONTEXT_FEATURE_ACCESS"] - }, - "ActivationToken": { - "type": "string", - "max": 16, - "min": 8 - }, - "ActiveFunctionalityList": { - "type": "list", - "member": { - "shape": "FunctionalityName" - }, - "max": 10, - "min": 0 - }, - "AdditionalContentEntry": { - "type": "structure", - "required": ["name", "description"], - "members": { - "name": { - "shape": "AdditionalContentEntryNameString", - "documentation": "

The name/identifier for this context entry

" - }, - "description": { - "shape": "AdditionalContentEntryDescriptionString", - "documentation": "

A description of what this context entry represents

" - }, - "innerContext": { - "shape": "AdditionalContentEntryInnerContextString", - "documentation": "

The actual contextual content

" - } - }, - "documentation": "

Structure representing a single entry of additional contextual content

" - }, - "AdditionalContentEntryDescriptionString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "AdditionalContentEntryInnerContextString": { - "type": "string", - "max": 8192, - "min": 1, - "sensitive": true - }, - "AdditionalContentEntryNameString": { - "type": "string", - "max": 1024, - "min": 1, - "pattern": "[a-z]+(?:-[a-z0-9]+)*", - "sensitive": true - }, - "AdditionalContentList": { - "type": "list", - "member": { - "shape": "AdditionalContentEntry" - }, - "documentation": "

A list of additional content entries, limited to 20 items

", - "max": 20, - "min": 0 - }, - "AgenticChatEventStatus": { - "type": "string", - "enum": ["SUCCEEDED", "CANCELLED", "FAILED"] - }, - "AppStudioState": { - "type": "structure", - "required": ["namespace", "propertyName", "propertyContext"], - "members": { - "namespace": { - "shape": "AppStudioStateNamespaceString", - "documentation": "

The namespace of the context. Examples: 'ui.Button', 'ui.Table.DataSource', 'ui.Table.RowActions.Button', 'logic.invokeAWS', 'logic.JavaScript'

" - }, - "propertyName": { - "shape": "AppStudioStatePropertyNameString", - "documentation": "

The name of the property. Examples: 'visibility', 'disability', 'value', 'code'

" - }, - "propertyValue": { - "shape": "AppStudioStatePropertyValueString", - "documentation": "

The value of the property.

" - }, - "propertyContext": { - "shape": "AppStudioStatePropertyContextString", - "documentation": "

Context about how the property is used

" - } - }, - "documentation": "

Description of a user's context when they are calling Q Chat from AppStudio

" - }, - "AppStudioStateNamespaceString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "AppStudioStatePropertyContextString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "AppStudioStatePropertyNameString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "AppStudioStatePropertyValueString": { - "type": "string", - "max": 10240, - "min": 0, - "sensitive": true - }, - "ApplicationProperties": { - "type": "structure", - "required": ["tenantId", "applicationArn", "tenantUrl", "applicationType"], - "members": { - "tenantId": { - "shape": "TenantId" - }, - "applicationArn": { - "shape": "ResourceArn" - }, - "tenantUrl": { - "shape": "Url" - }, - "applicationType": { - "shape": "FunctionalityName" - } - } - }, - "ApplicationPropertiesList": { - "type": "list", - "member": { - "shape": "ApplicationProperties" - } - }, - "ArtifactId": { - "type": "string", - "max": 126, - "min": 1, - "pattern": "[a-zA-Z0-9-_]+" - }, - "ArtifactMap": { - "type": "map", - "key": { - "shape": "ArtifactType" - }, - "value": { - "shape": "UploadId" - }, - "max": 64, - "min": 1 - }, - "ArtifactType": { - "type": "string", - "enum": ["SourceCode", "BuiltJars"] - }, - "AssistantResponseMessage": { - "type": "structure", - "required": ["content"], - "members": { - "messageId": { - "shape": "MessageId" - }, - "content": { - "shape": "AssistantResponseMessageContentString", - "documentation": "

The content of the text message in markdown format.

" - }, - "supplementaryWebLinks": { - "shape": "SupplementaryWebLinks", - "documentation": "

Web References

" - }, - "references": { - "shape": "References", - "documentation": "

Code References

" - }, - "followupPrompt": { - "shape": "FollowupPrompt", - "documentation": "

Followup Prompt

" - }, - "toolUses": { - "shape": "ToolUses", - "documentation": "

ToolUse Request

" - } - }, - "documentation": "

Markdown text message.

" - }, - "AssistantResponseMessageContentString": { - "type": "string", - "max": 100000, - "min": 0, - "sensitive": true - }, - "AttributesMap": { - "type": "map", - "key": { - "shape": "AttributesMapKeyString" - }, - "value": { - "shape": "StringList" - }, - "documentation": "

Attributes is a map of key-value pairs

" - }, - "AttributesMapKeyString": { - "type": "string", - "max": 128, - "min": 1 - }, - "Base64EncodedPaginationToken": { - "type": "string", - "max": 2048, - "min": 1, - "pattern": "(?:[A-Za-z0-9\\+/]{4})*(?:[A-Za-z0-9\\+/]{2}\\=\\=|[A-Za-z0-9\\+/]{3}\\=)?" - }, - "Boolean": { - "type": "boolean", - "box": true - }, - "ByUserAnalytics": { - "type": "structure", - "required": ["toggle"], - "members": { - "s3Uri": { - "shape": "S3Uri" - }, - "toggle": { - "shape": "OptInFeatureToggle" - } - } - }, - "ChangeLogGranularityType": { - "type": "string", - "enum": ["STANDARD", "BUSINESS"] - }, - "ChangeLogOptions": { - "type": "structure", - "required": ["granularity"], - "members": { - "granularity": { - "shape": "ChangeLogGranularityType" - } - } - }, - "ChatAddMessageEvent": { - "type": "structure", - "required": ["conversationId", "messageId"], - "members": { - "conversationId": { - "shape": "ConversationId" - }, - "messageId": { - "shape": "MessageId" - }, - "customizationArn": { - "shape": "CustomizationArn" - }, - "userIntent": { - "shape": "UserIntent" - }, - "hasCodeSnippet": { - "shape": "Boolean" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage" - }, - "activeEditorTotalCharacters": { - "shape": "Integer" - }, - "timeToFirstChunkMilliseconds": { - "shape": "Double" - }, - "timeBetweenChunks": { - "shape": "timeBetweenChunks" - }, - "fullResponselatency": { - "shape": "Double" - }, - "requestLength": { - "shape": "Integer" - }, - "responseLength": { - "shape": "Integer" - }, - "numberOfCodeBlocks": { - "shape": "Integer" - }, - "hasProjectLevelContext": { - "shape": "Boolean" - }, - "result": { - "shape": "AgenticChatEventStatus" - } - } - }, - "ChatHistory": { - "type": "list", - "member": { - "shape": "ChatMessage" - }, - "documentation": "

Indicates Participant in Chat conversation

", - "max": 250, - "min": 0 - }, - "ChatInteractWithMessageEvent": { - "type": "structure", - "required": ["conversationId", "messageId"], - "members": { - "conversationId": { - "shape": "ConversationId" - }, - "messageId": { - "shape": "MessageId" - }, - "customizationArn": { - "shape": "CustomizationArn" - }, - "interactionType": { - "shape": "ChatMessageInteractionType" - }, - "interactionTarget": { - "shape": "ChatInteractWithMessageEventInteractionTargetString" - }, - "acceptedCharacterCount": { - "shape": "Integer" - }, - "acceptedLineCount": { - "shape": "Integer" - }, - "acceptedSnippetHasReference": { - "shape": "Boolean" - }, - "hasProjectLevelContext": { - "shape": "Boolean" - }, - "userIntent": { - "shape": "UserIntent" - }, - "addedIdeDiagnostics": { - "shape": "IdeDiagnosticList" - }, - "removedIdeDiagnostics": { - "shape": "IdeDiagnosticList" - } - } - }, - "ChatInteractWithMessageEventInteractionTargetString": { - "type": "string", - "max": 1024, - "min": 1 - }, - "ChatMessage": { - "type": "structure", - "members": { - "userInputMessage": { - "shape": "UserInputMessage" - }, - "assistantResponseMessage": { - "shape": "AssistantResponseMessage" - } - }, - "union": true - }, - "ChatMessageInteractionType": { - "type": "string", - "documentation": "

Chat Message Interaction Type

", - "enum": [ - "INSERT_AT_CURSOR", - "COPY_SNIPPET", - "COPY", - "CLICK_LINK", - "CLICK_BODY_LINK", - "CLICK_FOLLOW_UP", - "HOVER_REFERENCE", - "UPVOTE", - "DOWNVOTE" - ] - }, - "ChatTriggerType": { - "type": "string", - "documentation": "

Trigger Reason for Chat

", - "enum": ["MANUAL", "DIAGNOSTIC", "INLINE_CHAT"] - }, - "ChatUserModificationEvent": { - "type": "structure", - "required": ["conversationId", "messageId", "modificationPercentage"], - "members": { - "conversationId": { - "shape": "ConversationId" - }, - "customizationArn": { - "shape": "CustomizationArn" - }, - "messageId": { - "shape": "MessageId" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage" - }, - "modificationPercentage": { - "shape": "Double" - }, - "hasProjectLevelContext": { - "shape": "Boolean" - } - } - }, - "ClientId": { - "type": "string", - "max": 255, - "min": 1 - }, - "CodeAnalysisFindingsSchema": { - "type": "string", - "enum": ["codeanalysis/findings/1.0"] - }, - "CodeAnalysisScope": { - "type": "string", - "enum": ["FILE", "PROJECT", "AGENTIC"] - }, - "CodeAnalysisStatus": { - "type": "string", - "enum": ["Completed", "Pending", "Failed"] - }, - "CodeAnalysisUploadContext": { - "type": "structure", - "required": ["codeScanName"], - "members": { - "codeScanName": { - "shape": "CodeScanName" - } - } - }, - "CodeCoverageEvent": { - "type": "structure", - "required": ["programmingLanguage", "acceptedCharacterCount", "totalCharacterCount", "timestamp"], - "members": { - "customizationArn": { - "shape": "CustomizationArn" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage" - }, - "acceptedCharacterCount": { - "shape": "PrimitiveInteger" - }, - "totalCharacterCount": { - "shape": "PrimitiveInteger" - }, - "timestamp": { - "shape": "Timestamp" - }, - "unmodifiedAcceptedCharacterCount": { - "shape": "PrimitiveInteger" - }, - "totalNewCodeCharacterCount": { - "shape": "PrimitiveInteger" - }, - "totalNewCodeLineCount": { - "shape": "PrimitiveInteger" - }, - "userWrittenCodeCharacterCount": { - "shape": "CodeCoverageEventUserWrittenCodeCharacterCountInteger" - }, - "userWrittenCodeLineCount": { - "shape": "CodeCoverageEventUserWrittenCodeLineCountInteger" - }, - "addedCharacterCount": { - "shape": "CodeCoverageEventAddedCharacterCountInteger" - } - } - }, - "CodeCoverageEventAddedCharacterCountInteger": { - "type": "integer", - "min": 0 - }, - "CodeCoverageEventUserWrittenCodeCharacterCountInteger": { - "type": "integer", - "min": 0 - }, - "CodeCoverageEventUserWrittenCodeLineCountInteger": { - "type": "integer", - "min": 0 - }, - "CodeDescription": { - "type": "structure", - "required": ["href"], - "members": { - "href": { - "shape": "CodeDescriptionHrefString", - "documentation": "

An URI to open with more information about the diagnostic error.

" - } - }, - "documentation": "

Structure to capture a description for an error code.

" - }, - "CodeDescriptionHrefString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "CodeDiffMetadata": { - "type": "structure", - "members": { - "codeDiffPath": { - "shape": "CodeDiffPath" - } - } - }, - "CodeDiffPath": { - "type": "string", - "max": 1024, - "min": 0, - "pattern": "/[\\S]+/" - }, - "CodeFixAcceptanceEvent": { - "type": "structure", - "required": ["jobId"], - "members": { - "jobId": { - "shape": "String" - }, - "ruleId": { - "shape": "String" - }, - "detectorId": { - "shape": "String" - }, - "findingId": { - "shape": "String" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage" - }, - "linesOfCodeAccepted": { - "shape": "Integer" - }, - "charsOfCodeAccepted": { - "shape": "Integer" - } - } - }, - "CodeFixGenerationEvent": { - "type": "structure", - "required": ["jobId"], - "members": { - "jobId": { - "shape": "String" - }, - "ruleId": { - "shape": "String" - }, - "detectorId": { - "shape": "String" - }, - "findingId": { - "shape": "String" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage" - }, - "linesOfCodeGenerated": { - "shape": "Integer" - }, - "charsOfCodeGenerated": { - "shape": "Integer" - } - } - }, - "CodeFixJobStatus": { - "type": "string", - "enum": ["Succeeded", "InProgress", "Failed"] - }, - "CodeFixName": { - "type": "string", - "documentation": "

Code fix name

", - "max": 128, - "min": 1, - "pattern": "[a-zA-Z0-9-_$:.]*" - }, - "CodeFixUploadContext": { - "type": "structure", - "required": ["codeFixName"], - "members": { - "codeFixName": { - "shape": "CodeFixName" - } - } - }, - "CodeGenerationId": { - "type": "string", - "documentation": "

ID which represents a single code generation in a conversation

", - "max": 128, - "min": 1 - }, - "CodeGenerationStatus": { - "type": "structure", - "required": ["status", "currentStage"], - "members": { - "status": { - "shape": "CodeGenerationWorkflowStatus" - }, - "currentStage": { - "shape": "CodeGenerationWorkflowStage" - } - } - }, - "CodeGenerationStatusDetail": { - "type": "string", - "documentation": "

Detailed message about the code generation status

", - "sensitive": true - }, - "CodeGenerationWorkflowStage": { - "type": "string", - "enum": ["InitialCodeGeneration", "CodeRefinement"] - }, - "CodeGenerationWorkflowStatus": { - "type": "string", - "enum": ["InProgress", "Complete", "Failed"] - }, - "CodeScanEvent": { - "type": "structure", - "required": ["programmingLanguage", "codeScanJobId", "timestamp"], - "members": { - "programmingLanguage": { - "shape": "ProgrammingLanguage" - }, - "codeScanJobId": { - "shape": "CodeScanJobId" - }, - "timestamp": { - "shape": "Timestamp" - }, - "codeAnalysisScope": { - "shape": "CodeAnalysisScope" - } - }, - "documentation": "

Published when a security scan or code review starts

" - }, - "CodeScanFailedEvent": { - "type": "structure", - "required": ["programmingLanguage", "codeScanJobId", "timestamp"], - "members": { - "programmingLanguage": { - "shape": "ProgrammingLanguage" - }, - "codeScanJobId": { - "shape": "CodeScanJobId" - }, - "timestamp": { - "shape": "Timestamp" - }, - "codeAnalysisScope": { - "shape": "CodeAnalysisScope" - } - }, - "documentation": "

Published when a security scan or code review fails

" - }, - "CodeScanJobId": { - "type": "string", - "max": 128, - "min": 1 - }, - "CodeScanName": { - "type": "string", - "documentation": "

Code analysis scan name

", - "max": 128, - "min": 1 - }, - "CodeScanRemediationsEvent": { - "type": "structure", - "members": { - "programmingLanguage": { - "shape": "ProgrammingLanguage" - }, - "CodeScanRemediationsEventType": { - "shape": "CodeScanRemediationsEventType" - }, - "timestamp": { - "shape": "Timestamp" - }, - "detectorId": { - "shape": "String" - }, - "findingId": { - "shape": "String" - }, - "ruleId": { - "shape": "String" - }, - "component": { - "shape": "String" - }, - "reason": { - "shape": "String" - }, - "result": { - "shape": "String" - }, - "includesFix": { - "shape": "Boolean" - } - } - }, - "CodeScanRemediationsEventType": { - "type": "string", - "documentation": "

Code Scan Remediations Interaction Type

", - "enum": ["CODESCAN_ISSUE_HOVER", "CODESCAN_ISSUE_APPLY_FIX", "CODESCAN_ISSUE_VIEW_DETAILS"] - }, - "CodeScanSucceededEvent": { - "type": "structure", - "required": ["programmingLanguage", "codeScanJobId", "timestamp", "numberOfFindings"], - "members": { - "programmingLanguage": { - "shape": "ProgrammingLanguage" - }, - "codeScanJobId": { - "shape": "CodeScanJobId" - }, - "timestamp": { - "shape": "Timestamp" - }, - "numberOfFindings": { - "shape": "PrimitiveInteger" - }, - "codeAnalysisScope": { - "shape": "CodeAnalysisScope" - } - }, - "documentation": "

Published when a security scan or code review completes successfully

" - }, - "Completion": { - "type": "structure", - "required": ["content"], - "members": { - "content": { - "shape": "CompletionContentString" - }, - "references": { - "shape": "References" - }, - "mostRelevantMissingImports": { - "shape": "Imports" - } - } - }, - "CompletionContentString": { - "type": "string", - "max": 5120, - "min": 1, - "sensitive": true - }, - "CompletionType": { - "type": "string", - "enum": ["BLOCK", "LINE"] - }, - "SuggestionType": { - "type": "string", - "enum": ["COMPLETIONS", "EDITS"] - }, - "Completions": { - "type": "list", - "member": { - "shape": "Completion" - }, - "max": 10, - "min": 0 - }, - "ConflictException": { - "type": "structure", - "required": ["message"], - "members": { - "message": { - "shape": "String" - }, - "reason": { - "shape": "ConflictExceptionReason" - } - }, - "documentation": "

This exception is thrown when the action to perform could not be completed because the resource is in a conflicting state.

", - "exception": true - }, - "ConflictExceptionReason": { - "type": "string", - "documentation": "

Reason for ConflictException

", - "enum": ["CUSTOMER_KMS_KEY_INVALID_KEY_POLICY", "CUSTOMER_KMS_KEY_DISABLED", "MISMATCHED_KMS_KEY"] - }, - "ConsoleState": { - "type": "structure", - "members": { - "region": { - "shape": "String" - }, - "consoleUrl": { - "shape": "SensitiveString" - }, - "serviceId": { - "shape": "String" - }, - "serviceConsolePage": { - "shape": "String" - }, - "serviceSubconsolePage": { - "shape": "String" - }, - "taskName": { - "shape": "SensitiveString" - } - }, - "documentation": "

Information about the state of the AWS management console page from which the user is calling

" - }, - "ContentChecksumType": { - "type": "string", - "enum": ["SHA_256"] - }, - "ContentType": { - "type": "string", - "documentation": "

The type of content

", - "enum": ["FILE", "PROMPT", "CODE", "WORKSPACE"] - }, - "ContextTruncationScheme": { - "type": "string", - "documentation": "

Workspace context truncation schemes based on usecase

", - "enum": ["ANALYSIS", "GUMBY"] - }, - "ConversationId": { - "type": "string", - "documentation": "

ID which represents a multi-turn conversation

", - "max": 128, - "min": 1 - }, - "ConversationState": { - "type": "structure", - "required": ["currentMessage", "chatTriggerType"], - "members": { - "conversationId": { - "shape": "ConversationId", - "documentation": "

Unique identifier for the chat conversation stream

" - }, - "workspaceId": { - "shape": "UUID", - "documentation": "

Unique identifier for remote workspace

" - }, - "history": { - "shape": "ChatHistory", - "documentation": "

Holds the history of chat messages.

" - }, - "currentMessage": { - "shape": "ChatMessage", - "documentation": "

Holds the current message being processed or displayed.

" - }, - "chatTriggerType": { - "shape": "ChatTriggerType", - "documentation": "

Trigger Reason for Chat

" - }, - "customizationArn": { - "shape": "ResourceArn" - } - }, - "documentation": "

Structure to represent the current state of a chat conversation.

" - }, - "CreateSubscriptionTokenRequest": { - "type": "structure", - "members": { - "clientToken": { - "shape": "IdempotencyToken", - "idempotencyToken": true - }, - "statusOnly": { - "shape": "Boolean" - } - } - }, - "CreateSubscriptionTokenResponse": { - "type": "structure", - "required": ["status"], - "members": { - "encodedVerificationUrl": { - "shape": "EncodedVerificationUrl" - }, - "token": { - "shape": "ActivationToken" - }, - "status": { - "shape": "SubscriptionStatus" - } - } - }, - "CreateTaskAssistConversationRequest": { - "type": "structure", - "members": { - "profileArn": { - "shape": "ProfileArn" - } - }, - "documentation": "

Structure to represent bootstrap conversation request.

" - }, - "CreateTaskAssistConversationResponse": { - "type": "structure", - "required": ["conversationId"], - "members": { - "conversationId": { - "shape": "ConversationId" - } - }, - "documentation": "

Structure to represent bootstrap conversation response.

" - }, - "CreateUploadUrlRequest": { - "type": "structure", - "members": { - "contentMd5": { - "shape": "CreateUploadUrlRequestContentMd5String" - }, - "contentChecksum": { - "shape": "CreateUploadUrlRequestContentChecksumString" - }, - "contentChecksumType": { - "shape": "ContentChecksumType" - }, - "contentLength": { - "shape": "CreateUploadUrlRequestContentLengthLong" - }, - "artifactType": { - "shape": "ArtifactType" - }, - "uploadIntent": { - "shape": "UploadIntent" - }, - "uploadContext": { - "shape": "UploadContext" - }, - "uploadId": { - "shape": "UploadId" - }, - "profileArn": { - "shape": "ProfileArn" - } - } - }, - "CreateUploadUrlRequestContentChecksumString": { - "type": "string", - "max": 512, - "min": 1, - "sensitive": true - }, - "CreateUploadUrlRequestContentLengthLong": { - "type": "long", - "box": true, - "min": 1 - }, - "CreateUploadUrlRequestContentMd5String": { - "type": "string", - "max": 128, - "min": 1, - "sensitive": true - }, - "CreateUploadUrlResponse": { - "type": "structure", - "required": ["uploadId", "uploadUrl"], - "members": { - "uploadId": { - "shape": "UploadId" - }, - "uploadUrl": { - "shape": "PreSignedUrl" - }, - "kmsKeyArn": { - "shape": "ResourceArn" - }, - "requestHeaders": { - "shape": "RequestHeaders" - } - } - }, - "CreateUserMemoryEntryInput": { - "type": "structure", - "required": ["memoryEntryString", "origin"], - "members": { - "memoryEntryString": { - "shape": "CreateUserMemoryEntryInputMemoryEntryStringString" - }, - "origin": { - "shape": "Origin" - }, - "profileArn": { - "shape": "CreateUserMemoryEntryInputProfileArnString", - "documentation": "

ProfileArn for the managing Q Profile

" - }, - "clientToken": { - "shape": "IdempotencyToken", - "idempotencyToken": true - } - } - }, - "CreateUserMemoryEntryInputMemoryEntryStringString": { - "type": "string", - "max": 500, - "min": 1, - "sensitive": true - }, - "CreateUserMemoryEntryInputProfileArnString": { - "type": "string", - "min": 1, - "pattern": "arn:aws:(codewhisperer|transform):[-.a-z0-9]{1,63}:\\d{12}:profile/([a-zA-Z0-9]){12}" - }, - "CreateUserMemoryEntryOutput": { - "type": "structure", - "required": ["memoryEntry"], - "members": { - "memoryEntry": { - "shape": "MemoryEntry" - } - } - }, - "CreateWorkspaceRequest": { - "type": "structure", - "required": ["workspaceRoot"], - "members": { - "workspaceRoot": { - "shape": "CreateWorkspaceRequestWorkspaceRootString" - }, - "profileArn": { - "shape": "ProfileArn" - } - } - }, - "CreateWorkspaceRequestWorkspaceRootString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "CreateWorkspaceResponse": { - "type": "structure", - "required": ["workspace"], - "members": { - "workspace": { - "shape": "WorkspaceMetadata" - } - } - }, - "CursorState": { - "type": "structure", - "members": { - "position": { - "shape": "Position", - "documentation": "

Represents a cursor position in a Text Document

" - }, - "range": { - "shape": "Range", - "documentation": "

Represents a text selection in a Text Document

" - } - }, - "documentation": "

Represents the state of the Cursor in an Editor

", - "union": true - }, - "Customization": { - "type": "structure", - "required": ["arn"], - "members": { - "arn": { - "shape": "CustomizationArn" - }, - "name": { - "shape": "CustomizationName" - }, - "description": { - "shape": "Description" - }, - "modelId": { - "shape": "ModelId" - } - } - }, - "CustomizationArn": { - "type": "string", - "max": 950, - "min": 0, - "pattern": "arn:[-.a-z0-9]{1,63}:codewhisperer:([-.a-z0-9]{0,63}:){2}([a-zA-Z0-9-_:/]){1,1023}" - }, - "CustomizationName": { - "type": "string", - "max": 100, - "min": 1, - "pattern": "[a-zA-Z][a-zA-Z0-9_-]*" - }, - "Customizations": { - "type": "list", - "member": { - "shape": "Customization" - } - }, - "DashboardAnalytics": { - "type": "structure", - "required": ["toggle"], - "members": { - "toggle": { - "shape": "OptInFeatureToggle" - } - } - }, - "DeleteTaskAssistConversationRequest": { - "type": "structure", - "required": ["conversationId"], - "members": { - "conversationId": { - "shape": "ConversationId" - }, - "profileArn": { - "shape": "ProfileArn" - } - }, - "documentation": "

Structure to represent bootstrap conversation request.

" - }, - "DeleteTaskAssistConversationResponse": { - "type": "structure", - "required": ["conversationId"], - "members": { - "conversationId": { - "shape": "ConversationId" - } - }, - "documentation": "

Structure to represent bootstrap conversation response.

" - }, - "DeleteUserMemoryEntryInput": { - "type": "structure", - "required": ["id"], - "members": { - "id": { - "shape": "DeleteUserMemoryEntryInputIdString" - }, - "profileArn": { - "shape": "DeleteUserMemoryEntryInputProfileArnString", - "documentation": "

ProfileArn for the managing Q Profile

" - } - } - }, - "DeleteUserMemoryEntryInputIdString": { - "type": "string", - "max": 36, - "min": 36, - "pattern": "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}" - }, - "DeleteUserMemoryEntryInputProfileArnString": { - "type": "string", - "min": 1, - "pattern": "arn:aws:(codewhisperer|transform):[-.a-z0-9]{1,63}:\\d{12}:profile/([a-zA-Z0-9]){12}" - }, - "DeleteUserMemoryEntryOutput": { - "type": "structure", - "members": {} - }, - "DeleteWorkspaceRequest": { - "type": "structure", - "required": ["workspaceId"], - "members": { - "workspaceId": { - "shape": "UUID" - }, - "profileArn": { - "shape": "ProfileArn" - } - } - }, - "DeleteWorkspaceResponse": { - "type": "structure", - "members": {} - }, - "Description": { - "type": "string", - "max": 256, - "min": 0, - "pattern": "[\\sa-zA-Z0-9_-]*" - }, - "Diagnostic": { - "type": "structure", - "members": { - "textDocumentDiagnostic": { - "shape": "TextDocumentDiagnostic", - "documentation": "

Diagnostics originating from a TextDocument

" - }, - "runtimeDiagnostic": { - "shape": "RuntimeDiagnostic", - "documentation": "

Diagnostics originating from a Runtime

" - } - }, - "documentation": "

Represents a Diagnostic message

", - "union": true - }, - "DiagnosticLocation": { - "type": "structure", - "required": ["uri", "range"], - "members": { - "uri": { - "shape": "DiagnosticLocationUriString" - }, - "range": { - "shape": "Range" - } - }, - "documentation": "

Represents a location inside a resource, such as a line inside a text file.

" - }, - "DiagnosticLocationUriString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "DiagnosticRelatedInformation": { - "type": "structure", - "required": ["location", "message"], - "members": { - "location": { - "shape": "DiagnosticLocation", - "documentation": "

The location of this related diagnostic information.

" - }, - "message": { - "shape": "DiagnosticRelatedInformationMessageString", - "documentation": "

The message of this related diagnostic information.

" - } - }, - "documentation": "

Represents a related message and source code location for a diagnostic.

" - }, - "DiagnosticRelatedInformationList": { - "type": "list", - "member": { - "shape": "DiagnosticRelatedInformation" - }, - "documentation": "

List of DiagnosticRelatedInformation

", - "max": 1024, - "min": 0 - }, - "DiagnosticRelatedInformationMessageString": { - "type": "string", - "max": 1024, - "min": 0, - "sensitive": true - }, - "DiagnosticSeverity": { - "type": "string", - "documentation": "

Diagnostic Error types

", - "enum": ["ERROR", "WARNING", "INFORMATION", "HINT"] - }, - "DiagnosticTag": { - "type": "string", - "documentation": "

The diagnostic tags.

", - "enum": ["UNNECESSARY", "DEPRECATED"] - }, - "DiagnosticTagList": { - "type": "list", - "member": { - "shape": "DiagnosticTag" - }, - "documentation": "

List of DiagnosticTag

", - "max": 1024, - "min": 0 - }, - "Dimension": { - "type": "structure", - "members": { - "name": { - "shape": "DimensionNameString" - }, - "value": { - "shape": "DimensionValueString" - } - } - }, - "DimensionList": { - "type": "list", - "member": { - "shape": "Dimension" - }, - "max": 30, - "min": 0 - }, - "DimensionNameString": { - "type": "string", - "max": 255, - "min": 1, - "pattern": "[-a-zA-Z0-9._]*" - }, - "DimensionValueString": { - "type": "string", - "max": 1024, - "min": 1, - "pattern": "[-a-zA-Z0-9._]*" - }, - "DocFolderLevel": { - "type": "string", - "documentation": "

Specifies the folder depth level where the document should be generated

", - "enum": ["SUB_FOLDER", "ENTIRE_WORKSPACE"] - }, - "DocGenerationEvent": { - "type": "structure", - "required": ["conversationId"], - "members": { - "conversationId": { - "shape": "ConversationId" - }, - "numberOfAddChars": { - "shape": "PrimitiveInteger" - }, - "numberOfAddLines": { - "shape": "PrimitiveInteger" - }, - "numberOfAddFiles": { - "shape": "PrimitiveInteger" - }, - "userDecision": { - "shape": "DocUserDecision" - }, - "interactionType": { - "shape": "DocInteractionType" - }, - "userIdentity": { - "shape": "String" - }, - "numberOfNavigation": { - "shape": "PrimitiveInteger" - }, - "folderLevel": { - "shape": "DocFolderLevel" - } - }, - "documentation": "

Deprecated: use DocV2AcceptanceEvent for tracking acceptance and DocV2GenerationEvent for tracking generation

" - }, - "DocInteractionType": { - "type": "string", - "documentation": "

Tracks whether user chose to generate a new document, update an existing one, or edit document

", - "enum": ["GENERATE_README", "UPDATE_README", "EDIT_README"] - }, - "DocUserDecision": { - "type": "string", - "enum": ["ACCEPT", "REJECT"] - }, - "DocV2AcceptanceEvent": { - "type": "structure", - "required": [ - "conversationId", - "numberOfAddedChars", - "numberOfAddedLines", - "numberOfAddedFiles", - "userDecision", - "interactionType", - "numberOfNavigations", - "folderLevel" - ], - "members": { - "conversationId": { - "shape": "ConversationId" - }, - "numberOfAddedChars": { - "shape": "DocV2AcceptanceEventNumberOfAddedCharsInteger" - }, - "numberOfAddedLines": { - "shape": "DocV2AcceptanceEventNumberOfAddedLinesInteger" - }, - "numberOfAddedFiles": { - "shape": "DocV2AcceptanceEventNumberOfAddedFilesInteger" - }, - "userDecision": { - "shape": "DocUserDecision" - }, - "interactionType": { - "shape": "DocInteractionType" - }, - "numberOfNavigations": { - "shape": "DocV2AcceptanceEventNumberOfNavigationsInteger" - }, - "folderLevel": { - "shape": "DocFolderLevel" - } - }, - "documentation": "

Interaction event for /doc, emitted when user accepts or rejects the generated content

" - }, - "DocV2AcceptanceEventNumberOfAddedCharsInteger": { - "type": "integer", - "min": 0 - }, - "DocV2AcceptanceEventNumberOfAddedFilesInteger": { - "type": "integer", - "min": 0 - }, - "DocV2AcceptanceEventNumberOfAddedLinesInteger": { - "type": "integer", - "min": 0 - }, - "DocV2AcceptanceEventNumberOfNavigationsInteger": { - "type": "integer", - "min": 0 - }, - "DocV2GenerationEvent": { - "type": "structure", - "required": [ - "conversationId", - "numberOfGeneratedChars", - "numberOfGeneratedLines", - "numberOfGeneratedFiles" - ], - "members": { - "conversationId": { - "shape": "ConversationId" - }, - "numberOfGeneratedChars": { - "shape": "DocV2GenerationEventNumberOfGeneratedCharsInteger" - }, - "numberOfGeneratedLines": { - "shape": "DocV2GenerationEventNumberOfGeneratedLinesInteger" - }, - "numberOfGeneratedFiles": { - "shape": "DocV2GenerationEventNumberOfGeneratedFilesInteger" - }, - "interactionType": { - "shape": "DocInteractionType" - }, - "numberOfNavigations": { - "shape": "DocV2GenerationEventNumberOfNavigationsInteger" - }, - "folderLevel": { - "shape": "DocFolderLevel" - } - }, - "documentation": "

Generation event for /doc, emitted when user requests document generation

" - }, - "DocV2GenerationEventNumberOfGeneratedCharsInteger": { - "type": "integer", - "min": 0 - }, - "DocV2GenerationEventNumberOfGeneratedFilesInteger": { - "type": "integer", - "min": 0 - }, - "DocV2GenerationEventNumberOfGeneratedLinesInteger": { - "type": "integer", - "min": 0 - }, - "DocV2GenerationEventNumberOfNavigationsInteger": { - "type": "integer", - "min": 0 - }, - "Document": { - "type": "structure", - "members": {}, - "document": true - }, - "DocumentSymbol": { - "type": "structure", - "required": ["name", "type"], - "members": { - "name": { - "shape": "DocumentSymbolNameString", - "documentation": "

Name of the Document Symbol

" - }, - "type": { - "shape": "SymbolType", - "documentation": "

Symbol type - DECLARATION / USAGE

" - }, - "source": { - "shape": "DocumentSymbolSourceString", - "documentation": "

Symbol package / source for FullyQualified names

" - } - } - }, - "DocumentSymbolNameString": { - "type": "string", - "max": 256, - "min": 1 - }, - "DocumentSymbolSourceString": { - "type": "string", - "max": 256, - "min": 1 - }, - "DocumentSymbols": { - "type": "list", - "member": { - "shape": "DocumentSymbol" - }, - "max": 1000, - "min": 0 - }, - "DocumentationIntentContext": { - "type": "structure", - "required": ["type"], - "members": { - "scope": { - "shape": "DocumentationIntentContextScopeString" - }, - "type": { - "shape": "DocumentationType" - }, - "changeLogOptions": { - "shape": "ChangeLogOptions" - } - } - }, - "DocumentationIntentContextScopeString": { - "type": "string", - "max": 4096, - "min": 1, - "sensitive": true - }, - "DocumentationType": { - "type": "string", - "enum": ["README", "CHANGE_LOG"] - }, - "Double": { - "type": "double", - "box": true - }, - "Edit": { - "type": "structure", - "required": ["content"], - "members": { - "content": { - "shape": "EditContentString" - }, - "references": { - "shape": "References" - } - } - }, - "EditContentString": { - "type": "string", - "max": 5120, - "min": 1, - "sensitive": true - }, - "EditorState": { - "type": "structure", - "members": { - "document": { - "shape": "TextDocument", - "documentation": "

Represents currently edited file

" - }, - "cursorState": { - "shape": "CursorState", - "documentation": "

Position of the cursor

" - }, - "relevantDocuments": { - "shape": "RelevantDocumentList", - "documentation": "

Represents IDE provided relevant files

" - }, - "useRelevantDocuments": { - "shape": "Boolean", - "documentation": "

Whether service should use relevant document in prompt

" - }, - "workspaceFolders": { - "shape": "WorkspaceFolderList", - "documentation": "

Represents IDE provided list of workspace folders

" - } - }, - "documentation": "

Represents the state of an Editor

" - }, - "EncodedVerificationUrl": { - "type": "string", - "max": 8192, - "min": 1 - }, - "EnvState": { - "type": "structure", - "members": { - "operatingSystem": { - "shape": "EnvStateOperatingSystemString", - "documentation": "

The name of the operating system in use

" - }, - "currentWorkingDirectory": { - "shape": "EnvStateCurrentWorkingDirectoryString", - "documentation": "

The current working directory of the environment

" - }, - "environmentVariables": { - "shape": "EnvironmentVariables", - "documentation": "

The environment variables set in the current environment

" - }, - "timezoneOffset": { - "shape": "EnvStateTimezoneOffsetInteger", - "documentation": "

Local timezone offset of the client. For more information, see documentation https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset

" - } - }, - "documentation": "

State related to the user's environment

" - }, - "EnvStateCurrentWorkingDirectoryString": { - "type": "string", - "max": 256, - "min": 1, - "sensitive": true - }, - "EnvStateOperatingSystemString": { - "type": "string", - "max": 32, - "min": 1, - "pattern": "(macos|linux|windows)" - }, - "EnvStateTimezoneOffsetInteger": { - "type": "integer", - "box": true, - "max": 1440, - "min": -1440 - }, - "EnvironmentVariable": { - "type": "structure", - "members": { - "key": { - "shape": "EnvironmentVariableKeyString", - "documentation": "

The key of an environment variable

" - }, - "value": { - "shape": "EnvironmentVariableValueString", - "documentation": "

The value of an environment variable

" - } - }, - "documentation": "

An environment variable

" - }, - "EnvironmentVariableKeyString": { - "type": "string", - "max": 256, - "min": 1, - "sensitive": true - }, - "EnvironmentVariableValueString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "EnvironmentVariables": { - "type": "list", - "member": { - "shape": "EnvironmentVariable" - }, - "documentation": "

A list of environment variables

", - "max": 100, - "min": 0 - }, - "ErrorDetails": { - "type": "string", - "max": 2048, - "min": 0 - }, - "Event": { - "type": "structure", - "required": ["eventId", "generationId", "eventTimestamp", "eventType", "eventBlob"], - "members": { - "eventId": { - "shape": "UUID" - }, - "generationId": { - "shape": "UUID" - }, - "eventTimestamp": { - "shape": "SyntheticTimestamp_date_time" - }, - "eventType": { - "shape": "EventType" - }, - "eventBlob": { - "shape": "EventBlob" - } - } - }, - "EventBlob": { - "type": "blob", - "max": 400000, - "min": 1, - "sensitive": true - }, - "EventList": { - "type": "list", - "member": { - "shape": "Event" - }, - "max": 10, - "min": 1 - }, - "EventType": { - "type": "string", - "max": 100, - "min": 1 - }, - "ExternalIdentityDetails": { - "type": "structure", - "members": { - "issuerUrl": { - "shape": "IssuerUrl" - }, - "clientId": { - "shape": "ClientId" - }, - "scimEndpoint": { - "shape": "String" - } - } - }, - "FeatureDevCodeAcceptanceEvent": { - "type": "structure", - "required": ["conversationId", "linesOfCodeAccepted", "charactersOfCodeAccepted"], - "members": { - "conversationId": { - "shape": "ConversationId" - }, - "linesOfCodeAccepted": { - "shape": "FeatureDevCodeAcceptanceEventLinesOfCodeAcceptedInteger" - }, - "charactersOfCodeAccepted": { - "shape": "FeatureDevCodeAcceptanceEventCharactersOfCodeAcceptedInteger" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage" - } - } - }, - "FeatureDevCodeAcceptanceEventCharactersOfCodeAcceptedInteger": { - "type": "integer", - "min": 0 - }, - "FeatureDevCodeAcceptanceEventLinesOfCodeAcceptedInteger": { - "type": "integer", - "min": 0 - }, - "FeatureDevCodeGenerationEvent": { - "type": "structure", - "required": ["conversationId", "linesOfCodeGenerated", "charactersOfCodeGenerated"], - "members": { - "conversationId": { - "shape": "ConversationId" - }, - "linesOfCodeGenerated": { - "shape": "FeatureDevCodeGenerationEventLinesOfCodeGeneratedInteger" - }, - "charactersOfCodeGenerated": { - "shape": "FeatureDevCodeGenerationEventCharactersOfCodeGeneratedInteger" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage" - } - } - }, - "FeatureDevCodeGenerationEventCharactersOfCodeGeneratedInteger": { - "type": "integer", - "min": 0 - }, - "FeatureDevCodeGenerationEventLinesOfCodeGeneratedInteger": { - "type": "integer", - "min": 0 - }, - "FeatureDevEvent": { - "type": "structure", - "required": ["conversationId"], - "members": { - "conversationId": { - "shape": "ConversationId" - } - } - }, - "FeatureEvaluation": { - "type": "structure", - "required": ["feature", "variation", "value"], - "members": { - "feature": { - "shape": "FeatureName" - }, - "variation": { - "shape": "FeatureVariation" - }, - "value": { - "shape": "FeatureValue" - } - } - }, - "FeatureEvaluationsList": { - "type": "list", - "member": { - "shape": "FeatureEvaluation" - }, - "max": 50, - "min": 0 - }, - "FeatureName": { - "type": "string", - "max": 128, - "min": 1, - "pattern": "[-a-zA-Z0-9._]*" - }, - "FeatureValue": { - "type": "structure", - "members": { - "boolValue": { - "shape": "Boolean" - }, - "doubleValue": { - "shape": "Double" - }, - "longValue": { - "shape": "Long" - }, - "stringValue": { - "shape": "FeatureValueStringType" - } - }, - "union": true - }, - "FeatureValueStringType": { - "type": "string", - "max": 512, - "min": 0 - }, - "FeatureVariation": { - "type": "string", - "max": 128, - "min": 1, - "pattern": "[-a-zA-Z0-9._]*" - }, - "FileContext": { - "type": "structure", - "required": ["leftFileContent", "rightFileContent", "filename", "programmingLanguage"], - "members": { - "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, - "min": 1, - "sensitive": true - }, - "FileContextLeftFileContentString": { - "type": "string", - "max": 10240, - "min": 0, - "sensitive": true - }, - "FileContextRightFileContentString": { - "type": "string", - "max": 10240, - "min": 0, - "sensitive": true - }, - "FollowupPrompt": { - "type": "structure", - "required": ["content"], - "members": { - "content": { - "shape": "FollowupPromptContentString", - "documentation": "

The content of the text message in markdown format.

" - }, - "userIntent": { - "shape": "UserIntent", - "documentation": "

User Intent

" - } - }, - "documentation": "

Followup Prompt for the Assistant Response

" - }, - "FollowupPromptContentString": { - "type": "string", - "max": 4096, - "min": 0, - "sensitive": true - }, - "FunctionalityName": { - "type": "string", - "enum": [ - "COMPLETIONS", - "ANALYSIS", - "CONVERSATIONS", - "TASK_ASSIST", - "TRANSFORMATIONS", - "CHAT_CUSTOMIZATION", - "TRANSFORMATIONS_WEBAPP", - "FEATURE_DEVELOPMENT" - ], - "max": 64, - "min": 1 - }, - "GenerateCompletionsRequest": { - "type": "structure", - "required": ["fileContext"], - "members": { - "fileContext": { - "shape": "FileContext" - }, - "editorState": { - "shape": "EditorState" - }, - "maxResults": { - "shape": "GenerateCompletionsRequestMaxResultsInteger" - }, - "predictionTypes": { - "shape": "PredictionTypes" - }, - "nextToken": { - "shape": "GenerateCompletionsRequestNextTokenString" - }, - "referenceTrackerConfiguration": { - "shape": "ReferenceTrackerConfiguration" - }, - "supplementalContexts": { - "shape": "SupplementalContextList" - }, - "customizationArn": { - "shape": "CustomizationArn" - }, - "optOutPreference": { - "shape": "OptOutPreference" - }, - "userContext": { - "shape": "UserContext" - }, - "profileArn": { - "shape": "ProfileArn" - }, - "workspaceId": { - "shape": "UUID" - }, - "modelId": { - "shape": "ModelId" - } - } - }, - "GenerateCompletionsRequestMaxResultsInteger": { - "type": "integer", - "box": true, - "max": 10, - "min": 1 - }, - "GenerateCompletionsRequestNextTokenString": { - "type": "string", - "max": 2048, - "min": 0, - "pattern": "(?:[A-Za-z0-9\\+/]{4})*(?:[A-Za-z0-9\\+/]{2}\\=\\=|[A-Za-z0-9\\+/]{3}\\=)?", - "sensitive": true - }, - "GenerateCompletionsResponse": { - "type": "structure", - "members": { - "predictions": { - "shape": "Predictions" - }, - "completions": { - "shape": "Completions" - }, - "nextToken": { - "shape": "SensitiveString" - }, - "modelId": { - "shape": "ModelId" - } - } - }, - "GetCodeAnalysisRequest": { - "type": "structure", - "required": ["jobId"], - "members": { - "jobId": { - "shape": "GetCodeAnalysisRequestJobIdString" - }, - "profileArn": { - "shape": "ProfileArn" - } - } - }, - "GetCodeAnalysisRequestJobIdString": { - "type": "string", - "max": 256, - "min": 1 - }, - "GetCodeAnalysisResponse": { - "type": "structure", - "required": ["status"], - "members": { - "status": { - "shape": "CodeAnalysisStatus" - }, - "errorMessage": { - "shape": "SensitiveString" - } - } - }, - "GetCodeFixJobRequest": { - "type": "structure", - "required": ["jobId"], - "members": { - "jobId": { - "shape": "GetCodeFixJobRequestJobIdString" - }, - "profileArn": { - "shape": "ProfileArn" - } - } - }, - "GetCodeFixJobRequestJobIdString": { - "type": "string", - "max": 256, - "min": 1, - "pattern": ".*[A-Za-z0-9-:]+.*" - }, - "GetCodeFixJobResponse": { - "type": "structure", - "members": { - "jobStatus": { - "shape": "CodeFixJobStatus" - }, - "suggestedFix": { - "shape": "SuggestedFix" - } - } - }, - "GetProfileRequest": { - "type": "structure", - "required": ["profileArn"], - "members": { - "profileArn": { - "shape": "ProfileArn" - } - } - }, - "GetProfileResponse": { - "type": "structure", - "required": ["profile"], - "members": { - "profile": { - "shape": "ProfileInfo" - } - } - }, - "GetTaskAssistCodeGenerationRequest": { - "type": "structure", - "required": ["conversationId", "codeGenerationId"], - "members": { - "conversationId": { - "shape": "ConversationId" - }, - "codeGenerationId": { - "shape": "CodeGenerationId" - }, - "profileArn": { - "shape": "ProfileArn" - } - }, - "documentation": "

Request for getting task assist code generation.

" - }, - "GetTaskAssistCodeGenerationResponse": { - "type": "structure", - "required": ["conversationId", "codeGenerationStatus"], - "members": { - "conversationId": { - "shape": "ConversationId" - }, - "codeGenerationStatus": { - "shape": "CodeGenerationStatus" - }, - "codeGenerationStatusDetail": { - "shape": "CodeGenerationStatusDetail" - }, - "codeGenerationRemainingIterationCount": { - "shape": "Integer" - }, - "codeGenerationTotalIterationCount": { - "shape": "Integer" - } - }, - "documentation": "

Response for getting task assist code generation status.

" - }, - "GetTestGenerationRequest": { - "type": "structure", - "required": ["testGenerationJobGroupName", "testGenerationJobId"], - "members": { - "testGenerationJobGroupName": { - "shape": "TestGenerationJobGroupName" - }, - "testGenerationJobId": { - "shape": "UUID" - }, - "profileArn": { - "shape": "ProfileArn" - } - }, - "documentation": "

Structure to represent get test generation request.

" - }, - "GetTestGenerationResponse": { - "type": "structure", - "members": { - "testGenerationJob": { - "shape": "TestGenerationJob" - } - }, - "documentation": "

Structure to represent get test generation response.

" - }, - "GetTransformationPlanRequest": { - "type": "structure", - "required": ["transformationJobId"], - "members": { - "transformationJobId": { - "shape": "TransformationJobId" - }, - "profileArn": { - "shape": "ProfileArn" - } - }, - "documentation": "

Structure to represent get code transformation plan request.

" - }, - "GetTransformationPlanResponse": { - "type": "structure", - "required": ["transformationPlan"], - "members": { - "transformationPlan": { - "shape": "TransformationPlan" - } - }, - "documentation": "

Structure to represent get code transformation plan response.

" - }, - "GetTransformationRequest": { - "type": "structure", - "required": ["transformationJobId"], - "members": { - "transformationJobId": { - "shape": "TransformationJobId" - }, - "profileArn": { - "shape": "ProfileArn" - } - }, - "documentation": "

Structure to represent get code transformation request.

" - }, - "GetTransformationResponse": { - "type": "structure", - "required": ["transformationJob"], - "members": { - "transformationJob": { - "shape": "TransformationJob" - } - }, - "documentation": "

Structure to represent get code transformation response.

" - }, - "GetUsageLimitsRequest": { - "type": "structure", - "members": { - "profileArn": { - "shape": "ProfileArn", - "documentation": "

The ARN of the Q Developer profile. Required for enterprise customers, optional for Builder ID users.

" - } - } - }, - "GetUsageLimitsResponse": { - "type": "structure", - "required": ["limits", "daysUntilReset"], - "members": { - "limits": { - "shape": "UsageLimits" - }, - "daysUntilReset": { - "shape": "Integer", - "documentation": "

Number of days remaining until the usage metrics reset

" - } - } - }, - "GitState": { - "type": "structure", - "members": { - "status": { - "shape": "GitStateStatusString", - "documentation": "

The output of the command git status --porcelain=v1 -b

" - } - }, - "documentation": "

State related to the Git VSC

" - }, - "GitStateStatusString": { - "type": "string", - "max": 4096, - "min": 0, - "sensitive": true - }, - "IdeCategory": { - "type": "string", - "enum": ["JETBRAINS", "VSCODE", "CLI", "JUPYTER_MD", "JUPYTER_SM", "ECLIPSE", "VISUAL_STUDIO"], - "max": 64, - "min": 1 - }, - "IdeDiagnostic": { - "type": "structure", - "required": ["ideDiagnosticType"], - "members": { - "range": { - "shape": "Range", - "documentation": "

The range at which the message applies.

" - }, - "source": { - "shape": "IdeDiagnosticSourceString", - "documentation": "

A human-readable string describing the source of the diagnostic

" - }, - "severity": { - "shape": "DiagnosticSeverity", - "documentation": "

Diagnostic Error type

" - }, - "ideDiagnosticType": { - "shape": "IdeDiagnosticType", - "documentation": "

Type of the diagnostic

" - } - }, - "documentation": "

Structure to represent metadata about a Diagnostic from user local IDE

" - }, - "IdeDiagnosticList": { - "type": "list", - "member": { - "shape": "IdeDiagnostic" - }, - "documentation": "

List of IDE Diagnostics

", - "max": 1024, - "min": 0 - }, - "IdeDiagnosticSourceString": { - "type": "string", - "max": 1024, - "min": 0, - "sensitive": true - }, - "IdeDiagnosticType": { - "type": "string", - "enum": ["SYNTAX_ERROR", "TYPE_ERROR", "REFERENCE_ERROR", "BEST_PRACTICE", "SECURITY", "OTHER"] - }, - "IdempotencyToken": { - "type": "string", - "max": 256, - "min": 1 - }, - "IdentityDetails": { - "type": "structure", - "members": { - "ssoIdentityDetails": { - "shape": "SSOIdentityDetails" - }, - "externalIdentityDetails": { - "shape": "ExternalIdentityDetails" - } - }, - "union": true - }, - "ImageBlock": { - "type": "structure", - "required": ["format", "source"], - "members": { - "format": { - "shape": "ImageFormat" - }, - "source": { - "shape": "ImageSource" - } - }, - "documentation": "

Represents the image source itself and the format of the image.

" - }, - "ImageBlocks": { - "type": "list", - "member": { - "shape": "ImageBlock" - }, - "max": 10, - "min": 0 - }, - "ImageFormat": { - "type": "string", - "enum": ["png", "jpeg", "gif", "webp"] - }, - "ImageSource": { - "type": "structure", - "members": { - "bytes": { - "shape": "ImageSourceBytesBlob" - } - }, - "documentation": "

Image bytes limited to ~10MB considering overhead of base64 encoding

", - "sensitive": true, - "union": true - }, - "ImageSourceBytesBlob": { - "type": "blob", - "max": 2800000, - "min": 1 - }, - "Import": { - "type": "structure", - "members": { - "statement": { - "shape": "ImportStatementString" - } - } - }, - "ImportStatementString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "Imports": { - "type": "list", - "member": { - "shape": "Import" - }, - "max": 10, - "min": 0 - }, - "InlineChatEvent": { - "type": "structure", - "required": ["requestId", "timestamp"], - "members": { - "requestId": { - "shape": "UUID" - }, - "timestamp": { - "shape": "Timestamp" - }, - "inputLength": { - "shape": "PrimitiveInteger" - }, - "numSelectedLines": { - "shape": "PrimitiveInteger" - }, - "numSuggestionAddChars": { - "shape": "PrimitiveInteger" - }, - "numSuggestionAddLines": { - "shape": "PrimitiveInteger" - }, - "numSuggestionDelChars": { - "shape": "PrimitiveInteger" - }, - "numSuggestionDelLines": { - "shape": "PrimitiveInteger" - }, - "codeIntent": { - "shape": "Boolean" - }, - "userDecision": { - "shape": "InlineChatUserDecision" - }, - "responseStartLatency": { - "shape": "Double" - }, - "responseEndLatency": { - "shape": "Double" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage" - } - } - }, - "InlineChatUserDecision": { - "type": "string", - "enum": ["ACCEPT", "REJECT", "DISMISS"] - }, - "Integer": { - "type": "integer", - "box": true - }, - "Intent": { - "type": "string", - "enum": ["DEV", "DOC"] - }, - "IntentContext": { - "type": "structure", - "members": { - "documentation": { - "shape": "DocumentationIntentContext" - } - }, - "union": true - }, - "InternalServerException": { - "type": "structure", - "required": ["message"], - "members": { - "message": { - "shape": "String" - }, - "reason": { - "shape": "InternalServerExceptionReason" - } - }, - "documentation": "

This exception is thrown when an unexpected error occurred during the processing of a request.

", - "exception": true, - "fault": true, - "retryable": { - "throttling": false - } - }, - "InternalServerExceptionReason": { - "type": "string", - "documentation": "

Reason for InternalServerException

", - "enum": ["MODEL_TEMPORARILY_UNAVAILABLE"] - }, - "IssuerUrl": { - "type": "string", - "max": 255, - "min": 1 - }, - "LineRangeList": { - "type": "list", - "member": { - "shape": "Range" - } - }, - "ListAvailableCustomizationsRequest": { - "type": "structure", - "members": { - "maxResults": { - "shape": "ListAvailableCustomizationsRequestMaxResultsInteger" - }, - "nextToken": { - "shape": "Base64EncodedPaginationToken" - }, - "profileArn": { - "shape": "ProfileArn" - } - } - }, - "ListAvailableCustomizationsRequestMaxResultsInteger": { - "type": "integer", - "box": true, - "max": 100, - "min": 1 - }, - "ListAvailableCustomizationsResponse": { - "type": "structure", - "required": ["customizations"], - "members": { - "customizations": { - "shape": "Customizations" - }, - "nextToken": { - "shape": "Base64EncodedPaginationToken" - } - } - }, - "ListAvailableModelsRequest": { - "type": "structure", - "required": ["origin"], - "members": { - "origin": { - "shape": "Origin", - "documentation": "

The origin context for which to list available models

" - }, - "maxResults": { - "shape": "ListAvailableModelsRequestMaxResultsInteger", - "documentation": "

Maximum number of models to return in a single response

" - }, - "nextToken": { - "shape": "Base64EncodedPaginationToken", - "documentation": "

Token for retrieving the next page of results

" - }, - "profileArn": { - "shape": "ProfileArn", - "documentation": "

ARN of the profile to use for model filtering

" - }, - "modelProvider": { - "shape": "ModelProvider", - "documentation": "

Provider of AI models

" - } - } - }, - "ListAvailableModelsRequestMaxResultsInteger": { - "type": "integer", - "box": true, - "max": 100, - "min": 1 - }, - "ListAvailableModelsResponse": { - "type": "structure", - "required": ["models"], - "members": { - "models": { - "shape": "Models", - "documentation": "

List of available models

" - }, - "defaultModel": { - "shape": "Model", - "documentation": "

Default model set by the client

" - }, - "nextToken": { - "shape": "Base64EncodedPaginationToken", - "documentation": "

Token for retrieving the next page of results

" - } - } - }, - "ListAvailableProfilesRequest": { - "type": "structure", - "members": { - "maxResults": { - "shape": "ListAvailableProfilesRequestMaxResultsInteger" - }, - "nextToken": { - "shape": "Base64EncodedPaginationToken" - } - } - }, - "ListAvailableProfilesRequestMaxResultsInteger": { - "type": "integer", - "box": true, - "max": 10, - "min": 1 - }, - "ListAvailableProfilesResponse": { - "type": "structure", - "required": ["profiles"], - "members": { - "profiles": { - "shape": "ProfileList" - }, - "nextToken": { - "shape": "Base64EncodedPaginationToken" - } - } - }, - "ListCodeAnalysisFindingsRequest": { - "type": "structure", - "required": ["jobId", "codeAnalysisFindingsSchema"], - "members": { - "jobId": { - "shape": "ListCodeAnalysisFindingsRequestJobIdString" - }, - "nextToken": { - "shape": "PaginationToken" - }, - "codeAnalysisFindingsSchema": { - "shape": "CodeAnalysisFindingsSchema" - }, - "profileArn": { - "shape": "ProfileArn" - } - } - }, - "ListCodeAnalysisFindingsRequestJobIdString": { - "type": "string", - "max": 256, - "min": 1 - }, - "ListCodeAnalysisFindingsResponse": { - "type": "structure", - "required": ["codeAnalysisFindings"], - "members": { - "nextToken": { - "shape": "PaginationToken" - }, - "codeAnalysisFindings": { - "shape": "SensitiveString" - } - } - }, - "ListEventsRequest": { - "type": "structure", - "required": ["conversationId"], - "members": { - "conversationId": { - "shape": "UUID" - }, - "maxResults": { - "shape": "ListEventsRequestMaxResultsInteger" - }, - "nextToken": { - "shape": "NextToken" - } - } - }, - "ListEventsRequestMaxResultsInteger": { - "type": "integer", - "box": true, - "max": 50, - "min": 1 - }, - "ListEventsResponse": { - "type": "structure", - "required": ["conversationId", "events"], - "members": { - "conversationId": { - "shape": "UUID" - }, - "events": { - "shape": "EventList" - }, - "nextToken": { - "shape": "NextToken" - } - } - }, - "ListFeatureEvaluationsRequest": { - "type": "structure", - "required": ["userContext"], - "members": { - "userContext": { - "shape": "UserContext" - }, - "profileArn": { - "shape": "ProfileArn" - } - } - }, - "ListFeatureEvaluationsResponse": { - "type": "structure", - "required": ["featureEvaluations"], - "members": { - "featureEvaluations": { - "shape": "FeatureEvaluationsList" - } - } - }, - "ListUserMemoryEntriesInput": { - "type": "structure", - "members": { - "maxResults": { - "shape": "ListUserMemoryEntriesInputMaxResultsInteger" - }, - "profileArn": { - "shape": "ListUserMemoryEntriesInputProfileArnString", - "documentation": "

ProfileArn for the managing Q Profile

" - }, - "nextToken": { - "shape": "ListUserMemoryEntriesInputNextTokenString" - } - } - }, - "ListUserMemoryEntriesInputMaxResultsInteger": { - "type": "integer", - "box": true, - "max": 100, - "min": 1 - }, - "ListUserMemoryEntriesInputNextTokenString": { - "type": "string", - "min": 1, - "pattern": "[A-Za-z0-9_-]+" - }, - "ListUserMemoryEntriesInputProfileArnString": { - "type": "string", - "min": 1, - "pattern": "arn:aws:(codewhisperer|transform):[-.a-z0-9]{1,63}:\\d{12}:profile/([a-zA-Z0-9]){12}" - }, - "ListUserMemoryEntriesOutput": { - "type": "structure", - "required": ["memoryEntries"], - "members": { - "memoryEntries": { - "shape": "MemoryEntryList" - }, - "nextToken": { - "shape": "ListUserMemoryEntriesOutputNextTokenString" - } - } - }, - "ListUserMemoryEntriesOutputNextTokenString": { - "type": "string", - "min": 1, - "pattern": "[A-Za-z0-9_-]+" - }, - "ListWorkspaceMetadataRequest": { - "type": "structure", - "members": { - "workspaceRoot": { - "shape": "ListWorkspaceMetadataRequestWorkspaceRootString" - }, - "nextToken": { - "shape": "String" - }, - "maxResults": { - "shape": "Integer" - }, - "profileArn": { - "shape": "ProfileArn" - } - } - }, - "ListWorkspaceMetadataRequestWorkspaceRootString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "ListWorkspaceMetadataResponse": { - "type": "structure", - "required": ["workspaces"], - "members": { - "workspaces": { - "shape": "WorkspaceList" - }, - "nextToken": { - "shape": "String" - } - } - }, - "Long": { - "type": "long", - "box": true - }, - "MCPConfiguration": { - "type": "structure", - "required": ["toggle"], - "members": { - "toggle": { - "shape": "OptInFeatureToggle" - } - } - }, - "MemoryEntry": { - "type": "structure", - "required": ["id", "memoryEntryString", "metadata"], - "members": { - "id": { - "shape": "MemoryEntryIdString", - "documentation": "

A unique identifier for a single memory entry

" - }, - "memoryEntryString": { - "shape": "MemoryEntryMemoryEntryStringString" - }, - "metadata": { - "shape": "MemoryEntryMetadata" - } - }, - "documentation": "

MemoryEntry corresponds to a single user memory

" - }, - "MemoryEntryIdString": { - "type": "string", - "max": 36, - "min": 36, - "pattern": "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}" - }, - "MemoryEntryList": { - "type": "list", - "member": { - "shape": "MemoryEntry" - }, - "documentation": "

List of user memories

" - }, - "MemoryEntryMemoryEntryStringString": { - "type": "string", - "max": 500, - "min": 1, - "sensitive": true - }, - "MemoryEntryMetadata": { - "type": "structure", - "required": ["origin", "createdAt", "updatedAt"], - "members": { - "origin": { - "shape": "Origin" - }, - "attributes": { - "shape": "AttributesMap" - }, - "createdAt": { - "shape": "Timestamp" - }, - "updatedAt": { - "shape": "Timestamp" - }, - "memoryStatus": { - "shape": "MemoryStatus" - } - }, - "documentation": "

Metadata for a single memory entry

" - }, - "MemoryStatus": { - "type": "string", - "documentation": "

Status of user memory

", - "enum": ["DECRYPTION_FAILURE", "VALID"] - }, - "MessageId": { - "type": "string", - "documentation": "

Unique identifier for the chat message

", - "max": 128, - "min": 0 - }, - "MetricData": { - "type": "structure", - "required": ["metricName", "metricValue", "timestamp", "product"], - "members": { - "metricName": { - "shape": "MetricDataMetricNameString" - }, - "metricValue": { - "shape": "Double" - }, - "timestamp": { - "shape": "Timestamp" - }, - "product": { - "shape": "MetricDataProductString" - }, - "dimensions": { - "shape": "DimensionList" - } - } - }, - "MetricDataMetricNameString": { - "type": "string", - "max": 1024, - "min": 1, - "pattern": "[-a-zA-Z0-9._]*" - }, - "MetricDataProductString": { - "type": "string", - "max": 128, - "min": 1, - "pattern": "[-a-zA-Z0-9._]*" - }, - "Model": { - "type": "structure", - "required": ["modelId"], - "members": { - "modelId": { - "shape": "ModelId", - "documentation": "

Unique identifier for the model

" - }, - "modelName": { - "shape": "ModelName", - "documentation": "

User-facing display name

" - }, - "description": { - "shape": "Description", - "documentation": "

Description of the model

" - }, - "modelMetadata": { - "shape": "ModelMetadata", - "documentation": "

Technical metadata and capabilities of the model

" - } - } - }, - "ModelId": { - "type": "string", - "documentation": "

Unique identifier for the model

", - "max": 1024, - "min": 1, - "pattern": "[a-zA-Z0-9_:.-]+" - }, - "ModelName": { - "type": "string", - "documentation": "

Identifier for the model Name

", - "max": 1024, - "min": 1, - "pattern": "[a-zA-Z0-9-_.]+" - }, - "ModelMetadata": { - "type": "structure", - "members": { - "maxInputTokens": { - "shape": "ModelMetadataMaxInputTokensInteger", - "documentation": "

Maximum number of input tokens the model can process

" - }, - "supportsImages": { - "shape": "Boolean", - "documentation": "

Whether the model supports image input processing

" - } - } - }, - "ModelMetadataMaxInputTokensInteger": { - "type": "integer", - "box": true, - "min": 1 - }, - "ModelProvider": { - "type": "string", - "documentation": "

Provider of AI models

", - "enum": ["DEFAULT"] - }, - "Models": { - "type": "list", - "member": { - "shape": "Model" - } - }, - "NextToken": { - "type": "string", - "max": 1000, - "min": 0 - }, - "Notifications": { - "type": "list", - "member": { - "shape": "NotificationsFeature" - }, - "max": 10, - "min": 0 - }, - "NotificationsFeature": { - "type": "structure", - "required": ["feature", "toggle"], - "members": { - "feature": { - "shape": "FeatureName" - }, - "toggle": { - "shape": "OptInFeatureToggle" - } - } - }, - "OperatingSystem": { - "type": "string", - "enum": ["MAC", "WINDOWS", "LINUX"], - "max": 64, - "min": 1 - }, - "OptInFeatureToggle": { - "type": "string", - "enum": ["ON", "OFF"] - }, - "OptInFeatures": { - "type": "structure", - "members": { - "promptLogging": { - "shape": "PromptLogging" - }, - "byUserAnalytics": { - "shape": "ByUserAnalytics" - }, - "dashboardAnalytics": { - "shape": "DashboardAnalytics" - }, - "notifications": { - "shape": "Notifications" - }, - "workspaceContext": { - "shape": "WorkspaceContext" - }, - "mcpConfiguration": { - "shape": "MCPConfiguration" - } - } - }, - "OptOutPreference": { - "type": "string", - "enum": ["OPTIN", "OPTOUT"] - }, - "Origin": { - "type": "string", - "documentation": "

Enum to represent the origin application conversing with Sidekick.

", - "enum": [ - "CHATBOT", - "CONSOLE", - "DOCUMENTATION", - "MARKETING", - "MOBILE", - "SERVICE_INTERNAL", - "UNIFIED_SEARCH", - "UNKNOWN", - "MD", - "IDE", - "SAGE_MAKER", - "CLI", - "AI_EDITOR", - "OPENSEARCH_DASHBOARD", - "GITLAB" - ] - }, - "PackageInfo": { - "type": "structure", - "members": { - "executionCommand": { - "shape": "SensitiveString" - }, - "buildCommand": { - "shape": "SensitiveString" - }, - "buildOrder": { - "shape": "PackageInfoBuildOrderInteger" - }, - "testFramework": { - "shape": "String" - }, - "packageSummary": { - "shape": "PackageInfoPackageSummaryString" - }, - "packagePlan": { - "shape": "PackageInfoPackagePlanString" - }, - "targetFileInfoList": { - "shape": "TargetFileInfoList" - } - } - }, - "PackageInfoBuildOrderInteger": { - "type": "integer", - "box": true, - "min": 0 - }, - "PackageInfoList": { - "type": "list", - "member": { - "shape": "PackageInfo" - } - }, - "PackageInfoPackagePlanString": { - "type": "string", - "max": 30720, - "min": 0, - "sensitive": true - }, - "PackageInfoPackageSummaryString": { - "type": "string", - "max": 30720, - "min": 0, - "sensitive": true - }, - "PaginationToken": { - "type": "string", - "max": 2048, - "min": 1, - "pattern": "\\S+" - }, - "Position": { - "type": "structure", - "required": ["line", "character"], - "members": { - "line": { - "shape": "Integer", - "documentation": "

Line position in a document.

" - }, - "character": { - "shape": "Integer", - "documentation": "

Character offset on a line in a document (zero-based)

" - } - }, - "documentation": "

Indicates Cursor postion in a Text Document

" - }, - "PreSignedUrl": { - "type": "string", - "max": 2048, - "min": 1, - "sensitive": true - }, - "Prediction": { - "type": "structure", - "members": { - "completion": { - "shape": "Completion" - }, - "edit": { - "shape": "Edit" - } - }, - "union": true - }, - "PredictionType": { - "type": "string", - "enum": ["COMPLETIONS", "EDITS"] - }, - "PredictionTypes": { - "type": "list", - "member": { - "shape": "PredictionType" - } - }, - "Predictions": { - "type": "list", - "member": { - "shape": "Prediction" - }, - "max": 10, - "min": 0 - }, - "PreviousEditorStateMetadata": { - "type": "structure", - "required": ["timeOffset"], - "members": { - "timeOffset": { - "shape": "Integer" - } - } - }, - "PrimitiveInteger": { - "type": "integer" - }, - "Profile": { - "type": "structure", - "required": ["arn", "profileName"], - "members": { - "arn": { - "shape": "ProfileArn" - }, - "identityDetails": { - "shape": "IdentityDetails" - }, - "profileName": { - "shape": "ProfileName" - }, - "description": { - "shape": "ProfileDescription" - }, - "referenceTrackerConfiguration": { - "shape": "ReferenceTrackerConfiguration" - }, - "kmsKeyArn": { - "shape": "ResourceArn" - }, - "activeFunctionalities": { - "shape": "ActiveFunctionalityList" - }, - "status": { - "shape": "ProfileStatus" - }, - "errorDetails": { - "shape": "ErrorDetails" - }, - "resourcePolicy": { - "shape": "ResourcePolicy" - }, - "profileType": { - "shape": "ProfileType" - }, - "optInFeatures": { - "shape": "OptInFeatures" - }, - "permissionUpdateRequired": { - "shape": "Boolean" - }, - "applicationProperties": { - "shape": "ApplicationPropertiesList" - } - } - }, - "ProfileInfo": { - "type": "structure", - "required": ["arn"], - "members": { - "arn": { - "shape": "ProfileArn" - }, - "profileName": { - "shape": "ProfileName" - }, - "description": { - "shape": "ProfileDescription" - }, - "status": { - "shape": "ProfileStatus" - }, - "profileType": { - "shape": "ProfileType" - }, - "optInFeatures": { - "shape": "OptInFeatures" - } - } - }, - "ProfileArn": { - "type": "string", - "max": 950, - "min": 0, - "pattern": "arn:aws:(codewhisperer|transform):[-.a-z0-9]{1,63}:\\d{12}:profile/([a-zA-Z0-9]){12}" - }, - "ProfileDescription": { - "type": "string", - "max": 256, - "min": 1, - "pattern": "[\\sa-zA-Z0-9_-]*" - }, - "ProfileList": { - "type": "list", - "member": { - "shape": "Profile" - } - }, - "ProfileName": { - "type": "string", - "max": 100, - "min": 1, - "pattern": "[a-zA-Z][a-zA-Z0-9_-]*" - }, - "ProfileStatus": { - "type": "string", - "enum": ["ACTIVE", "CREATING", "CREATE_FAILED", "UPDATING", "UPDATE_FAILED", "DELETING", "DELETE_FAILED"] - }, - "ProfileType": { - "type": "string", - "enum": ["Q_DEVELOPER", "CODEWHISPERER"] - }, - "ProgrammingLanguage": { - "type": "structure", - "required": ["languageName"], - "members": { - "languageName": { - "shape": "ProgrammingLanguageLanguageNameString" - } - }, - "documentation": "

Programming Languages supported by CodeWhisperer

" - }, - "ProgrammingLanguageLanguageNameString": { - "type": "string", - "max": 128, - "min": 1, - "pattern": "(python|javascript|java|csharp|typescript|c|cpp|go|kotlin|php|ruby|rust|scala|shell|sql|json|yaml|vue|tf|tsx|jsx|plaintext|systemverilog|dart|lua|swift|hcl|powershell|r|abap)" - }, - "ProgressUpdates": { - "type": "list", - "member": { - "shape": "TransformationProgressUpdate" - } - }, - "PromptLogging": { - "type": "structure", - "required": ["s3Uri", "toggle"], - "members": { - "s3Uri": { - "shape": "S3Uri" - }, - "toggle": { - "shape": "OptInFeatureToggle" - } - } - }, - "PushTelemetryEventRequest": { - "type": "structure", - "required": ["eventType", "event"], - "members": { - "clientToken": { - "shape": "IdempotencyToken", - "idempotencyToken": true - }, - "eventType": { - "shape": "String" - }, - "event": { - "shape": "Document" - } - } - }, - "PushTelemetryEventResponse": { - "type": "structure", - "members": {} - }, - "Range": { - "type": "structure", - "required": ["start", "end"], - "members": { - "start": { - "shape": "Position", - "documentation": "

The range's start position.

" - }, - "end": { - "shape": "Position", - "documentation": "

The range's end position.

" - } - }, - "documentation": "

Indicates Range / Span in a Text Document

" - }, - "RecommendationsWithReferencesPreference": { - "type": "string", - "documentation": "

Recommendations with references setting for CodeWhisperer

", - "enum": ["BLOCK", "ALLOW"] - }, - "Reference": { - "type": "structure", - "members": { - "licenseName": { - "shape": "ReferenceLicenseNameString", - "documentation": "

License name

" - }, - "repository": { - "shape": "ReferenceRepositoryString", - "documentation": "

Code Repsitory for the associated reference

" - }, - "url": { - "shape": "ReferenceUrlString", - "documentation": "

Respository URL

" - }, - "recommendationContentSpan": { - "shape": "Span", - "documentation": "

Span / Range for the Reference

" - } - }, - "documentation": "

Code Reference / Repository details

" - }, - "ReferenceLicenseNameString": { - "type": "string", - "max": 1024, - "min": 1 - }, - "ReferenceRepositoryString": { - "type": "string", - "max": 1024, - "min": 1 - }, - "ReferenceTrackerConfiguration": { - "type": "structure", - "required": ["recommendationsWithReferences"], - "members": { - "recommendationsWithReferences": { - "shape": "RecommendationsWithReferencesPreference" - } - } - }, - "ReferenceUrlString": { - "type": "string", - "max": 1024, - "min": 1 - }, - "References": { - "type": "list", - "member": { - "shape": "Reference" - }, - "max": 10, - "min": 0 - }, - "RelevantDocumentList": { - "type": "list", - "member": { - "shape": "RelevantTextDocument" - }, - "max": 100, - "min": 0 - }, - "RelevantTextDocument": { - "type": "structure", - "required": ["relativeFilePath"], - "members": { - "relativeFilePath": { - "shape": "RelevantTextDocumentRelativeFilePathString", - "documentation": "

Filepath relative to the root of the workspace

" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage", - "documentation": "

The text document's language identifier.

" - }, - "text": { - "shape": "RelevantTextDocumentTextString", - "documentation": "

Content of the text document

" - }, - "documentSymbols": { - "shape": "DocumentSymbols", - "documentation": "

DocumentSymbols parsed from a text document

" - }, - "type": { - "shape": "ContentType", - "documentation": "

The type of content(file, prompt, symbol, or workspace)

" - } - }, - "documentation": "

Represents an IDE retrieved relevant Text Document / File

" - }, - "RelevantTextDocumentRelativeFilePathString": { - "type": "string", - "max": 4096, - "min": 1, - "sensitive": true - }, - "RelevantTextDocumentTextString": { - "type": "string", - "max": 40960, - "min": 0, - "sensitive": true - }, - "RequestHeaderKey": { - "type": "string", - "max": 64, - "min": 1 - }, - "RequestHeaderValue": { - "type": "string", - "max": 256, - "min": 1 - }, - "RequestHeaders": { - "type": "map", - "key": { - "shape": "RequestHeaderKey" - }, - "value": { - "shape": "RequestHeaderValue" - }, - "max": 16, - "min": 1, - "sensitive": true - }, - "ResourceArn": { - "type": "string", - "max": 1224, - "min": 0, - "pattern": "arn:([-.a-z0-9]{1,63}:){2}([-.a-z0-9]{0,63}:){2}([a-zA-Z0-9-_:/]){1,1023}" - }, - "ResourceNotFoundException": { - "type": "structure", - "required": ["message"], - "members": { - "message": { - "shape": "String" - } - }, - "documentation": "

This exception is thrown when describing a resource that does not exist.

", - "exception": true - }, - "ResourcePolicy": { - "type": "structure", - "required": ["effect"], - "members": { - "effect": { - "shape": "ResourcePolicyEffect" - } - } - }, - "ResourcePolicyEffect": { - "type": "string", - "enum": ["ALLOW", "DENY"] - }, - "ResumeTransformationRequest": { - "type": "structure", - "required": ["transformationJobId"], - "members": { - "transformationJobId": { - "shape": "TransformationJobId" - }, - "userActionStatus": { - "shape": "TransformationUserActionStatus" - }, - "profileArn": { - "shape": "ProfileArn" - } - }, - "documentation": "

Structure to represent stop code transformation request.

" - }, - "ResumeTransformationResponse": { - "type": "structure", - "required": ["transformationStatus"], - "members": { - "transformationStatus": { - "shape": "TransformationStatus" - } - }, - "documentation": "

Structure to represent stop code transformation response.

" - }, - "RuntimeDiagnostic": { - "type": "structure", - "required": ["source", "severity", "message"], - "members": { - "source": { - "shape": "RuntimeDiagnosticSourceString", - "documentation": "

A human-readable string describing the source of the diagnostic

" - }, - "severity": { - "shape": "DiagnosticSeverity", - "documentation": "

Diagnostic Error type

" - }, - "message": { - "shape": "RuntimeDiagnosticMessageString", - "documentation": "

The diagnostic's message.

" - } - }, - "documentation": "

Structure to represent metadata about a Runtime Diagnostics

" - }, - "RuntimeDiagnosticMessageString": { - "type": "string", - "max": 1024, - "min": 0, - "sensitive": true - }, - "RuntimeDiagnosticSourceString": { - "type": "string", - "max": 1024, - "min": 0, - "sensitive": true - }, - "S3Uri": { - "type": "string", - "max": 1024, - "min": 1, - "pattern": "s3://((?!xn--)[a-z0-9](?![^/]*[.]{2})[a-z0-9-.]{1,61}[a-z0-9](?This exception is thrown when request was denied due to caller exceeding their usage limits

", - "exception": true - }, - "ServiceQuotaExceededExceptionReason": { - "type": "string", - "documentation": "

Reason for ServiceQuotaExceededException

", - "enum": ["CONVERSATION_LIMIT_EXCEEDED"] - }, - "ShellHistory": { - "type": "list", - "member": { - "shape": "ShellHistoryEntry" - }, - "documentation": "

A list of shell history entries

", - "max": 20, - "min": 0 - }, - "ShellHistoryEntry": { - "type": "structure", - "required": ["command"], - "members": { - "command": { - "shape": "ShellHistoryEntryCommandString", - "documentation": "

The shell command that was run

" - }, - "directory": { - "shape": "ShellHistoryEntryDirectoryString", - "documentation": "

The directory the command was ran in

" - }, - "exitCode": { - "shape": "Integer", - "documentation": "

The exit code of the command after it finished

" - }, - "stdout": { - "shape": "ShellHistoryEntryStdoutString", - "documentation": "

The stdout from the command

" - }, - "stderr": { - "shape": "ShellHistoryEntryStderrString", - "documentation": "

The stderr from the command

" - } - }, - "documentation": "

An single entry in the shell history

" - }, - "ShellHistoryEntryCommandString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "ShellHistoryEntryDirectoryString": { - "type": "string", - "max": 256, - "min": 1, - "sensitive": true - }, - "ShellHistoryEntryStderrString": { - "type": "string", - "max": 4096, - "min": 0, - "sensitive": true - }, - "ShellHistoryEntryStdoutString": { - "type": "string", - "max": 4096, - "min": 0, - "sensitive": true - }, - "ShellState": { - "type": "structure", - "required": ["shellName"], - "members": { - "shellName": { - "shape": "ShellStateShellNameString", - "documentation": "

The name of the current shell

" - }, - "shellHistory": { - "shape": "ShellHistory", - "documentation": "

The history previous shell commands for the current shell

" - } - }, - "documentation": "

Represents the state of a shell

" - }, - "ShellStateShellNameString": { - "type": "string", - "max": 32, - "min": 1, - "pattern": "(zsh|bash|fish|pwsh|nu)" - }, - "Span": { - "type": "structure", - "members": { - "start": { - "shape": "SpanStartInteger" - }, - "end": { - "shape": "SpanEndInteger" - } - }, - "documentation": "

Represents span in a text.

" - }, - "SpanEndInteger": { - "type": "integer", - "box": true, - "min": 0 - }, - "SpanStartInteger": { - "type": "integer", - "box": true, - "min": 0 - }, - "StartCodeAnalysisRequest": { - "type": "structure", - "required": ["artifacts", "programmingLanguage"], - "members": { - "artifacts": { - "shape": "ArtifactMap" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage" - }, - "clientToken": { - "shape": "StartCodeAnalysisRequestClientTokenString", - "idempotencyToken": true - }, - "scope": { - "shape": "CodeAnalysisScope" - }, - "codeScanName": { - "shape": "CodeScanName" - }, - "codeDiffMetadata": { - "shape": "CodeDiffMetadata" - }, - "profileArn": { - "shape": "ProfileArn" - }, - "languageModelId": { - "shape": "ModelId" - }, - "clientType": { - "shape": "Origin" - } - } - }, - "StartCodeAnalysisRequestClientTokenString": { - "type": "string", - "max": 256, - "min": 1 - }, - "StartCodeAnalysisResponse": { - "type": "structure", - "required": ["jobId", "status"], - "members": { - "jobId": { - "shape": "StartCodeAnalysisResponseJobIdString" - }, - "status": { - "shape": "CodeAnalysisStatus" - }, - "errorMessage": { - "shape": "SensitiveString" - } - } - }, - "StartCodeAnalysisResponseJobIdString": { - "type": "string", - "max": 256, - "min": 1 - }, - "StartCodeFixJobRequest": { - "type": "structure", - "required": ["snippetRange", "uploadId"], - "members": { - "snippetRange": { - "shape": "Range" - }, - "uploadId": { - "shape": "UploadId" - }, - "description": { - "shape": "StartCodeFixJobRequestDescriptionString" - }, - "ruleId": { - "shape": "StartCodeFixJobRequestRuleIdString" - }, - "codeFixName": { - "shape": "CodeFixName" - }, - "referenceTrackerConfiguration": { - "shape": "ReferenceTrackerConfiguration" - }, - "profileArn": { - "shape": "ProfileArn" - } - } - }, - "StartCodeFixJobRequestDescriptionString": { - "type": "string", - "max": 5000, - "min": 1, - "sensitive": true - }, - "StartCodeFixJobRequestRuleIdString": { - "type": "string", - "max": 256, - "min": 1, - "pattern": ".*[A-Za-z0-9-]+.*" - }, - "StartCodeFixJobResponse": { - "type": "structure", - "members": { - "jobId": { - "shape": "StartCodeFixJobResponseJobIdString" - }, - "status": { - "shape": "CodeFixJobStatus" - } - } - }, - "StartCodeFixJobResponseJobIdString": { - "type": "string", - "max": 256, - "min": 1, - "pattern": ".*[A-Za-z0-9-:]+.*" - }, - "StartTaskAssistCodeGenerationRequest": { - "type": "structure", - "required": ["conversationState", "workspaceState"], - "members": { - "conversationState": { - "shape": "ConversationState" - }, - "workspaceState": { - "shape": "WorkspaceState" - }, - "taskAssistPlan": { - "shape": "TaskAssistPlan" - }, - "codeGenerationId": { - "shape": "CodeGenerationId" - }, - "currentCodeGenerationId": { - "shape": "CodeGenerationId" - }, - "intent": { - "shape": "Intent" - }, - "intentContext": { - "shape": "IntentContext" - }, - "profileArn": { - "shape": "ProfileArn" - } - }, - "documentation": "

Structure to represent start code generation request.

" - }, - "StartTaskAssistCodeGenerationResponse": { - "type": "structure", - "required": ["conversationId", "codeGenerationId"], - "members": { - "conversationId": { - "shape": "ConversationId" - }, - "codeGenerationId": { - "shape": "CodeGenerationId" - } - }, - "documentation": "

Structure to represent start code generation response.

" - }, - "StartTestGenerationRequest": { - "type": "structure", - "required": ["uploadId", "targetCodeList", "userInput"], - "members": { - "uploadId": { - "shape": "UploadId" - }, - "targetCodeList": { - "shape": "TargetCodeList" - }, - "userInput": { - "shape": "StartTestGenerationRequestUserInputString", - "documentation": "

The content of user input.

" - }, - "testGenerationJobGroupName": { - "shape": "TestGenerationJobGroupName" - }, - "clientToken": { - "shape": "StartTestGenerationRequestClientTokenString", - "idempotencyToken": true - }, - "profileArn": { - "shape": "ProfileArn" - }, - "referenceTrackerConfiguration": { - "shape": "ReferenceTrackerConfiguration" - } - }, - "documentation": "

Structure to represent test generation request.

" - }, - "StartTestGenerationRequestClientTokenString": { - "type": "string", - "max": 256, - "min": 1 - }, - "StartTestGenerationRequestUserInputString": { - "type": "string", - "max": 4096, - "min": 0, - "sensitive": true - }, - "StartTestGenerationResponse": { - "type": "structure", - "members": { - "testGenerationJob": { - "shape": "TestGenerationJob" - } - }, - "documentation": "

Structure to represent code transformation response.

" - }, - "StartTransformationRequest": { - "type": "structure", - "required": ["workspaceState", "transformationSpec"], - "members": { - "workspaceState": { - "shape": "WorkspaceState" - }, - "transformationSpec": { - "shape": "TransformationSpec" - }, - "profileArn": { - "shape": "ProfileArn" - } - }, - "documentation": "

Structure to represent code transformation request.

" - }, - "StartTransformationResponse": { - "type": "structure", - "required": ["transformationJobId"], - "members": { - "transformationJobId": { - "shape": "TransformationJobId" - } - }, - "documentation": "

Structure to represent code transformation response.

" - }, - "StepId": { - "type": "string", - "max": 126, - "min": 1 - }, - "StopTransformationRequest": { - "type": "structure", - "required": ["transformationJobId"], - "members": { - "transformationJobId": { - "shape": "TransformationJobId" - }, - "profileArn": { - "shape": "ProfileArn" - } - }, - "documentation": "

Structure to represent stop code transformation request.

" - }, - "StopTransformationResponse": { - "type": "structure", - "required": ["transformationStatus"], - "members": { - "transformationStatus": { - "shape": "TransformationStatus" - } - }, - "documentation": "

Structure to represent stop code transformation response.

" - }, - "String": { - "type": "string" - }, - "StringList": { - "type": "list", - "member": { - "shape": "StringListMemberString" - }, - "documentation": "

A list of strings

", - "max": 50, - "min": 0 - }, - "StringListMemberString": { - "type": "string", - "max": 256, - "min": 1, - "sensitive": true - }, - "SubscriptionStatus": { - "type": "string", - "enum": ["INACTIVE", "ACTIVE"] - }, - "SuggestedFix": { - "type": "structure", - "members": { - "codeDiff": { - "shape": "SuggestedFixCodeDiffString" - }, - "description": { - "shape": "SuggestedFixDescriptionString" - }, - "references": { - "shape": "References" - } - } - }, - "SuggestedFixCodeDiffString": { - "type": "string", - "max": 200000, - "min": 0, - "sensitive": true - }, - "SuggestedFixDescriptionString": { - "type": "string", - "max": 2000, - "min": 1, - "sensitive": true - }, - "SuggestionState": { - "type": "string", - "enum": ["ACCEPT", "REJECT", "DISCARD", "EMPTY", "MERGE"] - }, - "SupplementalContext": { - "type": "structure", - "required": ["filePath", "content"], - "members": { - "filePath": { - "shape": "SupplementalContextFilePathString" - }, - "content": { - "shape": "SupplementalContextContentString" - }, - "type": { - "shape": "SupplementalContextType" - }, - "metadata": { - "shape": "SupplementalContextMetadata" - } - } - }, - "SupplementalContextContentString": { - "type": "string", - "max": 10240, - "min": 1, - "sensitive": true - }, - "SupplementalContextFilePathString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "SupplementalContextList": { - "type": "list", - "member": { - "shape": "SupplementalContext" - }, - "max": 20, - "min": 0 - }, - "SupplementalContextMetadata": { - "type": "structure", - "members": { - "previousEditorStateMetadata": { - "shape": "PreviousEditorStateMetadata" - } - }, - "union": true - }, - "SupplementalContextType": { - "type": "string", - "enum": ["PreviousEditorState", "WorkspaceContext"] - }, - "SupplementaryWebLink": { - "type": "structure", - "required": ["url", "title"], - "members": { - "url": { - "shape": "SupplementaryWebLinkUrlString", - "documentation": "

URL of the web reference link.

" - }, - "title": { - "shape": "SupplementaryWebLinkTitleString", - "documentation": "

Title of the web reference link.

" - }, - "snippet": { - "shape": "SupplementaryWebLinkSnippetString", - "documentation": "

Relevant text snippet from the link.

" - } - }, - "documentation": "

Represents an additional reference link retured with the Chat message

" - }, - "SupplementaryWebLinkSnippetString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "SupplementaryWebLinkTitleString": { - "type": "string", - "max": 1024, - "min": 1, - "sensitive": true - }, - "SupplementaryWebLinkUrlString": { - "type": "string", - "max": 2048, - "min": 1, - "sensitive": true - }, - "SupplementaryWebLinks": { - "type": "list", - "member": { - "shape": "SupplementaryWebLink" - }, - "max": 10, - "min": 0 - }, - "SymbolType": { - "type": "string", - "enum": ["DECLARATION", "USAGE"] - }, - "SyntheticTimestamp_date_time": { - "type": "timestamp", - "timestampFormat": "iso8601" - }, - "TargetCode": { - "type": "structure", - "required": ["relativeTargetPath"], - "members": { - "relativeTargetPath": { - "shape": "TargetCodeRelativeTargetPathString", - "documentation": "

The file path relative to the root of the workspace, could be a single file or a folder.

" - }, - "targetLineRangeList": { - "shape": "LineRangeList" - } - } - }, - "TargetCodeList": { - "type": "list", - "member": { - "shape": "TargetCode" - }, - "min": 1 - }, - "TargetCodeRelativeTargetPathString": { - "type": "string", - "max": 4096, - "min": 1, - "sensitive": true - }, - "TargetFileInfo": { - "type": "structure", - "members": { - "filePath": { - "shape": "SensitiveString" - }, - "testFilePath": { - "shape": "SensitiveString" - }, - "testCoverage": { - "shape": "TargetFileInfoTestCoverageInteger" - }, - "fileSummary": { - "shape": "TargetFileInfoFileSummaryString" - }, - "filePlan": { - "shape": "TargetFileInfoFilePlanString" - }, - "codeReferences": { - "shape": "References" - }, - "numberOfTestMethods": { - "shape": "TargetFileInfoNumberOfTestMethodsInteger" - } - } - }, - "TargetFileInfoFilePlanString": { - "type": "string", - "max": 30720, - "min": 0, - "sensitive": true - }, - "TargetFileInfoFileSummaryString": { - "type": "string", - "max": 30720, - "min": 0, - "sensitive": true - }, - "TargetFileInfoList": { - "type": "list", - "member": { - "shape": "TargetFileInfo" - } - }, - "TargetFileInfoNumberOfTestMethodsInteger": { - "type": "integer", - "box": true, - "min": 0 - }, - "TargetFileInfoTestCoverageInteger": { - "type": "integer", - "box": true, - "max": 100, - "min": 0 - }, - "TaskAssistPlan": { - "type": "list", - "member": { - "shape": "TaskAssistPlanStep" - }, - "min": 0 - }, - "TaskAssistPlanStep": { - "type": "structure", - "required": ["filePath", "description"], - "members": { - "filePath": { - "shape": "TaskAssistPlanStepFilePathString", - "documentation": "

File path on which the step is working on.

" - }, - "description": { - "shape": "TaskAssistPlanStepDescriptionString", - "documentation": "

Description on the step.

" - }, - "startLine": { - "shape": "TaskAssistPlanStepStartLineInteger", - "documentation": "

Start line number of the related changes.

" - }, - "endLine": { - "shape": "TaskAssistPlanStepEndLineInteger", - "documentation": "

End line number of the related changes.

" - }, - "action": { - "shape": "TaskAssistPlanStepAction", - "documentation": "

Type of the action.

" - } - }, - "documentation": "

Structured plan step for a task assist plan.

" - }, - "TaskAssistPlanStepAction": { - "type": "string", - "documentation": "

Action for task assist plan step

", - "enum": ["MODIFY", "CREATE", "DELETE", "UNKNOWN"] - }, - "TaskAssistPlanStepDescriptionString": { - "type": "string", - "max": 1024, - "min": 1 - }, - "TaskAssistPlanStepEndLineInteger": { - "type": "integer", - "box": true, - "min": 0 - }, - "TaskAssistPlanStepFilePathString": { - "type": "string", - "max": 1024, - "min": 1 - }, - "TaskAssistPlanStepStartLineInteger": { - "type": "integer", - "box": true, - "min": 0 - }, - "TaskAssistPlanningUploadContext": { - "type": "structure", - "required": ["conversationId"], - "members": { - "conversationId": { - "shape": "ConversationId" - } - } - }, - "TelemetryEvent": { - "type": "structure", - "members": { - "userTriggerDecisionEvent": { - "shape": "UserTriggerDecisionEvent" - }, - "codeCoverageEvent": { - "shape": "CodeCoverageEvent" - }, - "userModificationEvent": { - "shape": "UserModificationEvent" - }, - "codeScanEvent": { - "shape": "CodeScanEvent" - }, - "codeScanSucceededEvent": { - "shape": "CodeScanSucceededEvent" - }, - "codeScanFailedEvent": { - "shape": "CodeScanFailedEvent" - }, - "codeScanRemediationsEvent": { - "shape": "CodeScanRemediationsEvent" - }, - "codeFixGenerationEvent": { - "shape": "CodeFixGenerationEvent" - }, - "codeFixAcceptanceEvent": { - "shape": "CodeFixAcceptanceEvent" - }, - "metricData": { - "shape": "MetricData" - }, - "chatAddMessageEvent": { - "shape": "ChatAddMessageEvent" - }, - "chatInteractWithMessageEvent": { - "shape": "ChatInteractWithMessageEvent" - }, - "chatUserModificationEvent": { - "shape": "ChatUserModificationEvent" - }, - "terminalUserInteractionEvent": { - "shape": "TerminalUserInteractionEvent" - }, - "featureDevEvent": { - "shape": "FeatureDevEvent" - }, - "featureDevCodeGenerationEvent": { - "shape": "FeatureDevCodeGenerationEvent" - }, - "featureDevCodeAcceptanceEvent": { - "shape": "FeatureDevCodeAcceptanceEvent" - }, - "inlineChatEvent": { - "shape": "InlineChatEvent" - }, - "transformEvent": { - "shape": "TransformEvent" - }, - "docGenerationEvent": { - "shape": "DocGenerationEvent" - }, - "docV2GenerationEvent": { - "shape": "DocV2GenerationEvent" - }, - "docV2AcceptanceEvent": { - "shape": "DocV2AcceptanceEvent" - }, - "testGenerationEvent": { - "shape": "TestGenerationEvent" - } - }, - "union": true - }, - "TenantId": { - "type": "string", - "max": 1024, - "min": 1 - }, - "TerminalUserInteractionEvent": { - "type": "structure", - "members": { - "terminalUserInteractionEventType": { - "shape": "TerminalUserInteractionEventType" - }, - "terminal": { - "shape": "String" - }, - "terminalVersion": { - "shape": "String" - }, - "shell": { - "shape": "String" - }, - "shellVersion": { - "shape": "String" - }, - "duration": { - "shape": "Integer" - }, - "timeToSuggestion": { - "shape": "Integer" - }, - "isCompletionAccepted": { - "shape": "Boolean" - }, - "cliToolCommand": { - "shape": "String" - } - } - }, - "TerminalUserInteractionEventType": { - "type": "string", - "documentation": "

CodeWhisperer terminal Interaction Type

", - "enum": ["CODEWHISPERER_TERMINAL_TRANSLATION_ACTION", "CODEWHISPERER_TERMINAL_COMPLETION_INSERTED"] - }, - "TestGenerationEvent": { - "type": "structure", - "required": ["jobId", "groupName"], - "members": { - "jobId": { - "shape": "UUID" - }, - "groupName": { - "shape": "TestGenerationJobGroupName" - }, - "timestamp": { - "shape": "Timestamp" - }, - "ideCategory": { - "shape": "IdeCategory" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage" - }, - "numberOfUnitTestCasesGenerated": { - "shape": "Integer" - }, - "numberOfUnitTestCasesAccepted": { - "shape": "Integer" - }, - "linesOfCodeGenerated": { - "shape": "Integer" - }, - "linesOfCodeAccepted": { - "shape": "Integer" - }, - "charsOfCodeGenerated": { - "shape": "Integer" - }, - "charsOfCodeAccepted": { - "shape": "Integer" - } - } - }, - "TestGenerationJob": { - "type": "structure", - "required": ["testGenerationJobId", "testGenerationJobGroupName", "status", "creationTime"], - "members": { - "testGenerationJobId": { - "shape": "UUID" - }, - "testGenerationJobGroupName": { - "shape": "TestGenerationJobGroupName" - }, - "status": { - "shape": "TestGenerationJobStatus" - }, - "shortAnswer": { - "shape": "SensitiveString" - }, - "creationTime": { - "shape": "Timestamp" - }, - "progressRate": { - "shape": "TestGenerationJobProgressRateInteger" - }, - "jobStatusReason": { - "shape": "String" - }, - "jobSummary": { - "shape": "TestGenerationJobJobSummaryString" - }, - "jobPlan": { - "shape": "TestGenerationJobJobPlanString" - }, - "packageInfoList": { - "shape": "PackageInfoList" - } - }, - "documentation": "

Represents a test generation job

" - }, - "TestGenerationJobGroupName": { - "type": "string", - "documentation": "

Test generation job group name

", - "max": 128, - "min": 1, - "pattern": "[a-zA-Z0-9-_]+" - }, - "TestGenerationJobJobPlanString": { - "type": "string", - "max": 30720, - "min": 0, - "sensitive": true - }, - "TestGenerationJobJobSummaryString": { - "type": "string", - "max": 30720, - "min": 0, - "sensitive": true - }, - "TestGenerationJobProgressRateInteger": { - "type": "integer", - "box": true, - "max": 100, - "min": 0 - }, - "TestGenerationJobStatus": { - "type": "string", - "enum": ["IN_PROGRESS", "FAILED", "COMPLETED"] - }, - "TextDocument": { - "type": "structure", - "required": ["relativeFilePath"], - "members": { - "relativeFilePath": { - "shape": "TextDocumentRelativeFilePathString", - "documentation": "

Filepath relative to the root of the workspace

" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage", - "documentation": "

The text document's language identifier.

" - }, - "text": { - "shape": "TextDocumentTextString", - "documentation": "

Content of the text document

" - }, - "documentSymbols": { - "shape": "DocumentSymbols", - "documentation": "

DocumentSymbols parsed from a text document

" - } - }, - "documentation": "

Represents a Text Document / File

" - }, - "TextDocumentDiagnostic": { - "type": "structure", - "required": ["document", "range", "source", "severity", "message"], - "members": { - "document": { - "shape": "TextDocument", - "documentation": "

Represents a Text Document associated with Diagnostic

" - }, - "range": { - "shape": "Range", - "documentation": "

The range at which the message applies.

" - }, - "source": { - "shape": "SensitiveString", - "documentation": "

A human-readable string describing the source of the diagnostic

" - }, - "severity": { - "shape": "DiagnosticSeverity", - "documentation": "

Diagnostic Error type

" - }, - "message": { - "shape": "TextDocumentDiagnosticMessageString", - "documentation": "

The diagnostic's message.

" - }, - "code": { - "shape": "TextDocumentDiagnosticCodeString", - "documentation": "

The diagnostic's code, which might appear in the user interface.

" - }, - "codeDescription": { - "shape": "CodeDescription", - "documentation": "

An optional property to describe the error code.

" - }, - "tags": { - "shape": "DiagnosticTagList", - "documentation": "

Additional metadata about the diagnostic.

" - }, - "relatedInformation": { - "shape": "DiagnosticRelatedInformationList", - "documentation": "

an array of related diagnostic information, e.g. when symbol-names within a scope collide all definitions can be marked via this property.

" - }, - "data": { - "shape": "TextDocumentDiagnosticDataString", - "documentation": "

A data entry field that is preserved between a textDocument/publishDiagnostics notification and textDocument/codeAction request.

" - } - }, - "documentation": "

Structure to represent metadata about a TextDocument Diagnostic

" - }, - "TextDocumentDiagnosticCodeString": { - "type": "string", - "max": 1024, - "min": 0, - "sensitive": true - }, - "TextDocumentDiagnosticDataString": { - "type": "string", - "max": 4096, - "min": 0, - "sensitive": true - }, - "TextDocumentDiagnosticMessageString": { - "type": "string", - "max": 1024, - "min": 0, - "sensitive": true - }, - "TextDocumentRelativeFilePathString": { - "type": "string", - "max": 4096, - "min": 1, - "sensitive": true - }, - "TextDocumentTextString": { - "type": "string", - "max": 40000, - "min": 0, - "sensitive": true - }, - "ThrottlingException": { - "type": "structure", - "required": ["message"], - "members": { - "message": { - "shape": "String" - }, - "reason": { - "shape": "ThrottlingExceptionReason" - } - }, - "documentation": "

This exception is thrown when request was denied due to request throttling.

", - "exception": true, - "retryable": { - "throttling": true - } - }, - "ThrottlingExceptionReason": { - "type": "string", - "documentation": "

Reason for ThrottlingException

", - "enum": ["MONTHLY_REQUEST_COUNT"] - }, - "Timestamp": { - "type": "timestamp" - }, - "Tool": { - "type": "structure", - "members": { - "toolSpecification": { - "shape": "ToolSpecification" - } - }, - "documentation": "

Information about a tool that can be used.

", - "union": true - }, - "ToolDescription": { - "type": "string", - "documentation": "

The description for the tool.

", - "max": 10240, - "min": 1, - "sensitive": true - }, - "ToolInputSchema": { - "type": "structure", - "members": { - "json": { - "shape": "SensitiveDocument" - } - }, - "documentation": "

The input schema for the tool in JSON format.

" - }, - "ToolName": { - "type": "string", - "documentation": "

The name for the tool.

", - "max": 64, - "min": 0, - "pattern": "[a-zA-Z0-9_-]+", - "sensitive": true - }, - "ToolResult": { - "type": "structure", - "required": ["toolUseId", "content"], - "members": { - "toolUseId": { - "shape": "ToolUseId" - }, - "content": { - "shape": "ToolResultContent", - "documentation": "

Content of the tool result.

" - }, - "status": { - "shape": "ToolResultStatus" - } - }, - "documentation": "

A tool result that contains the results for a tool request that was previously made.

" - }, - "ToolResultContent": { - "type": "list", - "member": { - "shape": "ToolResultContentBlock" - } - }, - "ToolResultContentBlock": { - "type": "structure", - "members": { - "text": { - "shape": "ToolResultContentBlockTextString", - "documentation": "

A tool result that is text.

" - }, - "json": { - "shape": "SensitiveDocument", - "documentation": "

A tool result that is JSON format data.

" - } - }, - "union": true - }, - "ToolResultContentBlockTextString": { - "type": "string", - "max": 800000, - "min": 0, - "sensitive": true - }, - "ToolResultStatus": { - "type": "string", - "documentation": "

Status of the tools result.

", - "enum": ["success", "error"] - }, - "ToolResults": { - "type": "list", - "member": { - "shape": "ToolResult" - }, - "max": 10, - "min": 0 - }, - "ToolSpecification": { - "type": "structure", - "required": ["inputSchema", "name"], - "members": { - "inputSchema": { - "shape": "ToolInputSchema" - }, - "name": { - "shape": "ToolName" - }, - "description": { - "shape": "ToolDescription" - } - }, - "documentation": "

The specification for the tool.

" - }, - "ToolUse": { - "type": "structure", - "required": ["toolUseId", "name", "input"], - "members": { - "toolUseId": { - "shape": "ToolUseId" - }, - "name": { - "shape": "ToolName" - }, - "input": { - "shape": "SensitiveDocument", - "documentation": "

The input to pass to the tool.

" - } - }, - "documentation": "

Contains information about a tool that the model is requesting be run. The model uses the result from the tool to generate a response.

" - }, - "ToolUseId": { - "type": "string", - "documentation": "

The ID for the tool request.

", - "max": 64, - "min": 0, - "pattern": "[a-zA-Z0-9_-]+" - }, - "ToolUses": { - "type": "list", - "member": { - "shape": "ToolUse" - }, - "max": 10, - "min": 0 - }, - "Tools": { - "type": "list", - "member": { - "shape": "Tool" - } - }, - "TransformEvent": { - "type": "structure", - "required": ["jobId"], - "members": { - "jobId": { - "shape": "TransformationJobId" - }, - "timestamp": { - "shape": "Timestamp" - }, - "ideCategory": { - "shape": "IdeCategory" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage" - }, - "linesOfCodeChanged": { - "shape": "Integer" - }, - "charsOfCodeChanged": { - "shape": "Integer" - }, - "linesOfCodeSubmitted": { - "shape": "Integer" - } - } - }, - "TransformationDotNetRuntimeEnv": { - "type": "string", - "enum": ["NET_5_0", "NET_6_0", "NET_7_0", "NET_8_0", "NET_9_0", "NET_STANDARD_2_0"] - }, - "TransformationDownloadArtifact": { - "type": "structure", - "members": { - "downloadArtifactType": { - "shape": "TransformationDownloadArtifactType" - }, - "downloadArtifactId": { - "shape": "ArtifactId" - } - } - }, - "TransformationDownloadArtifactType": { - "type": "string", - "enum": ["ClientInstructions", "Logs", "GeneratedCode"] - }, - "TransformationDownloadArtifacts": { - "type": "list", - "member": { - "shape": "TransformationDownloadArtifact" - }, - "max": 10, - "min": 0 - }, - "TransformationJavaRuntimeEnv": { - "type": "string", - "enum": ["JVM_8", "JVM_11", "JVM_17", "JVM_21"] - }, - "TransformationJob": { - "type": "structure", - "members": { - "jobId": { - "shape": "TransformationJobId" - }, - "transformationSpec": { - "shape": "TransformationSpec" - }, - "status": { - "shape": "TransformationStatus" - }, - "reason": { - "shape": "String" - }, - "creationTime": { - "shape": "Timestamp" - }, - "startExecutionTime": { - "shape": "Timestamp" - }, - "endExecutionTime": { - "shape": "Timestamp" - } - }, - "documentation": "

Represent a Transformation Job

" - }, - "TransformationJobId": { - "type": "string", - "documentation": "

Identifier for the Transformation Job

", - "max": 128, - "min": 1 - }, - "TransformationLanguage": { - "type": "string", - "enum": ["JAVA_8", "JAVA_11", "JAVA_17", "JAVA_21", "C_SHARP", "COBOL", "PL_I", "JCL"] - }, - "TransformationLanguages": { - "type": "list", - "member": { - "shape": "TransformationLanguage" - } - }, - "TransformationMainframeRuntimeEnv": { - "type": "string", - "enum": ["MAINFRAME"] - }, - "TransformationOperatingSystemFamily": { - "type": "string", - "enum": ["WINDOWS", "LINUX"] - }, - "TransformationPlan": { - "type": "structure", - "required": ["transformationSteps"], - "members": { - "transformationSteps": { - "shape": "TransformationSteps" - } - } - }, - "TransformationPlatformConfig": { - "type": "structure", - "members": { - "operatingSystemFamily": { - "shape": "TransformationOperatingSystemFamily" - } - } - }, - "TransformationProgressUpdate": { - "type": "structure", - "required": ["name", "status"], - "members": { - "name": { - "shape": "String" - }, - "status": { - "shape": "TransformationProgressUpdateStatus" - }, - "description": { - "shape": "String" - }, - "startTime": { - "shape": "Timestamp" - }, - "endTime": { - "shape": "Timestamp" - }, - "downloadArtifacts": { - "shape": "TransformationDownloadArtifacts" - } - } - }, - "TransformationProgressUpdateStatus": { - "type": "string", - "enum": ["IN_PROGRESS", "COMPLETED", "FAILED", "PAUSED", "AWAITING_CLIENT_ACTION", "SKIPPED"] - }, - "TransformationProjectArtifactDescriptor": { - "type": "structure", - "members": { - "sourceCodeArtifact": { - "shape": "TransformationSourceCodeArtifactDescriptor" - } - }, - "union": true - }, - "TransformationProjectState": { - "type": "structure", - "members": { - "language": { - "shape": "TransformationLanguage" - }, - "runtimeEnv": { - "shape": "TransformationRuntimeEnv" - }, - "platformConfig": { - "shape": "TransformationPlatformConfig" - }, - "projectArtifact": { - "shape": "TransformationProjectArtifactDescriptor" - } - } - }, - "TransformationRuntimeEnv": { - "type": "structure", - "members": { - "java": { - "shape": "TransformationJavaRuntimeEnv" - }, - "dotNet": { - "shape": "TransformationDotNetRuntimeEnv" - }, - "mainframe": { - "shape": "TransformationMainframeRuntimeEnv" - } - }, - "union": true - }, - "TransformationSourceCodeArtifactDescriptor": { - "type": "structure", - "members": { - "languages": { - "shape": "TransformationLanguages" - }, - "runtimeEnv": { - "shape": "TransformationRuntimeEnv" - } - } - }, - "TransformationSpec": { - "type": "structure", - "members": { - "transformationType": { - "shape": "TransformationType" - }, - "source": { - "shape": "TransformationProjectState" - }, - "target": { - "shape": "TransformationProjectState" - } - } - }, - "TransformationStatus": { - "type": "string", - "enum": [ - "CREATED", - "ACCEPTED", - "REJECTED", - "STARTED", - "PREPARING", - "PREPARED", - "PLANNING", - "PLANNED", - "TRANSFORMING", - "TRANSFORMED", - "FAILED", - "COMPLETED", - "PARTIALLY_COMPLETED", - "STOPPING", - "STOPPED", - "PAUSED", - "RESUMED" - ] - }, - "TransformationStep": { - "type": "structure", - "required": ["id", "name", "description", "status"], - "members": { - "id": { - "shape": "StepId" - }, - "name": { - "shape": "String" - }, - "description": { - "shape": "String" - }, - "status": { - "shape": "TransformationStepStatus" - }, - "progressUpdates": { - "shape": "ProgressUpdates" - }, - "startTime": { - "shape": "Timestamp" - }, - "endTime": { - "shape": "Timestamp" - } - } - }, - "TransformationStepStatus": { - "type": "string", - "enum": ["CREATED", "COMPLETED", "PARTIALLY_COMPLETED", "STOPPED", "FAILED", "PAUSED", "SKIPPED"] - }, - "TransformationSteps": { - "type": "list", - "member": { - "shape": "TransformationStep" - } - }, - "TransformationType": { - "type": "string", - "enum": ["LANGUAGE_UPGRADE", "DOCUMENT_GENERATION"] - }, - "TransformationUploadArtifactType": { - "type": "string", - "enum": ["Dependencies", "ClientBuildResult"] - }, - "TransformationUploadContext": { - "type": "structure", - "required": ["jobId", "uploadArtifactType"], - "members": { - "jobId": { - "shape": "TransformationJobId" - }, - "uploadArtifactType": { - "shape": "TransformationUploadArtifactType" - } - } - }, - "TransformationUserActionStatus": { - "type": "string", - "enum": ["COMPLETED", "REJECTED"] - }, - "UUID": { - "type": "string", - "max": 36, - "min": 36 - }, - "UpdateUsageLimitQuotaExceededException": { - "type": "structure", - "required": ["message"], - "members": { - "message": { - "shape": "String" - } - }, - "documentation": "

Exception thrown when the number of usage limit update requests exceeds the monthly quota (default 3 requests per month)

", - "exception": true - }, - "UpdateUsageLimitsRequest": { - "type": "structure", - "required": ["accountId", "featureType", "requestedLimit"], - "members": { - "accountId": { - "shape": "String" - }, - "accountlessUserId": { - "shape": "String" - }, - "featureType": { - "shape": "UsageLimitType" - }, - "requestedLimit": { - "shape": "Long" - }, - "justification": { - "shape": "String" - } - } - }, - "UpdateUsageLimitsResponse": { - "type": "structure", - "required": ["status"], - "members": { - "status": { - "shape": "UsageLimitUpdateRequestStatus" - }, - "approvedLimit": { - "shape": "Long" - }, - "remainingRequestsThisMonth": { - "shape": "Integer" - } - } - }, - "UploadContext": { - "type": "structure", - "members": { - "taskAssistPlanningUploadContext": { - "shape": "TaskAssistPlanningUploadContext" - }, - "transformationUploadContext": { - "shape": "TransformationUploadContext" - }, - "codeAnalysisUploadContext": { - "shape": "CodeAnalysisUploadContext" - }, - "codeFixUploadContext": { - "shape": "CodeFixUploadContext" - }, - "workspaceContextUploadContext": { - "shape": "WorkspaceContextUploadContext" - } - }, - "union": true - }, - "UploadId": { - "type": "string", - "documentation": "

Upload ID returned by CreateUploadUrl API

", - "max": 128, - "min": 1 - }, - "UploadIntent": { - "type": "string", - "documentation": "

Upload Intent

", - "enum": [ - "TRANSFORMATION", - "TASK_ASSIST_PLANNING", - "AUTOMATIC_FILE_SECURITY_SCAN", - "FULL_PROJECT_SECURITY_SCAN", - "UNIT_TESTS_GENERATION", - "CODE_FIX_GENERATION", - "WORKSPACE_CONTEXT", - "AGENTIC_CODE_REVIEW" - ] - }, - "Url": { - "type": "string", - "max": 1024, - "min": 1 - }, - "UsageLimitList": { - "type": "structure", - "required": ["type", "currentUsage", "totalUsageLimit"], - "members": { - "type": { - "shape": "UsageLimitType" - }, - "currentUsage": { - "shape": "Long" - }, - "totalUsageLimit": { - "shape": "Long" - }, - "percentUsed": { - "shape": "Double" - } - } - }, - "UsageLimitType": { - "type": "string", - "enum": ["CODE_COMPLETIONS", "AGENTIC_REQUEST", "AI_EDITOR", "TRANSFORM"] - }, - "UsageLimitUpdateRequestStatus": { - "type": "string", - "enum": ["APPROVED", "PENDING_REVIEW", "REJECTED"] - }, - "UsageLimits": { - "type": "list", - "member": { - "shape": "UsageLimitList" - }, - "max": 10, - "min": 0 - }, - "UserContext": { - "type": "structure", - "required": ["ideCategory", "operatingSystem", "product"], - "members": { - "ideCategory": { - "shape": "IdeCategory" - }, - "operatingSystem": { - "shape": "OperatingSystem" - }, - "product": { - "shape": "UserContextProductString" - }, - "clientId": { - "shape": "UUID" - }, - "ideVersion": { - "shape": "String" - }, - "pluginVersion": { - "shape": "String" - }, - "lspVersion": { - "shape": "String" - } - } - }, - "UserContextProductString": { - "type": "string", - "max": 128, - "min": 1, - "pattern": "[-a-zA-Z0-9._]*" - }, - "UserInputMessage": { - "type": "structure", - "required": ["content"], - "members": { - "content": { - "shape": "UserInputMessageContentString", - "documentation": "

The content of the chat message.

" - }, - "userInputMessageContext": { - "shape": "UserInputMessageContext", - "documentation": "

Chat message context associated with the Chat Message.

" - }, - "userIntent": { - "shape": "UserIntent", - "documentation": "

User Intent.

" - }, - "origin": { - "shape": "Origin", - "documentation": "

User Input Origin.

" - }, - "images": { - "shape": "ImageBlocks", - "documentation": "

Images associated with the Chat Message.

" - }, - "modelId": { - "shape": "ModelId", - "documentation": "

Unique identifier for the model used in this conversation

" - } - }, - "documentation": "

Structure to represent a chat input message from User.

" - }, - "UserInputMessageContentString": { - "type": "string", - "max": 600000, - "min": 0, - "sensitive": true - }, - "UserInputMessageContext": { - "type": "structure", - "members": { - "editorState": { - "shape": "EditorState", - "documentation": "

Editor state chat message context.

" - }, - "shellState": { - "shape": "ShellState", - "documentation": "

Shell state chat message context.

" - }, - "gitState": { - "shape": "GitState", - "documentation": "

Git state chat message context.

" - }, - "envState": { - "shape": "EnvState", - "documentation": "

Environment state chat message context.

" - }, - "appStudioContext": { - "shape": "AppStudioState", - "documentation": "

The state of a user's AppStudio UI when sending a message.

" - }, - "diagnostic": { - "shape": "Diagnostic", - "documentation": "

Diagnostic chat message context.

" - }, - "consoleState": { - "shape": "ConsoleState", - "documentation": "

Contextual information about the environment from which the user is calling.

" - }, - "userSettings": { - "shape": "UserSettings", - "documentation": "

Settings information, e.g., whether the user has enabled cross-region API calls.

" - }, - "additionalContext": { - "shape": "AdditionalContentList", - "documentation": "

List of additional contextual content entries that can be included with the message.

" - }, - "toolResults": { - "shape": "ToolResults", - "documentation": "

ToolResults for the requested ToolUses.

" - }, - "tools": { - "shape": "Tools", - "documentation": "

Tools that can be used.

" - } - }, - "documentation": "

Additional Chat message context associated with the Chat Message

" - }, - "UserIntent": { - "type": "string", - "documentation": "

User Intent

", - "enum": [ - "SUGGEST_ALTERNATE_IMPLEMENTATION", - "APPLY_COMMON_BEST_PRACTICES", - "IMPROVE_CODE", - "SHOW_EXAMPLES", - "CITE_SOURCES", - "EXPLAIN_LINE_BY_LINE", - "EXPLAIN_CODE_SELECTION", - "GENERATE_CLOUDFORMATION_TEMPLATE", - "GENERATE_UNIT_TESTS", - "CODE_GENERATION" - ] - }, - "UserModificationEvent": { - "type": "structure", - "required": [ - "sessionId", - "requestId", - "programmingLanguage", - "modificationPercentage", - "timestamp", - "acceptedCharacterCount", - "unmodifiedAcceptedCharacterCount" - ], - "members": { - "sessionId": { - "shape": "UUID" - }, - "requestId": { - "shape": "UUID" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage" - }, - "modificationPercentage": { - "shape": "Double" - }, - "customizationArn": { - "shape": "CustomizationArn" - }, - "timestamp": { - "shape": "Timestamp" - }, - "acceptedCharacterCount": { - "shape": "PrimitiveInteger" - }, - "unmodifiedAcceptedCharacterCount": { - "shape": "PrimitiveInteger" - }, - "addedCharacterCount": { - "shape": "UserModificationEventAddedCharacterCountInteger" - }, - "unmodifiedAddedCharacterCount": { - "shape": "UserModificationEventUnmodifiedAddedCharacterCountInteger" - } - } - }, - "UserModificationEventAddedCharacterCountInteger": { - "type": "integer", - "min": 0 - }, - "UserModificationEventUnmodifiedAddedCharacterCountInteger": { - "type": "integer", - "min": 0 - }, - "UserSettings": { - "type": "structure", - "members": { - "hasConsentedToCrossRegionCalls": { - "shape": "Boolean" - } - }, - "documentation": "

Settings information passed by the Q widget

" - }, - "UserTriggerDecisionEvent": { - "type": "structure", - "required": [ - "sessionId", - "requestId", - "programmingLanguage", - "completionType", - "suggestionState", - "recommendationLatencyMilliseconds", - "timestamp" - ], - "members": { - "sessionId": { - "shape": "UUID" - }, - "requestId": { - "shape": "UUID" - }, - "customizationArn": { - "shape": "CustomizationArn" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage" - }, - "completionType": { - "shape": "CompletionType" - }, - "suggestionState": { - "shape": "SuggestionState" - }, - "recommendationLatencyMilliseconds": { - "shape": "Double" - }, - "timestamp": { - "shape": "Timestamp" - }, - "triggerToResponseLatencyMilliseconds": { - "shape": "Double" - }, - "suggestionReferenceCount": { - "shape": "PrimitiveInteger" - }, - "generatedLine": { - "shape": "PrimitiveInteger" - }, - "numberOfRecommendations": { - "shape": "PrimitiveInteger" - }, - "perceivedLatencyMilliseconds": { - "shape": "Double" - }, - "acceptedCharacterCount": { - "shape": "PrimitiveInteger" - }, - "addedIdeDiagnostics": { - "shape": "IdeDiagnosticList" - }, - "removedIdeDiagnostics": { - "shape": "IdeDiagnosticList" - }, - "addedCharacterCount": { - "shape": "UserTriggerDecisionEventAddedCharacterCountInteger" - }, - "deletedCharacterCount": { - "shape": "UserTriggerDecisionEventDeletedCharacterCountInteger" - }, - "streakLength": { - "shape": "UserTriggerDecisionEventStreakLengthInteger" - }, - "suggestionType": { - "shape": "SuggestionType" - } - } - }, - "UserTriggerDecisionEventAddedCharacterCountInteger": { - "type": "integer", - "min": 0 - }, - "UserTriggerDecisionEventDeletedCharacterCountInteger": { - "type": "integer", - "min": 0 - }, - "UserTriggerDecisionEventStreakLengthInteger": { - "type": "integer", - "min": -1 - }, - "ValidationException": { - "type": "structure", - "required": ["message"], - "members": { - "message": { - "shape": "String" - }, - "reason": { - "shape": "ValidationExceptionReason" - } - }, - "documentation": "

This exception is thrown when the input fails to satisfy the constraints specified by the service.

", - "exception": true - }, - "ValidationExceptionReason": { - "type": "string", - "documentation": "

Reason for ValidationException

", - "enum": ["INVALID_CONVERSATION_ID", "CONTENT_LENGTH_EXCEEDS_THRESHOLD", "INVALID_KMS_GRANT"] - }, - "WorkspaceContext": { - "type": "structure", - "required": ["toggle"], - "members": { - "toggle": { - "shape": "OptInFeatureToggle" - } - } - }, - "WorkspaceContextUploadContext": { - "type": "structure", - "required": ["workspaceId", "relativePath", "programmingLanguage"], - "members": { - "workspaceId": { - "shape": "UUID" - }, - "relativePath": { - "shape": "SensitiveString" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage" - } - } - }, - "WorkspaceFolderList": { - "type": "list", - "member": { - "shape": "WorkspaceFolderListMemberString" - }, - "max": 100, - "min": 0 - }, - "WorkspaceFolderListMemberString": { - "type": "string", - "max": 4096, - "min": 1, - "sensitive": true - }, - "WorkspaceList": { - "type": "list", - "member": { - "shape": "WorkspaceMetadata" - } - }, - "WorkspaceMetadata": { - "type": "structure", - "required": ["workspaceId", "workspaceStatus"], - "members": { - "workspaceId": { - "shape": "UUID" - }, - "workspaceStatus": { - "shape": "WorkspaceStatus" - }, - "environmentAddress": { - "shape": "SensitiveString" - }, - "environmentId": { - "shape": "SensitiveString" - } - } - }, - "WorkspaceState": { - "type": "structure", - "required": ["uploadId", "programmingLanguage"], - "members": { - "uploadId": { - "shape": "UploadId", - "documentation": "

Upload ID representing an Upload using a PreSigned URL

" - }, - "programmingLanguage": { - "shape": "ProgrammingLanguage", - "documentation": "

Primary programming language of the Workspace

" - }, - "contextTruncationScheme": { - "shape": "ContextTruncationScheme", - "documentation": "

Workspace context truncation schemes based on usecase

" - } - }, - "documentation": "

Represents a Workspace state uploaded to S3 for Async Code Actions

" - }, - "WorkspaceStatus": { - "type": "string", - "enum": ["CREATED", "PENDING", "READY", "CONNECTED", "DELETING"] - }, - "timeBetweenChunks": { - "type": "list", - "member": { - "shape": "Double" - }, - "max": 100, - "min": 0 - } - } -} diff --git a/server/aws-lsp-codewhisperer/src/client/token/codewhisperer.ts b/server/aws-lsp-codewhisperer/src/client/token/codewhisperer.ts index 145073a7ba..9103897e18 100644 --- a/server/aws-lsp-codewhisperer/src/client/token/codewhisperer.ts +++ b/server/aws-lsp-codewhisperer/src/client/token/codewhisperer.ts @@ -1,49 +1,66 @@ -import { AWSError, Request, Service } from 'aws-sdk' -import { ServiceConfigurationOptions } from 'aws-sdk/lib/service' -const apiConfig = require('./bearer-token-service.json') -import CodeWhispererClient = require('./codewhispererbearertokenclient') -import { SDKInitializator, Logging } from '@aws/language-server-runtimes/server-interface' -// PROOF OF CONCEPT -// This client fiddling was copied from the AWS Toolkit for VS Code -// https://github.com/aws/aws-toolkit-vscode/blob/5d621c8405a8b20ffe571ad0ba10ae700178e051/src/shared/awsClientBuilder.ts#L68 -// We'll want to give this a common shape down in one of the core packages so -// that we can re-use it in other bearer token based clients. -export interface RequestExtras { - readonly service: AWS.Service - readonly operation: string - readonly params?: any -} +import { CodeWhispererRuntimeClient, CodeWhispererRuntimeClientConfig } from '@amzn/codewhisperer-runtime' +import { SDKInitializator, Logging, CredentialsProvider } from '@aws/language-server-runtimes/server-interface' +import { HttpResponse, HttpRequest } from '@smithy/types' -type RequestListener = (request: AWS.Request & RequestExtras) => void -export interface CodeWhispererTokenClientConfigurationOptions extends ServiceConfigurationOptions { - onRequestSetup?: RequestListener | RequestListener[] +export interface CodeWhispererTokenClientConfigurationOptions extends CodeWhispererRuntimeClientConfig { + // Add any custom options if needed } export function createCodeWhispererTokenClient( options: CodeWhispererTokenClientConfigurationOptions, sdkInitializator: SDKInitializator, - logging: Logging -): CodeWhispererClient { - return createService(options, sdkInitializator, logging) as CodeWhispererClient -} + logging: Logging, + credentialsProvider: CredentialsProvider, + shareCodeWhispererContentWithAWS: boolean +): CodeWhispererRuntimeClient { + logging.log( + `Passing client for class CodeWhispererRuntimeClient to sdkInitializator (v3) for additional setup (e.g. proxy)` + ) -function createService( - options: CodeWhispererTokenClientConfigurationOptions, - sdkInitializator: SDKInitializator, - logging: Logging -): Service { - const onRequest = options?.onRequestSetup ?? [] - const listeners = Array.isArray(onRequest) ? onRequest : [onRequest] - const opt = { ...options } - delete opt.onRequestSetup - logging.log(`Passing client for class Service to sdkInitializator (v2) for additional setup (e.g. proxy)`) - const client = sdkInitializator.v2(Service, { apiConfig, ...options } as any) - const originalClient = client.setupRequestListeners.bind(client) - - client.setupRequestListeners = (request: Request) => { - originalClient(request) - listeners.forEach(l => l(request as AWS.Request & RequestExtras)) - } + const client = sdkInitializator(CodeWhispererRuntimeClient, { + ...options, + }) + + // Add middleware for custom headers + client.middlewareStack.add( + next => async args => { + const request = args.request as HttpRequest + request.headers['x-amzn-codewhisperer-optout'] = `${!shareCodeWhispererContentWithAWS}` + + if (credentialsProvider.getConnectionType() === 'external_idp') { + request.headers['TokenType'] = 'EXTERNAL_IDP' + } + + return next(args) + }, + { step: 'build', priority: 'high' } + ) + + // Add middleware to capture HTTP headers + client.middlewareStack.add( + next => async args => { + const result = await next(args) + + // Store headers on the response metadata + if (result.response) { + const httpResponse = result.response as HttpResponse + if (httpResponse.headers && result.output?.$metadata) { + // Extend metadata to include headers + ;(result.output.$metadata as any).httpHeaders = httpResponse.headers + } + } + + return result + }, + { + step: 'deserialize', + name: 'captureHeaders', + priority: 'high', + } + ) return client } + +// Export the V3 client type for compatibility +export type CodeWhispererTokenClient = CodeWhispererRuntimeClient diff --git a/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts b/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts deleted file mode 100644 index 4c8018c84e..0000000000 --- a/server/aws-lsp-codewhisperer/src/client/token/codewhispererbearertokenclient.d.ts +++ /dev/null @@ -1,2191 +0,0 @@ - -/** - * THIS FILE IS AUTOGENERATED BY 'generateServiceClient.ts'. - * DO NOT EDIT BY HAND. - */ - -import {Request} from 'aws-sdk/lib/request'; -import {Response} from 'aws-sdk/lib/response'; -import {AWSError} from 'aws-sdk/lib/error'; -import {Service} from 'aws-sdk/lib/service'; -import {ServiceConfigurationOptions} from 'aws-sdk/lib/service'; -import {ConfigBase as Config} from 'aws-sdk/lib/config-base'; -interface Blob {} -declare class CodeWhispererBearerTokenClient extends Service { - /** - * Constructs a service object. This object has one method for each API operation. - */ - constructor(options?: CodeWhispererBearerTokenClient.Types.ClientConfiguration) - config: Config & CodeWhispererBearerTokenClient.Types.ClientConfiguration; - /** - * Creates a pre-signed, S3 write URL for uploading a repository zip archive. - */ - createArtifactUploadUrl(params: CodeWhispererBearerTokenClient.Types.CreateUploadUrlRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.CreateUploadUrlResponse) => void): Request; - /** - * Creates a pre-signed, S3 write URL for uploading a repository zip archive. - */ - createArtifactUploadUrl(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.CreateUploadUrlResponse) => void): Request; - /** - * - */ - createSubscriptionToken(params: CodeWhispererBearerTokenClient.Types.CreateSubscriptionTokenRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.CreateSubscriptionTokenResponse) => void): Request; - /** - * - */ - createSubscriptionToken(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.CreateSubscriptionTokenResponse) => void): Request; - /** - * API to create task assist conversation. - */ - createTaskAssistConversation(params: CodeWhispererBearerTokenClient.Types.CreateTaskAssistConversationRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.CreateTaskAssistConversationResponse) => void): Request; - /** - * API to create task assist conversation. - */ - createTaskAssistConversation(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.CreateTaskAssistConversationResponse) => void): Request; - /** - * Creates a pre-signed, S3 write URL for uploading a repository zip archive. - */ - createUploadUrl(params: CodeWhispererBearerTokenClient.Types.CreateUploadUrlRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.CreateUploadUrlResponse) => void): Request; - /** - * Creates a pre-signed, S3 write URL for uploading a repository zip archive. - */ - createUploadUrl(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.CreateUploadUrlResponse) => void): Request; - /** - * API to create a single user memory entry - */ - createUserMemoryEntry(params: CodeWhispererBearerTokenClient.Types.CreateUserMemoryEntryInput, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.CreateUserMemoryEntryOutput) => void): Request; - /** - * API to create a single user memory entry - */ - createUserMemoryEntry(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.CreateUserMemoryEntryOutput) => void): Request; - /** - * Create a workspace based on a workspace root - */ - createWorkspace(params: CodeWhispererBearerTokenClient.Types.CreateWorkspaceRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.CreateWorkspaceResponse) => void): Request; - /** - * Create a workspace based on a workspace root - */ - createWorkspace(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.CreateWorkspaceResponse) => void): Request; - /** - * API to delete task assist conversation. - */ - deleteTaskAssistConversation(params: CodeWhispererBearerTokenClient.Types.DeleteTaskAssistConversationRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.DeleteTaskAssistConversationResponse) => void): Request; - /** - * API to delete task assist conversation. - */ - deleteTaskAssistConversation(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.DeleteTaskAssistConversationResponse) => void): Request; - /** - * API to delete a single user memory entry - */ - deleteUserMemoryEntry(params: CodeWhispererBearerTokenClient.Types.DeleteUserMemoryEntryInput, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.DeleteUserMemoryEntryOutput) => void): Request; - /** - * API to delete a single user memory entry - */ - deleteUserMemoryEntry(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.DeleteUserMemoryEntryOutput) => void): Request; - /** - * Delete a workspace based on a workspaceId - */ - deleteWorkspace(params: CodeWhispererBearerTokenClient.Types.DeleteWorkspaceRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.DeleteWorkspaceResponse) => void): Request; - /** - * Delete a workspace based on a workspaceId - */ - deleteWorkspace(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.DeleteWorkspaceResponse) => void): Request; - /** - * Generate completions based on the provided file context in a paginated response. - */ - generateCompletions(params: CodeWhispererBearerTokenClient.Types.GenerateCompletionsRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GenerateCompletionsResponse) => void): Request; - /** - * Generate completions based on the provided file context in a paginated response. - */ - generateCompletions(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GenerateCompletionsResponse) => void): Request; - /** - * Gets the metadata of a code analysis job. - */ - getCodeAnalysis(params: CodeWhispererBearerTokenClient.Types.GetCodeAnalysisRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetCodeAnalysisResponse) => void): Request; - /** - * Gets the metadata of a code analysis job. - */ - getCodeAnalysis(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetCodeAnalysisResponse) => void): Request; - /** - * - */ - getCodeFixJob(params: CodeWhispererBearerTokenClient.Types.GetCodeFixJobRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetCodeFixJobResponse) => void): Request; - /** - * - */ - getCodeFixJob(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetCodeFixJobResponse) => void): Request; - /** - * API to get status of task assist code generation. - */ - getTaskAssistCodeGeneration(params: CodeWhispererBearerTokenClient.Types.GetTaskAssistCodeGenerationRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetTaskAssistCodeGenerationResponse) => void): Request; - /** - * API to get status of task assist code generation. - */ - getTaskAssistCodeGeneration(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetTaskAssistCodeGenerationResponse) => void): Request; - /** - * API to get test generation job. - */ - getTestGeneration(params: CodeWhispererBearerTokenClient.Types.GetTestGenerationRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetTestGenerationResponse) => void): Request; - /** - * API to get test generation job. - */ - getTestGeneration(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetTestGenerationResponse) => void): Request; - /** - * API to get code transformation status. - */ - getTransformation(params: CodeWhispererBearerTokenClient.Types.GetTransformationRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetTransformationResponse) => void): Request; - /** - * API to get code transformation status. - */ - getTransformation(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetTransformationResponse) => void): Request; - /** - * API to get code transformation status. - */ - getTransformationPlan(params: CodeWhispererBearerTokenClient.Types.GetTransformationPlanRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetTransformationPlanResponse) => void): Request; - /** - * API to get code transformation status. - */ - getTransformationPlan(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetTransformationPlanResponse) => void): Request; - /** - * Get the requested CodeWhisperer profile. - */ - getProfile(params: CodeWhispererBearerTokenClient.Types.GetProfileRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetProfileResponse) => void): Request; - /** - * Get the requested CodeWhisperer profile. - */ - getProfile(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetProfileResponse) => void): Request; - /** - * API to get current usage limits - */ - getUsageLimits(params: CodeWhispererBearerTokenClient.Types.GetUsageLimitsRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetUsageLimitsResponse) => void): Request; - /** - * API to get current usage limits - */ - getUsageLimits(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.GetUsageLimitsResponse) => void): Request; - /** - * - */ - listAvailableCustomizations(params: CodeWhispererBearerTokenClient.Types.ListAvailableCustomizationsRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListAvailableCustomizationsResponse) => void): Request; - /** - * - */ - listAvailableCustomizations(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListAvailableCustomizationsResponse) => void): Request; - /** - * - */ - listAvailableModels(params: CodeWhispererBearerTokenClient.Types.ListAvailableModelsRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListAvailableModelsResponse) => void): Request; - /** - * - */ - listAvailableModels(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListAvailableModelsResponse) => void): Request; - /** - * - */ - listAvailableProfiles(params: CodeWhispererBearerTokenClient.Types.ListAvailableProfilesRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListAvailableProfilesResponse) => void): Request; - /** - * - */ - listAvailableProfiles(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListAvailableProfilesResponse) => void): Request; - /** - * Lists the findings from a particular code analysis job. - */ - listCodeAnalysisFindings(params: CodeWhispererBearerTokenClient.Types.ListCodeAnalysisFindingsRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListCodeAnalysisFindingsResponse) => void): Request; - /** - * Lists the findings from a particular code analysis job. - */ - listCodeAnalysisFindings(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListCodeAnalysisFindingsResponse) => void): Request; - /** - * List events for agent activity - */ - listEvents(params: CodeWhispererBearerTokenClient.Types.ListEventsRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListEventsResponse) => void): Request; - /** - * List events for agent activity - */ - listEvents(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListEventsResponse) => void): Request; - /** - * Return configruations for each feature that has been setup for A/B testing. - */ - listFeatureEvaluations(params: CodeWhispererBearerTokenClient.Types.ListFeatureEvaluationsRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListFeatureEvaluationsResponse) => void): Request; - /** - * Return configruations for each feature that has been setup for A/B testing. - */ - listFeatureEvaluations(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListFeatureEvaluationsResponse) => void): Request; - /** - * API to list user memories - */ - listUserMemoryEntries(params: CodeWhispererBearerTokenClient.Types.ListUserMemoryEntriesInput, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListUserMemoryEntriesOutput) => void): Request; - /** - * API to list user memories - */ - listUserMemoryEntries(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListUserMemoryEntriesOutput) => void): Request; - /** - * List workspace metadata based on a workspace root - */ - listWorkspaceMetadata(params: CodeWhispererBearerTokenClient.Types.ListWorkspaceMetadataRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListWorkspaceMetadataResponse) => void): Request; - /** - * List workspace metadata based on a workspace root - */ - listWorkspaceMetadata(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ListWorkspaceMetadataResponse) => void): Request; - /** - * API to push telemetry events to CloudWatch, DataHub and EventBridge. - */ - pushTelemetryEvent(params: CodeWhispererBearerTokenClient.Types.PushTelemetryEventRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.PushTelemetryEventResponse) => void): Request; - /** - * API to push telemetry events to CloudWatch, DataHub and EventBridge. - */ - pushTelemetryEvent(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.PushTelemetryEventResponse) => void): Request; - /** - * API to resume transformation job. - */ - resumeTransformation(params: CodeWhispererBearerTokenClient.Types.ResumeTransformationRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ResumeTransformationResponse) => void): Request; - /** - * API to resume transformation job. - */ - resumeTransformation(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.ResumeTransformationResponse) => void): Request; - /** - * API to record telemetry events. - */ - sendTelemetryEvent(params: CodeWhispererBearerTokenClient.Types.SendTelemetryEventRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.SendTelemetryEventResponse) => void): Request; - /** - * API to record telemetry events. - */ - sendTelemetryEvent(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.SendTelemetryEventResponse) => void): Request; - /** - * Starts a code analysis job - */ - startCodeAnalysis(params: CodeWhispererBearerTokenClient.Types.StartCodeAnalysisRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.StartCodeAnalysisResponse) => void): Request; - /** - * Starts a code analysis job - */ - startCodeAnalysis(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.StartCodeAnalysisResponse) => void): Request; - /** - * - */ - startCodeFixJob(params: CodeWhispererBearerTokenClient.Types.StartCodeFixJobRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.StartCodeFixJobResponse) => void): Request; - /** - * - */ - startCodeFixJob(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.StartCodeFixJobResponse) => void): Request; - /** - * API to start task assist code generation. - */ - startTaskAssistCodeGeneration(params: CodeWhispererBearerTokenClient.Types.StartTaskAssistCodeGenerationRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.StartTaskAssistCodeGenerationResponse) => void): Request; - /** - * API to start task assist code generation. - */ - startTaskAssistCodeGeneration(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.StartTaskAssistCodeGenerationResponse) => void): Request; - /** - * API to start test generation. - */ - startTestGeneration(params: CodeWhispererBearerTokenClient.Types.StartTestGenerationRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.StartTestGenerationResponse) => void): Request; - /** - * API to start test generation. - */ - startTestGeneration(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.StartTestGenerationResponse) => void): Request; - /** - * API to start code translation. - */ - startTransformation(params: CodeWhispererBearerTokenClient.Types.StartTransformationRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.StartTransformationResponse) => void): Request; - /** - * API to start code translation. - */ - startTransformation(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.StartTransformationResponse) => void): Request; - /** - * API to stop code transformation status. - */ - stopTransformation(params: CodeWhispererBearerTokenClient.Types.StopTransformationRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.StopTransformationResponse) => void): Request; - /** - * API to stop code transformation status. - */ - stopTransformation(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.StopTransformationResponse) => void): Request; - /** - * API to update usage limits for enterprise customers - */ - updateUsageLimits(params: CodeWhispererBearerTokenClient.Types.UpdateUsageLimitsRequest, callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.UpdateUsageLimitsResponse) => void): Request; - /** - * API to update usage limits for enterprise customers - */ - updateUsageLimits(callback?: (err: AWSError, data: CodeWhispererBearerTokenClient.Types.UpdateUsageLimitsResponse) => void): Request; -} -declare namespace CodeWhispererBearerTokenClient { - export type ActivationToken = string; - export type ActiveFunctionalityList = FunctionalityName[]; - export interface AdditionalContentEntry { - /** - * The name/identifier for this context entry - */ - name: AdditionalContentEntryNameString; - /** - * A description of what this context entry represents - */ - description: AdditionalContentEntryDescriptionString; - /** - * The actual contextual content - */ - innerContext?: AdditionalContentEntryInnerContextString; - } - export type AdditionalContentEntryDescriptionString = string; - export type AdditionalContentEntryInnerContextString = string; - export type AdditionalContentEntryNameString = string; - export type AdditionalContentList = AdditionalContentEntry[]; - export type AgenticChatEventStatus = "SUCCEEDED"|"CANCELLED"|"FAILED"|string; - export interface AppStudioState { - /** - * The namespace of the context. Examples: 'ui.Button', 'ui.Table.DataSource', 'ui.Table.RowActions.Button', 'logic.invokeAWS', 'logic.JavaScript' - */ - namespace: AppStudioStateNamespaceString; - /** - * The name of the property. Examples: 'visibility', 'disability', 'value', 'code' - */ - propertyName: AppStudioStatePropertyNameString; - /** - * The value of the property. - */ - propertyValue?: AppStudioStatePropertyValueString; - /** - * Context about how the property is used - */ - propertyContext: AppStudioStatePropertyContextString; - } - export type AppStudioStateNamespaceString = string; - export type AppStudioStatePropertyContextString = string; - export type AppStudioStatePropertyNameString = string; - export type AppStudioStatePropertyValueString = string; - export interface ApplicationProperties { - tenantId: TenantId; - applicationArn: ResourceArn; - tenantUrl: Url; - applicationType: FunctionalityName; - } - export type ApplicationPropertiesList = ApplicationProperties[]; - export type ArtifactId = string; - export type ArtifactMap = {[key: string]: UploadId}; - export type ArtifactType = "SourceCode"|"BuiltJars"|string; - export interface AssistantResponseMessage { - messageId?: MessageId; - /** - * The content of the text message in markdown format. - */ - content: AssistantResponseMessageContentString; - /** - * Web References - */ - supplementaryWebLinks?: SupplementaryWebLinks; - /** - * Code References - */ - references?: References; - /** - * Followup Prompt - */ - followupPrompt?: FollowupPrompt; - /** - * ToolUse Request - */ - toolUses?: ToolUses; - } - export type AssistantResponseMessageContentString = string; - export type AttributesMap = {[key: string]: StringList}; - export type AttributesMapKeyString = string; - export type Base64EncodedPaginationToken = string; - export type Boolean = boolean; - export interface ByUserAnalytics { - s3Uri?: S3Uri; - toggle: OptInFeatureToggle; - } - export type ChangeLogGranularityType = "STANDARD"|"BUSINESS"|string; - export interface ChangeLogOptions { - granularity: ChangeLogGranularityType; - } - export interface ChatAddMessageEvent { - conversationId: ConversationId; - messageId: MessageId; - customizationArn?: CustomizationArn; - userIntent?: UserIntent; - hasCodeSnippet?: Boolean; - programmingLanguage?: ProgrammingLanguage; - activeEditorTotalCharacters?: Integer; - timeToFirstChunkMilliseconds?: Double; - timeBetweenChunks?: timeBetweenChunks; - fullResponselatency?: Double; - requestLength?: Integer; - responseLength?: Integer; - numberOfCodeBlocks?: Integer; - hasProjectLevelContext?: Boolean; - result?: AgenticChatEventStatus; - } - export type ChatHistory = ChatMessage[]; - export interface ChatInteractWithMessageEvent { - conversationId: ConversationId; - messageId: MessageId; - customizationArn?: CustomizationArn; - interactionType?: ChatMessageInteractionType; - interactionTarget?: ChatInteractWithMessageEventInteractionTargetString; - acceptedCharacterCount?: Integer; - acceptedLineCount?: Integer; - acceptedSnippetHasReference?: Boolean; - hasProjectLevelContext?: Boolean; - userIntent?: UserIntent; - addedIdeDiagnostics?: IdeDiagnosticList; - removedIdeDiagnostics?: IdeDiagnosticList; - } - export type ChatInteractWithMessageEventInteractionTargetString = string; - export interface ChatMessage { - userInputMessage?: UserInputMessage; - assistantResponseMessage?: AssistantResponseMessage; - } - export type ChatMessageInteractionType = "INSERT_AT_CURSOR"|"COPY_SNIPPET"|"COPY"|"CLICK_LINK"|"CLICK_BODY_LINK"|"CLICK_FOLLOW_UP"|"HOVER_REFERENCE"|"UPVOTE"|"DOWNVOTE"|string; - export type ChatTriggerType = "MANUAL"|"DIAGNOSTIC"|"INLINE_CHAT"|string; - export interface ChatUserModificationEvent { - conversationId: ConversationId; - customizationArn?: CustomizationArn; - messageId: MessageId; - programmingLanguage?: ProgrammingLanguage; - modificationPercentage: Double; - hasProjectLevelContext?: Boolean; - } - export type ClientId = string; - export type CodeAnalysisFindingsSchema = "codeanalysis/findings/1.0"|string; - export type CodeAnalysisScope = "FILE"|"PROJECT"|"AGENTIC"|string; - export type CodeAnalysisStatus = "Completed"|"Pending"|"Failed"|string; - export interface CodeAnalysisUploadContext { - codeScanName: CodeScanName; - } - export interface CodeCoverageEvent { - customizationArn?: CustomizationArn; - programmingLanguage: ProgrammingLanguage; - acceptedCharacterCount: PrimitiveInteger; - totalCharacterCount: PrimitiveInteger; - timestamp: Timestamp; - unmodifiedAcceptedCharacterCount?: PrimitiveInteger; - totalNewCodeCharacterCount?: PrimitiveInteger; - totalNewCodeLineCount?: PrimitiveInteger; - userWrittenCodeCharacterCount?: CodeCoverageEventUserWrittenCodeCharacterCountInteger; - userWrittenCodeLineCount?: CodeCoverageEventUserWrittenCodeLineCountInteger; - addedCharacterCount?: CodeCoverageEventAddedCharacterCountInteger; - } - export type CodeCoverageEventAddedCharacterCountInteger = number; - export type CodeCoverageEventUserWrittenCodeCharacterCountInteger = number; - export type CodeCoverageEventUserWrittenCodeLineCountInteger = number; - export interface CodeDescription { - /** - * An URI to open with more information about the diagnostic error. - */ - href: CodeDescriptionHrefString; - } - export type CodeDescriptionHrefString = string; - export interface CodeDiffMetadata { - codeDiffPath?: CodeDiffPath; - } - export type CodeDiffPath = string; - export interface CodeFixAcceptanceEvent { - jobId: String; - ruleId?: String; - detectorId?: String; - findingId?: String; - programmingLanguage?: ProgrammingLanguage; - linesOfCodeAccepted?: Integer; - charsOfCodeAccepted?: Integer; - } - export interface CodeFixGenerationEvent { - jobId: String; - ruleId?: String; - detectorId?: String; - findingId?: String; - programmingLanguage?: ProgrammingLanguage; - linesOfCodeGenerated?: Integer; - charsOfCodeGenerated?: Integer; - } - export type CodeFixJobStatus = "Succeeded"|"InProgress"|"Failed"|string; - export type CodeFixName = string; - export interface CodeFixUploadContext { - codeFixName: CodeFixName; - } - export type CodeGenerationId = string; - export interface CodeGenerationStatus { - status: CodeGenerationWorkflowStatus; - currentStage: CodeGenerationWorkflowStage; - } - export type CodeGenerationStatusDetail = string; - export type CodeGenerationWorkflowStage = "InitialCodeGeneration"|"CodeRefinement"|string; - export type CodeGenerationWorkflowStatus = "InProgress"|"Complete"|"Failed"|string; - export interface CodeScanEvent { - programmingLanguage: ProgrammingLanguage; - codeScanJobId: CodeScanJobId; - timestamp: Timestamp; - codeAnalysisScope?: CodeAnalysisScope; - } - export interface CodeScanFailedEvent { - programmingLanguage: ProgrammingLanguage; - codeScanJobId: CodeScanJobId; - timestamp: Timestamp; - codeAnalysisScope?: CodeAnalysisScope; - } - export type CodeScanJobId = string; - export type CodeScanName = string; - export interface CodeScanRemediationsEvent { - programmingLanguage?: ProgrammingLanguage; - CodeScanRemediationsEventType?: CodeScanRemediationsEventType; - timestamp?: Timestamp; - detectorId?: String; - findingId?: String; - ruleId?: String; - component?: String; - reason?: String; - result?: String; - includesFix?: Boolean; - } - export type CodeScanRemediationsEventType = "CODESCAN_ISSUE_HOVER"|"CODESCAN_ISSUE_APPLY_FIX"|"CODESCAN_ISSUE_VIEW_DETAILS"|string; - export interface CodeScanSucceededEvent { - programmingLanguage: ProgrammingLanguage; - codeScanJobId: CodeScanJobId; - timestamp: Timestamp; - numberOfFindings: PrimitiveInteger; - codeAnalysisScope?: CodeAnalysisScope; - } - export interface Completion { - content: CompletionContentString; - references?: References; - mostRelevantMissingImports?: Imports; - } - export type CompletionContentString = string; - export type CompletionType = "BLOCK"|"LINE"|string; - export type SuggestionType = "COMPLETIONS"|"EDITS"|string; - export type Completions = Completion[]; - export interface ConsoleState { - region?: String; - consoleUrl?: SensitiveString; - serviceId?: String; - serviceConsolePage?: String; - serviceSubconsolePage?: String; - taskName?: SensitiveString; - } - export type ContentChecksumType = "SHA_256"|string; - export type ContentType = "FILE"|"PROMPT"|"CODE"|"WORKSPACE"|string; - export type ContextTruncationScheme = "ANALYSIS"|"GUMBY"|string; - export type ConversationId = string; - export interface ConversationState { - /** - * Unique identifier for the chat conversation stream - */ - conversationId?: ConversationId; - /** - * Unique identifier for remote workspace - */ - workspaceId?: UUID; - /** - * Holds the history of chat messages. - */ - history?: ChatHistory; - /** - * Holds the current message being processed or displayed. - */ - currentMessage: ChatMessage; - /** - * Trigger Reason for Chat - */ - chatTriggerType: ChatTriggerType; - customizationArn?: ResourceArn; - } - export interface CreateSubscriptionTokenRequest { - clientToken?: IdempotencyToken; - statusOnly?: Boolean; - } - export interface CreateSubscriptionTokenResponse { - encodedVerificationUrl?: EncodedVerificationUrl; - token?: ActivationToken; - status: SubscriptionStatus; - } - export interface CreateTaskAssistConversationRequest { - profileArn?: ProfileArn; - } - export interface CreateTaskAssistConversationResponse { - conversationId: ConversationId; - } - export interface CreateUploadUrlRequest { - contentMd5?: CreateUploadUrlRequestContentMd5String; - contentChecksum?: CreateUploadUrlRequestContentChecksumString; - contentChecksumType?: ContentChecksumType; - contentLength?: CreateUploadUrlRequestContentLengthLong; - artifactType?: ArtifactType; - uploadIntent?: UploadIntent; - uploadContext?: UploadContext; - uploadId?: UploadId; - profileArn?: ProfileArn; - } - export type CreateUploadUrlRequestContentChecksumString = string; - export type CreateUploadUrlRequestContentLengthLong = number; - export type CreateUploadUrlRequestContentMd5String = string; - export interface CreateUploadUrlResponse { - uploadId: UploadId; - uploadUrl: PreSignedUrl; - kmsKeyArn?: ResourceArn; - requestHeaders?: RequestHeaders; - } - export interface CreateUserMemoryEntryInput { - memoryEntryString: CreateUserMemoryEntryInputMemoryEntryStringString; - origin: Origin; - /** - * ProfileArn for the managing Q Profile - */ - profileArn?: CreateUserMemoryEntryInputProfileArnString; - clientToken?: IdempotencyToken; - } - export type CreateUserMemoryEntryInputMemoryEntryStringString = string; - export type CreateUserMemoryEntryInputProfileArnString = string; - export interface CreateUserMemoryEntryOutput { - memoryEntry: MemoryEntry; - } - export interface CreateWorkspaceRequest { - workspaceRoot: CreateWorkspaceRequestWorkspaceRootString; - profileArn?: ProfileArn; - } - export type CreateWorkspaceRequestWorkspaceRootString = string; - export interface CreateWorkspaceResponse { - workspace: WorkspaceMetadata; - } - export interface CursorState { - /** - * Represents a cursor position in a Text Document - */ - position?: Position; - /** - * Represents a text selection in a Text Document - */ - range?: Range; - } - export interface Customization { - arn: CustomizationArn; - name?: CustomizationName; - description?: Description; - modelId?: ModelId; - } - export type CustomizationArn = string; - export type CustomizationName = string; - export type Customizations = Customization[]; - export interface DashboardAnalytics { - toggle: OptInFeatureToggle; - } - export interface DeleteTaskAssistConversationRequest { - conversationId: ConversationId; - profileArn?: ProfileArn; - } - export interface DeleteTaskAssistConversationResponse { - conversationId: ConversationId; - } - export interface DeleteUserMemoryEntryInput { - id: DeleteUserMemoryEntryInputIdString; - /** - * ProfileArn for the managing Q Profile - */ - profileArn?: DeleteUserMemoryEntryInputProfileArnString; - } - export type DeleteUserMemoryEntryInputIdString = string; - export type DeleteUserMemoryEntryInputProfileArnString = string; - export interface DeleteUserMemoryEntryOutput { - } - export interface DeleteWorkspaceRequest { - workspaceId: UUID; - profileArn?: ProfileArn; - } - export interface DeleteWorkspaceResponse { - } - export type Description = string; - export interface Diagnostic { - /** - * Diagnostics originating from a TextDocument - */ - textDocumentDiagnostic?: TextDocumentDiagnostic; - /** - * Diagnostics originating from a Runtime - */ - runtimeDiagnostic?: RuntimeDiagnostic; - } - export interface DiagnosticLocation { - uri: DiagnosticLocationUriString; - range: Range; - } - export type DiagnosticLocationUriString = string; - export interface DiagnosticRelatedInformation { - /** - * The location of this related diagnostic information. - */ - location: DiagnosticLocation; - /** - * The message of this related diagnostic information. - */ - message: DiagnosticRelatedInformationMessageString; - } - export type DiagnosticRelatedInformationList = DiagnosticRelatedInformation[]; - export type DiagnosticRelatedInformationMessageString = string; - export type DiagnosticSeverity = "ERROR"|"WARNING"|"INFORMATION"|"HINT"|string; - export type DiagnosticTag = "UNNECESSARY"|"DEPRECATED"|string; - export type DiagnosticTagList = DiagnosticTag[]; - export interface Dimension { - name?: DimensionNameString; - value?: DimensionValueString; - } - export type DimensionList = Dimension[]; - export type DimensionNameString = string; - export type DimensionValueString = string; - export type DocFolderLevel = "SUB_FOLDER"|"ENTIRE_WORKSPACE"|string; - export interface DocGenerationEvent { - conversationId: ConversationId; - numberOfAddChars?: PrimitiveInteger; - numberOfAddLines?: PrimitiveInteger; - numberOfAddFiles?: PrimitiveInteger; - userDecision?: DocUserDecision; - interactionType?: DocInteractionType; - userIdentity?: String; - numberOfNavigation?: PrimitiveInteger; - folderLevel?: DocFolderLevel; - } - export type DocInteractionType = "GENERATE_README"|"UPDATE_README"|"EDIT_README"|string; - export type DocUserDecision = "ACCEPT"|"REJECT"|string; - export interface DocV2AcceptanceEvent { - conversationId: ConversationId; - numberOfAddedChars: DocV2AcceptanceEventNumberOfAddedCharsInteger; - numberOfAddedLines: DocV2AcceptanceEventNumberOfAddedLinesInteger; - numberOfAddedFiles: DocV2AcceptanceEventNumberOfAddedFilesInteger; - userDecision: DocUserDecision; - interactionType: DocInteractionType; - numberOfNavigations: DocV2AcceptanceEventNumberOfNavigationsInteger; - folderLevel: DocFolderLevel; - } - export type DocV2AcceptanceEventNumberOfAddedCharsInteger = number; - export type DocV2AcceptanceEventNumberOfAddedFilesInteger = number; - export type DocV2AcceptanceEventNumberOfAddedLinesInteger = number; - export type DocV2AcceptanceEventNumberOfNavigationsInteger = number; - export interface DocV2GenerationEvent { - conversationId: ConversationId; - numberOfGeneratedChars: DocV2GenerationEventNumberOfGeneratedCharsInteger; - numberOfGeneratedLines: DocV2GenerationEventNumberOfGeneratedLinesInteger; - numberOfGeneratedFiles: DocV2GenerationEventNumberOfGeneratedFilesInteger; - interactionType?: DocInteractionType; - numberOfNavigations?: DocV2GenerationEventNumberOfNavigationsInteger; - folderLevel?: DocFolderLevel; - } - export type DocV2GenerationEventNumberOfGeneratedCharsInteger = number; - export type DocV2GenerationEventNumberOfGeneratedFilesInteger = number; - export type DocV2GenerationEventNumberOfGeneratedLinesInteger = number; - export type DocV2GenerationEventNumberOfNavigationsInteger = number; - export interface Document { - } - export interface DocumentSymbol { - /** - * Name of the Document Symbol - */ - name: DocumentSymbolNameString; - /** - * Symbol type - DECLARATION / USAGE - */ - type: SymbolType; - /** - * Symbol package / source for FullyQualified names - */ - source?: DocumentSymbolSourceString; - } - export type DocumentSymbolNameString = string; - export type DocumentSymbolSourceString = string; - export type DocumentSymbols = DocumentSymbol[]; - export interface DocumentationIntentContext { - scope?: DocumentationIntentContextScopeString; - type: DocumentationType; - changeLogOptions?: ChangeLogOptions; - } - export type DocumentationIntentContextScopeString = string; - export type DocumentationType = "README"|"CHANGE_LOG"|string; - export type Double = number; - export interface Edit { - content: EditContentString; - references?: References; - } - export type EditContentString = string; - export interface EditorState { - /** - * Represents currently edited file - */ - document?: TextDocument; - /** - * Position of the cursor - */ - cursorState?: CursorState; - /** - * Represents IDE provided relevant files - */ - relevantDocuments?: RelevantDocumentList; - /** - * Whether service should use relevant document in prompt - */ - useRelevantDocuments?: Boolean; - /** - * Represents IDE provided list of workspace folders - */ - workspaceFolders?: WorkspaceFolderList; - } - export type EncodedVerificationUrl = string; - export interface EnvState { - /** - * The name of the operating system in use - */ - operatingSystem?: EnvStateOperatingSystemString; - /** - * The current working directory of the environment - */ - currentWorkingDirectory?: EnvStateCurrentWorkingDirectoryString; - /** - * The environment variables set in the current environment - */ - environmentVariables?: EnvironmentVariables; - /** - * Local timezone offset of the client. For more information, see documentation https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset - */ - timezoneOffset?: EnvStateTimezoneOffsetInteger; - } - export type EnvStateCurrentWorkingDirectoryString = string; - export type EnvStateOperatingSystemString = string; - export type EnvStateTimezoneOffsetInteger = number; - export interface EnvironmentVariable { - /** - * The key of an environment variable - */ - key?: EnvironmentVariableKeyString; - /** - * The value of an environment variable - */ - value?: EnvironmentVariableValueString; - } - export type EnvironmentVariableKeyString = string; - export type EnvironmentVariableValueString = string; - export type EnvironmentVariables = EnvironmentVariable[]; - export type ErrorDetails = string; - export interface Event { - eventId: UUID; - generationId: UUID; - eventTimestamp: SyntheticTimestamp_date_time; - eventType: EventType; - eventBlob: EventBlob; - } - export type EventBlob = Buffer|Uint8Array|Blob|string; - export type EventList = Event[]; - export type EventType = string; - export interface ExternalIdentityDetails { - issuerUrl?: IssuerUrl; - clientId?: ClientId; - scimEndpoint?: String; - } - export interface FeatureDevCodeAcceptanceEvent { - conversationId: ConversationId; - linesOfCodeAccepted: FeatureDevCodeAcceptanceEventLinesOfCodeAcceptedInteger; - charactersOfCodeAccepted: FeatureDevCodeAcceptanceEventCharactersOfCodeAcceptedInteger; - programmingLanguage?: ProgrammingLanguage; - } - export type FeatureDevCodeAcceptanceEventCharactersOfCodeAcceptedInteger = number; - export type FeatureDevCodeAcceptanceEventLinesOfCodeAcceptedInteger = number; - export interface FeatureDevCodeGenerationEvent { - conversationId: ConversationId; - linesOfCodeGenerated: FeatureDevCodeGenerationEventLinesOfCodeGeneratedInteger; - charactersOfCodeGenerated: FeatureDevCodeGenerationEventCharactersOfCodeGeneratedInteger; - programmingLanguage?: ProgrammingLanguage; - } - export type FeatureDevCodeGenerationEventCharactersOfCodeGeneratedInteger = number; - export type FeatureDevCodeGenerationEventLinesOfCodeGeneratedInteger = number; - export interface FeatureDevEvent { - conversationId: ConversationId; - } - export interface FeatureEvaluation { - feature: FeatureName; - variation: FeatureVariation; - value: FeatureValue; - } - export type FeatureEvaluationsList = FeatureEvaluation[]; - export type FeatureName = string; - export interface FeatureValue { - boolValue?: Boolean; - doubleValue?: Double; - longValue?: Long; - stringValue?: FeatureValueStringType; - } - export type FeatureValueStringType = string; - export type FeatureVariation = string; - export interface FileContext { - leftFileContent: FileContextLeftFileContentString; - rightFileContent: FileContextRightFileContentString; - filename: FileContextFilenameString; - fileUri?: FileContextFileUriString; - programmingLanguage: ProgrammingLanguage; - } - export type FileContextFileUriString = string; - export type FileContextFilenameString = string; - export type FileContextLeftFileContentString = string; - export type FileContextRightFileContentString = string; - export interface FollowupPrompt { - /** - * The content of the text message in markdown format. - */ - content: FollowupPromptContentString; - /** - * User Intent - */ - userIntent?: UserIntent; - } - export type FollowupPromptContentString = string; - export type FunctionalityName = "COMPLETIONS"|"ANALYSIS"|"CONVERSATIONS"|"TASK_ASSIST"|"TRANSFORMATIONS"|"CHAT_CUSTOMIZATION"|"TRANSFORMATIONS_WEBAPP"|"FEATURE_DEVELOPMENT"|string; - export interface GenerateCompletionsRequest { - fileContext: FileContext; - editorState?: EditorState; - maxResults?: GenerateCompletionsRequestMaxResultsInteger; - predictionTypes?: PredictionTypes; - nextToken?: GenerateCompletionsRequestNextTokenString; - referenceTrackerConfiguration?: ReferenceTrackerConfiguration; - supplementalContexts?: SupplementalContextList; - customizationArn?: CustomizationArn; - optOutPreference?: OptOutPreference; - userContext?: UserContext; - profileArn?: ProfileArn; - workspaceId?: UUID; - modelId?: ModelId; - } - export type GenerateCompletionsRequestMaxResultsInteger = number; - export type GenerateCompletionsRequestNextTokenString = string; - export interface GenerateCompletionsResponse { - predictions?: Predictions; - completions?: Completions; - nextToken?: SensitiveString; - modelId?: ModelId; - } - export interface GetCodeAnalysisRequest { - jobId: GetCodeAnalysisRequestJobIdString; - profileArn?: ProfileArn; - } - export type GetCodeAnalysisRequestJobIdString = string; - export interface GetCodeAnalysisResponse { - status: CodeAnalysisStatus; - errorMessage?: SensitiveString; - } - export interface GetCodeFixJobRequest { - jobId: GetCodeFixJobRequestJobIdString; - profileArn?: ProfileArn; - } - export type GetCodeFixJobRequestJobIdString = string; - export interface GetCodeFixJobResponse { - jobStatus?: CodeFixJobStatus; - suggestedFix?: SuggestedFix; - } - export interface GetProfileRequest { - profileArn: ProfileArn; - } - export interface GetProfileResponse { - profile: ProfileInfo; - } - export interface GetTaskAssistCodeGenerationRequest { - conversationId: ConversationId; - codeGenerationId: CodeGenerationId; - profileArn?: ProfileArn; - } - export interface GetTaskAssistCodeGenerationResponse { - conversationId: ConversationId; - codeGenerationStatus: CodeGenerationStatus; - codeGenerationStatusDetail?: CodeGenerationStatusDetail; - codeGenerationRemainingIterationCount?: Integer; - codeGenerationTotalIterationCount?: Integer; - } - export interface GetTestGenerationRequest { - testGenerationJobGroupName: TestGenerationJobGroupName; - testGenerationJobId: UUID; - profileArn?: ProfileArn; - } - export interface GetTestGenerationResponse { - testGenerationJob?: TestGenerationJob; - } - export interface GetTransformationPlanRequest { - transformationJobId: TransformationJobId; - profileArn?: ProfileArn; - } - export interface GetTransformationPlanResponse { - transformationPlan: TransformationPlan; - } - export interface GetTransformationRequest { - transformationJobId: TransformationJobId; - profileArn?: ProfileArn; - } - export interface GetTransformationResponse { - transformationJob: TransformationJob; - } - export interface GetUsageLimitsRequest { - /** - * The ARN of the Q Developer profile. Required for enterprise customers, optional for Builder ID users. - */ - profileArn?: ProfileArn; - } - export interface GetUsageLimitsResponse { - limits: UsageLimits; - /** - * Number of days remaining until the usage metrics reset - */ - daysUntilReset: Integer; - } - export interface GitState { - /** - * The output of the command git status --porcelain=v1 -b - */ - status?: GitStateStatusString; - } - export type GitStateStatusString = string; - export type IdeCategory = "JETBRAINS"|"VSCODE"|"CLI"|"JUPYTER_MD"|"JUPYTER_SM"|"ECLIPSE"|"VISUAL_STUDIO"|string; - export interface IdeDiagnostic { - /** - * The range at which the message applies. - */ - range?: Range; - /** - * A human-readable string describing the source of the diagnostic - */ - source?: IdeDiagnosticSourceString; - /** - * Diagnostic Error type - */ - severity?: DiagnosticSeverity; - /** - * Type of the diagnostic - */ - ideDiagnosticType: IdeDiagnosticType; - } - export type IdeDiagnosticList = IdeDiagnostic[]; - export type IdeDiagnosticSourceString = string; - export type IdeDiagnosticType = "SYNTAX_ERROR"|"TYPE_ERROR"|"REFERENCE_ERROR"|"BEST_PRACTICE"|"SECURITY"|"OTHER"|string; - export type IdempotencyToken = string; - export interface IdentityDetails { - ssoIdentityDetails?: SSOIdentityDetails; - externalIdentityDetails?: ExternalIdentityDetails; - } - export interface ImageBlock { - format: ImageFormat; - source: ImageSource; - } - export type ImageBlocks = ImageBlock[]; - export type ImageFormat = "png"|"jpeg"|"gif"|"webp"|string; - export interface ImageSource { - bytes?: ImageSourceBytesBlob; - } - export type ImageSourceBytesBlob = Buffer|Uint8Array|Blob|string; - export interface Import { - statement?: ImportStatementString; - } - export type ImportStatementString = string; - export type Imports = Import[]; - export interface InlineChatEvent { - requestId: UUID; - timestamp: Timestamp; - inputLength?: PrimitiveInteger; - numSelectedLines?: PrimitiveInteger; - numSuggestionAddChars?: PrimitiveInteger; - numSuggestionAddLines?: PrimitiveInteger; - numSuggestionDelChars?: PrimitiveInteger; - numSuggestionDelLines?: PrimitiveInteger; - codeIntent?: Boolean; - userDecision?: InlineChatUserDecision; - responseStartLatency?: Double; - responseEndLatency?: Double; - programmingLanguage?: ProgrammingLanguage; - } - export type InlineChatUserDecision = "ACCEPT"|"REJECT"|"DISMISS"|string; - export type Integer = number; - export type Intent = "DEV"|"DOC"|string; - export interface IntentContext { - documentation?: DocumentationIntentContext; - } - export type IssuerUrl = string; - export type LineRangeList = Range[]; - export interface ListAvailableCustomizationsRequest { - maxResults?: ListAvailableCustomizationsRequestMaxResultsInteger; - nextToken?: Base64EncodedPaginationToken; - profileArn?: ProfileArn; - } - export type ListAvailableCustomizationsRequestMaxResultsInteger = number; - export interface ListAvailableCustomizationsResponse { - customizations: Customizations; - nextToken?: Base64EncodedPaginationToken; - } - export interface ListAvailableModelsRequest { - /** - * The origin context for which to list available models - */ - origin: Origin; - /** - * Maximum number of models to return in a single response - */ - maxResults?: ListAvailableModelsRequestMaxResultsInteger; - /** - * Token for retrieving the next page of results - */ - nextToken?: Base64EncodedPaginationToken; - /** - * ARN of the profile to use for model filtering - */ - profileArn?: ProfileArn; - /** - * Provider of AI models - */ - modelProvider?: ModelProvider; - } - export type ListAvailableModelsRequestMaxResultsInteger = number; - export interface ListAvailableModelsResponse { - /** - * List of available models - */ - models: Models; - /** - * Default model set by the client - */ - defaultModel?: Model; - /** - * Token for retrieving the next page of results - */ - nextToken?: Base64EncodedPaginationToken; - } - export interface ListAvailableProfilesRequest { - maxResults?: ListAvailableProfilesRequestMaxResultsInteger; - nextToken?: Base64EncodedPaginationToken; - } - export type ListAvailableProfilesRequestMaxResultsInteger = number; - export interface ListAvailableProfilesResponse { - profiles: ProfileList; - nextToken?: Base64EncodedPaginationToken; - } - export interface ListCodeAnalysisFindingsRequest { - jobId: ListCodeAnalysisFindingsRequestJobIdString; - nextToken?: PaginationToken; - codeAnalysisFindingsSchema: CodeAnalysisFindingsSchema; - profileArn?: ProfileArn; - } - export type ListCodeAnalysisFindingsRequestJobIdString = string; - export interface ListCodeAnalysisFindingsResponse { - nextToken?: PaginationToken; - codeAnalysisFindings: SensitiveString; - } - export interface ListEventsRequest { - conversationId: UUID; - maxResults?: ListEventsRequestMaxResultsInteger; - nextToken?: NextToken; - } - export type ListEventsRequestMaxResultsInteger = number; - export interface ListEventsResponse { - conversationId: UUID; - events: EventList; - nextToken?: NextToken; - } - export interface ListFeatureEvaluationsRequest { - userContext: UserContext; - profileArn?: ProfileArn; - } - export interface ListFeatureEvaluationsResponse { - featureEvaluations: FeatureEvaluationsList; - } - export interface ListUserMemoryEntriesInput { - maxResults?: ListUserMemoryEntriesInputMaxResultsInteger; - /** - * ProfileArn for the managing Q Profile - */ - profileArn?: ListUserMemoryEntriesInputProfileArnString; - nextToken?: ListUserMemoryEntriesInputNextTokenString; - } - export type ListUserMemoryEntriesInputMaxResultsInteger = number; - export type ListUserMemoryEntriesInputNextTokenString = string; - export type ListUserMemoryEntriesInputProfileArnString = string; - export interface ListUserMemoryEntriesOutput { - memoryEntries: MemoryEntryList; - nextToken?: ListUserMemoryEntriesOutputNextTokenString; - } - export type ListUserMemoryEntriesOutputNextTokenString = string; - export interface ListWorkspaceMetadataRequest { - workspaceRoot?: ListWorkspaceMetadataRequestWorkspaceRootString; - nextToken?: String; - maxResults?: Integer; - profileArn?: ProfileArn; - } - export type ListWorkspaceMetadataRequestWorkspaceRootString = string; - export interface ListWorkspaceMetadataResponse { - workspaces: WorkspaceList; - nextToken?: String; - } - export type Long = number; - export interface MCPConfiguration { - toggle: OptInFeatureToggle; - } - export interface MemoryEntry { - /** - * A unique identifier for a single memory entry - */ - id: MemoryEntryIdString; - memoryEntryString: MemoryEntryMemoryEntryStringString; - metadata: MemoryEntryMetadata; - } - export type MemoryEntryIdString = string; - export type MemoryEntryList = MemoryEntry[]; - export type MemoryEntryMemoryEntryStringString = string; - export interface MemoryEntryMetadata { - origin: Origin; - attributes?: AttributesMap; - createdAt: Timestamp; - updatedAt: Timestamp; - memoryStatus?: MemoryStatus; - } - export type MemoryStatus = "DECRYPTION_FAILURE"|"VALID"|string; - export type MessageId = string; - export interface MetricData { - metricName: MetricDataMetricNameString; - metricValue: Double; - timestamp: Timestamp; - product: MetricDataProductString; - dimensions?: DimensionList; - } - export type MetricDataMetricNameString = string; - export type MetricDataProductString = string; - export interface Model { - /** - * Unique identifier for the model - */ - modelId: ModelId; - /** - * User-facing display name - */ - modelName?: ModelName; - /** - * Description of the model - */ - description?: Description; - /** - * Technical metadata and capabilities of the model - */ - modelMetadata?: ModelMetadata; - } - export type ModelId = string; - export type ModelName = string; - export interface ModelMetadata { - /** - * Maximum number of input tokens the model can process - */ - maxInputTokens?: ModelMetadataMaxInputTokensInteger; - /** - * Whether the model supports image input processing - */ - supportsImages?: Boolean; - } - export type ModelMetadataMaxInputTokensInteger = number; - export type ModelProvider = "DEFAULT"|string; - export type Models = Model[]; - export type NextToken = string; - export type Notifications = NotificationsFeature[]; - export interface NotificationsFeature { - feature: FeatureName; - toggle: OptInFeatureToggle; - } - export type OperatingSystem = "MAC"|"WINDOWS"|"LINUX"|string; - export type OptInFeatureToggle = "ON"|"OFF"|string; - export interface OptInFeatures { - promptLogging?: PromptLogging; - byUserAnalytics?: ByUserAnalytics; - dashboardAnalytics?: DashboardAnalytics; - notifications?: Notifications; - workspaceContext?: WorkspaceContext; - mcpConfiguration?: MCPConfiguration; - } - export type OptOutPreference = "OPTIN"|"OPTOUT"|string; - export type Origin = "CHATBOT"|"CONSOLE"|"DOCUMENTATION"|"MARKETING"|"MOBILE"|"SERVICE_INTERNAL"|"UNIFIED_SEARCH"|"UNKNOWN"|"MD"|"IDE"|"SAGE_MAKER"|"CLI"|"AI_EDITOR"|"OPENSEARCH_DASHBOARD"|"GITLAB"|string; - export interface PackageInfo { - executionCommand?: SensitiveString; - buildCommand?: SensitiveString; - buildOrder?: PackageInfoBuildOrderInteger; - testFramework?: String; - packageSummary?: PackageInfoPackageSummaryString; - packagePlan?: PackageInfoPackagePlanString; - targetFileInfoList?: TargetFileInfoList; - } - export type PackageInfoBuildOrderInteger = number; - export type PackageInfoList = PackageInfo[]; - export type PackageInfoPackagePlanString = string; - export type PackageInfoPackageSummaryString = string; - export type PaginationToken = string; - export interface Position { - /** - * Line position in a document. - */ - line: Integer; - /** - * Character offset on a line in a document (zero-based) - */ - character: Integer; - } - export type PreSignedUrl = string; - export interface Prediction { - completion?: Completion; - edit?: Edit; - } - export type PredictionType = "COMPLETIONS"|"EDITS"|string; - export type PredictionTypes = PredictionType[]; - export type Predictions = Prediction[]; - export interface PreviousEditorStateMetadata { - timeOffset: Integer; - } - export type PrimitiveInteger = number; - export interface Profile { - arn: ProfileArn; - identityDetails?: IdentityDetails; - profileName: ProfileName; - description?: ProfileDescription; - referenceTrackerConfiguration?: ReferenceTrackerConfiguration; - kmsKeyArn?: ResourceArn; - activeFunctionalities?: ActiveFunctionalityList; - status?: ProfileStatus; - errorDetails?: ErrorDetails; - resourcePolicy?: ResourcePolicy; - profileType?: ProfileType; - optInFeatures?: OptInFeatures; - permissionUpdateRequired?: Boolean; - applicationProperties?: ApplicationPropertiesList; - } - export interface ProfileInfo { - arn: ProfileArn; - profileName?: ProfileName; - description?: ProfileDescription; - status?: ProfileStatus; - profileType?: ProfileType; - optInFeatures?: OptInFeatures; - } - export type ProfileArn = string; - export type ProfileDescription = string; - export type ProfileList = Profile[]; - export type ProfileName = string; - export type ProfileStatus = "ACTIVE"|"CREATING"|"CREATE_FAILED"|"UPDATING"|"UPDATE_FAILED"|"DELETING"|"DELETE_FAILED"|string; - export type ProfileType = "Q_DEVELOPER"|"CODEWHISPERER"|string; - export interface ProgrammingLanguage { - languageName: ProgrammingLanguageLanguageNameString; - } - export type ProgrammingLanguageLanguageNameString = string; - export type ProgressUpdates = TransformationProgressUpdate[]; - export interface PromptLogging { - s3Uri: S3Uri; - toggle: OptInFeatureToggle; - } - export interface PushTelemetryEventRequest { - clientToken?: IdempotencyToken; - eventType: String; - event: Document; - } - export interface PushTelemetryEventResponse { - } - export interface Range { - /** - * The range's start position. - */ - start: Position; - /** - * The range's end position. - */ - end: Position; - } - export type RecommendationsWithReferencesPreference = "BLOCK"|"ALLOW"|string; - export interface Reference { - /** - * License name - */ - licenseName?: ReferenceLicenseNameString; - /** - * Code Repsitory for the associated reference - */ - repository?: ReferenceRepositoryString; - /** - * Respository URL - */ - url?: ReferenceUrlString; - /** - * Span / Range for the Reference - */ - recommendationContentSpan?: Span; - } - export type ReferenceLicenseNameString = string; - export type ReferenceRepositoryString = string; - export interface ReferenceTrackerConfiguration { - recommendationsWithReferences: RecommendationsWithReferencesPreference; - } - export type ReferenceUrlString = string; - export type References = Reference[]; - export type RelevantDocumentList = RelevantTextDocument[]; - export interface RelevantTextDocument { - /** - * Filepath relative to the root of the workspace - */ - relativeFilePath: RelevantTextDocumentRelativeFilePathString; - /** - * The text document's language identifier. - */ - programmingLanguage?: ProgrammingLanguage; - /** - * Content of the text document - */ - text?: RelevantTextDocumentTextString; - /** - * DocumentSymbols parsed from a text document - */ - documentSymbols?: DocumentSymbols; - /** - * The type of content(file, prompt, symbol, or workspace) - */ - type?: ContentType; - } - export type RelevantTextDocumentRelativeFilePathString = string; - export type RelevantTextDocumentTextString = string; - export type RequestHeaderKey = string; - export type RequestHeaderValue = string; - export type RequestHeaders = {[key: string]: RequestHeaderValue}; - export type ResourceArn = string; - export interface ResourcePolicy { - effect: ResourcePolicyEffect; - } - export type ResourcePolicyEffect = "ALLOW"|"DENY"|string; - export interface ResumeTransformationRequest { - transformationJobId: TransformationJobId; - userActionStatus?: TransformationUserActionStatus; - profileArn?: ProfileArn; - } - export interface ResumeTransformationResponse { - transformationStatus: TransformationStatus; - } - export interface RuntimeDiagnostic { - /** - * A human-readable string describing the source of the diagnostic - */ - source: RuntimeDiagnosticSourceString; - /** - * Diagnostic Error type - */ - severity: DiagnosticSeverity; - /** - * The diagnostic's message. - */ - message: RuntimeDiagnosticMessageString; - } - export type RuntimeDiagnosticMessageString = string; - export type RuntimeDiagnosticSourceString = string; - export type S3Uri = string; - export interface SSOIdentityDetails { - instanceArn: ResourceArn; - oidcClientId: String; - ssoRegion?: SSORegion; - } - export type SSORegion = string; - export interface SendTelemetryEventRequest { - clientToken?: IdempotencyToken; - telemetryEvent: TelemetryEvent; - optOutPreference?: OptOutPreference; - userContext?: UserContext; - profileArn?: ProfileArn; - modelId?: ModelId; - } - export interface SendTelemetryEventResponse { - } - export interface SensitiveDocument { - } - export type SensitiveString = string; - export type ShellHistory = ShellHistoryEntry[]; - export interface ShellHistoryEntry { - /** - * The shell command that was run - */ - command: ShellHistoryEntryCommandString; - /** - * The directory the command was ran in - */ - directory?: ShellHistoryEntryDirectoryString; - /** - * The exit code of the command after it finished - */ - exitCode?: Integer; - /** - * The stdout from the command - */ - stdout?: ShellHistoryEntryStdoutString; - /** - * The stderr from the command - */ - stderr?: ShellHistoryEntryStderrString; - } - export type ShellHistoryEntryCommandString = string; - export type ShellHistoryEntryDirectoryString = string; - export type ShellHistoryEntryStderrString = string; - export type ShellHistoryEntryStdoutString = string; - export interface ShellState { - /** - * The name of the current shell - */ - shellName: ShellStateShellNameString; - /** - * The history previous shell commands for the current shell - */ - shellHistory?: ShellHistory; - } - export type ShellStateShellNameString = string; - export interface Span { - start?: SpanStartInteger; - end?: SpanEndInteger; - } - export type SpanEndInteger = number; - export type SpanStartInteger = number; - export interface StartCodeAnalysisRequest { - artifacts: ArtifactMap; - programmingLanguage: ProgrammingLanguage; - clientToken?: StartCodeAnalysisRequestClientTokenString; - scope?: CodeAnalysisScope; - codeScanName?: CodeScanName; - codeDiffMetadata?: CodeDiffMetadata; - profileArn?: ProfileArn; - languageModelId?: ModelId; - clientType?: Origin; - } - export type StartCodeAnalysisRequestClientTokenString = string; - export interface StartCodeAnalysisResponse { - jobId: StartCodeAnalysisResponseJobIdString; - status: CodeAnalysisStatus; - errorMessage?: SensitiveString; - } - export type StartCodeAnalysisResponseJobIdString = string; - export interface StartCodeFixJobRequest { - snippetRange: Range; - uploadId: UploadId; - description?: StartCodeFixJobRequestDescriptionString; - ruleId?: StartCodeFixJobRequestRuleIdString; - codeFixName?: CodeFixName; - referenceTrackerConfiguration?: ReferenceTrackerConfiguration; - profileArn?: ProfileArn; - } - export type StartCodeFixJobRequestDescriptionString = string; - export type StartCodeFixJobRequestRuleIdString = string; - export interface StartCodeFixJobResponse { - jobId?: StartCodeFixJobResponseJobIdString; - status?: CodeFixJobStatus; - } - export type StartCodeFixJobResponseJobIdString = string; - export interface StartTaskAssistCodeGenerationRequest { - conversationState: ConversationState; - workspaceState: WorkspaceState; - taskAssistPlan?: TaskAssistPlan; - codeGenerationId?: CodeGenerationId; - currentCodeGenerationId?: CodeGenerationId; - intent?: Intent; - intentContext?: IntentContext; - profileArn?: ProfileArn; - } - export interface StartTaskAssistCodeGenerationResponse { - conversationId: ConversationId; - codeGenerationId: CodeGenerationId; - } - export interface StartTestGenerationRequest { - uploadId: UploadId; - targetCodeList: TargetCodeList; - /** - * The content of user input. - */ - userInput: StartTestGenerationRequestUserInputString; - testGenerationJobGroupName?: TestGenerationJobGroupName; - clientToken?: StartTestGenerationRequestClientTokenString; - profileArn?: ProfileArn; - referenceTrackerConfiguration?: ReferenceTrackerConfiguration; - } - export type StartTestGenerationRequestClientTokenString = string; - export type StartTestGenerationRequestUserInputString = string; - export interface StartTestGenerationResponse { - testGenerationJob?: TestGenerationJob; - } - export interface StartTransformationRequest { - workspaceState: WorkspaceState; - transformationSpec: TransformationSpec; - profileArn?: ProfileArn; - } - export interface StartTransformationResponse { - transformationJobId: TransformationJobId; - } - export type StepId = string; - export interface StopTransformationRequest { - transformationJobId: TransformationJobId; - profileArn?: ProfileArn; - } - export interface StopTransformationResponse { - transformationStatus: TransformationStatus; - } - export type String = string; - export type StringList = StringListMemberString[]; - export type StringListMemberString = string; - export type SubscriptionStatus = "INACTIVE"|"ACTIVE"|string; - export interface SuggestedFix { - codeDiff?: SuggestedFixCodeDiffString; - description?: SuggestedFixDescriptionString; - references?: References; - } - export type SuggestedFixCodeDiffString = string; - export type SuggestedFixDescriptionString = string; - export type SuggestionState = "ACCEPT"|"REJECT"|"DISCARD"|"EMPTY"|"MERGE"|string; - export interface SupplementalContext { - filePath: SupplementalContextFilePathString; - content: SupplementalContextContentString; - type?: SupplementalContextType; - metadata?: SupplementalContextMetadata; - } - export type SupplementalContextContentString = string; - export type SupplementalContextFilePathString = string; - export type SupplementalContextList = SupplementalContext[]; - export interface SupplementalContextMetadata { - previousEditorStateMetadata?: PreviousEditorStateMetadata; - } - export type SupplementalContextType = "PreviousEditorState"|"WorkspaceContext"|string; - export interface SupplementaryWebLink { - /** - * URL of the web reference link. - */ - url: SupplementaryWebLinkUrlString; - /** - * Title of the web reference link. - */ - title: SupplementaryWebLinkTitleString; - /** - * Relevant text snippet from the link. - */ - snippet?: SupplementaryWebLinkSnippetString; - } - export type SupplementaryWebLinkSnippetString = string; - export type SupplementaryWebLinkTitleString = string; - export type SupplementaryWebLinkUrlString = string; - export type SupplementaryWebLinks = SupplementaryWebLink[]; - export type SymbolType = "DECLARATION"|"USAGE"|string; - export type SyntheticTimestamp_date_time = Date; - export interface TargetCode { - /** - * The file path relative to the root of the workspace, could be a single file or a folder. - */ - relativeTargetPath: TargetCodeRelativeTargetPathString; - targetLineRangeList?: LineRangeList; - } - export type TargetCodeList = TargetCode[]; - export type TargetCodeRelativeTargetPathString = string; - export interface TargetFileInfo { - filePath?: SensitiveString; - testFilePath?: SensitiveString; - testCoverage?: TargetFileInfoTestCoverageInteger; - fileSummary?: TargetFileInfoFileSummaryString; - filePlan?: TargetFileInfoFilePlanString; - codeReferences?: References; - numberOfTestMethods?: TargetFileInfoNumberOfTestMethodsInteger; - } - export type TargetFileInfoFilePlanString = string; - export type TargetFileInfoFileSummaryString = string; - export type TargetFileInfoList = TargetFileInfo[]; - export type TargetFileInfoNumberOfTestMethodsInteger = number; - export type TargetFileInfoTestCoverageInteger = number; - export type TaskAssistPlan = TaskAssistPlanStep[]; - export interface TaskAssistPlanStep { - /** - * File path on which the step is working on. - */ - filePath: TaskAssistPlanStepFilePathString; - /** - * Description on the step. - */ - description: TaskAssistPlanStepDescriptionString; - /** - * Start line number of the related changes. - */ - startLine?: TaskAssistPlanStepStartLineInteger; - /** - * End line number of the related changes. - */ - endLine?: TaskAssistPlanStepEndLineInteger; - /** - * Type of the action. - */ - action?: TaskAssistPlanStepAction; - } - export type TaskAssistPlanStepAction = "MODIFY"|"CREATE"|"DELETE"|"UNKNOWN"|string; - export type TaskAssistPlanStepDescriptionString = string; - export type TaskAssistPlanStepEndLineInteger = number; - export type TaskAssistPlanStepFilePathString = string; - export type TaskAssistPlanStepStartLineInteger = number; - export interface TaskAssistPlanningUploadContext { - conversationId: ConversationId; - } - export interface TelemetryEvent { - userTriggerDecisionEvent?: UserTriggerDecisionEvent; - codeCoverageEvent?: CodeCoverageEvent; - userModificationEvent?: UserModificationEvent; - codeScanEvent?: CodeScanEvent; - codeScanSucceededEvent?: CodeScanSucceededEvent; - codeScanFailedEvent?: CodeScanFailedEvent; - codeScanRemediationsEvent?: CodeScanRemediationsEvent; - codeFixGenerationEvent?: CodeFixGenerationEvent; - codeFixAcceptanceEvent?: CodeFixAcceptanceEvent; - metricData?: MetricData; - chatAddMessageEvent?: ChatAddMessageEvent; - chatInteractWithMessageEvent?: ChatInteractWithMessageEvent; - chatUserModificationEvent?: ChatUserModificationEvent; - terminalUserInteractionEvent?: TerminalUserInteractionEvent; - featureDevEvent?: FeatureDevEvent; - featureDevCodeGenerationEvent?: FeatureDevCodeGenerationEvent; - featureDevCodeAcceptanceEvent?: FeatureDevCodeAcceptanceEvent; - inlineChatEvent?: InlineChatEvent; - transformEvent?: TransformEvent; - docGenerationEvent?: DocGenerationEvent; - docV2GenerationEvent?: DocV2GenerationEvent; - docV2AcceptanceEvent?: DocV2AcceptanceEvent; - testGenerationEvent?: TestGenerationEvent; - } - export type TenantId = string; - export interface TerminalUserInteractionEvent { - terminalUserInteractionEventType?: TerminalUserInteractionEventType; - terminal?: String; - terminalVersion?: String; - shell?: String; - shellVersion?: String; - duration?: Integer; - timeToSuggestion?: Integer; - isCompletionAccepted?: Boolean; - cliToolCommand?: String; - } - export type TerminalUserInteractionEventType = "CODEWHISPERER_TERMINAL_TRANSLATION_ACTION"|"CODEWHISPERER_TERMINAL_COMPLETION_INSERTED"|string; - export interface TestGenerationEvent { - jobId: UUID; - groupName: TestGenerationJobGroupName; - timestamp?: Timestamp; - ideCategory?: IdeCategory; - programmingLanguage?: ProgrammingLanguage; - numberOfUnitTestCasesGenerated?: Integer; - numberOfUnitTestCasesAccepted?: Integer; - linesOfCodeGenerated?: Integer; - linesOfCodeAccepted?: Integer; - charsOfCodeGenerated?: Integer; - charsOfCodeAccepted?: Integer; - } - export interface TestGenerationJob { - testGenerationJobId: UUID; - testGenerationJobGroupName: TestGenerationJobGroupName; - status: TestGenerationJobStatus; - shortAnswer?: SensitiveString; - creationTime: Timestamp; - progressRate?: TestGenerationJobProgressRateInteger; - jobStatusReason?: String; - jobSummary?: TestGenerationJobJobSummaryString; - jobPlan?: TestGenerationJobJobPlanString; - packageInfoList?: PackageInfoList; - } - export type TestGenerationJobGroupName = string; - export type TestGenerationJobJobPlanString = string; - export type TestGenerationJobJobSummaryString = string; - export type TestGenerationJobProgressRateInteger = number; - export type TestGenerationJobStatus = "IN_PROGRESS"|"FAILED"|"COMPLETED"|string; - export interface TextDocument { - /** - * Filepath relative to the root of the workspace - */ - relativeFilePath: TextDocumentRelativeFilePathString; - /** - * The text document's language identifier. - */ - programmingLanguage?: ProgrammingLanguage; - /** - * Content of the text document - */ - text?: TextDocumentTextString; - /** - * DocumentSymbols parsed from a text document - */ - documentSymbols?: DocumentSymbols; - } - export interface TextDocumentDiagnostic { - /** - * Represents a Text Document associated with Diagnostic - */ - document: TextDocument; - /** - * The range at which the message applies. - */ - range: Range; - /** - * A human-readable string describing the source of the diagnostic - */ - source: SensitiveString; - /** - * Diagnostic Error type - */ - severity: DiagnosticSeverity; - /** - * The diagnostic's message. - */ - message: TextDocumentDiagnosticMessageString; - /** - * The diagnostic's code, which might appear in the user interface. - */ - code?: TextDocumentDiagnosticCodeString; - /** - * An optional property to describe the error code. - */ - codeDescription?: CodeDescription; - /** - * Additional metadata about the diagnostic. - */ - tags?: DiagnosticTagList; - /** - * an array of related diagnostic information, e.g. when symbol-names within a scope collide all definitions can be marked via this property. - */ - relatedInformation?: DiagnosticRelatedInformationList; - /** - * A data entry field that is preserved between a textDocument/publishDiagnostics notification and textDocument/codeAction request. - */ - data?: TextDocumentDiagnosticDataString; - } - export type TextDocumentDiagnosticCodeString = string; - export type TextDocumentDiagnosticDataString = string; - export type TextDocumentDiagnosticMessageString = string; - export type TextDocumentRelativeFilePathString = string; - export type TextDocumentTextString = string; - export type Timestamp = Date; - export interface Tool { - toolSpecification?: ToolSpecification; - } - export type ToolDescription = string; - export interface ToolInputSchema { - json?: SensitiveDocument; - } - export type ToolName = string; - export interface ToolResult { - toolUseId: ToolUseId; - /** - * Content of the tool result. - */ - content: ToolResultContent; - status?: ToolResultStatus; - } - export type ToolResultContent = ToolResultContentBlock[]; - export interface ToolResultContentBlock { - /** - * A tool result that is text. - */ - text?: ToolResultContentBlockTextString; - /** - * A tool result that is JSON format data. - */ - json?: SensitiveDocument; - } - export type ToolResultContentBlockTextString = string; - export type ToolResultStatus = "success"|"error"|string; - export type ToolResults = ToolResult[]; - export interface ToolSpecification { - inputSchema: ToolInputSchema; - name: ToolName; - description?: ToolDescription; - } - export interface ToolUse { - toolUseId: ToolUseId; - name: ToolName; - /** - * The input to pass to the tool. - */ - input: SensitiveDocument; - } - export type ToolUseId = string; - export type ToolUses = ToolUse[]; - export type Tools = Tool[]; - export interface TransformEvent { - jobId: TransformationJobId; - timestamp?: Timestamp; - ideCategory?: IdeCategory; - programmingLanguage?: ProgrammingLanguage; - linesOfCodeChanged?: Integer; - charsOfCodeChanged?: Integer; - linesOfCodeSubmitted?: Integer; - } - export type TransformationDotNetRuntimeEnv = "NET_5_0"|"NET_6_0"|"NET_7_0"|"NET_8_0"|"NET_9_0"|"NET_STANDARD_2_0"|string; - export interface TransformationDownloadArtifact { - downloadArtifactType?: TransformationDownloadArtifactType; - downloadArtifactId?: ArtifactId; - } - export type TransformationDownloadArtifactType = "ClientInstructions"|"Logs"|"GeneratedCode"|string; - export type TransformationDownloadArtifacts = TransformationDownloadArtifact[]; - export type TransformationJavaRuntimeEnv = "JVM_8"|"JVM_11"|"JVM_17"|"JVM_21"|string; - export interface TransformationJob { - jobId?: TransformationJobId; - transformationSpec?: TransformationSpec; - status?: TransformationStatus; - reason?: String; - creationTime?: Timestamp; - startExecutionTime?: Timestamp; - endExecutionTime?: Timestamp; - } - export type TransformationJobId = string; - export type TransformationLanguage = "JAVA_8"|"JAVA_11"|"JAVA_17"|"JAVA_21"|"C_SHARP"|"COBOL"|"PL_I"|"JCL"|string; - export type TransformationLanguages = TransformationLanguage[]; - export type TransformationMainframeRuntimeEnv = "MAINFRAME"|string; - export type TransformationOperatingSystemFamily = "WINDOWS"|"LINUX"|string; - export interface TransformationPlan { - transformationSteps: TransformationSteps; - } - export interface TransformationPlatformConfig { - operatingSystemFamily?: TransformationOperatingSystemFamily; - } - export interface TransformationProgressUpdate { - name: String; - status: TransformationProgressUpdateStatus; - description?: String; - startTime?: Timestamp; - endTime?: Timestamp; - downloadArtifacts?: TransformationDownloadArtifacts; - } - export type TransformationProgressUpdateStatus = "IN_PROGRESS"|"COMPLETED"|"FAILED"|"PAUSED"|"AWAITING_CLIENT_ACTION"|"SKIPPED"|string; - export interface TransformationProjectArtifactDescriptor { - sourceCodeArtifact?: TransformationSourceCodeArtifactDescriptor; - } - export interface TransformationProjectState { - language?: TransformationLanguage; - runtimeEnv?: TransformationRuntimeEnv; - platformConfig?: TransformationPlatformConfig; - projectArtifact?: TransformationProjectArtifactDescriptor; - } - export interface TransformationRuntimeEnv { - java?: TransformationJavaRuntimeEnv; - dotNet?: TransformationDotNetRuntimeEnv; - mainframe?: TransformationMainframeRuntimeEnv; - } - export interface TransformationSourceCodeArtifactDescriptor { - languages?: TransformationLanguages; - runtimeEnv?: TransformationRuntimeEnv; - } - export interface TransformationSpec { - transformationType?: TransformationType; - source?: TransformationProjectState; - target?: TransformationProjectState; - } - export type TransformationStatus = "CREATED"|"ACCEPTED"|"REJECTED"|"STARTED"|"PREPARING"|"PREPARED"|"PLANNING"|"PLANNED"|"TRANSFORMING"|"TRANSFORMED"|"FAILED"|"COMPLETED"|"PARTIALLY_COMPLETED"|"STOPPING"|"STOPPED"|"PAUSED"|"RESUMED"|string; - export interface TransformationStep { - id: StepId; - name: String; - description: String; - status: TransformationStepStatus; - progressUpdates?: ProgressUpdates; - startTime?: Timestamp; - endTime?: Timestamp; - } - export type TransformationStepStatus = "CREATED"|"COMPLETED"|"PARTIALLY_COMPLETED"|"STOPPED"|"FAILED"|"PAUSED"|"SKIPPED"|string; - export type TransformationSteps = TransformationStep[]; - export type TransformationType = "LANGUAGE_UPGRADE"|"DOCUMENT_GENERATION"|string; - export type TransformationUploadArtifactType = "Dependencies"|"ClientBuildResult"|string; - export interface TransformationUploadContext { - jobId: TransformationJobId; - uploadArtifactType: TransformationUploadArtifactType; - } - export type TransformationUserActionStatus = "COMPLETED"|"REJECTED"|string; - export type UUID = string; - export interface UpdateUsageLimitsRequest { - accountId: String; - accountlessUserId?: String; - featureType: UsageLimitType; - requestedLimit: Long; - justification?: String; - } - export interface UpdateUsageLimitsResponse { - status: UsageLimitUpdateRequestStatus; - approvedLimit?: Long; - remainingRequestsThisMonth?: Integer; - } - export interface UploadContext { - taskAssistPlanningUploadContext?: TaskAssistPlanningUploadContext; - transformationUploadContext?: TransformationUploadContext; - codeAnalysisUploadContext?: CodeAnalysisUploadContext; - codeFixUploadContext?: CodeFixUploadContext; - workspaceContextUploadContext?: WorkspaceContextUploadContext; - } - export type UploadId = string; - export type UploadIntent = "TRANSFORMATION"|"TASK_ASSIST_PLANNING"|"AUTOMATIC_FILE_SECURITY_SCAN"|"FULL_PROJECT_SECURITY_SCAN"|"UNIT_TESTS_GENERATION"|"CODE_FIX_GENERATION"|"WORKSPACE_CONTEXT"|"AGENTIC_CODE_REVIEW"|string; - export type Url = string; - export interface UsageLimitList { - type: UsageLimitType; - currentUsage: Long; - totalUsageLimit: Long; - percentUsed?: Double; - } - export type UsageLimitType = "CODE_COMPLETIONS"|"AGENTIC_REQUEST"|"AI_EDITOR"|"TRANSFORM"|string; - export type UsageLimitUpdateRequestStatus = "APPROVED"|"PENDING_REVIEW"|"REJECTED"|string; - export type UsageLimits = UsageLimitList[]; - export interface UserContext { - ideCategory: IdeCategory; - operatingSystem: OperatingSystem; - product: UserContextProductString; - clientId?: UUID; - ideVersion?: String; - pluginVersion?: String; - lspVersion?: String; - } - export type UserContextProductString = string; - export interface UserInputMessage { - /** - * The content of the chat message. - */ - content: UserInputMessageContentString; - /** - * Chat message context associated with the Chat Message. - */ - userInputMessageContext?: UserInputMessageContext; - /** - * User Intent. - */ - userIntent?: UserIntent; - /** - * User Input Origin. - */ - origin?: Origin; - /** - * Images associated with the Chat Message. - */ - images?: ImageBlocks; - /** - * Unique identifier for the model used in this conversation - */ - modelId?: ModelId; - } - export type UserInputMessageContentString = string; - export interface UserInputMessageContext { - /** - * Editor state chat message context. - */ - editorState?: EditorState; - /** - * Shell state chat message context. - */ - shellState?: ShellState; - /** - * Git state chat message context. - */ - gitState?: GitState; - /** - * Environment state chat message context. - */ - envState?: EnvState; - /** - * The state of a user's AppStudio UI when sending a message. - */ - appStudioContext?: AppStudioState; - /** - * Diagnostic chat message context. - */ - diagnostic?: Diagnostic; - /** - * Contextual information about the environment from which the user is calling. - */ - consoleState?: ConsoleState; - /** - * Settings information, e.g., whether the user has enabled cross-region API calls. - */ - userSettings?: UserSettings; - /** - * List of additional contextual content entries that can be included with the message. - */ - additionalContext?: AdditionalContentList; - /** - * ToolResults for the requested ToolUses. - */ - toolResults?: ToolResults; - /** - * Tools that can be used. - */ - tools?: Tools; - } - export type UserIntent = "SUGGEST_ALTERNATE_IMPLEMENTATION"|"APPLY_COMMON_BEST_PRACTICES"|"IMPROVE_CODE"|"SHOW_EXAMPLES"|"CITE_SOURCES"|"EXPLAIN_LINE_BY_LINE"|"EXPLAIN_CODE_SELECTION"|"GENERATE_CLOUDFORMATION_TEMPLATE"|"GENERATE_UNIT_TESTS"|"CODE_GENERATION"|string; - export interface UserModificationEvent { - sessionId: UUID; - requestId: UUID; - programmingLanguage: ProgrammingLanguage; - modificationPercentage: Double; - customizationArn?: CustomizationArn; - timestamp: Timestamp; - acceptedCharacterCount: PrimitiveInteger; - unmodifiedAcceptedCharacterCount: PrimitiveInteger; - addedCharacterCount?: UserModificationEventAddedCharacterCountInteger; - unmodifiedAddedCharacterCount?: UserModificationEventUnmodifiedAddedCharacterCountInteger; - } - export type UserModificationEventAddedCharacterCountInteger = number; - export type UserModificationEventUnmodifiedAddedCharacterCountInteger = number; - export interface UserSettings { - hasConsentedToCrossRegionCalls?: Boolean; - } - export interface UserTriggerDecisionEvent { - sessionId: UUID; - requestId: UUID; - customizationArn?: CustomizationArn; - programmingLanguage: ProgrammingLanguage; - completionType: CompletionType; - suggestionState: SuggestionState; - recommendationLatencyMilliseconds: Double; - timestamp: Timestamp; - triggerToResponseLatencyMilliseconds?: Double; - suggestionReferenceCount?: PrimitiveInteger; - generatedLine?: PrimitiveInteger; - numberOfRecommendations?: PrimitiveInteger; - perceivedLatencyMilliseconds?: Double; - acceptedCharacterCount?: PrimitiveInteger; - addedIdeDiagnostics?: IdeDiagnosticList; - removedIdeDiagnostics?: IdeDiagnosticList; - addedCharacterCount?: UserTriggerDecisionEventAddedCharacterCountInteger; - deletedCharacterCount?: UserTriggerDecisionEventDeletedCharacterCountInteger; - streakLength?: UserTriggerDecisionEventStreakLengthInteger; - suggestionType?: SuggestionType; - } - export type UserTriggerDecisionEventAddedCharacterCountInteger = number; - export type UserTriggerDecisionEventDeletedCharacterCountInteger = number; - export type UserTriggerDecisionEventStreakLengthInteger = number; - export interface WorkspaceContext { - toggle: OptInFeatureToggle; - } - export interface WorkspaceContextUploadContext { - workspaceId: UUID; - relativePath: SensitiveString; - programmingLanguage: ProgrammingLanguage; - } - export type WorkspaceFolderList = WorkspaceFolderListMemberString[]; - export type WorkspaceFolderListMemberString = string; - export type WorkspaceList = WorkspaceMetadata[]; - export interface WorkspaceMetadata { - workspaceId: UUID; - workspaceStatus: WorkspaceStatus; - environmentAddress?: SensitiveString; - environmentId?: SensitiveString; - } - export interface WorkspaceState { - /** - * Upload ID representing an Upload using a PreSigned URL - */ - uploadId: UploadId; - /** - * Primary programming language of the Workspace - */ - programmingLanguage: ProgrammingLanguage; - /** - * Workspace context truncation schemes based on usecase - */ - contextTruncationScheme?: ContextTruncationScheme; - } - export type WorkspaceStatus = "CREATED"|"PENDING"|"READY"|"CONNECTED"|"DELETING"|string; - export type timeBetweenChunks = Double[]; - /** - * A string in YYYY-MM-DD format that represents the latest possible API version that can be used in this service. Specify 'latest' to use the latest possible version. - */ - export type apiVersion = "2022-11-11"|"latest"|string; - export interface ClientApiVersions { - /** - * A string in YYYY-MM-DD format that represents the latest possible API version that can be used in this service. Specify 'latest' to use the latest possible version. - */ - apiVersion?: apiVersion; - } - export type ClientConfiguration = ServiceConfigurationOptions & ClientApiVersions; - /** - * Contains interfaces for use with the CodeWhispererBearerTokenClient client. - */ - export import Types = CodeWhispererBearerTokenClient; -} -export = CodeWhispererBearerTokenClient; - - \ No newline at end of file diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index e59513a799..844e8e4609 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -230,7 +230,7 @@ import { FALLBACK_MODEL_OPTIONS, FALLBACK_MODEL_RECORD, BEDROCK_MODEL_TO_MODEL_I import { DEFAULT_IMAGE_VERIFICATION_OPTIONS, verifyServerImage } from '../../shared/imageVerification' import { sanitize } from '@aws/lsp-core/out/util/path' import { ActiveUserTracker } from '../../shared/activeUserTracker' -import { UserContext } from '../../client/token/codewhispererbearertokenclient' +import { UserContext } from '@amzn/codewhisperer-runtime' import { CodeWhispererServiceToken } from '../../shared/codeWhispererService' import { DisplayFindings } from './tools/qCodeAnalysis/displayFindings' import { IDE } from '../../shared/constants' @@ -726,11 +726,13 @@ export class AgenticChatController implements ChatHandlers { // Wait for the response to be completed before proceeding this.#log('Model Response: ', JSON.stringify(responseResult, null, 2)) - models = Object.values(responseResult.models).map(({ modelId, modelName, description }) => ({ - id: modelId, - name: modelName ?? modelId, - description: description ?? '', - })) + if (responseResult.models) { + models = Object.values(responseResult.models).map(({ modelId, modelName, description }) => ({ + id: modelId ?? 'unknown', + name: modelName ?? modelId ?? 'unknown', + description: description ?? '', + })) + } defaultModelId = responseResult.defaultModel?.modelId // Cache the models with defaultModelId @@ -4942,10 +4944,12 @@ export class AgenticChatController implements ChatHandlers { codeWhispererServiceToken .listFeatureEvaluations({ userContext }) .then(result => { - const feature = result.featureEvaluations?.find(feature => - ['MaestroWorkspaceContext', 'SematicSearchTool'].includes(feature.feature) + const feature = result.featureEvaluations?.find( + feature => + feature.feature && + ['MaestroWorkspaceContext', 'SematicSearchTool'].includes(feature.feature) ) - if (feature) { + if (feature && feature.feature && feature.variation) { this.#abTestingAllocation = { experimentName: feature.feature, userVariation: feature.variation, diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts index 204bd31c42..7efd71c171 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts @@ -359,7 +359,7 @@ export class CodeReview { uploadResult: PrepareAndUploadArtifactsResult, chatStreamWriter: WritableStreamDefaultWriter | undefined ) { - let status = 'Pending' + let status: string | undefined = 'Pending' let attemptCount = 0 while (status === 'Pending' && attemptCount < CodeReview.MAX_POLLING_ATTEMPTS) { @@ -895,7 +895,14 @@ export class CodeReview { * @param programmingLanguage programming language * @returns Parsed and validated findings array */ - private parseFindings(findingsJson: string, jobId: string, programmingLanguage: string): CodeReviewFinding[] { + private parseFindings( + findingsJson: string | undefined, + jobId: string, + programmingLanguage: string + ): CodeReviewFinding[] { + if (findingsJson === undefined) { + return [] + } try { const findingsResponseJSON = JSON.parse(findingsJson) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts index 8f67ebab08..8d1ac616d8 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts @@ -36,7 +36,7 @@ export type PrepareAndUploadArtifactsResult = { export type StartCodeAnalysisResult = { jobId: string - status: string + status: string | undefined } export type CodeReviewResult = { diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/chatController.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/chatController.ts index 1edba5a82c..0128dbc37f 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/chatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/chatController.ts @@ -41,7 +41,7 @@ import { createAuthFollowUpResult, getAuthFollowUpType, getDefaultChatResponse } import { ChatSessionManagementService } from './chatSessionManagementService' import { ChatTelemetryController } from './telemetry/chatTelemetryController' import { QuickAction } from './quickActions' -import { getErrorMessage, isAwsError, isNullish, isObject } from '../../shared/utils' +import { getErrorId, getErrorMessage, isNullish, isObject, isServiceException } from '../../shared/utils' import { Metric } from '../../shared/telemetry/metric' import { QChatTriggerContext, TriggerContext } from './contexts/triggerContext' import { HELP_MESSAGE } from './constants' @@ -171,8 +171,11 @@ export class ChatController implements ChatHandlers { response = await session.sendMessage(requestInput) this.#log('Response for conversation id:', conversationIdentifier, JSON.stringify(response.$metadata)) } catch (err) { - if (isAwsError(err) || (isObject(err) && 'statusCode' in err && typeof err.statusCode === 'number')) { - metric.setDimension('cwsprChatRepsonseCode', (err as any).statusCode ?? 400) + if ( + isServiceException(err) || + (isObject(err) && 'statusCode' in err && typeof err.statusCode === 'number') + ) { + metric.setDimension('cwsprChatRepsonseCode', err.$metadata.httpStatusCode ?? 400) this.#telemetryController.emitMessageResponseError(params.tabId, metric.metric) } @@ -289,7 +292,7 @@ export class ChatController implements ChatHandlers { name: 'codewhisperer_inlineChatServiceInvocation', result: 'Failed', data: { - codewhispererRequestId: isAwsError(err) ? (err as any).requestId : undefined, + codewhispererRequestId: isServiceException(err) ? err.$metadata.requestId : undefined, codewhispererTriggerType: this.#inlineChatTriggerType, duration: this.#inlineChatResponseLatency, codewhispererLanguage: this.#inlineChatLanguage, @@ -302,8 +305,8 @@ export class ChatController implements ChatHandlers { }, errorData: { reason: err instanceof Error ? err.name : 'UnknownError', - errorCode: isAwsError(err) ? (err as any).code : undefined, - httpStatusCode: isAwsError(err) ? (err as any).statusCode : undefined, + errorCode: err instanceof Error ? getErrorId(err) : undefined, + httpStatusCode: isServiceException(err) ? err.$metadata.httpStatusCode : undefined, }, }) @@ -370,8 +373,8 @@ export class ChatController implements ChatHandlers { }, errorData: { reason: err instanceof Error ? err.name : 'UnknownError', - errorCode: isAwsError(err) ? (err as any).code : undefined, - httpStatusCode: isAwsError(err) ? (err as any).statusCode : undefined, + errorCode: err instanceof Error ? getErrorId(err) : undefined, + httpStatusCode: isServiceException(err) ? err.$metadata.httpStatusCode : undefined, }, }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts index 2088b31dcf..931d646f4b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts @@ -326,7 +326,7 @@ export class ChatTelemetryController { conversationId: conversationId, messageId: metric.cwsprChatMessageId, customizationArn: metric.codewhispererCustomizationArn, - userIntent: metric.cwsprChatUserIntent, + userIntent: metric.cwsprChatUserIntent as UserIntent, hasCodeSnippet: metric.cwsprChatHasCodeSnippet, programmingLanguage: metric.cwsprChatProgrammingLanguage as CodewhispererLanguage, activeEditorTotalCharacters: metric.cwsprChatActiveEditorTotalCharacters, diff --git a/server/aws-lsp-codewhisperer/src/language-server/configuration/qConfigurationServer.test.ts b/server/aws-lsp-codewhisperer/src/language-server/configuration/qConfigurationServer.test.ts index 97d3a084d6..312515fbb2 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/configuration/qConfigurationServer.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/configuration/qConfigurationServer.test.ts @@ -251,11 +251,11 @@ describe('ServerConfigurationProvider', () => { codeWhispererService = stubInterface() codeWhispererService.listAvailableCustomizations.resolves({ customizations: mockCustomizations, - $response: {} as any, + $metadata: {}, }) codeWhispererService.listAvailableProfiles.resolves({ profiles: [], - $response: {} as any, + $metadata: {}, }) testFeatures = new TestFeatures() @@ -365,14 +365,14 @@ describe('ServerConfigurationProvider', () => { // Return different customizations for each profile listAvailableCustomizationsForProfileAndRegionStub - .withArgs(mockProfiles[0].arn, mockProfiles[0].identityDetails!.region) + .withArgs(mockProfiles[0].arn!, mockProfiles[0].identityDetails!.region) .resolves([ { arn: 'customization1', name: 'Customization 1' }, { arn: 'customization2', name: 'Customization 2' }, ]) listAvailableCustomizationsForProfileAndRegionStub - .withArgs(mockProfiles[1].arn, mockProfiles[1].identityDetails!.region) + .withArgs(mockProfiles[1].arn!, mockProfiles[1].identityDetails!.region) .resolves([{ arn: 'customization3', name: 'Customization 3' }]) const result = await serverConfigurationProvider.listAllAvailableCustomizationsWithMetadata( @@ -438,11 +438,11 @@ describe('ServerConfigurationProvider', () => { // Return different customizations for each profile listAvailableCustomizationsForProfileAndRegionStub - .withArgs(mockProfiles[0].arn, mockProfiles[0].identityDetails!.region) + .withArgs(mockProfiles[0].arn!, mockProfiles[0].identityDetails!.region) .resolves([]) listAvailableCustomizationsForProfileAndRegionStub - .withArgs(mockProfiles[1].arn, mockProfiles[1].identityDetails!.region) + .withArgs(mockProfiles[1].arn!, mockProfiles[1].identityDetails!.region) .resolves([{ arn: 'customization3', name: 'Customization 3' }]) const result = await serverConfigurationProvider.listAllAvailableCustomizationsWithMetadata( @@ -509,7 +509,7 @@ describe('ServerConfigurationProvider', () => { // Return different customizations for each profile listAvailableCustomizationsForProfileAndRegionStub - .withArgs(mockProfiles[0].arn, mockProfiles[0].identityDetails!.region) + .withArgs(mockProfiles[0].arn!, mockProfiles[0].identityDetails!.region) .resolves([{ arn: 'customization1', name: 'Customization 1' }]) // Call with provided profiles @@ -561,12 +561,12 @@ describe('ServerConfigurationProvider', () => { // First profile succeeds listAvailableCustomizationsForProfileAndRegionStub - .withArgs(mockProfiles[0].arn, mockProfiles[0].identityDetails!.region) + .withArgs(mockProfiles[0].arn!, mockProfiles[0].identityDetails!.region) .resolves([{ arn: 'customization1', name: 'Customization 1' }]) // Second profile fails listAvailableCustomizationsForProfileAndRegionStub - .withArgs(mockProfiles[1].arn, mockProfiles[1].identityDetails!.region) + .withArgs(mockProfiles[1].arn!, mockProfiles[1].identityDetails!.region) .rejects(new Error('Failed to fetch customizations')) const result = await serverConfigurationProvider.listAllAvailableCustomizationsWithMetadata( diff --git a/server/aws-lsp-codewhisperer/src/language-server/configuration/qConfigurationServer.ts b/server/aws-lsp-codewhisperer/src/language-server/configuration/qConfigurationServer.ts index 5f96d526b1..7eca4c4233 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/configuration/qConfigurationServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/configuration/qConfigurationServer.ts @@ -13,7 +13,7 @@ import { getListAllAvailableProfilesHandler, ListAllAvailableProfilesHandler, } from '../../shared/amazonQServiceManager/qDeveloperProfiles' -import { Customization, Customizations } from '../../client/token/codewhispererbearertokenclient' +import { Customization } from '@amzn/codewhisperer-runtime' import { AmazonQTokenServiceManager } from '../../shared/amazonQServiceManager/AmazonQTokenServiceManager' import { AWS_Q_ENDPOINTS, Q_CONFIGURATION_SECTION } from '../../shared/constants' import { AmazonQError } from '../../shared/amazonQServiceManager/errors' @@ -120,7 +120,7 @@ export const QConfigurationServerToken = ): Promise => { const section = params.section - let customizations: Customizations | CustomizationWithMetadata[] = [] + let customizations: Customization[] | CustomizationWithMetadata[] = [] let developerProfiles: AmazonQDeveloperProfile[] = [] try { @@ -228,19 +228,22 @@ export class ServerConfigurationProvider { } } - async listAvailableCustomizations(): Promise { + async listAvailableCustomizations(): Promise { try { const customizations = ( await this.serviceManager.getCodewhispererService().listAvailableCustomizations({ maxResults: 100 }) ).customizations - return customizations + return customizations ?? [] } catch (error) { throw this.getResponseError(`${ON_GET_CONFIGURATION_FROM_SERVER_ERROR_PREFIX}${Q_CUSTOMIZATIONS}`, error) } } - async listAvailableCustomizationsForProfileAndRegion(profileArn: string, region: string): Promise { + async listAvailableCustomizationsForProfileAndRegion( + profileArn: string | undefined, + region: string + ): Promise { try { // Create a new service for the specific region const service = this.serviceManager.getServiceFactory()(region, AWS_Q_ENDPOINTS.get(region) || '') @@ -248,7 +251,7 @@ export class ServerConfigurationProvider { const customizations = (await service.listAvailableCustomizations({ maxResults: 100 })).customizations - return customizations + return customizations ?? [] } catch (error) { throw this.getResponseError(`${ON_GET_CONFIGURATION_FROM_SERVER_ERROR_PREFIX}${Q_CUSTOMIZATIONS}`, error) } @@ -289,11 +292,11 @@ export class ServerConfigurationProvider { return [ defaultCustomization, - ...customizations.map(customization => ({ + ...(customizations?.map(customization => ({ ...customization, isDefault: false, profile: profile, - })), + })) ?? []), ] }) .catch(error => { diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts index ade8e8ca7a..b86ec13356 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts @@ -10,7 +10,7 @@ import { } from '@aws/language-server-runtimes/server-interface' import { TestFeatures } from '@aws/language-server-runtimes/testing' import * as assert from 'assert' -import { AWSError } from 'aws-sdk' +import { ServiceException } from '@smithy/smithy-client' import sinon, { StubbedInstance } from 'ts-sinon' import { CodeWhispererServer, CodewhispererServerFactory } from './codeWhispererServer' import { @@ -764,12 +764,12 @@ describe('CodeWhisperer Server', () => { const secondCallArgs = service.generateSuggestions.secondCall.args[0] // Verify context truncation in first call - assert.strictEqual(firstCallArgs.fileContext.leftFileContent.length, CONTEXT_CHARACTERS_LIMIT) - assert.strictEqual(firstCallArgs.fileContext.rightFileContent.length, CONTEXT_CHARACTERS_LIMIT) + assert.strictEqual(firstCallArgs.fileContext?.leftFileContent?.length, CONTEXT_CHARACTERS_LIMIT) + assert.strictEqual(firstCallArgs.fileContext.rightFileContent?.length, CONTEXT_CHARACTERS_LIMIT) // Verify context truncation in second call (pagination) - assert.strictEqual(secondCallArgs.fileContext.leftFileContent.length, CONTEXT_CHARACTERS_LIMIT) - assert.strictEqual(secondCallArgs.fileContext.rightFileContent.length, CONTEXT_CHARACTERS_LIMIT) + assert.strictEqual(secondCallArgs.fileContext?.leftFileContent?.length, CONTEXT_CHARACTERS_LIMIT) + assert.strictEqual(secondCallArgs.fileContext.rightFileContent?.length, CONTEXT_CHARACTERS_LIMIT) // Verify second call included the nextToken assert.strictEqual(secondCallArgs.nextToken, EXPECTED_NEXT_TOKEN) @@ -1774,7 +1774,7 @@ describe('CodeWhisperer Server', () => { }, errorData: { reason: 'TestError', - errorCode: undefined, + errorCode: 'TestError', httpStatusCode: undefined, }, } @@ -1826,15 +1826,16 @@ describe('CodeWhisperer Server', () => { sinon.assert.calledOnceWithExactly(features.telemetry.emitMetric, expectedServiceInvocationMetric) }) - it('should emit Failure ServiceInvocation telemetry with request metadata on failed response with AWSError error type', async () => { - const error: AWSError = new Error('Fake Error') as AWSError - error.name = 'TestAWSError' - error.code = 'TestErrorStatusCode' - error.statusCode = 500 - error.time = new Date() - error.requestId = 'failed-request-id' - // Add $metadata to make isAwsError return true - ;(error as any).$metadata = {} + it('should emit Failure ServiceInvocation telemetry with request metadata on failed response with ServiceException error type', async () => { + const error = new ServiceException({ + name: 'TestServiceException', + $fault: 'client', + $metadata: { + httpStatusCode: 500, + requestId: 'failed-request-id', + }, + message: 'Fake Error', + }) service.generateSuggestions.callsFake(_request => { clock.tick(1000) @@ -1861,7 +1862,7 @@ describe('CodeWhisperer Server', () => { codewhispererLastSuggestionIndex: -1, codewhispererTriggerType: 'OnDemand', codewhispererAutomatedTriggerType: undefined, - reason: 'CodeWhisperer Invocation Exception: TestAWSError', + reason: 'CodeWhisperer Invocation Exception: TestServiceException', duration: 1000, codewhispererLineNumber: 0, codewhispererCursorOffset: 0, @@ -1877,8 +1878,8 @@ describe('CodeWhisperer Server', () => { traceId: 'notSet', }, errorData: { - reason: 'TestAWSError', - errorCode: 'TestErrorStatusCode', + reason: 'TestServiceException', + errorCode: 'TestServiceException', httpStatusCode: 500, }, } diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts index c9e1d25d66..2ea75f00dc 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts @@ -254,7 +254,7 @@ export class EditCompletionHandler { document: { relativeFilePath: textDocument.uri, programmingLanguage: { - languageName: generateCompletionReq.fileContext.programmingLanguage.languageName, + languageName: generateCompletionReq.fileContext?.programmingLanguage?.languageName, }, text: textDocument.getText(), }, @@ -393,15 +393,15 @@ export class EditCompletionHandler { .map(suggestion => { // Check if this suggestion is similar to a previously rejected edit const isSimilarToRejected = this.rejectedEditTracker.isSimilarToRejected( - suggestion.content, + suggestion.content ?? '', textDocument?.uri || '' ) const processedSuggestion = processEditSuggestion( - suggestion.content, + suggestion.content ?? '', session.startPosition, session.document, - session.requestContext.fileContext.rightFileContent + session.requestContext.fileContext?.rightFileContent ?? '' ) const isInlineEdit = processedSuggestion.type === SuggestionType.EDIT diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts index ed125e08ac..720f70389c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts @@ -16,7 +16,6 @@ import { import { autoTrigger, getAutoTriggerType, getNormalizeOsName, triggerType } from '../auto-trigger/autoTrigger' import { FileContext, - BaseGenerateSuggestionsRequest, CodeWhispererServiceToken, GenerateIAMSuggestionsRequest, GenerateTokenSuggestionsRequest, @@ -119,9 +118,11 @@ export class InlineCompletionHandler { try { const suggestionResponse = await codeWhispererService.generateSuggestions({ ...currentSession.requestContext, - fileContext: { - ...currentSession.requestContext.fileContext, - }, + fileContext: currentSession.requestContext.fileContext + ? { + ...currentSession.requestContext.fileContext, + } + : undefined, nextToken: `${params.partialResultToken}`, }) return await this.processSuggestionResponse( @@ -316,13 +317,13 @@ export class InlineCompletionHandler { // Add extra context to request context const { extraContext } = this.amazonQServiceManager.getConfiguration().inlineSuggestions - if (extraContext) { + if (extraContext && requestContext.fileContext) { requestContext.fileContext.leftFileContent = extraContext + '\n' + requestContext.fileContext.leftFileContent } // Create the appropriate request based on service type - let generateCompletionReq: BaseGenerateSuggestionsRequest + let generateCompletionReq: GenerateSuggestionsRequest if (codeWhispererService instanceof CodeWhispererServiceToken) { const tokenRequest = requestContext as GenerateTokenSuggestionsRequest @@ -432,7 +433,7 @@ export class InlineCompletionHandler { const { includeImportsWithSuggestions } = this.amazonQServiceManager.getConfiguration() const suggestionsWithRightContext = mergeSuggestionsWithRightContext( - session.requestContext.fileContext.rightFileContent, + session.requestContext.fileContext?.rightFileContent ?? '', filteredSuggestions, includeImportsWithSuggestions, selectionRange diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.ts index 7ad1389377..77107c726c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.ts @@ -3,6 +3,7 @@ import { LogInlineCompletionSessionResultsParams, Telemetry, } from '@aws/language-server-runtimes/server-interface' +import { IdeDiagnostic } from '@amzn/codewhisperer-runtime' import { SessionManager } from '../session/sessionManager' import { CodePercentageTracker } from '../tracker/codePercentageTracker' import { RejectedEditTracker } from '../tracker/rejectedEditTracker' @@ -41,7 +42,7 @@ export class SessionResultsHandler { fileUrl: session.document.uri, languageId: session.language, time: Date.now(), - originalString: originalString, + originalString: originalString ?? '', startPosition: session.startPosition, endPosition: endPosition, customizationArn: session.customizationArn, @@ -153,8 +154,8 @@ export class SessionResultsHandler { this.getTimeSinceLastUserModification(), addedLengthForEdits, deletedLengthForEdits, - addedDiagnostics, - removedDiagnostics, + addedDiagnostics as IdeDiagnostic[], + removedDiagnostics as IdeDiagnostic[], streakLength, Object.keys(params.completionSessionResult)[0] ) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry/telemetry.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry/telemetry.ts index e1a6ed5ffc..dc70bd4e22 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry/telemetry.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/telemetry/telemetry.ts @@ -1,18 +1,19 @@ -import { Telemetry, IdeDiagnostic } from '@aws/language-server-runtimes/server-interface' -import { AWSError } from 'aws-sdk' +import { Telemetry } from '@aws/language-server-runtimes/server-interface' +import { IdeDiagnostic } from '@amzn/codewhisperer-runtime' +import { ServiceException } from '@smithy/smithy-client' import { CodeWhispererSession, UserTriggerDecision } from '../session/sessionManager' import { CodeWhispererPerceivedLatencyEvent, CodeWhispererServiceInvocationEvent, } from '../../../shared/telemetry/types' -import { getCompletionType, isAwsError } from '../../../shared/utils' +import { getCompletionType, isServiceException, getErrorId } from '../../../shared/utils' import { TelemetryService } from '../../../shared/telemetry/telemetryService' import { SuggestionType } from '../../../shared/codeWhispererService' export const emitServiceInvocationTelemetry = ( telemetry: Telemetry, session: CodeWhispererSession, - requestId: string + requestId: string | undefined ) => { const duration = new Date().getTime() - session.startTime const data: CodeWhispererServiceInvocationEvent = { @@ -49,10 +50,10 @@ export const emitServiceInvocationTelemetry = ( export const emitServiceInvocationFailure = ( telemetry: Telemetry, session: CodeWhispererSession, - error: Error | AWSError + error: Error | ServiceException ) => { const duration = new Date().getTime() - session.startTime - const codewhispererRequestId = isAwsError(error) ? (error as any).requestId : undefined + const codewhispererRequestId = isServiceException(error) ? error.$metadata.requestId : undefined const data: CodeWhispererServiceInvocationEvent = { codewhispererRequestId: codewhispererRequestId, @@ -82,8 +83,8 @@ export const emitServiceInvocationFailure = ( data, errorData: { reason: error.name || 'UnknownError', - errorCode: isAwsError(error) ? (error as any).code : undefined, - httpStatusCode: isAwsError(error) ? (error as any).statusCode : undefined, + errorCode: getErrorId(error), + httpStatusCode: isServiceException(error) ? error.$metadata.httpStatusCode : undefined, }, }) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.ts index b0634a7748..c6451d7d82 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/mergeRightUtils.ts @@ -40,7 +40,7 @@ export const mergeSuggestionsWithRightContext = ( range?: Range ): InlineCompletionItemWithReferences[] => { return suggestions.map(suggestion => { - const insertText: string = truncateOverlapWithRightContext(rightFileContext, suggestion.content) + const insertText: string = truncateOverlapWithRightContext(rightFileContext, suggestion.content ?? '') let references = suggestion.references ?.filter( ref => diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/converter.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/converter.ts index dc29d20b57..bf97bc94e6 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/converter.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/converter.ts @@ -1,28 +1,22 @@ -import { AWSError } from 'aws-sdk' -import { PromiseResult } from 'aws-sdk/lib/request' import { StartTransformRequest, StartTransformResponse, TransformProjectMetadata } from './models' -import CodeWhispererTokenUserClient = require('../../client/token/codewhispererbearertokenclient') +import { + StartTransformationRequest, + StartTransformationResponse, + TransformationDotNetRuntimeEnv, +} from '@amzn/codewhisperer-runtime' import { Logging } from '@aws/language-server-runtimes/server-interface' -//sequence of targetFrameworkMap matters a lot because we are using as sorted indices of old to new .net versions -export const targetFrameworkMap = new Map([ - ['net8.0', 'NET_8_0'], - ['net9.0', 'NET_9_0'], - ['netstandard2.0', 'NET_STANDARD_2_0'], -]) - -const dummyVersionIndex = 999 - -const targetFrameworkKeysArray = Array.from(targetFrameworkMap.keys()) -function getKeyIndexOfVersion(key: any) { - return targetFrameworkKeysArray.indexOf(key) +const targetFrameworkRecord: Record = { + 'net8.0': 'NET_8_0', + 'net9.0': 'NET_9_0', + 'netstandard2.0': 'NET_STANDARD_2_0', } export function getCWStartTransformRequest( userInputRequest: StartTransformRequest, - uploadId: string, + uploadId: string | undefined, logging: Logging -): CodeWhispererTokenUserClient.StartTransformationRequest { +): StartTransformationRequest { return { workspaceState: { uploadId: uploadId, @@ -48,9 +42,7 @@ export function getCWStartTransformRequest( target: { language: 'C_SHARP', runtimeEnv: { - dotNet: targetFrameworkMap.has(userInputRequest.TargetFramework) - ? targetFrameworkMap.get(userInputRequest.TargetFramework) - : 'NET_8_0', + dotNet: targetFrameworkRecord[userInputRequest.TargetFramework] ?? 'NET_8_0', }, platformConfig: { operatingSystemFamily: 'LINUX', @@ -61,8 +53,8 @@ export function getCWStartTransformRequest( } export function getCWStartTransformResponse( - response: PromiseResult, - uploadId: string, + response: StartTransformationResponse, + uploadId: string | undefined, artifactPath: string, unsupportedProjects: string[], containsUnsupportedViews: boolean diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/metrics.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/metrics.ts index 9459eb3ee4..f40c79d7bf 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/metrics.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/metrics.ts @@ -1,5 +1,5 @@ import { Logging, Telemetry } from '@aws/language-server-runtimes/server-interface' -import { TransformationSpec } from '../../client/token/codewhispererbearertokenclient' +import { TransformationSpec } from '@amzn/codewhisperer-runtime' import { CancelTransformRequest, CancelTransformResponse, @@ -225,7 +225,7 @@ export const emitTransformationPlanReceivedTelemetry = ( ) => { const data: TransformationPlanReceivedEvent = { category: CODETRANSFORM_CATEGORY, - transformationJobId: jobId as string, + transformationJobId: jobId, transformationSteps: response.TransformationPlan.transformationSteps, } diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/models.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/models.ts index 5175403fd9..6b8eead1e4 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/models.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/models.ts @@ -1,5 +1,5 @@ import { ExecuteCommandParams } from 'vscode-languageserver' -import { TransformationJob, TransformationPlan } from '../../client/token/codewhispererbearertokenclient' +import { TransformationJob, TransformationPlan } from '@amzn/codewhisperer-runtime' /** * Error codes for transformation job failures. @@ -29,8 +29,8 @@ export interface StartTransformRequest extends ExecuteCommandParams { } export interface StartTransformResponse { - UploadId: string - TransformationJobId: string + UploadId: string | undefined + TransformationJobId: string | undefined ArtifactPath: string Error?: string IsSupported?: boolean diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/converter.test.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/converter.test.ts index 81c078e874..fb3d98f87b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/converter.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/converter.test.ts @@ -1,119 +1,31 @@ import { expect } from 'chai' -import { AWSError, HttpResponse } from 'aws-sdk' -import { PromiseResult } from 'aws-sdk/lib/request' -import { Response } from 'aws-sdk/lib/response' -import { StartTransformRequest, TransformProjectMetadata } from '../models' -import { getCWStartTransformRequest, getCWStartTransformResponse, targetFrameworkMap } from '../converter' -import CodeWhispererTokenUserClient = require('../../../client/token/codewhispererbearertokenclient') -import { Logging } from '@aws/language-server-runtimes/server-interface' -import { stubInterface } from 'ts-sinon' -import sinon = require('sinon') - -const mockedLogging = stubInterface() -const sampleStartTransformationRequest: CodeWhispererTokenUserClient.StartTransformationRequest = { - workspaceState: { - uploadId: '', - programmingLanguage: { - languageName: '', - }, - contextTruncationScheme: 'ANALYSIS', - }, - transformationSpec: { - transformationType: 'LANGUAGE_UPGRADE', - source: { - language: 'C_SHARP', - platformConfig: { - operatingSystemFamily: 'WINDOWS', - }, - }, - target: { - language: 'C_SHARP', - runtimeEnv: { - dotNet: '', - }, - platformConfig: { - operatingSystemFamily: 'LINUX', - }, - }, - }, -} - -const sampleUserInputRequest: StartTransformRequest = { - SolutionRootPath: '', - SolutionFilePath: '', - TargetFramework: '', - ProgramLanguage: '', - SelectedProjectPath: '', - SolutionConfigPaths: [], - ProjectMetadata: [ - { - Name: '', - ProjectPath: '', - ProjectLanguage: 'csharp', - ProjectType: '', - ExternalReferences: [], - ProjectTargetFramework: '', - SourceCodeFilePaths: [], - }, - ], - TransformNetStandardProjects: false, - EnableRazorViewTransform: false, - EnableWebFormsTransform: false, - command: '', - PackageReferences: [], -} - -function safeSet(obj: any, path: string[], value: any): void { - let current = obj - for (let i = 0; i < path.length - 1; i++) { - if (current[path[i]] === undefined) { - current[path[i]] = {} - } - current = current[path[i]] - } - current[path[path.length - 1]] = value -} +import { getCWStartTransformResponse } from '../converter' +import { StartTransformationCommandOutput, StartTransformationResponse } from '@amzn/codewhisperer-runtime' describe('Test Converter', () => { describe('Test get CW StartTransformResponse', () => { it('should return the correct StarTransformResponse object', () => { - const mockResponseData: CodeWhispererTokenUserClient.StartTransformationResponse = { + const mockResponseData: StartTransformationResponse = { transformationJobId: 'testJobId', } - const mockHttpResponse: HttpResponse = { - createUnbufferedStream: () => new XMLHttpRequest(), - statusCode: 200, - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(mockResponseData), - statusMessage: '', - streaming: false, + const mockCommandOutput: StartTransformationCommandOutput = { + ...mockResponseData, + $metadata: { + httpStatusCode: 200, + requestId: 'request-id-123', + attempts: 1, + totalRetryDelay: 0, + }, } - let mockResponse: Response = { - hasNextPage: () => false, - nextPage: () => null, - data: mockResponseData, - error: undefined, - requestId: 'request-id-123', - redirectCount: 0, - retryCount: 0, - httpResponse: mockHttpResponse, - } - - const mockPromiseResult: PromiseResult = - { - ...mockResponseData, - $response: mockResponse, - } - const uploadId = 'upload-id-456' const artifactPath = '/path/to/artifact' const unsupportedProjects = ['project1', 'project2'] const containsUnsupportedViews = true const result = getCWStartTransformResponse( - mockPromiseResult, + mockCommandOutput, uploadId, artifactPath, unsupportedProjects, diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/transformHandler.test.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/transformHandler.test.ts index efaa69e3cf..81c17a141c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/transformHandler.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/transformHandler.test.ts @@ -3,49 +3,26 @@ import { Logging, Workspace, SDKInitializator, - SDKClientConstructorV2, SDKClientConstructorV3, Runtime, } from '@aws/language-server-runtimes/server-interface' import * as assert from 'assert' -import { HttpResponse } from 'aws-sdk' import { expect } from 'chai' import * as fs from 'fs' import got from 'got' -import { StubbedInstance, default as simon, stubInterface } from 'ts-sinon' +import { StubbedInstance, stubInterface } from 'ts-sinon' import { StreamingClient, createStreamingClient } from '../../../client/streamingClient/codewhispererStreamingClient' import { CodeWhispererServiceToken } from '../../../shared/codeWhispererService' -import { - CancelTransformRequest, - CancellationJobStatus, - GetTransformPlanRequest, - GetTransformRequest, - StartTransformRequest, -} from '../models' +import { CancelTransformRequest, CancellationJobStatus, GetTransformPlanRequest, GetTransformRequest } from '../models' import { TransformHandler } from '../transformHandler' -import { EXAMPLE_REQUEST } from './mockData' import sinon = require('sinon') import { DEFAULT_AWS_Q_ENDPOINT_URL, DEFAULT_AWS_Q_REGION } from '../../../shared/constants' -import { Service } from 'aws-sdk' -import { ServiceConfigurationOptions } from 'aws-sdk/lib/service' import { Readable } from 'stream' import { ArtifactManager } from '../artifactManager' import path = require('path') import { IZipEntry } from 'adm-zip' import { AmazonQTokenServiceManager } from '../../../shared/amazonQServiceManager/AmazonQTokenServiceManager' -const mocked$Response = { - $response: { - hasNextPage: simon.mock(), - nextPage: simon.mock(), - data: undefined, - error: undefined, - requestId: '', - redirectCount: 0, - retryCount: 0, - httpResponse: new HttpResponse(), - }, -} const testUploadId = 'test-upoload-id' const testTransformId = 'test-transform-id' const payloadFileName = 'C:\\test.zip' @@ -81,7 +58,6 @@ describe('Test Transform handler ', () => { uploadId: testUploadId, uploadUrl: 'dummy-upload-url', kmsKeyArn: 'ResourceArn', - ...mocked$Response, }, 'dummy-256' ) @@ -103,7 +79,6 @@ describe('Test Transform handler ', () => { uploadId: testUploadId, uploadUrl: 'dummy-upload-url', kmsKeyArn: 'ResourceArn', - ...mocked$Response, }, 'dummy-256' ) @@ -127,7 +102,7 @@ describe('Test Transform handler ', () => { uploadId: testUploadId, uploadUrl: 'dummy-upload-url', kmsKeyArn: 'ResourceArn', - ...mocked$Response, + $metadata: {}, }) }) @@ -201,7 +176,7 @@ describe('Test Transform handler ', () => { client.codeModernizerStopCodeTransformation.returns( Promise.resolve({ transformationStatus: 'STOPPED', - ...mocked$Response, + $metadata: {}, }) ) }) @@ -218,7 +193,7 @@ describe('Test Transform handler ', () => { client.codeModernizerStopCodeTransformation.returns( Promise.resolve({ transformationStatus: 'COMPLETED', - ...mocked$Response, + $metadata: {}, }) ) @@ -235,14 +210,7 @@ describe('Test Transform handler ', () => { const mockSdkInitializator: SDKInitializator = Object.assign( // Default callable function for v3 clients - (Ctor: SDKClientConstructorV3, current_config: P): T => new Ctor({ ...current_config }), - // Property for v2 clients - { - v2: ( - Ctor: SDKClientConstructorV2, - current_config: P - ): T => new Ctor({ ...current_config }), - } + (Ctor: SDKClientConstructorV3, current_config: P): T => new Ctor({ ...current_config }) ) describe('StreamingClient', () => { @@ -280,9 +248,8 @@ describe('Test Transform handler ', () => { transformationJob: { jobId: testTransformId, status: 'COMPLETED', - ...mocked$Response, }, - ...mocked$Response, + $metadata: {}, }) ) }) @@ -304,9 +271,8 @@ describe('Test Transform handler ', () => { transformationJob: { jobId: testTransformId, status: 'FAILED', - ...mocked$Response, }, - ...mocked$Response, + $metadata: {}, }) ) }) @@ -356,9 +322,9 @@ describe('Test Transform handler ', () => { const request = JSON.parse(requestString) as GetTransformPlanRequest const res = await transformHandler.getTransformationPlan(request) - expect(res.TransformationPlan.transformationSteps[0].status).to.equal('COMPLETED') - expect(res.TransformationPlan.transformationSteps[0].name).to.equal('PlanStepName 1') - if (res.TransformationPlan.transformationSteps[0].progressUpdates) { + expect(res.TransformationPlan.transformationSteps?.[0].status).to.equal('COMPLETED') + expect(res.TransformationPlan.transformationSteps?.[0].name).to.equal('PlanStepName 1') + if (res.TransformationPlan.transformationSteps?.[0].progressUpdates) { expect(res.TransformationPlan.transformationSteps[0].progressUpdates[0].name).to.equal( 'ProgressUpdateName 1 for PlanStep 1' ) diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/validation.getTransformationErrorCode.test.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/validation.getTransformationErrorCode.test.ts index 0332c8400e..a951e61de4 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/validation.getTransformationErrorCode.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/tests/validation.getTransformationErrorCode.test.ts @@ -1,7 +1,7 @@ import { expect } from 'chai' import { TransformationErrorCode } from '../models' import { getTransformationErrorCode } from '../validation' -import { TransformationJob } from '../../../client/token/codewhispererbearertokenclient' +import { TransformationJob } from '@amzn/codewhisperer-runtime' describe('getTransformationErrorCode', () => { it('should return NONE when transformationJob is undefined', () => { diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/transformHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/transformHandler.ts index ee4f6f97cd..72c4f9fba1 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/transformHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/transformHandler.ts @@ -8,7 +8,7 @@ import { GetTransformationRequest, StopTransformationRequest, TransformationJob, -} from '../../client/token/codewhispererbearertokenclient' +} from '@amzn/codewhisperer-runtime' import { ArtifactManager } from './artifactManager' import { getCWStartTransformRequest, getCWStartTransformResponse } from './converter' import { @@ -95,7 +95,7 @@ export class TransformHandler { } } - async preTransformationUploadCode(payloadFilePath: string): Promise { + async preTransformationUploadCode(payloadFilePath: string): Promise { try { const uploadId = await this.uploadPayloadAsync(payloadFilePath) this.logging.log('Artifact was successfully uploaded. Upload tracking id: ' + uploadId) @@ -106,7 +106,7 @@ export class TransformHandler { } } - async uploadPayloadAsync(payloadFileName: string): Promise { + async uploadPayloadAsync(payloadFileName: string): Promise { const sha256 = await ArtifactManager.getSha256Async(payloadFileName) let response: CreateUploadUrlResponse try { @@ -144,7 +144,7 @@ export class TransformHandler { const headersObj = this.getHeadersObj(sha256, resp.kmsKeyArn) try { const fileStream = fs.createReadStream(fileName) - const response = await got.put(resp.uploadUrl, { + const response = await got.put(resp.uploadUrl ?? 'invalid-url', { body: fileStream, headers: headersObj, }) @@ -331,7 +331,7 @@ export class TransformHandler { break } - status = response.transformationJob.status! + status = response.transformationJob?.status! await this.sleep(10 * 1000) timer += 10 @@ -472,7 +472,11 @@ export class TransformHandler { return exponentialDelay + jitteredDelay // returns in milliseconds } - logSuggestionForFailureResponse(request: GetTransformRequest, job: TransformationJob, failureStates: string[]) { + logSuggestionForFailureResponse( + request: GetTransformRequest, + job: TransformationJob | undefined, + failureStates: string[] + ) { let status = job?.status ?? PollTransformationStatus.NOT_FOUND let reason = job?.reason ?? '' if (failureStates.includes(status)) { @@ -481,8 +485,7 @@ export class TransformHandler { suggestion = 'Please close Visual Studio, delete the directories where build artifacts are generated (e.g. bin and obj), and try running the transformation again.' } - this.logging - .log(`Transformation job for job ${request.TransformationJobId} is ${status} due to "${reason}". + this.logging.log(`Transformation job for job ${request.TransformationJobId} is ${status} due to "${reason}".                 ${suggestion}`) } } diff --git a/server/aws-lsp-codewhisperer/src/language-server/netTransform/validation.ts b/server/aws-lsp-codewhisperer/src/language-server/netTransform/validation.ts index efb443fb0f..4bd5b0a7c8 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/netTransform/validation.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/netTransform/validation.ts @@ -2,8 +2,8 @@ import * as fs from 'fs' import { StartTransformRequest, TransformProjectMetadata } from './models' import { supportedProjects, unsupportedViewComponents } from './resources/SupportedProjects' import { Logging } from '@aws/language-server-runtimes/server-interface' -import { TransformationJob } from '../../client/token/codewhispererbearertokenclient' import { TransformationErrorCode } from './models' +import { TransformationJob } from '@amzn/codewhisperer-runtime' /** * Project type validation moved to backend service. diff --git a/server/aws-lsp-codewhisperer/src/language-server/securityScan/codeWhispererSecurityScanServer.ts b/server/aws-lsp-codewhisperer/src/language-server/securityScan/codeWhispererSecurityScanServer.ts index 3eca7e77c8..a9593c1179 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/securityScan/codeWhispererSecurityScanServer.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/securityScan/codeWhispererSecurityScanServer.ts @@ -8,12 +8,11 @@ import { } from '@aws/language-server-runtimes/server-interface' import { performance } from 'perf_hooks' import { pathToFileURL } from 'url' -import { ArtifactMap } from '../../client/token/codewhispererbearertokenclient' import { DependencyGraphFactory } from './dependencyGraph/dependencyGraphFactory' import { getSupportedLanguageId, supportedSecurityScanLanguages } from '../../shared/languageDetection' import SecurityScanDiagnosticsProvider from './securityScanDiagnosticsProvider' import { SecurityScanCancelledError, SecurityScanHandler } from './securityScanHandler' -import { SecurityScanRequestParams, SecurityScanResponse } from './types' +import { ArtifactMap, SecurityScanRequestParams, SecurityScanResponse } from './types' import { SecurityScanEvent } from '../../shared/telemetry/types' import { getErrorMessage, parseJson } from '../../shared/utils' import { v4 as uuidv4 } from 'uuid' @@ -38,7 +37,7 @@ export const SecurityScanServerToken = */ logging.log(`Starting security scan`) await diagnosticsProvider.resetDiagnostics() - let jobStatus: string + let jobStatus: string | undefined const securityScanStartTime = performance.now() let serviceInvocationStartTime = 0 const securityScanTelemetryEntry: Partial = { diff --git a/server/aws-lsp-codewhisperer/src/language-server/securityScan/securityScanHandler.test.ts b/server/aws-lsp-codewhisperer/src/language-server/securityScan/securityScanHandler.test.ts index 6b6d045c3d..d2cd02608c 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/securityScan/securityScanHandler.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/securityScan/securityScanHandler.test.ts @@ -1,10 +1,9 @@ import { Logging, Workspace } from '@aws/language-server-runtimes/server-interface' import * as assert from 'assert' -import { HttpResponse } from 'aws-sdk' import got from 'got' import * as Sinon from 'sinon' import { StubbedInstance, default as simon, stubInterface } from 'ts-sinon' -import { StartCodeAnalysisRequest } from '../../client/token/codewhispererbearertokenclient' +import { ListCodeAnalysisFindingsRequest, StartCodeAnalysisRequest } from '@amzn/codewhisperer-runtime' import { CodeWhispererServiceToken } from '../../shared/codeWhispererService' import { SecurityScanHandler } from './securityScanHandler' import { RawCodeScanIssue } from './types' @@ -45,7 +44,7 @@ const mocked$Response = { requestId: '', redirectCount: 0, retryCount: 0, - httpResponse: new HttpResponse(), + httpResponse: {}, }, } @@ -71,6 +70,7 @@ describe('securityScanHandler', () => { uploadId: 'dummy-upload-id', uploadUrl: 'dummy-upload-url', kmsKeyArn: 'ResourceArn', + $metadata: {}, ...mocked$Response, }) putStub = Sinon.stub(got, 'put').resolves({ statusCode: 'Success' }) @@ -93,6 +93,7 @@ describe('securityScanHandler', () => { Promise.resolve({ jobId: 'dummy-job-id', status: 'Pending', + $metadata: {}, ...mocked$Response, }) ) @@ -118,6 +119,7 @@ describe('securityScanHandler', () => { // mock default return value for getCodeAnalysis client.getCodeAnalysis.resolves({ status: 'Pending', + $metadata: {}, ...mocked$Response, }) }) @@ -125,10 +127,12 @@ describe('securityScanHandler', () => { it('should change job status from pending to completed', async () => { client.getCodeAnalysis.onCall(0).resolves({ status: 'Pending', + $metadata: {}, ...mocked$Response, }) client.getCodeAnalysis.onCall(1).resolves({ status: 'Completed', + $metadata: {}, ...mocked$Response, }) const dummyJobId = 'dummy-job-id' @@ -142,10 +146,12 @@ describe('securityScanHandler', () => { it('should change job status from pending to failed', async () => { client.getCodeAnalysis.onCall(0).resolves({ status: 'Pending', + $metadata: {}, ...mocked$Response, }) client.getCodeAnalysis.onCall(1).resolves({ status: 'Failed', + $metadata: {}, ...mocked$Response, }) const dummyJobId = 'dummy-job-id' @@ -162,6 +168,7 @@ describe('securityScanHandler', () => { // mock default return value for listCodeAnalysisFindings client.listCodeAnalysisFindings.resolves({ codeAnalysisFindings: mockCodeScanFindings, + $metadata: {}, ...mocked$Response, }) workspace.fs.exists = simon.stub().resolves(true) @@ -171,7 +178,10 @@ describe('securityScanHandler', () => { const dummyJobId = 'dummy-job-id' const codeAnalysisFindingsSchema = 'codeanalysis/findings/1.0' const dummyProjectPath = 'C:\\workspace\\workspaceFolder\\python3.7-plain-sam-app\\hello_world' - const requestParams = { jobId: dummyJobId, codeAnalysisFindingsSchema } + const requestParams = { + jobId: dummyJobId, + codeAnalysisFindingsSchema, + } satisfies ListCodeAnalysisFindingsRequest const aggregatedCodeScanIssueList = await securityScanhandler.listScanResults(dummyJobId, dummyProjectPath) simon.assert.calledWith(client.listCodeAnalysisFindings, requestParams) @@ -181,12 +191,16 @@ describe('securityScanHandler', () => { it('should return zero issues', async () => { client.listCodeAnalysisFindings.resolves({ codeAnalysisFindings: '[]', + $metadata: {}, ...mocked$Response, }) const dummyJobId = 'dummy-job-id' const codeAnalysisFindingsSchema = 'codeanalysis/findings/1.0' const dummyProjectPath = 'C:\\workspace\\workspaceFolder\\python3.7-plain-sam-app\\hello_world' - const requestParams = { jobId: dummyJobId, codeAnalysisFindingsSchema } + const requestParams = { + jobId: dummyJobId, + codeAnalysisFindingsSchema, + } satisfies ListCodeAnalysisFindingsRequest const aggregatedCodeScanIssueList = await securityScanhandler.listScanResults(dummyJobId, dummyProjectPath) simon.assert.calledWith(client.listCodeAnalysisFindings, requestParams) diff --git a/server/aws-lsp-codewhisperer/src/language-server/securityScan/securityScanHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/securityScan/securityScanHandler.ts index cba587b706..da8eb47716 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/securityScan/securityScanHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/securityScan/securityScanHandler.ts @@ -10,15 +10,14 @@ import * as path from 'path' import * as ScanConstants from './constants' import { - ArtifactMap, CreateUploadUrlRequest, CreateUploadUrlResponse, GetCodeAnalysisRequest, ListCodeAnalysisFindingsRequest, StartCodeAnalysisRequest, -} from '../../client/token/codewhispererbearertokenclient' +} from '@amzn/codewhisperer-runtime' import { sleep } from './dependencyGraph/commonUtil' -import { AggregatedCodeScanIssue, RawCodeScanIssue } from './types' +import { AggregatedCodeScanIssue, ArtifactMap, RawCodeScanIssue } from './types' import { AmazonQTokenServiceManager } from '../../shared/amazonQServiceManager/AmazonQTokenServiceManager' export class SecurityScanHandler { @@ -65,7 +64,7 @@ export class SecurityScanHandler { try { this.logging.log('Prepare for uploading src context...') const response = await this.serviceManager.getCodewhispererService().createUploadUrl(request) - this.logging.log(`Request id: ${response.$response.requestId}`) + this.logging.log(`Request id: ${response.$metadata.requestId}`) this.logging.log(`Complete Getting presigned Url for uploading src context.`) this.logging.log(`Uploading src context...`) await this.uploadArtifactToS3(zipContent, response) @@ -99,7 +98,7 @@ export class SecurityScanHandler { 'Content-Type': 'application/zip', 'x-amz-server-side-encryption-context': Buffer.from(encryptionContext, 'utf8').toString('base64'), } - const response = await got.put(resp.uploadUrl, { + const response = await got.put(resp.uploadUrl ?? 'invalid-url', { body: zipBuffer, headers: resp?.requestHeaders ?? headersObj, }) @@ -118,16 +117,16 @@ export class SecurityScanHandler { this.logging.log(`Creating scan job...`) try { const resp = await this.serviceManager.getCodewhispererService().startCodeAnalysis(req) - this.logging.log(`Request id: ${resp.$response.requestId}`) + this.logging.log(`Request id: ${resp.$metadata.requestId}`) return resp } catch (error) { this.logging.log(`Error while creating scan job: ${error}`) throw error } } - async pollScanJobStatus(jobId: string) { + async pollScanJobStatus(jobId: string | undefined) { this.logging.log(`Polling scan job status...`) - let status = 'Pending' + let status: string | undefined = 'Pending' let timer = 0 const codeScanJobPollingIntervalSeconds = 1 const codeScanJobTimeoutSeconds = ScanConstants.standardScanTimeoutMs @@ -137,7 +136,7 @@ export class SecurityScanHandler { jobId: jobId, } const resp = await this.serviceManager.getCodewhispererService().getCodeAnalysis(req) - this.logging.log(`Request id: ${resp.$response.requestId}`) + this.logging.log(`Request id: ${resp.$metadata.requestId}`) if (resp.status !== 'Pending') { status = resp.status @@ -156,19 +155,22 @@ export class SecurityScanHandler { return status } - async listScanResults(jobId: string, projectPath: string) { + async listScanResults(jobId: string | undefined, projectPath: string) { const request: ListCodeAnalysisFindingsRequest = { jobId, codeAnalysisFindingsSchema: 'codeanalysis/findings/1.0', } const response = await this.serviceManager.getCodewhispererService().listCodeAnalysisFindings(request) - this.logging.log(`Request id: ${response.$response.requestId}`) + this.logging.log(`Request id: ${response.$metadata.requestId}`) const aggregatedCodeScanIssueList = await this.mapToAggregatedList(response.codeAnalysisFindings, projectPath) return aggregatedCodeScanIssueList } - async mapToAggregatedList(json: string, projectPath: string) { + async mapToAggregatedList(json: string | undefined, projectPath: string) { + if (json === undefined) { + return [] + } const codeScanIssueMap: Map = new Map() const aggregatedCodeScanIssueList: AggregatedCodeScanIssue[] = [] diff --git a/server/aws-lsp-codewhisperer/src/language-server/securityScan/types.ts b/server/aws-lsp-codewhisperer/src/language-server/securityScan/types.ts index 471b5ea6bc..e2c2862c8f 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/securityScan/types.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/securityScan/types.ts @@ -69,3 +69,7 @@ export interface SecurityScanFindings { findingsWithFixes: number scannedFiles: string } + +export type ArtifactMap = { + [key: string]: string | undefined +} diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/util.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/util.ts index 21d6d41397..0b38e0eaf7 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/util.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/util.ts @@ -1,5 +1,5 @@ import { CredentialsProvider, WorkspaceFolder } from '@aws/language-server-runtimes/server-interface' -import { CreateUploadUrlResponse } from '../../client/token/codewhispererbearertokenclient' +import { CreateUploadUrlResponse } from '@amzn/codewhisperer-runtime' import { URI } from 'vscode-uri' import * as fs from 'fs' import * as crypto from 'crypto' @@ -56,7 +56,7 @@ export const uploadArtifactToS3 = async (content: Buffer, resp: CreateUploadUrlR 'x-amz-server-side-encryption-context': Buffer.from(encryptionContext, 'utf8').toString('base64'), }) } - await axios.put(resp.uploadUrl, content, { headers: headersObj }) + await axios.put(resp.uploadUrl ?? 'invalid-url', content, { headers: headersObj }) } export const isDirectory = (path: string): boolean => { diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts index e9f252d7a6..45bf780ef3 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.test.ts @@ -6,9 +6,9 @@ import { DependencyDiscoverer } from './dependency/dependencyDiscoverer' import { WorkspaceFolder } from 'vscode-languageserver-protocol' import { ArtifactManager } from './artifactManager' import { CodeWhispererServiceToken } from '../../shared/codeWhispererService' -import { ListWorkspaceMetadataResponse } from '../../client/token/codewhispererbearertokenclient' +import { ListWorkspaceMetadataResponse, WorkspaceStatus } from '@amzn/codewhisperer-runtime' import { IdleWorkspaceManager } from './IdleWorkspaceManager' -import { AWSError } from 'aws-sdk' +import { ServiceException } from '@smithy/smithy-client' import { SemanticSearch } from '../agenticChat/tools/workspaceContext/semanticSearch' describe('WorkspaceFolderManager', () => { @@ -148,15 +148,14 @@ describe('WorkspaceFolderManager', () => { }, ] - // Mock listWorkspaceMetadata to throw AccessDeniedException with feature not supported - const mockError: AWSError = { + const mockError = new ServiceException({ name: 'AccessDeniedException', message: 'Feature is not supported', - code: 'AccessDeniedException', - time: new Date(), - retryable: false, - statusCode: 403, - } + $fault: 'client', + $metadata: { + httpStatusCode: 403, + }, + }) mockCodeWhispererService.listWorkspaceMetadata.rejects(mockError) @@ -202,7 +201,8 @@ describe('WorkspaceFolderManager', () => { workspaces: [ { workspaceId: 'test-workspace-id', - workspaceStatus: 'RUNNING', + // TODO: RUNNING does not exist in WorkspaceStatus so we need to use type assertion for now. + workspaceStatus: 'RUNNING' as WorkspaceStatus, }, ], } @@ -458,14 +458,14 @@ describe('WorkspaceFolderManager', () => { sinon.stub(IdleWorkspaceManager, 'isSessionIdle').returns(false) // Mock listWorkspaceMetadata to throw AccessDeniedException with feature not supported - const mockError: AWSError = { + const mockError = new ServiceException({ name: 'AccessDeniedException', message: 'Feature is not supported', - code: 'AccessDeniedException', - time: new Date(), - retryable: false, - statusCode: 403, - } + $fault: 'client', + $metadata: { + httpStatusCode: 403, + }, + }) mockCodeWhispererService.listWorkspaceMetadata.rejects(mockError) diff --git a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts index 2b59be910f..ca274b67a4 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/workspaceContext/workspaceFolderManager.ts @@ -5,7 +5,7 @@ import { CreateWorkspaceResponse, WorkspaceMetadata, WorkspaceStatus, -} from '../../client/token/codewhispererbearertokenclient' +} from '@amzn/codewhisperer-runtime' import { Agent, CredentialsProvider, Logging, ToolClassification } from '@aws/language-server-runtimes/server-interface' import { ArtifactManager, FileMetadata } from './artifactManager' import { @@ -19,7 +19,7 @@ import { DependencyDiscoverer } from './dependency/dependencyDiscoverer' import { AmazonQTokenServiceManager } from '../../shared/amazonQServiceManager/AmazonQTokenServiceManager' import { URI } from 'vscode-uri' import path = require('path') -import { isAwsError } from '../../shared/utils' +import { isAwsError, isServiceException } from '../../shared/utils' import { IdleWorkspaceManager } from './IdleWorkspaceManager' import { SemanticSearch, SemanticSearchParams } from '../agenticChat/tools/workspaceContext/semanticSearch' @@ -126,7 +126,8 @@ export class WorkspaceFolderManager { this.remoteWorkspaceIdResolver = resolve }) this.workspaceState = { - remoteWorkspaceState: 'CREATION_PENDING', + // TODO: CREATION_PENDING does not exist in WorkspaceStatus so we need to use type assertion for now. + remoteWorkspaceState: 'CREATION_PENDING' as WorkspaceStatus, messageQueue: [], } } @@ -419,8 +420,9 @@ export class WorkspaceFolderManager { return } - this.workspaceState.remoteWorkspaceState = metadata.workspaceStatus - + if (metadata.workspaceStatus) { + this.workspaceState.remoteWorkspaceState = metadata.workspaceStatus + } switch (metadata.workspaceStatus) { case 'READY': const client = this.workspaceState.webSocketClient @@ -504,8 +506,10 @@ export class WorkspaceFolderManager { return } - this.workspaceState.remoteWorkspaceState = metadata.workspaceStatus - if (this.workspaceState.workspaceId === undefined) { + if (metadata.workspaceStatus) { + this.workspaceState.remoteWorkspaceState = metadata.workspaceStatus + } + if (this.workspaceState.workspaceId === undefined && metadata.workspaceId) { this.setRemoteWorkspaceId(metadata.workspaceId) } @@ -722,8 +726,10 @@ export class WorkspaceFolderManager { return createWorkspaceResult } - this.workspaceState.remoteWorkspaceState = workspaceDetails.workspace.workspaceStatus - if (this.workspaceState.workspaceId === undefined) { + if (workspaceDetails.workspace?.workspaceStatus) { + this.workspaceState.remoteWorkspaceState = workspaceDetails.workspace?.workspaceStatus + } + if (this.workspaceState.workspaceId === undefined && workspaceDetails.workspace?.workspaceId) { this.setRemoteWorkspaceId(workspaceDetails.workspace.workspaceId) } @@ -823,7 +829,7 @@ export class WorkspaceFolderManager { try { const params = workspaceRoot ? { workspaceRoot } : {} const response = await this.serviceManager.getCodewhispererService().listWorkspaceMetadata(params) - metadata = response && response.workspaces.length ? response.workspaces[0] : null + metadata = response && response.workspaces?.length ? response.workspaces[0] : null } catch (e: any) { error = e this.logging.warn(`Error while fetching workspace (${workspaceRoot}) metadata: ${e?.message}`) @@ -834,12 +840,10 @@ export class WorkspaceFolderManager { this.logging.log(`User's administrator opted out server-side workspace context`) optOut = true } - if ( - isAwsError(e) && - (e as any).code === 'AccessDeniedException' && - e.message.includes('Feature is not supported') - ) { - featureDisabled = true + if (isServiceException(e) && e.name === 'AccessDeniedException') { + if (e.message.includes('Feature is not supported')) { + featureDisabled = true + } } } return { metadata, optOut, featureDisabled, error } @@ -861,7 +865,7 @@ export class WorkspaceFolderManager { this.logging.warn( `Error while creating workspace (${workspaceRoot}): ${e.message}. Error is ${e.retryable ? '' : 'not'} retryable}` ) - if (isAwsError(e) && (e as any).code === 'ServiceQuotaExceededException') { + if (isServiceException(e) && e.name === 'ServiceQuotaExceededException') { isServiceQuotaExceeded = true } error = { diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.test.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.test.ts index 73af1c14fc..bd37da2346 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.test.ts @@ -57,7 +57,6 @@ const TEST_ENDPOINT_EU_CENTRAL_1 = 'http://amazon-q-in-eu-central-1-endpoint' describe('AmazonQTokenServiceManager', () => { let codewhispererServiceStub: StubbedInstance let codewhispererStubFactory: sinon.SinonStub> - let sdkInitializatorSpy: sinon.SinonSpy let getListAllAvailableProfilesHandlerStub: sinon.SinonStub let amazonQTokenServiceManager: AmazonQTokenServiceManager @@ -84,10 +83,6 @@ describe('AmazonQTokenServiceManager', () => { features = new TestFeatures() - sdkInitializatorSpy = Object.assign(sinon.spy(features.sdkInitializator), { - v2: sinon.spy(features.sdkInitializator.v2), - }) - codewhispererServiceStub = stubInterface() // @ts-ignore codewhispererServiceStub.client = sinon.stub() diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts index 5cd43f3cc7..ee706c0b22 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/AmazonQTokenServiceManager.ts @@ -547,19 +547,17 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager< } private serviceFactory(region: string, endpoint: string): CodeWhispererServiceToken { + const customUserAgent = this.getCustomUserAgent() const service = new CodeWhispererServiceToken( this.features.credentialsProvider, this.features.workspace, this.features.logging, region, endpoint, - this.features.sdkInitializator + this.features.sdkInitializator, + customUserAgent ) - const customUserAgent = this.getCustomUserAgent() - service.updateClientConfig({ - customUserAgent: customUserAgent, - }) service.customizationArn = this.configurationCache.getProperty('customizationArn') service.profileArn = this.activeIdcProfile?.arn service.shareCodeWhispererContentWithAWS = this.configurationCache.getProperty( diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts index 1cd4f254be..d8aa1b0b48 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/BaseAmazonQServiceManager.ts @@ -17,7 +17,6 @@ import { } from './configurationUtils' import { AmazonQServiceInitializationError } from './errors' import { StreamingClientServiceBase } from '../streamingClientService' -import { UserContext } from '../../client/token/codewhispererbearertokenclient' export interface QServiceManagerFeatures { lsp: Lsp diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.test.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.test.ts index 8bf938bfa4..819c300280 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.test.ts @@ -15,6 +15,7 @@ import { } from './qDeveloperProfiles' import { DEFAULT_AWS_Q_ENDPOINT_URL, DEFAULT_AWS_Q_REGION } from '../../shared/constants' import { AmazonQServiceProfileThrottlingError } from './errors' +import { ListAvailableProfilesCommandOutput } from '@amzn/codewhisperer-runtime' const SOME_Q_DEVELOPER_PROFILE_ARN = 'some-random-q-developer-profile-arn' const SOME_Q_DEVELOPER_PROFILE_NAME = 'some-random-q-developer-profile-name' @@ -49,8 +50,8 @@ describe('ListAllAvailableProfiles Handler', () => { profileName: SOME_Q_DEVELOPER_PROFILE_NAME, }, ], - $response: {} as any, - } + $metadata: {}, + } satisfies ListAvailableProfilesCommandOutput beforeEach(() => { logging = stubInterface() diff --git a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.ts b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.ts index 20354d4fdb..495a49b572 100644 --- a/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.ts +++ b/server/aws-lsp-codewhisperer/src/shared/amazonQServiceManager/qDeveloperProfiles.ts @@ -12,8 +12,8 @@ import { CodeWhispererServiceToken } from '../codeWhispererService' import { AmazonQServiceProfileThrottlingError } from './errors' export interface AmazonQDeveloperProfile { - arn: string - name: string + arn: string | undefined + name: string | undefined identityDetails?: IdentityDetails } @@ -148,13 +148,14 @@ async function fetchProfilesFromRegion( logging.debug(`Raw response from ${region}: ${JSON.stringify(response)}`) - const profiles = response.profiles.map(profile => ({ - arn: profile.arn, - name: profile.profileName, - identityDetails: { - region, - }, - })) + const profiles = + response.profiles?.map(profile => ({ + arn: profile.arn, + name: profile.profileName, + identityDetails: { + region, + }, + })) ?? [] logging.log(`Fetched ${profiles.length} profiles from ${region} (page: ${numberOfPages + 1})`) if (profiles.length > 0) { diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.test.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.test.ts index 75c691a5e3..ccc8a8ecb0 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.test.ts @@ -14,7 +14,6 @@ import { CancellationToken, InlineCompletionWithReferencesParams, } from '@aws/language-server-runtimes/server-interface' -import { ConfigurationOptions } from 'aws-sdk' import * as sinon from 'sinon' import * as assert from 'assert' import { @@ -28,7 +27,7 @@ import { } from './codeWhispererService' import { RecentEditTracker } from '../language-server/inline-completion/tracker/codeEditTracker' import { CodeWhispererSupplementalContext } from './models/model' -import CodeWhispererTokenClient = require('../client/token/codewhispererbearertokenclient') +import { SupplementalContext } from '@amzn/codewhisperer-runtime' describe('CodeWhispererService', function () { let sandbox: sinon.SinonSandbox @@ -92,7 +91,7 @@ describe('CodeWhispererService', function () { ): Promise< | { supContextData: CodeWhispererSupplementalContext - items: CodeWhispererTokenClient.SupplementalContextList + items: SupplementalContext[] } | undefined > { @@ -139,76 +138,23 @@ describe('CodeWhispererService', function () { }) describe('request tracking', function () { - it('should track inflight requests', function () { - const mockRequest = { - abort: sandbox.stub(), - } as any - - service.trackRequest(mockRequest) - assert.strictEqual(service.inflightRequests.size, 1) - assert.strictEqual(service.inflightRequests.has(mockRequest), true) - }) - - it('should complete and remove tracked requests', function () { - const mockRequest = { - abort: sandbox.stub(), - } as any - - service.trackRequest(mockRequest) - service.completeRequest(mockRequest) - - assert.strictEqual(service.inflightRequests.size, 0) - assert.strictEqual(service.inflightRequests.has(mockRequest), false) - }) - it('should abort all inflight requests', function () { - const mockRequest1 = { abort: sandbox.stub() } as any - const mockRequest2 = { abort: sandbox.stub() } as any + const mockController1 = new AbortController() + const mockController2 = new AbortController() + const abortSpy1 = sandbox.spy(mockController1, 'abort') + const abortSpy2 = sandbox.spy(mockController2, 'abort') - service.trackRequest(mockRequest1) - service.trackRequest(mockRequest2) + service.inflightRequests.add(mockController1) + service.inflightRequests.add(mockController2) service.abortInflightRequests() - assert.strictEqual(mockRequest1.abort.calledOnce, true) - assert.strictEqual(mockRequest2.abort.calledOnce, true) + assert.strictEqual(abortSpy1.calledOnce, true) + assert.strictEqual(abortSpy2.calledOnce, true) assert.strictEqual(service.inflightRequests.size, 0) }) }) - describe('updateClientConfig', function () { - it('should update client configuration', function () { - const mockClient = { - config: { - update: sandbox.stub(), - }, - // Add minimal required properties to satisfy the interface - createCodeScan: sandbox.stub(), - createCodeScanUploadUrl: sandbox.stub(), - createProfile: sandbox.stub(), - deleteProfile: sandbox.stub(), - generateCompletions: sandbox.stub(), - generateSuggestions: sandbox.stub(), - getCodeAnalysis: sandbox.stub(), - getCodeScan: sandbox.stub(), - listCodeAnalysisFindings: sandbox.stub(), - listCodeScans: sandbox.stub(), - listFeatureEvaluations: sandbox.stub(), - listProfiles: sandbox.stub(), - sendTelemetryEvent: sandbox.stub(), - startCodeAnalysis: sandbox.stub(), - stopCodeAnalysis: sandbox.stub(), - updateProfile: sandbox.stub(), - } as any - service.client = mockClient - - const options: ConfigurationOptions = { region: 'us-west-2' } - service.updateClientConfig(options) - - assert.strictEqual(mockClient.config.update.calledOnceWith(options), true) - }) - }) - describe('generateItemId', function () { it('should generate unique item IDs', function () { const id1 = service.generateItemId() @@ -227,20 +173,17 @@ describe('CodeWhispererService', function () { beforeEach(function () { // Mock the createCodeWhispererSigv4Client function to avoid real client creation const mockClient = { - generateRecommendations: sandbox.stub().returns({ - promise: sandbox.stub().resolves({ - recommendations: [], - $response: { - requestId: 'test-request-id', - httpResponse: { - headers: { 'x-amzn-sessionid': 'test-session-id' }, - }, - }, - }), + send: sandbox.stub().resolves({ + recommendations: [], + $metadata: { + requestId: 'test-request-id', + }, + $httpHeaders: { + 'x-amzn-sessionid': 'test-session-id', + }, }), - setupRequestListeners: sandbox.stub(), - config: { - update: sandbox.stub(), + middlewareStack: { + add: sandbox.stub(), }, } @@ -302,8 +245,8 @@ describe('CodeWhispererService', function () { await service.generateSuggestions(mockRequest) // Verify that the client was called with the customizationArn - const clientCall = (service.client.generateRecommendations as sinon.SinonStub).getCall(0) - assert.strictEqual(clientCall.args[0].customizationArn, 'test-arn') + const clientCall = (service.client.send as sinon.SinonStub).getCall(0) + assert.strictEqual(clientCall.args[0].input.customizationArn, 'test-arn') }) it('should include serviceType in response', async function () { diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index 27dac024af..2067708c9d 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -13,23 +13,19 @@ import { InlineCompletionWithReferencesParams, } from '@aws/language-server-runtimes/server-interface' import { waitUntil } from '@aws/lsp-core/out/util/timeoutUtils' -import { AWSError, ConfigurationOptions, CredentialProviderChain, Credentials } from 'aws-sdk' -import { PromiseResult } from 'aws-sdk/lib/request' -import { Request } from 'aws-sdk/lib/core' +import { AwsCredentialIdentity } from '@aws-sdk/types' import { v4 as uuidv4 } from 'uuid' import { + CodeWhispererSigv4Client, CodeWhispererSigv4ClientConfigurationOptions, createCodeWhispererSigv4Client, } from '../client/sigv4/codewhisperer' import { CodeWhispererTokenClientConfigurationOptions, createCodeWhispererTokenClient, - RequestExtras, + CodeWhispererTokenClient, } from '../client/token/codewhisperer' -import CodeWhispererSigv4Client = require('../client/sigv4/codewhisperersigv4client') -import CodeWhispererTokenClient = require('../client/token/codewhispererbearertokenclient') import { getErrorId } from './utils' -import { GenerateCompletionsResponse } from '../client/token/codewhispererbearertokenclient' import { getRelativePath } from '../language-server/workspaceContext/util' import { CodewhispererLanguage, getRuntimeLanguage } from './languageDetection' import { RecentEditTracker } from '../language-server/inline-completion/tracker/codeEditTracker' @@ -41,32 +37,76 @@ import { FILE_URI_CHARS_LIMIT, FILENAME_CHARS_LIMIT, } from '../language-server/inline-completion/contants/constants' +import { + Completion, + CreateSubscriptionTokenCommand, + CreateSubscriptionTokenRequest, + CreateSubscriptionTokenResponse, + CreateUploadUrlCommand, + CreateUploadUrlRequest, + CreateWorkspaceCommand, + CreateWorkspaceRequest, + DeleteWorkspaceCommand, + DeleteWorkspaceRequest, + GenerateCompletionsCommand, + GenerateCompletionsRequest, + GenerateCompletionsResponse, + GetCodeAnalysisCommand, + GetCodeAnalysisRequest, + GetProfileCommand, + GetProfileRequest, + GetTransformationCommand, + GetTransformationPlanCommand, + GetTransformationPlanRequest, + GetTransformationRequest, + ListAvailableCustomizationsCommand, + ListAvailableCustomizationsRequest, + ListAvailableModelsCommand, + ListAvailableModelsRequest, + ListAvailableProfilesCommand, + ListAvailableProfilesRequest, + ListCodeAnalysisFindingsCommand, + ListCodeAnalysisFindingsRequest, + ListFeatureEvaluationsCommand, + ListFeatureEvaluationsRequest, + ListWorkspaceMetadataCommand, + ListWorkspaceMetadataRequest, + SendTelemetryEventCommand, + SendTelemetryEventRequest, + StartCodeAnalysisCommand, + StartCodeAnalysisRequest, + StartTransformationCommand, + StartTransformationRequest, + StopTransformationCommand, + StopTransformationRequest, + SupplementalContext, + SupplementalContextType, +} from '@amzn/codewhisperer-runtime' +import { + GenerateRecommendationsCommand, + GenerateRecommendationsRequest, + GenerateRecommendationsResponse, + Recommendation, +} from '@amzn/codewhisperer' // Type guards for request classification -export function isTokenRequest(request: BaseGenerateSuggestionsRequest): request is GenerateTokenSuggestionsRequest { +export function isTokenRequest(request: GenerateSuggestionsRequest): request is GenerateTokenSuggestionsRequest { return 'editorState' in request || 'predictionTypes' in request || 'supplementalContexts' in request } -export function isIAMRequest(request: BaseGenerateSuggestionsRequest): request is GenerateIAMSuggestionsRequest { +export function isIAMRequest(request: GenerateSuggestionsRequest): request is GenerateIAMSuggestionsRequest { return !isTokenRequest(request) } -export interface Suggestion extends CodeWhispererTokenClient.Completion, CodeWhispererSigv4Client.Recommendation { +export interface Suggestion extends Completion, Recommendation { itemId: string } -// Base request interface with common fields - using union type for FileContext compatibility -export interface BaseGenerateSuggestionsRequest { - fileContext: FileContext - maxResults?: number - nextToken?: string -} - // IAM-specific request interface that directly extends the SigV4 client request -export interface GenerateIAMSuggestionsRequest extends CodeWhispererSigv4Client.GenerateRecommendationsRequest {} +export interface GenerateIAMSuggestionsRequest extends GenerateRecommendationsRequest {} // Token-specific request interface that directly extends the Token client request -export interface GenerateTokenSuggestionsRequest extends CodeWhispererTokenClient.GenerateCompletionsRequest {} +export interface GenerateTokenSuggestionsRequest extends GenerateCompletionsRequest {} // Union type for backward compatibility export type GenerateSuggestionsRequest = GenerateIAMSuggestionsRequest | GenerateTokenSuggestionsRequest @@ -83,7 +123,7 @@ export type FileContext = { } export interface ResponseContext { - requestId: string + requestId: string | undefined codewhispererSessionId: string nextToken?: string authType?: 'iam' | 'token' @@ -152,7 +192,7 @@ export abstract class CodeWhispererServiceBase { public profileArn?: string abstract client: CodeWhispererSigv4Client | CodeWhispererTokenClient - inflightRequests: Set & RequestExtras> = new Set() + inflightRequests: Set = new Set() abortInflightRequests() { this.inflightRequests.forEach(request => { @@ -161,17 +201,9 @@ export abstract class CodeWhispererServiceBase { this.inflightRequests.clear() } - trackRequest(request: AWS.Request & RequestExtras) { - this.inflightRequests.add(request) - } - - completeRequest(request: AWS.Request & RequestExtras) { - this.inflightRequests.delete(request) - } - abstract getCredentialsType(): CredentialsType - abstract generateSuggestions(request: BaseGenerateSuggestionsRequest): Promise + abstract generateSuggestions(request: GenerateSuggestionsRequest): Promise abstract constructSupplementalContext( document: TextDocument, @@ -185,7 +217,7 @@ export abstract class CodeWhispererServiceBase { ): Promise< | { supContextData: CodeWhispererSupplementalContext - items: CodeWhispererTokenClient.SupplementalContextList + items: SupplementalContext[] } | undefined > @@ -195,13 +227,6 @@ export abstract class CodeWhispererServiceBase { this.codeWhispererEndpoint = codeWhispererEndpoint } - /** - * Updates Service Client options after client was instantiated. - */ - public updateClientConfig(options: ConfigurationOptions) { - this.client.config.update(options) - } - generateItemId = () => uuidv4() async getSubscriptionStatus( @@ -233,58 +258,33 @@ export class CodeWhispererServiceIAM extends CodeWhispererServiceBase { const options: CodeWhispererSigv4ClientConfigurationOptions = { region: this.codeWhispererRegion, endpoint: this.codeWhispererEndpoint, - credentialProvider: new CredentialProviderChain([ - () => { - const credentials = new Credentials({ - accessKeyId: '', - secretAccessKey: '', - sessionToken: '', - }) - - credentials.get = callback => { - logging.info('CodeWhispererServiceIAM: Attempting to get credentials') - - Promise.resolve(credentialsProvider.getCredentials('iam')) - .then((creds: any) => { - logging.info('CodeWhispererServiceIAM: Successfully got credentials') - - credentials.accessKeyId = creds.accessKeyId as string - credentials.secretAccessKey = creds.secretAccessKey as string - credentials.sessionToken = creds.sessionToken as string - credentials.expireTime = creds.expiration as Date - callback() - }) - .catch(err => { - logging.error(`CodeWhispererServiceIAM: Failed to get credentials: ${err.message}`) - callback(err) - }) + credentials: async () => { + logging.info('CodeWhispererService IAM: Attempting to get credentials') + + try { + const creds = credentialsProvider.getCredentials('iam') as AwsCredentialIdentity + logging.info('CodeWhispererService IAM: Successfully got credentials') + + return { + accessKeyId: creds.accessKeyId, + secretAccessKey: creds.secretAccessKey, + sessionToken: creds.sessionToken, + expiration: creds.expiration, } - - credentials.needsRefresh = () => { - return ( - !credentials.accessKeyId || - !credentials.secretAccessKey || - (credentials.expireTime && credentials.expireTime.getTime() - Date.now() < 60000) - ) // 1 min buffer + } catch (err) { + if (err instanceof Error) { + logging.error(`CodeWhispererServiceIAM: Failed to get credentials: ${err.message}`) } - - credentials.refresh = callback => { - credentials.get(callback) - } - - return credentials - }, - ]), - } - this.client = createCodeWhispererSigv4Client(options, sdkInitializator, logging) - // Avoid overwriting any existing client listeners - const clientRequestListeners = this.client.setupRequestListeners - this.client.setupRequestListeners = (request: Request) => { - if (clientRequestListeners) { - clientRequestListeners.call(this.client, request) - } - request.httpRequest.headers['x-amzn-codewhisperer-optout'] = `${!this.shareCodeWhispererContentWithAWS}` + throw err + } + }, } + this.client = createCodeWhispererSigv4Client( + options, + sdkInitializator, + logging, + this.shareCodeWhispererContentWithAWS + ) } getCredentialsType(): CredentialsType { @@ -303,14 +303,14 @@ export class CodeWhispererServiceIAM extends CodeWhispererServiceBase { ): Promise< | { supContextData: CodeWhispererSupplementalContext - items: CodeWhispererTokenClient.SupplementalContextList + items: SupplementalContext[] } | undefined > { return undefined } - async generateSuggestions(request: BaseGenerateSuggestionsRequest): Promise { + async generateSuggestions(request: GenerateSuggestionsRequest): Promise { // Cast is now safe because GenerateIAMSuggestionsRequest extends GenerateRecommendationsRequest const iamRequest = request as GenerateIAMSuggestionsRequest @@ -324,18 +324,18 @@ export class CodeWhispererServiceIAM extends CodeWhispererServiceBase { console.warn('Advanced features not supported - using basic completion') } - const response = await this.client.generateRecommendations(iamRequest).promise() + const response = await this.client.send(new GenerateRecommendationsCommand(iamRequest)) return this.mapCodeWhispererApiResponseToSuggestion(response, { - requestId: response?.$response?.requestId, - codewhispererSessionId: response?.$response?.httpResponse?.headers['x-amzn-sessionid'], + requestId: response?.$metadata?.requestId ?? 'unknown', + codewhispererSessionId: (response as any)?.$httpHeaders?.['x-amzn-sessionid'] ?? 'unknown', nextToken: response.nextToken, authType: 'iam' as const, }) } private mapCodeWhispererApiResponseToSuggestion( - apiResponse: CodeWhispererSigv4Client.GenerateRecommendationsResponse, + apiResponse: GenerateRecommendationsResponse, responseContext: ResponseContext ): GenerateSuggestionsResponse { for (const recommendation of apiResponse?.recommendations ?? []) { @@ -356,7 +356,7 @@ export class CodeWhispererServiceIAM extends CodeWhispererServiceBase { export class CodeWhispererServiceToken extends CodeWhispererServiceBase { client: CodeWhispererTokenClient /** Debounce createSubscriptionToken by storing the current, pending promise (if any). */ - #createSubscriptionTokenPromise?: Promise + #createSubscriptionTokenPromise?: Promise /** If user clicks "Upgrade" multiple times, cancel the previous wait-promise. */ #waitUntilSubscriptionCancelSource?: CancellationTokenSource @@ -366,61 +366,32 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { private logging: Logging, codeWhispererRegion: string, codeWhispererEndpoint: string, - sdkInitializator: SDKInitializator + sdkInitializator: SDKInitializator, + customUserAgent?: string ) { super(codeWhispererRegion, codeWhispererEndpoint) + const tokenProvider = async () => { + const creds = credentialsProvider.getCredentials('bearer') as BearerCredentials + if (!creds?.token) { + throw new Error('Authorization failed, bearer token is not set') + } + return { token: creds.token, expiration: new Date() } + } + const options: CodeWhispererTokenClientConfigurationOptions = { region: this.codeWhispererRegion, endpoint: this.codeWhispererEndpoint, - onRequestSetup: [ - req => { - logging.debug(`CodeWhispererServiceToken: req=${req.operation}`) - this.trackRequest(req) - req.on('build', async ({ httpRequest }) => { - try { - const creds = credentialsProvider.getCredentials('bearer') as BearerCredentials - if (!creds?.token) { - throw new Error('Authorization failed, bearer token is not set') - } - if (credentialsProvider.getConnectionType() === 'external_idp') { - httpRequest.headers['TokenType'] = 'EXTERNAL_IDP' - } - - httpRequest.headers['Authorization'] = `Bearer ${creds.token}` - httpRequest.headers['x-amzn-codewhisperer-optout'] = - `${!this.shareCodeWhispererContentWithAWS}` - } catch (err) { - this.completeRequest(req) - throw err - } - }) - req.on('complete', response => { - const requestStartTime = req.startTime?.getTime() || 0 - const requestEndTime = new Date().getTime() - const latency = requestStartTime > 0 ? requestEndTime - requestStartTime : 0 - - const requestBody = req.httpRequest.body ? JSON.parse(String(req.httpRequest.body)) : {} - this.completeRequest(req) - }) - req.on('error', async (error, response) => { - const requestStartTime = req.startTime?.getTime() || 0 - const requestEndTime = new Date().getTime() - const latency = requestStartTime > 0 ? requestEndTime - requestStartTime : 0 - - const requestBody = req.httpRequest.body ? JSON.parse(String(req.httpRequest.body)) : {} - this.completeRequest(req) - }) - req.on('error', () => { - this.completeRequest(req) - }) - req.on('error', () => { - this.completeRequest(req) - }) - }, - ], + token: tokenProvider, + ...(customUserAgent && { customUserAgent }), } - this.client = createCodeWhispererTokenClient(options, sdkInitializator, logging) + this.client = createCodeWhispererTokenClient( + options, + sdkInitializator, + logging, + credentialsProvider, + this.shareCodeWhispererContentWithAWS + ) } getCredentialsType(): CredentialsType { @@ -439,11 +410,11 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { ): Promise< | { supContextData: CodeWhispererSupplementalContext - items: CodeWhispererTokenClient.SupplementalContextList + items: SupplementalContext[] } | undefined > { - const items: CodeWhispererTokenClient.SupplementalContext[] = [] + const items: SupplementalContext[] = [] const projectContext = await fetchSupplementalContext( document, @@ -470,7 +441,7 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { ...recentEditsContext.supplementalContextItems.map(item => ({ content: item.content, filePath: item.filePath, - type: 'PreviousEditorState', + type: SupplementalContextType.PREVIOUS_EDITOR_STATE, metadata: { previousEditorStateMetadata: { timeOffset: 1000, @@ -508,7 +479,7 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { return { ...request, profileArn: this.profileArn } } - async generateSuggestions(request: BaseGenerateSuggestionsRequest): Promise { + async generateSuggestions(request: GenerateSuggestionsRequest): Promise { // Cast is now safe because GenerateTokenSuggestionsRequest extends GenerateCompletionsRequest // add cancellation check // add error check @@ -541,19 +512,19 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { logstr += `@@request metadata@@ "endpoint": ${this.codeWhispererEndpoint}, "predictionType": ${tokenRequest.predictionTypes?.toString() ?? 'Not specified (COMPLETIONS)'}, - "filename": ${tokenRequest.fileContext.filename}, - "leftContextLength": ${request.fileContext.leftFileContent.length}, - rightContextLength: ${request.fileContext.rightFileContent.length}, - "language": ${tokenRequest.fileContext.programmingLanguage.languageName}, + "filename": ${tokenRequest.fileContext?.filename}, + "leftContextLength": ${tokenRequest.fileContext?.leftFileContent?.length}, + rightContextLength: ${tokenRequest.fileContext?.rightFileContent?.length}, + "language": ${tokenRequest.fileContext?.programmingLanguage?.languageName}, "supplementalContextCount": ${tokenRequest.supplementalContexts?.length ?? 0}, "request.nextToken": ${tokenRequest.nextToken}` // "recentEdits": ${recentEditsLogStr}\n` - const response = await this.client.generateCompletions(this.withProfileArn(tokenRequest)).promise() + const response = await this.client.send(new GenerateCompletionsCommand(this.withProfileArn(tokenRequest))) - const responseContext = { - requestId: response?.$response?.requestId, - codewhispererSessionId: response?.$response?.httpResponse?.headers['x-amzn-sessionid'], + const responseContext: ResponseContext = { + requestId: response?.$metadata?.requestId ?? 'unknown', + codewhispererSessionId: (response?.$metadata as any)?.httpHeaders?.['x-amzn-sessionid'] ?? 'unknown', nextToken: response.nextToken, // CRITICAL: Add service type for proper error handling authType: 'token' as const, @@ -612,10 +583,8 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { } } - public async codeModernizerCreateUploadUrl( - request: CodeWhispererTokenClient.CreateUploadUrlRequest - ): Promise { - return this.client.createUploadUrl(this.withProfileArn(request)).promise() + public async codeModernizerCreateUploadUrl(request: CreateUploadUrlRequest) { + return this.client.send(new CreateUploadUrlCommand(this.withProfileArn(request))) } /** * @description Use this function to start the transformation job. @@ -623,10 +592,8 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { * @returns transformationJobId - String id for the Job */ - public async codeModernizerStartCodeTransformation( - request: CodeWhispererTokenClient.StartTransformationRequest - ): Promise> { - return await this.client.startTransformation(this.withProfileArn(request)).promise() + public async codeModernizerStartCodeTransformation(request: StartTransformationRequest) { + return await this.client.send(new StartTransformationCommand(this.withProfileArn(request))) } /** @@ -634,10 +601,8 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { * @param request * @returns transformationJobId - String id for the Job */ - public async codeModernizerStopCodeTransformation( - request: CodeWhispererTokenClient.StopTransformationRequest - ): Promise> { - return await this.client.stopTransformation(this.withProfileArn(request)).promise() + public async codeModernizerStopCodeTransformation(request: StopTransformationRequest) { + return await this.client.send(new StopTransformationCommand(this.withProfileArn(request))) } /** @@ -645,10 +610,8 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { * be polling this function periodically to get updated results. When this function * returns COMPLETED we know the transformation is done. */ - public async codeModernizerGetCodeTransformation( - request: CodeWhispererTokenClient.GetTransformationRequest - ): Promise> { - return await this.client.getTransformation(this.withProfileArn(request)).promise() + public async codeModernizerGetCodeTransformation(request: GetTransformationRequest) { + return await this.client.send(new GetTransformationCommand(this.withProfileArn(request))) } /** @@ -656,109 +619,99 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { * transformation plan to the user. * @params tranformationJobId - String id returned from StartCodeTransformationResponse */ - public async codeModernizerGetCodeTransformationPlan( - request: CodeWhispererTokenClient.GetTransformationPlanRequest - ): Promise> { - return this.client.getTransformationPlan(this.withProfileArn(request)).promise() + public async codeModernizerGetCodeTransformationPlan(request: GetTransformationPlanRequest) { + return this.client.send(new GetTransformationPlanCommand(this.withProfileArn(request))) } /** * @description get a pre-signed url to upload source code into S3 bucket */ - async createUploadUrl( - request: CodeWhispererTokenClient.CreateUploadUrlRequest - ): Promise> { - return this.client.createUploadUrl(this.withProfileArn(request)).promise() + async createUploadUrl(request: CreateUploadUrlRequest) { + return this.client.send(new CreateUploadUrlCommand(this.withProfileArn(request))) } /** * @description Once source code uploaded to S3, send a request to run security scan on uploaded source code. */ - async startCodeAnalysis( - request: CodeWhispererTokenClient.StartCodeAnalysisRequest - ): Promise> { - return this.client.startCodeAnalysis(this.withProfileArn(request)).promise() + async startCodeAnalysis(request: StartCodeAnalysisRequest) { + return this.client.send(new StartCodeAnalysisCommand(this.withProfileArn(request))) } /** * @description Send a request to get the code scan status detail. */ - async getCodeAnalysis( - request: CodeWhispererTokenClient.GetCodeAnalysisRequest - ): Promise> { - return this.client.getCodeAnalysis(this.withProfileArn(request)).promise() + async getCodeAnalysis(request: GetCodeAnalysisRequest) { + return this.client.send(new GetCodeAnalysisCommand(this.withProfileArn(request))) } /** * @description Get profile details */ - async getProfile(request: { profileArn: string }) { - return this.client.getProfile(request).promise() + async getProfile(request: GetProfileRequest) { + return this.client.send(new GetProfileCommand(request)) } /** * @description Once scan completed successfully, send a request to get list of all the findings for the given scan. */ - async listCodeAnalysisFindings( - request: CodeWhispererTokenClient.ListCodeAnalysisFindingsRequest - ): Promise> { - return this.client.listCodeAnalysisFindings(this.withProfileArn(request)).promise() + async listCodeAnalysisFindings(request: ListCodeAnalysisFindingsRequest) { + return this.client.send(new ListCodeAnalysisFindingsCommand(this.withProfileArn(request))) } /** * @description Get list of available customizations */ - async listAvailableCustomizations(request: CodeWhispererTokenClient.ListAvailableCustomizationsRequest) { - return this.client.listAvailableCustomizations(this.withProfileArn(request)).promise() + async listAvailableCustomizations(request: ListAvailableCustomizationsRequest) { + return this.client.send(new ListAvailableCustomizationsCommand(this.withProfileArn(request))) } /** * @description Get list of available profiles */ - async listAvailableProfiles(request: CodeWhispererTokenClient.ListAvailableProfilesRequest) { - return this.client.listAvailableProfiles(request).promise() + async listAvailableProfiles(request: ListAvailableProfilesRequest) { + return this.client.send(new ListAvailableProfilesCommand(request)) } /** * @description Get list of available models */ - async listAvailableModels(request: CodeWhispererTokenClient.ListAvailableModelsRequest) { - return this.client.listAvailableModels(request).promise() + async listAvailableModels(request: ListAvailableModelsRequest) { + return this.client.send(new ListAvailableModelsCommand(request)) } /** * @description send telemetry event to code whisperer data warehouse */ - async sendTelemetryEvent(request: CodeWhispererTokenClient.SendTelemetryEventRequest) { - return this.client.sendTelemetryEvent(this.withProfileArn(request)).promise() + async sendTelemetryEvent(request: SendTelemetryEventRequest) { + return this.client.send(new SendTelemetryEventCommand(this.withProfileArn(request))) } /** * @description create a remote workspace */ - async createWorkspace(request: CodeWhispererTokenClient.CreateWorkspaceRequest) { - return this.client.createWorkspace(this.withProfileArn(request)).promise() + async createWorkspace(request: CreateWorkspaceRequest) { + return this.client.send(new CreateWorkspaceCommand(this.withProfileArn(request))) } /** * @description get list of workspace metadata */ - async listWorkspaceMetadata(request: CodeWhispererTokenClient.ListWorkspaceMetadataRequest) { - return this.client.listWorkspaceMetadata(this.withProfileArn(request)).promise() + async listWorkspaceMetadata(request: ListWorkspaceMetadataRequest) { + return this.client.send(new ListWorkspaceMetadataCommand(this.withProfileArn(request))) } /** * @description delete the remote workspace */ - async deleteWorkspace(request: CodeWhispererTokenClient.DeleteWorkspaceRequest) { - return this.client.deleteWorkspace(this.withProfileArn(request)).promise() + async deleteWorkspace(request: DeleteWorkspaceRequest) { + return this.client.send(new DeleteWorkspaceCommand(this.withProfileArn(request))) } /* * @description get the list of feature evaluations */ - async listFeatureEvaluations(request: CodeWhispererTokenClient.ListFeatureEvaluationsRequest) { - return this.client.listFeatureEvaluations(this.withProfileArn(request)).promise() + async listFeatureEvaluations(request: ListFeatureEvaluationsRequest) { + return this.client.send(new ListFeatureEvaluationsCommand(this.withProfileArn(request))) } /** @@ -766,7 +719,7 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { * * cool api you have there 🥹 */ - async createSubscriptionToken(request: CodeWhispererTokenClient.CreateSubscriptionTokenRequest) { + async createSubscriptionToken(request: CreateSubscriptionTokenRequest) { // Debounce. if (this.#createSubscriptionTokenPromise) { return this.#createSubscriptionTokenPromise @@ -774,7 +727,7 @@ export class CodeWhispererServiceToken extends CodeWhispererServiceBase { this.#createSubscriptionTokenPromise = (async () => { try { - const r = await this.client.createSubscriptionToken(this.withProfileArn(request)).promise() + const r = await this.client.send(new CreateSubscriptionTokenCommand(this.withProfileArn(request))) if (!r.encodedVerificationUrl) { this.logging.error(`setpaidtier request: ${JSON.stringify(request)} diff --git a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts index aa3c1e6c44..373c2b54c4 100644 --- a/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/streamingClientService.ts @@ -19,8 +19,8 @@ import { IamCredentials, } from '@aws/language-server-runtimes/server-interface' import { getBearerTokenFromProvider, isUsageLimitError } from './utils' -import { Credentials } from 'aws-sdk' import { CLIENT_TIMEOUT_MS, MAX_REQUEST_ATTEMPTS } from '../language-server/agenticChat/constants/constants' + import { AmazonQUsageLimitError } from './amazonQServiceManager/errors' import { NodeHttpHandler } from '@smithy/node-http-handler' import { AwsCredentialIdentity, AwsCredentialIdentityProvider } from '@aws-sdk/types' diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetry.test.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetry.test.ts index 86b9e4ec9d..e5a2ddd71d 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetry.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetry.test.ts @@ -93,7 +93,7 @@ class HelloWorld await features.doChangeTextDocument({ textDocument: { uri: SOME_FILE.uri, version: updatedDocument.version }, contentChanges: [ - { range: { start: endPosition, end: endPosition }, text: EXPECTED_SUGGESTION[0].content }, + { range: { start: endPosition, end: endPosition }, text: EXPECTED_SUGGESTION[0].content! }, ], }) @@ -109,8 +109,8 @@ class HelloWorld isInlineEdit: false, }) - const totalInsertCharacters = SOME_TYPING.length + EXPECTED_SUGGESTION[0].content.length - const codeWhispererCharacters = EXPECTED_SUGGESTION[0].content.length + const totalInsertCharacters = SOME_TYPING.length + EXPECTED_SUGGESTION[0].content!.length + const codeWhispererCharacters = EXPECTED_SUGGESTION[0].content!.length const codePercentage = Math.round((codeWhispererCharacters / totalInsertCharacters) * 10000) / 100 clock.tick(5000 * 60) diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts index 8c7975c5ce..32536f73fd 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.test.ts @@ -10,7 +10,6 @@ import { SsoConnectionType, } from '@aws/language-server-runtimes/server-interface' -import { UserContext, OptOutPreference } from '../../client/token/codewhispererbearertokenclient' import { CodeWhispererSession } from '../../language-server/inline-completion/session/sessionManager' import sinon, { StubbedInstance, stubInterface } from 'ts-sinon' import { BUILDER_ID_START_URL } from '../constants' @@ -18,6 +17,7 @@ import { ChatInteractionType } from './types' import { CodeWhispererServiceToken } from '../codeWhispererService' import { initBaseTestServiceManager, TestAmazonQServiceManager } from '../amazonQServiceManager/testUtils' import { TestFeatures } from '@aws/language-server-runtimes/testing' +import { OptOutPreference, SendTelemetryEventRequest, UserContext } from '@amzn/codewhisperer-runtime' class MockCredentialsProvider implements CredentialsProvider { private mockIamCredentials: IamCredentials | undefined @@ -281,7 +281,7 @@ describe('TelemetryService', () => { }, }, optOutPreference: 'OPTIN', - } + } satisfies SendTelemetryEventRequest mockCredentialsProvider.setConnectionMetadata({ sso: { startUrl: 'idc-start-url', @@ -391,7 +391,7 @@ describe('TelemetryService', () => { hasProjectLevelContext: false, }, }, - } + } satisfies SendTelemetryEventRequest sinon.assert.calledOnceWithExactly(codeWhisperServiceStub.sendTelemetryEvent, expectedEvent) sinon.assert.calledOnceWithExactly(telemetry.emitMetric as sinon.SinonStub, { @@ -544,7 +544,7 @@ describe('TelemetryService', () => { }, }, optOutPreference: 'OPTIN', - } + } satisfies SendTelemetryEventRequest mockCredentialsProvider.setConnectionMetadata({ sso: { startUrl: 'idc-start-url', @@ -655,7 +655,7 @@ describe('TelemetryService', () => { }, }, optOutPreference: 'OPTIN', - } + } satisfies SendTelemetryEventRequest sinon.assert.calledOnceWithExactly(telemetry.emitMetric as sinon.SinonStub, { name: 'codewhisperer_userModification', data: { @@ -700,7 +700,7 @@ describe('TelemetryService', () => { }, }, optOutPreference: 'OPTIN', - } + } satisfies SendTelemetryEventRequest sinon.assert.calledOnceWithExactly(codeWhisperServiceStub.sendTelemetryEvent, expectedEvent) sinon.assert.calledOnceWithExactly(telemetry.emitMetric as sinon.SinonStub, { name: 'amazonq_modifyCode', @@ -810,7 +810,7 @@ describe('TelemetryService', () => { result: 'SUCCEEDED', }, }, - } + } satisfies SendTelemetryEventRequest sinon.assert.calledOnceWithExactly(codeWhisperServiceStub.sendTelemetryEvent, expectedEvent) sinon.assert.calledOnceWithExactly(telemetry.emitMetric as sinon.SinonStub, { @@ -994,7 +994,7 @@ describe('TelemetryService', () => { }, }, }, - } + } satisfies SendTelemetryEventRequest sinon.assert.calledOnceWithExactly(codeWhisperServiceStub.sendTelemetryEvent, expectedEvent) }) diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts index 2e8c2eb638..643bad392a 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/telemetryService.ts @@ -24,8 +24,11 @@ import { InlineChatEvent, IdeDiagnostic, UserModificationEvent, -} from '../../client/token/codewhispererbearertokenclient' -import { getCompletionType, getSsoConnectionType, isAwsError } from '../utils' + CompletionType, + InlineChatUserDecision, + AgenticChatEventStatus, +} from '@amzn/codewhisperer-runtime' +import { getCompletionType, getSsoConnectionType, isServiceException } from '../utils' import { ChatConversationType, ChatHistoryActionEvent, @@ -150,8 +153,8 @@ export class TelemetryService { private logSendTelemetryEventFailure(error: any) { let requestId: string | undefined - if (isAwsError(error)) { - requestId = (error as any).requestId + if (isServiceException(error)) { + requestId = error.$metadata.requestId } this.logging.log( @@ -180,7 +183,7 @@ export class TelemetryService { request.modelId = this.modelId } const r = await this.getService().sendTelemetryEvent(request) - this.logging.log(`SendTelemetryEvent succeeded, requestId: ${r.$response.requestId}`) + this.logging.log(`SendTelemetryEvent succeeded, requestId: ${r.$metadata.requestId}`) } catch (error) { this.logSendTelemetryEventFailure(error) } @@ -244,9 +247,9 @@ export class TelemetryService { } const acceptedSuggestion = session.suggestions.find(s => s.itemId === session.acceptedSuggestionId) const generatedLines = - acceptedSuggestion === undefined || acceptedSuggestion.content.trim() === '' + acceptedSuggestion === undefined || acceptedSuggestion.content?.trim() === '' ? 0 - : acceptedSuggestion.content.split('\n').length + : acceptedSuggestion.content?.split('\n').length const referenceCount = acceptedSuggestion === undefined ? 0 @@ -268,7 +271,11 @@ export class TelemetryService { languageName: getRuntimeLanguage(session.language), }, completionType: - session.suggestions.length > 0 ? getCompletionType(session.suggestions[0]).toUpperCase() : 'LINE', + session.suggestions.length > 0 + ? getCompletionType(session.suggestions[0]) === 'Line' + ? CompletionType.Line + : CompletionType.Block + : CompletionType.Line, suggestionState: this.getSuggestionState(userTriggerDecision), recommendationLatencyMilliseconds: session.firstCompletionDisplayLatency ?? 0, timestamp: new Date(Date.now()), @@ -641,7 +648,7 @@ export class TelemetryService { responseLength: params.responseLength, numberOfCodeBlocks: params.numberOfCodeBlocks, hasProjectLevelContext: false, - result: params.result?.toUpperCase() ?? 'SUCCEEDED', + result: (params.result?.toUpperCase() ?? AgenticChatEventStatus.Succeeded) as AgenticChatEventStatus, } if (params.customizationArn) { event.customizationArn = params.customizationArn @@ -667,7 +674,7 @@ export class TelemetryService { numSuggestionDelChars: params.suggestionDeletedChars, numSuggestionDelLines: params.suggestionDeletedLines, codeIntent: params.codeIntent, - userDecision: params.userDecision, + userDecision: params.userDecision as InlineChatUserDecision, responseStartLatency: params.responseStartLatency, responseEndLatency: params.responseEndLatency, } diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts index fa07ff1036..659efbf19d 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts @@ -1,4 +1,4 @@ -import { TransformationSpec, TransformationSteps } from '../../client/token/codewhispererbearertokenclient' +import { TransformationSpec, TransformationStep } from '@amzn/codewhisperer-runtime' import { CodewhispererLanguage } from '../languageDetection' import { CancellationJobStatus } from '../../language-server/netTransform/models' import { UserDecision } from '../../language-server/inline-completion/session/sessionManager' @@ -144,8 +144,8 @@ export interface SecurityScanEvent { export interface TransformationJobStartedEvent { category: string - transformationJobId: string - uploadId: string + transformationJobId: string | undefined + uploadId: string | undefined error: string } @@ -163,7 +163,7 @@ export interface TransformationJobReceivedEvent { export interface TransformationPlanReceivedEvent { category: string transformationJobId: string - transformationSteps: TransformationSteps + transformationSteps: TransformationStep[] | undefined } export interface TransformationJobCancelledEvent { diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.ts b/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.ts index e682263f7e..0181580002 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetryUtils.ts @@ -1,5 +1,5 @@ import { InitializeParams, Platform, ServerInfo } from '@aws/language-server-runtimes/server-interface' -import { IdeCategory, UserContext } from '../client/token/codewhispererbearertokenclient' +import { IdeCategory, OperatingSystem, UserContext } from '@amzn/codewhisperer-runtime' const USER_AGENT_PREFIX = 'AWS-Language-Servers' @@ -48,38 +48,38 @@ export const getUserAgent = (initializeParams: InitializeParams, serverInfo?: Se const IDE_CATEGORY_MAP: { [key: string]: IdeCategory } = { // TODO: VSCode key needs to change for getting the correct coefficient value for inline - 'AmazonQ-For-VSCode': 'VSCODE', - 'Amazon Q For JetBrains': 'JETBRAINS', - 'Amazon Q For Eclipse': 'ECLIPSE', - 'AWS Toolkit For VisualStudio': 'VISUAL_STUDIO', + 'AmazonQ-For-VSCode': IdeCategory.VSCode, + 'Amazon Q For JetBrains': IdeCategory.JetBrains, + 'Amazon Q For Eclipse': IdeCategory.Eclipse, + 'AWS Toolkit For VisualStudio': IdeCategory.VisualStudio, } -const mapClientNameToIdeCategory = (clientName: string): string | undefined => { +const mapClientNameToIdeCategory = (clientName: string): IdeCategory | undefined => { return IDE_CATEGORY_MAP[clientName] } // Use InitializeParams.initializationOptions.aws.clientInfo.extension to derive IDE Category from calling client // https://github.com/aws/language-server-runtimes/blob/main/runtimes/protocol/lsp.ts#L60-L69 export const getIdeCategory = (initializeParams: InitializeParams) => { - let ideCategory + let ideCategory: IdeCategory | undefined if (initializeParams.initializationOptions?.aws?.clientInfo?.extension?.name) { ideCategory = mapClientNameToIdeCategory(initializeParams.initializationOptions.aws.clientInfo.extension.name) } - return ideCategory || 'UNKNOWN' + return ideCategory } // Map result from https://github.com/aws/language-server-runtimes/blob/main/runtimes/server-interface/runtime.ts#L6 to expected Operating system const getOperatingSystem = (platform: Platform) => { switch (platform) { case 'darwin': - return 'MAC' + return OperatingSystem.Mac case 'win32': - return 'WINDOWS' + return OperatingSystem.Windows case 'linux': - return 'LINUX' + return OperatingSystem.Linux default: - return 'UNKNOWN' + return undefined } } @@ -107,7 +107,7 @@ export const makeUserContextObject = ( lspVersion: lspVersion, } - if (userContext.ideCategory === 'UNKNOWN' || userContext.operatingSystem === 'UNKNOWN') { + if (userContext.ideCategory === undefined || userContext.operatingSystem === undefined) { return } diff --git a/server/aws-lsp-codewhisperer/src/shared/utils.test.ts b/server/aws-lsp-codewhisperer/src/shared/utils.test.ts index 19f226fc38..dc5aacc01b 100644 --- a/server/aws-lsp-codewhisperer/src/shared/utils.test.ts +++ b/server/aws-lsp-codewhisperer/src/shared/utils.test.ts @@ -5,6 +5,7 @@ import { } from '@amzn/codewhisperer-streaming' import { CredentialsProvider, Position, InitializeParams } from '@aws/language-server-runtimes/server-interface' import * as assert from 'assert' +import { ServiceException } from '@smithy/smithy-client' import { expect } from 'chai' import * as sinon from 'sinon' import * as os from 'os' @@ -17,7 +18,6 @@ import { getUnmodifiedAcceptedTokens, isAwsThrottlingError, isUsageLimitError, - isQuotaExceededError, isStringOrNull, safeGet, getFileExtensionName, @@ -461,9 +461,12 @@ describe('isAwsThrottlingError', function () { }) it('false for non-throttling AWS errors', function () { - const nonThrottlingError = new Error('Not a throttling error') - ;(nonThrottlingError as any).name = 'SomeOtherError' - ;(nonThrottlingError as any).$metadata = {} + const nonThrottlingError = new ServiceException({ + name: 'AWSError', + message: 'Not a throttling error', + $fault: 'server', + $metadata: {}, + }) assert.strictEqual(isAwsThrottlingError(nonThrottlingError), false) }) @@ -518,62 +521,6 @@ describe('isMonthlyLimitError', function () { }) }) -describe('isQuotaExceededError', function () { - it('false for non-AWS errors', function () { - const regularError = new Error('Some error') - assert.strictEqual(isQuotaExceededError(regularError), false) - - assert.strictEqual(isQuotaExceededError(undefined), false) - assert.strictEqual(isQuotaExceededError(null), false) - assert.strictEqual(isQuotaExceededError('error string'), false) - }) - - it('true for free tier limit errors', function () { - const e = new ThrottlingException({ - message: 'Free tier limit reached', - $metadata: {}, - }) - - assert.strictEqual(isQuotaExceededError(e), true) - }) - - it('true for ServiceQuotaExceededException errors', function () { - const e = new ServiceQuotaExceededException({ - message: 'Service quota exceeded', - $metadata: {}, - }) - - assert.strictEqual(isQuotaExceededError(e), true) - }) - - it('true for specific messages', function () { - const reachedForThisMonth = new ThrottlingException({ - message: 'You have reached the limit for this month', - $metadata: {}, - }) - - const limitForIterationsError = new ThrottlingException({ - message: 'You have reached the limit for number of iterations', - $metadata: {}, - }) - - assert.strictEqual(isQuotaExceededError(reachedForThisMonth), true) - assert.strictEqual(isQuotaExceededError(limitForIterationsError), true) - - // Invalid cases - const invalidError1 = new ThrottlingException({ - message: 'some other messsage', - $metadata: {}, - }) - const invalidError2 = new ThrottlingException({ - message: 'foo bar', - $metadata: {}, - }) - assert.strictEqual(isQuotaExceededError(invalidError1), false) - assert.strictEqual(isQuotaExceededError(invalidError2), false) - }) -}) - describe('getFileExtensionName', () => { it('should return empty string for null or undefined input', () => { assert.strictEqual(getFileExtensionName(null as unknown as string), '') diff --git a/server/aws-lsp-codewhisperer/src/shared/utils.ts b/server/aws-lsp-codewhisperer/src/shared/utils.ts index 8968176b54..9dfea144fa 100644 --- a/server/aws-lsp-codewhisperer/src/shared/utils.ts +++ b/server/aws-lsp-codewhisperer/src/shared/utils.ts @@ -1,17 +1,13 @@ import { - AwsResponseError, BearerCredentials, CredentialsProvider, Position, SsoConnectionType, } from '@aws/language-server-runtimes/server-interface' -import { AwsCredentialIdentity } from '@aws-sdk/types' - import { distance } from 'fastest-levenshtein' import { Suggestion } from './codeWhispererService' import { CodewhispererCompletionType } from './telemetry/types' import { - BUILDER_ID_START_URL, COMMON_GITIGNORE_PATTERNS, crashMonitoringDirName, driveLetterRegex, @@ -21,7 +17,6 @@ import { import { CodeWhispererStreamingServiceException, Origin, - ServiceQuotaExceededException, ThrottlingException, ThrottlingExceptionReason, } from '@amzn/codewhisperer-streaming' @@ -34,7 +29,11 @@ import { InitializeParams } from '@aws/language-server-runtimes/server-interface import { QClientCapabilities } from '../language-server/configuration/qConfigurationServer' import escapeHTML = require('escape-html') -export function isAwsError(error: unknown): error is ServiceException { +export function isServiceException(error: unknown): error is ServiceException { + return error instanceof ServiceException +} + +export function isAwsError(error: unknown): error is Error & { code: string; time: Date } { if (error === undefined) { return false } @@ -54,7 +53,11 @@ export function isAwsThrottlingError(e: unknown): e is ThrottlingException { // return true // } - if (e instanceof ThrottlingException || (isAwsError(e) && e.name === 'ThrottlingException')) { + if ( + e instanceof ThrottlingException || + (isAwsError(e) && e.code === 'ThrottlingException') || + (isServiceException(e) && e.name === 'ThrottlingException') + ) { return true } @@ -91,38 +94,6 @@ export function isUsageLimitError(e: unknown): e is ThrottlingException { return false } -export function isQuotaExceededError(e: unknown): e is ServiceException { - if (!e) { - return false - } - - // From client/token/bearer-token-service.json - if (isUsageLimitError(e)) { - return true - } - - // https://github.com/aws/aws-toolkit-vscode/blob/db673c9b74b36591bb5642b3da7d4bc7ae2afaf4/packages/core/src/amazonqFeatureDev/client/featureDev.ts#L199 - // "Backend service will throw ServiceQuota if code generation iteration limit is reached". - if (e instanceof ServiceQuotaExceededException || (isAwsError(e) && e.name == 'ServiceQuotaExceededException')) { - return true - } - - // https://github.com/aws/aws-toolkit-vscode/blob/db673c9b74b36591bb5642b3da7d4bc7ae2afaf4/packages/core/src/amazonqFeatureDev/client/featureDev.ts#L199 - // "API Front-end will throw Throttling if conversation limit is reached. - // API Front-end monitors StartCodeGeneration for throttling" - if ( - isAwsThrottlingError(e) && - (e.message.includes('reached for this month') || - e.message.includes('limit for this month') || - e.message.includes('limit reached') || - e.message.includes('limit for number of iterations')) - ) { - return true - } - - return false -} - /** * Returns the identifier the given error. * Depending on the implementation, the identifier may exist on a @@ -317,9 +288,9 @@ export function isBool(value: unknown): value is boolean { } export function getCompletionType(suggestion: Suggestion): CodewhispererCompletionType { - const nonBlankLines = suggestion.content.split('\n').filter(line => line.trim() !== '').length + const nonBlankLines = suggestion.content?.split('\n').filter(line => line.trim() !== '').length - return nonBlankLines > 1 ? 'Block' : 'Line' + return nonBlankLines && nonBlankLines > 1 ? 'Block' : 'Line' } export function enabledModelSelection(params: InitializeParams | undefined): boolean { @@ -451,7 +422,7 @@ export function getUnmodifiedAcceptedTokens(origin: string, after: string) { return Math.max(origin.length, after.length) - distance(origin, after) } -export function getEndPositionForAcceptedSuggestion(content: string, startPosition: Position): Position { +export function getEndPositionForAcceptedSuggestion(content: string = '', startPosition: Position): Position { const insertedLines = content.split('\n') const numberOfInsertedLines = insertedLines.length diff --git a/server/aws-lsp-identity/package.json b/server/aws-lsp-identity/package.json index e5e2009798..a7962e9f7a 100644 --- a/server/aws-lsp-identity/package.json +++ b/server/aws-lsp-identity/package.json @@ -26,8 +26,8 @@ "dependencies": { "@aws-sdk/client-sso-oidc": "^3.616.0", "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.2.129", - "@aws/lsp-core": "^0.0.12", + "@aws/language-server-runtimes": "^0.3.0", + "@aws/lsp-core": "^0.0.16", "@smithy/node-http-handler": "^3.2.5", "@smithy/shared-ini-file-loader": "^4.0.1", "https-proxy-agent": "^7.0.5", diff --git a/server/aws-lsp-json/package.json b/server/aws-lsp-json/package.json index e4c5b50679..0c391fb122 100644 --- a/server/aws-lsp-json/package.json +++ b/server/aws-lsp-json/package.json @@ -26,7 +26,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" @@ -42,6 +42,7 @@ "endOfLine": "lf" }, "devDependencies": { - "c8": "^10.1.2" + "c8": "^10.1.2", + "ts-mocha": "^11.1.0" } } diff --git a/server/aws-lsp-notification/package.json b/server/aws-lsp-notification/package.json index de4646132f..344db460e6 100644 --- a/server/aws-lsp-notification/package.json +++ b/server/aws-lsp-notification/package.json @@ -22,8 +22,8 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", - "@aws/lsp-core": "^0.0.12", + "@aws/language-server-runtimes": "^0.3.0", + "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/server/aws-lsp-partiql/package.json b/server/aws-lsp-partiql/package.json index da7a3a8a53..afd6ef4ba4 100644 --- a/server/aws-lsp-partiql/package.json +++ b/server/aws-lsp-partiql/package.json @@ -24,9 +24,9 @@ "out" ], "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", - "antlr4-c3": "3.4.2", - "antlr4ng": "3.0.14", + "@aws/language-server-runtimes": "^0.3.0", + "antlr4-c3": "3.4.4", + "antlr4ng": "3.0.16", "web-tree-sitter": "0.22.6" }, "devDependencies": { diff --git a/server/aws-lsp-s3/package.json b/server/aws-lsp-s3/package.json index 067230017d..338bb0ccdf 100644 --- a/server/aws-lsp-s3/package.json +++ b/server/aws-lsp-s3/package.json @@ -9,8 +9,8 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.2.129", - "@aws/lsp-core": "^0.0.12", + "@aws/language-server-runtimes": "^0.3.0", + "@aws/lsp-core": "^0.0.15", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" } diff --git a/server/aws-lsp-yaml/package.json b/server/aws-lsp-yaml/package.json index 719f94bf6e..0418feb4f7 100644 --- a/server/aws-lsp-yaml/package.json +++ b/server/aws-lsp-yaml/package.json @@ -26,7 +26,7 @@ "postinstall": "node patchYamlPackage.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", diff --git a/server/device-sso-auth-lsp/package.json b/server/device-sso-auth-lsp/package.json index 2093f85a07..e417a5c4a6 100644 --- a/server/device-sso-auth-lsp/package.json +++ b/server/device-sso-auth-lsp/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/server/hello-world-lsp/package.json b/server/hello-world-lsp/package.json index b411c0b52f..b8b2a4f6c0 100644 --- a/server/hello-world-lsp/package.json +++ b/server/hello-world-lsp/package.json @@ -13,12 +13,13 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.2.129", + "@aws/language-server-runtimes": "^0.3.0", "vscode-languageserver": "^9.0.1" }, "devDependencies": { "c8": "^10.1.2", "ts-loader": "^9.4.4", + "ts-mocha": "^11.1.0", "webpack": "^5.94.0", "webpack-cli": "^6.0.1" } From c96106d18c9e9d846765665ce2ee50304af4ff7f Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Mon, 13 Oct 2025 23:27:37 -0700 Subject: [PATCH 139/158] fix: inline, nep telemetry not sent and throw sessionId not found (#2419) --- .../inline-completion/handler/sessionResultsHandler.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.ts index 77107c726c..0475b1d73b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/sessionResultsHandler.ts @@ -64,9 +64,15 @@ export class SessionResultsHandler { removedDiagnostics, } = params - const sessionManager = params.isInlineEdit ? this.editSessionManager : this.completionSessionManager + // Comment this out because Edit request might return Completion as well so we can't rely on this flag + // const sessionManager = params.isInlineEdit ? this.editSessionManager : this.completionSessionManager - const session = sessionManager.getSessionById(sessionId) + // TODO: Not elegant, worth refactoring + const editSession = this.editSessionManager.getSessionById(sessionId) + const completionSession = this.completionSessionManager.getSessionById(sessionId) + + const session = editSession ?? completionSession + const sessionManager = editSession ? this.editSessionManager : this.completionSessionManager if (!session) { this.logging.log(`ERROR: Session ID ${sessionId} was not found`) return From e11c544804e4fbe7dbad3e5373223ba919a34758 Mon Sep 17 00:00:00 2001 From: Alice Koreman Date: Tue, 14 Oct 2025 20:22:10 +0200 Subject: [PATCH 140/158] fix: set resolveProvider to false in init handler json and yaml language servers (#2391) Problem Currently, both the JSON and YAML generic language servers respond with resolveProvider: true in their initialization response. This signals to clients that these language servers support completion item resolve requests, which these servers don't actually support, resulting in errors when clients send resolve requests. Solution This updates resolveProvider to false to accurately describe the capabilities of these language servers. Co-authored-by: Alice Koreman --- server/aws-lsp-json/src/language-server/jsonServer.ts | 2 +- server/aws-lsp-yaml/src/language-server/yamlServer.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/aws-lsp-json/src/language-server/jsonServer.ts b/server/aws-lsp-json/src/language-server/jsonServer.ts index e7494a6995..33cf8d6295 100644 --- a/server/aws-lsp-json/src/language-server/jsonServer.ts +++ b/server/aws-lsp-json/src/language-server/jsonServer.ts @@ -36,7 +36,7 @@ export const JsonServerFactory = const onInitializeHandler = () => { return { capabilities: { - completionProvider: { resolveProvider: true }, + completionProvider: { resolveProvider: false }, hoverProvider: true, documentFormattingProvider: true, textDocumentSync: { diff --git a/server/aws-lsp-yaml/src/language-server/yamlServer.ts b/server/aws-lsp-yaml/src/language-server/yamlServer.ts index 7f9525b33d..6103f1112c 100644 --- a/server/aws-lsp-yaml/src/language-server/yamlServer.ts +++ b/server/aws-lsp-yaml/src/language-server/yamlServer.ts @@ -36,7 +36,7 @@ export const YamlServerFactory = const onInitializeHandler = () => { return { capabilities: { - completionProvider: { resolveProvider: true }, + completionProvider: { resolveProvider: false }, hoverProvider: true, documentFormattingProvider: true, textDocumentSync: { From ac4f2a440c3602ddc9378dfc492b847f74d66bab Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:56:11 -0700 Subject: [PATCH 141/158] chore(release): release packages from branch main (#2421) --- .release-please-manifest.json | 6 +++--- package-lock.json | 6 +++--- server/aws-lsp-codewhisperer/CHANGELOG.md | 7 +++++++ server/aws-lsp-codewhisperer/package.json | 2 +- server/aws-lsp-json/CHANGELOG.md | 7 +++++++ server/aws-lsp-json/package.json | 2 +- server/aws-lsp-yaml/CHANGELOG.md | 7 +++++++ server/aws-lsp-yaml/package.json | 2 +- 8 files changed, 30 insertions(+), 9 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 62a41204e9..1abd0ec3c0 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -2,8 +2,8 @@ "chat-client": "0.1.39", "core/aws-lsp-core": "0.0.16", "server/aws-lsp-antlr4": "0.1.20", - "server/aws-lsp-codewhisperer": "0.0.84", - "server/aws-lsp-json": "0.1.20", + "server/aws-lsp-codewhisperer": "0.0.85", + "server/aws-lsp-json": "0.1.21", "server/aws-lsp-partiql": "0.0.18", - "server/aws-lsp-yaml": "0.1.20" + "server/aws-lsp-yaml": "0.1.21" } diff --git a/package-lock.json b/package-lock.json index a830bf52df..4db7812895 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28193,7 +28193,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.84", + "version": "0.0.85", "bundleDependencies": [ "@amzn/codewhisperer", "@amzn/codewhisperer-runtime", @@ -28937,7 +28937,7 @@ }, "server/aws-lsp-json": { "name": "@aws/lsp-json", - "version": "0.1.20", + "version": "0.1.21", "license": "Apache-2.0", "dependencies": { "@aws/language-server-runtimes": "^0.3.0", @@ -29150,7 +29150,7 @@ }, "server/aws-lsp-yaml": { "name": "@aws/lsp-yaml", - "version": "0.1.20", + "version": "0.1.21", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index e3a342833c..dcca563d24 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.0.85](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.84...lsp-codewhisperer/v0.0.85) (2025-10-14) + + +### Bug Fixes + +* inline, nep telemetry not sent and throw sessionId not found ([#2419](https://github.com/aws/language-servers/issues/2419)) ([c96106d](https://github.com/aws/language-servers/commit/c96106d18c9e9d846765665ce2ee50304af4ff7f)) + ## [0.0.84](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.83...lsp-codewhisperer/v0.0.84) (2025-10-09) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 9656bbe1e1..799258c054 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.84", + "version": "0.0.85", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { diff --git a/server/aws-lsp-json/CHANGELOG.md b/server/aws-lsp-json/CHANGELOG.md index 4d7881502c..d3bf1949b5 100644 --- a/server/aws-lsp-json/CHANGELOG.md +++ b/server/aws-lsp-json/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.1.21](https://github.com/aws/language-servers/compare/lsp-json/v0.1.20...lsp-json/v0.1.21) (2025-10-14) + + +### Bug Fixes + +* set resolveProvider to false in init handler json and yaml language servers ([#2391](https://github.com/aws/language-servers/issues/2391)) ([e11c544](https://github.com/aws/language-servers/commit/e11c544804e4fbe7dbad3e5373223ba919a34758)) + ## [0.1.20](https://github.com/aws/language-servers/compare/lsp-json/v0.1.19...lsp-json/v0.1.20) (2025-10-01) diff --git a/server/aws-lsp-json/package.json b/server/aws-lsp-json/package.json index 0c391fb122..5fde4b4578 100644 --- a/server/aws-lsp-json/package.json +++ b/server/aws-lsp-json/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-json", - "version": "0.1.20", + "version": "0.1.21", "description": "JSON Language Server", "main": "out/index.js", "repository": { diff --git a/server/aws-lsp-yaml/CHANGELOG.md b/server/aws-lsp-yaml/CHANGELOG.md index bedb0ee095..c3e85718c7 100644 --- a/server/aws-lsp-yaml/CHANGELOG.md +++ b/server/aws-lsp-yaml/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.1.21](https://github.com/aws/language-servers/compare/lsp-yaml/v0.1.20...lsp-yaml/v0.1.21) (2025-10-14) + + +### Bug Fixes + +* set resolveProvider to false in init handler json and yaml language servers ([#2391](https://github.com/aws/language-servers/issues/2391)) ([e11c544](https://github.com/aws/language-servers/commit/e11c544804e4fbe7dbad3e5373223ba919a34758)) + ## [0.1.20](https://github.com/aws/language-servers/compare/lsp-yaml/v0.1.19...lsp-yaml/v0.1.20) (2025-10-01) diff --git a/server/aws-lsp-yaml/package.json b/server/aws-lsp-yaml/package.json index 0418feb4f7..8188db3de4 100644 --- a/server/aws-lsp-yaml/package.json +++ b/server/aws-lsp-yaml/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-yaml", - "version": "0.1.20", + "version": "0.1.21", "description": "YAML Language Server", "main": "out/index.js", "repository": { From 088f0ba353c1ce370eca550a53274910fa71aad0 Mon Sep 17 00:00:00 2001 From: Shruti Sinha <44882001+shruti0085@users.noreply.github.com> Date: Tue, 14 Oct 2025 18:08:44 -0700 Subject: [PATCH 142/158] chore: bump agentic version: 1.39.0 (#2422) --- app/aws-lsp-codewhisperer-runtimes/src/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/src/version.json b/app/aws-lsp-codewhisperer-runtimes/src/version.json index f8ad8ef349..7629bf75a5 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/version.json +++ b/app/aws-lsp-codewhisperer-runtimes/src/version.json @@ -1,3 +1,3 @@ { - "agenticChat": "1.38.0" + "agenticChat": "1.39.0" } From 3f48b12bce4faba474404f7c74a9520c379552fe Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Wed, 15 Oct 2025 13:05:39 -0700 Subject: [PATCH 143/158] revert: revert for mid-loop compaction This reverts commit 35f0795fa5d09f3610e6a29cb72d49f32cc5534e. --- .../agenticChat/agenticChatController.test.ts | 22 ++--- .../agenticChat/agenticChatController.ts | 97 ++----------------- .../agenticChat/constants/constants.ts | 2 - .../context/agenticChatTriggerContext.ts | 5 +- .../chat/chatSessionService.ts | 1 - .../chat/telemetry/chatTelemetryController.ts | 12 --- .../src/shared/telemetry/types.ts | 9 -- 7 files changed, 16 insertions(+), 132 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts index 367870e3e7..b8eeffad42 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.test.ts @@ -1185,21 +1185,15 @@ describe('AgenticChatController', () => { it('truncate input to 500k character ', async function () { const input = 'X'.repeat(GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT + 10) - const request: GenerateAssistantResponseCommandInput = { - conversationState: { - currentMessage: { - userInputMessage: { - content: input, - }, - }, - chatTriggerType: undefined, - }, - } - - chatController.truncateRequest(request) - + generateAssistantResponseStub.restore() + generateAssistantResponseStub = sinon.stub(CodeWhispererStreaming.prototype, 'generateAssistantResponse') + generateAssistantResponseStub.callsFake(() => {}) + await chatController.onChatPrompt({ tabId: mockTabId, prompt: { prompt: input } }, mockCancellationToken) + assert.ok(generateAssistantResponseStub.called) + const calledRequestInput: GenerateAssistantResponseCommandInput = + generateAssistantResponseStub.firstCall.firstArg assert.deepStrictEqual( - request.conversationState?.currentMessage?.userInputMessage?.content?.length, + calledRequestInput.conversationState?.currentMessage?.userInputMessage?.content?.length, GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT ) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 844e8e4609..377d58fc7a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -191,8 +191,6 @@ import { MAX_OVERALL_CHARACTERS, FSREAD_MEMORY_BANK_MAX_PER_FILE, FSREAD_MEMORY_BANK_MAX_TOTAL, - MID_LOOP_COMPACTION_HANDOFF_PROMPT, - COMPACTION_PROMPT, } from './constants/constants' import { AgenticChatError, @@ -948,11 +946,6 @@ export class AgenticChatController implements ChatHandlers { const compactIds = session.getAllDeferredCompactMessageIds() await this.#invalidateCompactCommand(params.tabId, compactIds) - // Set compactionDeclined flag if there were pending compaction requests - // This prevents endless compaction warning loops when user declines compaction once - if (compactIds.length > 0) { - session.compactionDeclined = true - } session.rejectAllDeferredToolExecutions(new ToolApprovalException('Command ignored: new prompt', false)) await this.#invalidateAllShellCommands(params.tabId, session) @@ -988,10 +981,6 @@ export class AgenticChatController implements ChatHandlers { session.abortRequest() const compactIds = session.getAllDeferredCompactMessageIds() await this.#invalidateCompactCommand(params.tabId, compactIds) - // Set compactionDeclined flag if there were pending compaction requests - if (compactIds.length > 0) { - session.compactionDeclined = true - } void this.#invalidateAllShellCommands(params.tabId, session) session.rejectAllDeferredToolExecutions(new CancellationError('user')) @@ -1109,7 +1098,7 @@ export class AgenticChatController implements ChatHandlers { } // Result Handling - This happens only once - const result = await this.#handleFinalResult( + return await this.#handleFinalResult( finalResult, session, params.tabId, @@ -1118,13 +1107,6 @@ export class AgenticChatController implements ChatHandlers { isNewConversation, chatResultStream ) - - // Reset compactionDeclined flag after successful completion - if (session.compactionDeclined) { - session.compactionDeclined = false - } - - return result } catch (err) { // HACK: the chat-client needs to have a partial event with the associated messageId sent before it can accept the final result. // Without this, the `working` indicator never goes away. @@ -1196,7 +1178,7 @@ export class AgenticChatController implements ChatHandlers { /** * Prepares the initial request input for the chat prompt */ - #getCompactionRequestInput(session: ChatSessionService, toolResults?: any[]): ChatCommandInput { + #getCompactionRequestInput(session: ChatSessionService): ChatCommandInput { this.#debug('Preparing compaction request input') // Get profileArn from the service manager if available const profileArn = this.#serviceManager?.getActiveProfileArn() @@ -1204,8 +1186,7 @@ export class AgenticChatController implements ChatHandlers { profileArn, this.#getTools(session), session.modelId, - this.#origin, - toolResults + this.#origin ) return requestInput } @@ -1213,12 +1194,9 @@ export class AgenticChatController implements ChatHandlers { /** * Runs the compaction, making requests and processing tool uses until completion */ - #shouldCompact(currentRequestCount: number, session: ChatSessionService): boolean { - const EFFECTIVE_COMPACTION_THRESHOLD = COMPACTION_CHARACTER_THRESHOLD - COMPACTION_PROMPT.length - if (currentRequestCount > EFFECTIVE_COMPACTION_THRESHOLD && !session.compactionDeclined) { - this.#debug( - `Current request total character count is: ${currentRequestCount}, prompting user to compact (threshold: ${EFFECTIVE_COMPACTION_THRESHOLD})` - ) + #shouldCompact(currentRequestCount: number): boolean { + if (currentRequestCount > COMPACTION_CHARACTER_THRESHOLD) { + this.#debug(`Current request total character count is: ${currentRequestCount}, prompting user to compact`) return true } else { return false @@ -1401,10 +1379,6 @@ export class AgenticChatController implements ChatHandlers { let currentRequestCount = 0 const pinnedContext = additionalContext?.filter(item => item.pinned) - // Store initial non-empty prompt for compaction handoff - const initialPrompt = - initialRequestInput.conversationState?.currentMessage?.userInputMessage?.content?.trim() || '' - metric.recordStart() this.logSystemInformation() while (true) { @@ -1469,63 +1443,6 @@ export class AgenticChatController implements ChatHandlers { this.#llmRequestStartTime = Date.now() // Phase 3: Request Execution currentRequestInput = sanitizeRequestInput(currentRequestInput) - - if (this.#shouldCompact(currentRequestCount, session)) { - this.#features.logging.info( - `Entering mid-loop compaction at iteration ${iterationCount} with ${currentRequestCount} characters` - ) - this.#telemetryController.emitMidLoopCompaction( - currentRequestCount, - iterationCount, - this.#features.runtime.serverInfo.version ?? '' - ) - const messageId = this.#getMessageIdForCompact(uuid()) - const confirmationResult = this.#processCompactConfirmation(messageId, currentRequestCount) - const cachedButtonBlockId = await chatResultStream.writeResultBlock(confirmationResult) - await this.waitForCompactApproval(messageId, chatResultStream, cachedButtonBlockId, session) - - // Run compaction - const toolResults = - currentRequestInput.conversationState?.currentMessage?.userInputMessage?.userInputMessageContext - ?.toolResults || [] - const compactionRequestInput = this.#getCompactionRequestInput(session, toolResults) - const compactionResult = await this.#runCompaction( - compactionRequestInput, - session, - metric, - chatResultStream, - tabId, - promptId, - CompactHistoryActionType.Nudge, - session.conversationId, - token, - documentReference - ) - - if (!compactionResult.success) { - this.#features.logging.error(`Compaction failed: ${compactionResult.error}`) - return compactionResult - } - - // Show compaction summary to user before continuing - await chatResultStream.writeResultBlock({ - type: 'answer', - body: - (compactionResult.data?.chatResult.body || '') + - '\n\nConversation history has been compacted successfully!', - messageId: uuid(), - }) - - currentRequestInput = this.#updateRequestInputWithToolResults( - currentRequestInput, - [], - MID_LOOP_COMPACTION_HANDOFF_PROMPT + initialPrompt - ) - shouldDisplayMessage = false - this.#features.logging.info(`Completed mid-loop compaction, restarting loop with handoff prompt`) - continue - } - // Note: these logs are very noisy, but contain information redacted on the backend. this.#debug( `generateAssistantResponse/SendMessage Request: ${JSON.stringify(currentRequestInput, this.#imageReplacer, 2)}` @@ -1754,7 +1671,7 @@ export class AgenticChatController implements ChatHandlers { currentRequestInput = this.#updateRequestInputWithToolResults(currentRequestInput, toolResults, content) } - if (this.#shouldCompact(currentRequestCount, session)) { + if (this.#shouldCompact(currentRequestCount)) { this.#telemetryController.emitCompactNudge( currentRequestCount, this.#features.runtime.serverInfo.version ?? '' diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts index b291367e2c..fb710eae9b 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/constants/constants.ts @@ -18,8 +18,6 @@ export const GENERATE_ASSISTANT_RESPONSE_INPUT_LIMIT = 500_000 // 200K tokens * 3.5 = 700K characters, intentionally overestimating with 3.5:1 ratio export const MAX_OVERALL_CHARACTERS = 700_000 export const COMPACTION_CHARACTER_THRESHOLD = 0.7 * MAX_OVERALL_CHARACTERS -// TODO: We need to carefully craft a prompt for this supported by the science team -export const MID_LOOP_COMPACTION_HANDOFF_PROMPT = `CONTEXT HANDOFF: Previous conversation was compacted. Continue with user's request: ` export const COMPACTION_BODY = (threshold: number) => `The context window is almost full (${threshold}%) and exceeding it will clear your history. Amazon Q can compact your history instead.` export const COMPACTION_HEADER_BODY = 'Compact chat history?' diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/agenticChatTriggerContext.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/agenticChatTriggerContext.ts index 1eddf3afa5..9baa192ea5 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/agenticChatTriggerContext.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/agenticChatTriggerContext.ts @@ -113,15 +113,13 @@ export class AgenticChatTriggerContext { * @param tools Optional Bedrock tools * @param modelId Optional model ID * @param origin Optional origin - * @param toolResults Optional tool results to include in compaction context * @returns ChatCommandInput - which is either SendMessageInput or GenerateAssistantResponseInput */ getCompactionChatCommandInput( profileArn?: string, tools: BedrockTools = [], modelId?: string, - origin?: Origin, - toolResults?: any[] + origin?: Origin ): ChatCommandInput { const data: ChatCommandInput = { conversationState: { @@ -132,7 +130,6 @@ export class AgenticChatTriggerContext { userInputMessageContext: { tools, envState: this.#mapPlatformToEnvState(process.platform), - toolResults: toolResults, }, userIntent: undefined, origin: origin ? origin : 'IDE', diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts index bb76ceabaa..bb67a8aed0 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/chatSessionService.ts @@ -30,7 +30,6 @@ export class ChatSessionService { public contextListSent: boolean = false public modelId: string | undefined public isMemoryBankGeneration: boolean = false - public compactionDeclined: boolean = false #lsp?: Features['lsp'] #abortController?: AbortController #currentPromptId?: string diff --git a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts index 931d646f4b..95e9bc5157 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/chat/telemetry/chatTelemetryController.ts @@ -243,18 +243,6 @@ export class ChatTelemetryController { }) } - public emitMidLoopCompaction(characters: number, iterationCount: number, languageServerVersion: string) { - this.#telemetry.emitMetric({ - name: ChatTelemetryEventName.MidLoopCompaction, - data: { - characters, - iterationCount, - credentialStartUrl: this.#credentialsProvider.getConnectionMetadata()?.sso?.startUrl, - languageServerVersion: languageServerVersion, - }, - }) - } - public emitToolUseSuggested( toolUse: ToolUse, conversationId: string, diff --git a/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts b/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts index 659efbf19d..6b22972428 100644 --- a/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts +++ b/server/aws-lsp-codewhisperer/src/shared/telemetry/types.ts @@ -207,7 +207,6 @@ export enum ChatTelemetryEventName { LoadHistory = 'amazonq_loadHistory', CompactHistory = 'amazonq_compactHistory', CompactNudge = 'amazonq_compactNudge', - MidLoopCompaction = 'amazonq_midLoopCompaction', ChatHistoryAction = 'amazonq_performChatHistoryAction', ExportTab = 'amazonq_exportTab', UiClick = 'ui_click', @@ -234,7 +233,6 @@ export interface ChatTelemetryEventMap { [ChatTelemetryEventName.LoadHistory]: LoadHistoryEvent [ChatTelemetryEventName.CompactHistory]: CompactHistoryEvent [ChatTelemetryEventName.CompactNudge]: CompactNudgeEvent - [ChatTelemetryEventName.MidLoopCompaction]: MidLoopCompactionEvent [ChatTelemetryEventName.ChatHistoryAction]: ChatHistoryActionEvent [ChatTelemetryEventName.ExportTab]: ExportTabEvent [ChatTelemetryEventName.UiClick]: UiClickEvent @@ -406,13 +404,6 @@ export type CompactNudgeEvent = { languageServerVersion?: string } -export type MidLoopCompactionEvent = { - characters: number - iterationCount: number - credentialStartUrl?: string - languageServerVersion?: string -} - export type ChatHistoryActionEvent = { action: ChatHistoryActionType result: Result From 6e9c384028a2990cfdfe512ba4ae52484fe4f4f1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 Oct 2025 13:51:56 -0700 Subject: [PATCH 144/158] chore(release): release packages from branch main (#2426) --- .release-please-manifest.json | 2 +- package-lock.json | 2 +- server/aws-lsp-codewhisperer/CHANGELOG.md | 7 +++++++ server/aws-lsp-codewhisperer/package.json | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1abd0ec3c0..aad7c2b66d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -2,7 +2,7 @@ "chat-client": "0.1.39", "core/aws-lsp-core": "0.0.16", "server/aws-lsp-antlr4": "0.1.20", - "server/aws-lsp-codewhisperer": "0.0.85", + "server/aws-lsp-codewhisperer": "0.0.86", "server/aws-lsp-json": "0.1.21", "server/aws-lsp-partiql": "0.0.18", "server/aws-lsp-yaml": "0.1.21" diff --git a/package-lock.json b/package-lock.json index 4db7812895..22b2cb7c8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28193,7 +28193,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.85", + "version": "0.0.86", "bundleDependencies": [ "@amzn/codewhisperer", "@amzn/codewhisperer-runtime", diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index dcca563d24..2fbe94a439 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.0.86](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.85...lsp-codewhisperer/v0.0.86) (2025-10-15) + + +### Reverts + +* revert for mid-loop compaction ([3f48b12](https://github.com/aws/language-servers/commit/3f48b12bce4faba474404f7c74a9520c379552fe)) + ## [0.0.85](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.84...lsp-codewhisperer/v0.0.85) (2025-10-14) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 799258c054..f461131308 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.85", + "version": "0.0.86", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { From bf9f997a95ed3c0bcba53fde9eccbeb6a3b1527b Mon Sep 17 00:00:00 2001 From: Shruti Sinha <44882001+shruti0085@users.noreply.github.com> Date: Wed, 15 Oct 2025 16:30:22 -0700 Subject: [PATCH 145/158] chore: bump agentic version: 1.40.0 (#2427) --- app/aws-lsp-codewhisperer-runtimes/src/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/src/version.json b/app/aws-lsp-codewhisperer-runtimes/src/version.json index 7629bf75a5..7638b8c43d 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/version.json +++ b/app/aws-lsp-codewhisperer-runtimes/src/version.json @@ -1,3 +1,3 @@ { - "agenticChat": "1.39.0" + "agenticChat": "1.40.0" } From 30b33a1c5d7767bbe7867bcbbfad0beb25414698 Mon Sep 17 00:00:00 2001 From: Sherry Lu <75588211+XiaoxuanLu@users.noreply.github.com> Date: Fri, 17 Oct 2025 10:56:32 -0700 Subject: [PATCH 146/158] chore: bump runtimes to 0.3.1 (#2428) * chore: bump chat-client-ui-types to latest * chore: bump up language-server-runtimes-types to latest * chore: bump language-server-runtimes to latest --- app/aws-lsp-antlr4-runtimes/package.json | 2 +- app/aws-lsp-buildspec-runtimes/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- app/aws-lsp-identity-runtimes/package.json | 2 +- app/aws-lsp-json-runtimes/package.json | 2 +- .../package.json | 2 +- app/aws-lsp-partiql-runtimes/package.json | 2 +- app/aws-lsp-s3-runtimes/package.json | 2 +- app/aws-lsp-yaml-json-webworker/package.json | 2 +- app/aws-lsp-yaml-runtimes/package.json | 2 +- app/hello-world-lsp-runtimes/package.json | 2 +- chat-client/CHANGELOG.md | 8 +-- chat-client/package.json | 6 +- client/vscode/package.json | 4 +- core/aws-lsp-core/package.json | 2 +- .../q-agentic-chat-server/package.json | 2 +- package-lock.json | 68 +++++++++---------- package.json | 2 +- server/aws-lsp-antlr4/package.json | 2 +- server/aws-lsp-buildspec/package.json | 2 +- server/aws-lsp-cloudformation/package.json | 2 +- server/aws-lsp-codewhisperer/package.json | 6 +- server/aws-lsp-identity/package.json | 2 +- server/aws-lsp-json/package.json | 2 +- server/aws-lsp-notification/package.json | 2 +- server/aws-lsp-partiql/package.json | 2 +- server/aws-lsp-s3/package.json | 2 +- server/aws-lsp-yaml/package.json | 2 +- server/device-sso-auth-lsp/package.json | 2 +- server/hello-world-lsp/package.json | 2 +- 31 files changed, 72 insertions(+), 72 deletions(-) diff --git a/app/aws-lsp-antlr4-runtimes/package.json b/app/aws-lsp-antlr4-runtimes/package.json index a82c01197b..747645c40d 100644 --- a/app/aws-lsp-antlr4-runtimes/package.json +++ b/app/aws-lsp-antlr4-runtimes/package.json @@ -12,7 +12,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-antlr4": "*", "antlr4-c3": "^3.4.2", "antlr4ng": "^3.0.14" diff --git a/app/aws-lsp-buildspec-runtimes/package.json b/app/aws-lsp-buildspec-runtimes/package.json index 141d9e6d6b..8daa91b5e1 100644 --- a/app/aws-lsp-buildspec-runtimes/package.json +++ b/app/aws-lsp-buildspec-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-buildspec": "^0.0.1" } } diff --git a/app/aws-lsp-cloudformation-runtimes/package.json b/app/aws-lsp-cloudformation-runtimes/package.json index 9dfcc2bf33..e4e277ecde 100644 --- a/app/aws-lsp-cloudformation-runtimes/package.json +++ b/app/aws-lsp-cloudformation-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-cloudformation": "^0.0.1" } } diff --git a/app/aws-lsp-codewhisperer-runtimes/package.json b/app/aws-lsp-codewhisperer-runtimes/package.json index ba48f15994..fac1a07ce9 100644 --- a/app/aws-lsp-codewhisperer-runtimes/package.json +++ b/app/aws-lsp-codewhisperer-runtimes/package.json @@ -23,7 +23,7 @@ "local-build": "node scripts/local-build.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", diff --git a/app/aws-lsp-identity-runtimes/package.json b/app/aws-lsp-identity-runtimes/package.json index 44a4651c2b..74fa7c332b 100644 --- a/app/aws-lsp-identity-runtimes/package.json +++ b/app/aws-lsp-identity-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-identity": "^0.0.1" } } diff --git a/app/aws-lsp-json-runtimes/package.json b/app/aws-lsp-json-runtimes/package.json index 7cca7ccd46..4348ae866a 100644 --- a/app/aws-lsp-json-runtimes/package.json +++ b/app/aws-lsp-json-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-json": "*" }, "devDependencies": { diff --git a/app/aws-lsp-notification-runtimes/package.json b/app/aws-lsp-notification-runtimes/package.json index b40ae649d2..47ea043b34 100644 --- a/app/aws-lsp-notification-runtimes/package.json +++ b/app/aws-lsp-notification-runtimes/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-notification": "^0.0.1" } } diff --git a/app/aws-lsp-partiql-runtimes/package.json b/app/aws-lsp-partiql-runtimes/package.json index 50ca5d9230..9b8ef07a25 100644 --- a/app/aws-lsp-partiql-runtimes/package.json +++ b/app/aws-lsp-partiql-runtimes/package.json @@ -11,7 +11,7 @@ "package": "npm run compile && npm run compile:webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-partiql": "^0.0.18" }, "devDependencies": { diff --git a/app/aws-lsp-s3-runtimes/package.json b/app/aws-lsp-s3-runtimes/package.json index 28779147bb..6afd693a46 100644 --- a/app/aws-lsp-s3-runtimes/package.json +++ b/app/aws-lsp-s3-runtimes/package.json @@ -10,7 +10,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-s3": "^0.0.1" } } diff --git a/app/aws-lsp-yaml-json-webworker/package.json b/app/aws-lsp-yaml-json-webworker/package.json index 7877c221ab..262e48b798 100644 --- a/app/aws-lsp-yaml-json-webworker/package.json +++ b/app/aws-lsp-yaml-json-webworker/package.json @@ -11,7 +11,7 @@ "serve:webpack": "NODE_ENV=development webpack serve" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, diff --git a/app/aws-lsp-yaml-runtimes/package.json b/app/aws-lsp-yaml-runtimes/package.json index e408b07bcd..6bd43690ef 100644 --- a/app/aws-lsp-yaml-runtimes/package.json +++ b/app/aws-lsp-yaml-runtimes/package.json @@ -11,7 +11,7 @@ "webpack": "webpack" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-yaml": "*" }, "devDependencies": { diff --git a/app/hello-world-lsp-runtimes/package.json b/app/hello-world-lsp-runtimes/package.json index 792629426d..7b1bf6f9cd 100644 --- a/app/hello-world-lsp-runtimes/package.json +++ b/app/hello-world-lsp-runtimes/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@aws/hello-world-lsp": "^0.0.1", - "@aws/language-server-runtimes": "^0.3.0" + "@aws/language-server-runtimes": "^0.3.1" }, "devDependencies": { "@types/chai": "^4.3.5", diff --git a/chat-client/CHANGELOG.md b/chat-client/CHANGELOG.md index 79a0f67ac4..4451ffb5fe 100644 --- a/chat-client/CHANGELOG.md +++ b/chat-client/CHANGELOG.md @@ -496,8 +496,8 @@ ### Changed -- Update `@aws/chat-client-ui-types` to 0.1.35 -- Update `@aws/language-server-runtimes-types` to 0.1.29 +- Update `@aws/chat-client-ui-types` to 0.1.63 +- Update `@aws/language-server-runtimes-types` to 0.1.57 - Shortened legal text in the footer ## [0.0.9] - 2024-11-20 @@ -521,8 +521,8 @@ ### Changed - Changed legal text in the footer -- Update `@aws/chat-client-ui-types` to 0.1.35 -- Update `@aws/language-server-runtimes-types` to 0.1.29 +- Update `@aws/chat-client-ui-types` to 0.1.63 +- Update `@aws/language-server-runtimes-types` to 0.1.57 - Upgraded dependency: `@aws/mynah-ui` from 4.15.11 to 4.18.0: - Inline code elements now wrap onto new lines - Send button no longer shifts out of the window when horizontally filling the prompt input without spaces (now it wraps) diff --git a/chat-client/package.json b/chat-client/package.json index 51662618b5..0639c785ec 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -24,9 +24,9 @@ "package": "webpack" }, "dependencies": { - "@aws/chat-client-ui-types": "^0.1.57", - "@aws/language-server-runtimes": "^0.3.0", - "@aws/language-server-runtimes-types": "^0.1.56", + "@aws/chat-client-ui-types": "^0.1.63", + "@aws/language-server-runtimes": "^0.3.1", + "@aws/language-server-runtimes-types": "^0.1.57", "@aws/mynah-ui": "^4.36.8" }, "devDependencies": { diff --git a/client/vscode/package.json b/client/vscode/package.json index 3c970d47bd..7a2e502264 100644 --- a/client/vscode/package.json +++ b/client/vscode/package.json @@ -351,8 +351,8 @@ "devDependencies": { "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", - "@aws/chat-client-ui-types": "^0.1.57", - "@aws/language-server-runtimes": "^0.3.0", + "@aws/chat-client-ui-types": "^0.1.63", + "@aws/language-server-runtimes": "^0.3.1", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", diff --git a/core/aws-lsp-core/package.json b/core/aws-lsp-core/package.json index cb7dd9f94c..156ccb8814 100644 --- a/core/aws-lsp-core/package.json +++ b/core/aws-lsp-core/package.json @@ -28,7 +28,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", diff --git a/integration-tests/q-agentic-chat-server/package.json b/integration-tests/q-agentic-chat-server/package.json index ba8312a569..92882f1859 100644 --- a/integration-tests/q-agentic-chat-server/package.json +++ b/integration-tests/q-agentic-chat-server/package.json @@ -9,7 +9,7 @@ "test-integ": "npm run compile && mocha --timeout 30000 \"./out/**/*.test.js\" --retries 2" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "*" }, "devDependencies": { diff --git a/package-lock.json b/package-lock.json index 22b2cb7c8b..e8d1927351 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "integration-tests/*" ], "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@smithy/types": "4.2.0", "clean": "^4.0.2", "typescript": "^5.8.2" @@ -48,7 +48,7 @@ "name": "@aws/lsp-antlr4-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-antlr4": "*", "antlr4-c3": "^3.4.2", "antlr4ng": "^3.0.14" @@ -71,7 +71,7 @@ "name": "@aws/lsp-buildspec-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-buildspec": "^0.0.1" } }, @@ -79,7 +79,7 @@ "name": "@aws/lsp-cloudformation-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-cloudformation": "^0.0.1" } }, @@ -87,7 +87,7 @@ "name": "@aws/lsp-codewhisperer-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-codewhisperer": "*", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", @@ -136,7 +136,7 @@ "name": "@aws/lsp-identity-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-identity": "^0.0.1" } }, @@ -144,7 +144,7 @@ "name": "@aws/lsp-json-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-json": "*" }, "devDependencies": { @@ -164,7 +164,7 @@ "name": "@aws/lsp-notification-runtimes", "version": "0.1.0", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-notification": "^0.0.1" } }, @@ -172,7 +172,7 @@ "name": "@aws/lsp-partiql-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-partiql": "^0.0.18" }, "devDependencies": { @@ -186,7 +186,7 @@ "name": "@aws/lsp-s3-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-s3": "^0.0.1" }, "bin": { @@ -197,7 +197,7 @@ "name": "@aws/lsp-yaml-json-webworker", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*" }, @@ -217,7 +217,7 @@ "name": "@aws/lsp-yaml-runtimes", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-yaml": "*" }, "devDependencies": { @@ -239,7 +239,7 @@ "version": "0.0.1", "dependencies": { "@aws/hello-world-lsp": "^0.0.1", - "@aws/language-server-runtimes": "^0.3.0" + "@aws/language-server-runtimes": "^0.3.1" }, "devDependencies": { "@types/chai": "^4.3.5", @@ -259,9 +259,9 @@ "version": "0.1.39", "license": "Apache-2.0", "dependencies": { - "@aws/chat-client-ui-types": "^0.1.57", - "@aws/language-server-runtimes": "^0.3.0", - "@aws/language-server-runtimes-types": "^0.1.56", + "@aws/chat-client-ui-types": "^0.1.63", + "@aws/language-server-runtimes": "^0.3.1", + "@aws/language-server-runtimes-types": "^0.1.57", "@aws/mynah-ui": "^4.36.8" }, "devDependencies": { @@ -320,8 +320,8 @@ "devDependencies": { "@aws-sdk/credential-providers": "^3.731.1", "@aws-sdk/types": "^3.734.0", - "@aws/chat-client-ui-types": "^0.1.57", - "@aws/language-server-runtimes": "^0.3.0", + "@aws/chat-client-ui-types": "^0.1.63", + "@aws/language-server-runtimes": "^0.3.1", "@types/uuid": "^9.0.8", "@types/vscode": "^1.98.0", "jose": "^5.2.4", @@ -337,7 +337,7 @@ "version": "0.0.16", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@gerhobbelt/gitignore-parser": "^0.2.0-9", "cross-spawn": "7.0.6", "jose": "^5.2.4", @@ -368,7 +368,7 @@ "name": "@aws/q-agentic-chat-server-integration-tests", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "*" }, "devDependencies": { @@ -28132,7 +28132,7 @@ "version": "0.1.20", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "^0.0.16" }, "devDependencies": { @@ -28173,7 +28173,7 @@ "name": "@aws/lsp-buildspec", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", @@ -28184,7 +28184,7 @@ "name": "@aws/lsp-cloudformation", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", @@ -28210,8 +28210,8 @@ "@aws-sdk/types": "^3.734.0", "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", - "@aws/chat-client-ui-types": "^0.1.57", - "@aws/language-server-runtimes": "^0.3.0", + "@aws/chat-client-ui-types": "^0.1.63", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "^0.0.16", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", @@ -28413,7 +28413,7 @@ "dependencies": { "@aws-sdk/client-sso-oidc": "^3.616.0", "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "^0.0.16", "@smithy/node-http-handler": "^3.2.5", "@smithy/shared-ini-file-loader": "^4.0.1", @@ -28940,7 +28940,7 @@ "version": "0.1.21", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" @@ -28996,7 +28996,7 @@ "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1" }, @@ -29073,7 +29073,7 @@ "version": "0.0.18", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "antlr4-c3": "3.4.4", "antlr4ng": "3.0.16", "web-tree-sitter": "0.22.6" @@ -29095,7 +29095,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "^0.0.15", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" @@ -29122,7 +29122,7 @@ "version": "0.2.129", "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes-types": "^0.1.56", + "@aws/language-server-runtimes-types": "^0.1.57", "@opentelemetry/api": "^1.9.0", "@opentelemetry/api-logs": "^0.200.0", "@opentelemetry/core": "^2.0.0", @@ -29154,7 +29154,7 @@ "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", @@ -29168,7 +29168,7 @@ "name": "@amzn/device-sso-auth-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "vscode-languageserver": "^9.0.1" }, "devDependencies": { @@ -29179,7 +29179,7 @@ "name": "@aws/hello-world-lsp", "version": "0.0.1", "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/package.json b/package.json index 4e7f440ac4..e314f953fe 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "ci:generate:agentic:attribution": "ts-node ./script/prepare-agentic-attribution-dependencies.ts && ./script/generate-agentic-attribution.sh && git restore package.json" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@smithy/types": "4.2.0", "clean": "^4.0.2", "typescript": "^5.8.2" diff --git a/server/aws-lsp-antlr4/package.json b/server/aws-lsp-antlr4/package.json index 565a3732e1..e515580e58 100644 --- a/server/aws-lsp-antlr4/package.json +++ b/server/aws-lsp-antlr4/package.json @@ -28,7 +28,7 @@ "clean": "rm -rf node_modules" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "^0.0.16" }, "peerDependencies": { diff --git a/server/aws-lsp-buildspec/package.json b/server/aws-lsp-buildspec/package.json index 32da0c8306..562ed8d18a 100644 --- a/server/aws-lsp-buildspec/package.json +++ b/server/aws-lsp-buildspec/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-json": "*", "@aws/lsp-yaml": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-cloudformation/package.json b/server/aws-lsp-cloudformation/package.json index 4b5087c74a..155a075ca7 100644 --- a/server/aws-lsp-cloudformation/package.json +++ b/server/aws-lsp-cloudformation/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "*", "@aws/lsp-json": "*", "vscode-languageserver": "^9.0.1", diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index f461131308..a0c6bac08f 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -33,17 +33,17 @@ "@amzn/codewhisperer": "file:../../core/codewhisperer/amzn-codewhisperer-1.0.0.tgz", "@amzn/codewhisperer-runtime": "file:../../core/codewhisperer-runtime/amzn-codewhisperer-runtime-1.0.0.tgz", "@amzn/codewhisperer-streaming": "file:../../core/codewhisperer-streaming/amzn-codewhisperer-streaming-1.0.0.tgz", + "@aws-sdk/types": "^3.734.0", "@aws-sdk/util-arn-parser": "^3.723.0", "@aws-sdk/util-retry": "^3.374.0", - "@aws/chat-client-ui-types": "^0.1.57", - "@aws/language-server-runtimes": "^0.3.0", + "@aws/chat-client-ui-types": "^0.1.63", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "^0.0.16", "@modelcontextprotocol/sdk": "^1.15.0", "@smithy/node-http-handler": "^2.5.0", "adm-zip": "^0.5.10", "archiver": "^7.0.1", "async-mutex": "^0.5.0", - "@aws-sdk/types": "^3.734.0", "axios": "^1.8.4", "chokidar": "^4.0.3", "deepmerge": "^4.3.1", diff --git a/server/aws-lsp-identity/package.json b/server/aws-lsp-identity/package.json index a7962e9f7a..fbebf05628 100644 --- a/server/aws-lsp-identity/package.json +++ b/server/aws-lsp-identity/package.json @@ -26,7 +26,7 @@ "dependencies": { "@aws-sdk/client-sso-oidc": "^3.616.0", "@aws-sdk/token-providers": "^3.744.0", - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "^0.0.16", "@smithy/node-http-handler": "^3.2.5", "@smithy/shared-ini-file-loader": "^4.0.1", diff --git a/server/aws-lsp-json/package.json b/server/aws-lsp-json/package.json index 5fde4b4578..41c2c0b750 100644 --- a/server/aws-lsp-json/package.json +++ b/server/aws-lsp-json/package.json @@ -26,7 +26,7 @@ "prepack": "shx cp ../../LICENSE ../../NOTICE ../../SECURITY.md ." }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" diff --git a/server/aws-lsp-notification/package.json b/server/aws-lsp-notification/package.json index 344db460e6..e52d9195d1 100644 --- a/server/aws-lsp-notification/package.json +++ b/server/aws-lsp-notification/package.json @@ -22,7 +22,7 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1" }, diff --git a/server/aws-lsp-partiql/package.json b/server/aws-lsp-partiql/package.json index afd6ef4ba4..87470433cd 100644 --- a/server/aws-lsp-partiql/package.json +++ b/server/aws-lsp-partiql/package.json @@ -24,7 +24,7 @@ "out" ], "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "antlr4-c3": "3.4.4", "antlr4ng": "3.0.16", "web-tree-sitter": "0.22.6" diff --git a/server/aws-lsp-s3/package.json b/server/aws-lsp-s3/package.json index 338bb0ccdf..5ca107043b 100644 --- a/server/aws-lsp-s3/package.json +++ b/server/aws-lsp-s3/package.json @@ -9,7 +9,7 @@ "dependencies": { "@aws-sdk/client-s3": "^3.623.0", "@aws-sdk/types": "^3.734.0", - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "^0.0.15", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8" diff --git a/server/aws-lsp-yaml/package.json b/server/aws-lsp-yaml/package.json index 8188db3de4..7140ad02ef 100644 --- a/server/aws-lsp-yaml/package.json +++ b/server/aws-lsp-yaml/package.json @@ -26,7 +26,7 @@ "postinstall": "node patchYamlPackage.js" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "@aws/lsp-core": "^0.0.16", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.8", diff --git a/server/device-sso-auth-lsp/package.json b/server/device-sso-auth-lsp/package.json index e417a5c4a6..19e77c04dc 100644 --- a/server/device-sso-auth-lsp/package.json +++ b/server/device-sso-auth-lsp/package.json @@ -7,7 +7,7 @@ "compile": "tsc --build" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "vscode-languageserver": "^9.0.1" }, "devDependencies": { diff --git a/server/hello-world-lsp/package.json b/server/hello-world-lsp/package.json index b8b2a4f6c0..e45a891713 100644 --- a/server/hello-world-lsp/package.json +++ b/server/hello-world-lsp/package.json @@ -13,7 +13,7 @@ "coverage:report": "c8 report --reporter=html --reporter=text" }, "dependencies": { - "@aws/language-server-runtimes": "^0.3.0", + "@aws/language-server-runtimes": "^0.3.1", "vscode-languageserver": "^9.0.1" }, "devDependencies": { From bee5cadeaf8840a8af08acfe8b58442aac7ad567 Mon Sep 17 00:00:00 2001 From: Sherry Lu <75588211+XiaoxuanLu@users.noreply.github.com> Date: Fri, 17 Oct 2025 16:03:22 -0700 Subject: [PATCH 147/158] feat: send pinned context button immediately with pending state (#2353) * feat: context command pending state passed to ui, triggered when indexing complete * refactored pending flow * fix: removed extra spaces * fix: workspace pending turned back on when building index (when config is changed) * fix: log errors if inital context commands fail to send * refactor: changed pending state from boolean to string to send to ui * refactor: update from pending to disabledText * fix: send intial pending state before any other action in contextCommandsProvider * fix: send initial pending context commands onReady, instead of before * test: added unit test for onReady * test: added unit test for when indexingInProgress is changed * chore: fix the mynal ui test * chore: fix the mynal test for lack of disabled field --------- Co-authored-by: Conor Stewart Co-authored-by: constewart9 <150978709+constewart9@users.noreply.github.com> Co-authored-by: manodnyab <66754471+manodnyab@users.noreply.github.com> --- chat-client/src/client/mynahUi.test.ts | 4 +- chat-client/src/client/mynahUi.ts | 1 + .../agenticChat/agenticChatController.ts | 2 + .../context/contextCommandsProvider.test.ts | 52 +++++++++++++++++++ .../context/contextCommandsProvider.ts | 31 ++++++++++- .../shared/localProjectContextController.ts | 4 ++ 6 files changed, 92 insertions(+), 2 deletions(-) diff --git a/chat-client/src/client/mynahUi.test.ts b/chat-client/src/client/mynahUi.test.ts index 3a13772926..1f9f6c4e57 100644 --- a/chat-client/src/client/mynahUi.test.ts +++ b/chat-client/src/client/mynahUi.test.ts @@ -634,6 +634,7 @@ describe('MynahUI', () => { route: ['/workspace', 'src/file1.ts'], icon: 'file', children: undefined, + disabled: false, }, ], promptTopBarTitle: '@', @@ -690,6 +691,7 @@ describe('MynahUI', () => { ...activeEditorCommand, description: 'file:///workspace/src/active.ts', children: undefined, + disabled: false, }, ], promptTopBarTitle: '@Pin Context', @@ -729,7 +731,7 @@ describe('MynahUI', () => { // Verify updateStore was called with empty context items // Active editor should be removed since no textDocument was provided sinon.assert.calledWith(updateStoreSpy, tabId, { - promptTopBarContextItems: [{ ...fileCommand, children: undefined }], + promptTopBarContextItems: [{ ...fileCommand, children: undefined, disabled: false }], promptTopBarTitle: '@', promptTopBarButton: null, }) diff --git a/chat-client/src/client/mynahUi.ts b/chat-client/src/client/mynahUi.ts index 0bcdf9bacd..63995c6bc8 100644 --- a/chat-client/src/client/mynahUi.ts +++ b/chat-client/src/client/mynahUi.ts @@ -1560,6 +1560,7 @@ ${params.message}`, commands: toContextCommands(child.commands), })), icon: toMynahIcon(command.icon), + disabled: command.disabledText != null, })) } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts index 377d58fc7a..56e577e9af 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/agenticChatController.ts @@ -3847,9 +3847,11 @@ export class AgenticChatController implements ChatHandlers { */ async onReady() { await this.restorePreviousChats() + this.#contextCommandsProvider.onReady() try { const localProjectContextController = await LocalProjectContextController.getInstance() const contextItems = await localProjectContextController.getContextCommandItems() + this.#contextCommandsProvider.setFilesAndFoldersPending(false) await this.#contextCommandsProvider.processContextCommandUpdate(contextItems) void this.#contextCommandsProvider.maybeUpdateCodeSymbols() } catch (error) { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/contextCommandsProvider.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/contextCommandsProvider.test.ts index d387c96d82..dbada5b8d7 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/contextCommandsProvider.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/contextCommandsProvider.test.ts @@ -3,6 +3,7 @@ import * as sinon from 'sinon' import { TestFeatures } from '@aws/language-server-runtimes/testing' import * as chokidar from 'chokidar' import { ContextCommandItem } from 'local-indexing' +import { LocalProjectContextController } from '../../../shared/localProjectContextController' describe('ContextCommandsProvider', () => { let provider: ContextCommandsProvider @@ -21,6 +22,12 @@ describe('ContextCommandsProvider', () => { testFeatures.workspace.fs.exists = fsExistsStub testFeatures.workspace.fs.readdir = fsReadDirStub + + sinon.stub(LocalProjectContextController, 'getInstance').resolves({ + onContextItemsUpdated: sinon.stub(), + onIndexingInProgressChanged: sinon.stub(), + } as any) + provider = new ContextCommandsProvider( testFeatures.logging, testFeatures.chat, @@ -58,6 +65,26 @@ describe('ContextCommandsProvider', () => { }) }) + describe('onReady', () => { + it('should call processContextCommandUpdate with empty array on first call', async () => { + const processUpdateSpy = sinon.spy(provider, 'processContextCommandUpdate') + + provider.onReady() + + sinon.assert.calledOnce(processUpdateSpy) + sinon.assert.calledWith(processUpdateSpy, []) + }) + + it('should not call processContextCommandUpdate on subsequent calls', async () => { + const processUpdateSpy = sinon.spy(provider, 'processContextCommandUpdate') + + provider.onReady() + provider.onReady() + + sinon.assert.calledOnce(processUpdateSpy) + }) + }) + describe('onContextItemsUpdated', () => { it('should call processContextCommandUpdate when controller raises event', async () => { const mockContextItems: ContextCommandItem[] = [ @@ -78,4 +105,29 @@ describe('ContextCommandsProvider', () => { sinon.assert.calledWith(processUpdateSpy, mockContextItems) }) }) + + describe('onIndexingInProgressChanged', () => { + it('should update workspacePending and call processContextCommandUpdate when indexing status changes', async () => { + let capturedCallback: ((indexingInProgress: boolean) => void) | undefined + + const mockController = { + onContextItemsUpdated: sinon.stub(), + set onIndexingInProgressChanged(callback: (indexingInProgress: boolean) => void) { + capturedCallback = callback + }, + } + + const processUpdateSpy = sinon.spy(provider, 'processContextCommandUpdate') + ;(LocalProjectContextController.getInstance as sinon.SinonStub).resolves(mockController as any) + + // Set initial state to false so condition is met + ;(provider as any).workspacePending = false + + await (provider as any).registerContextCommandHandler() + + capturedCallback?.(true) + + sinon.assert.calledWith(processUpdateSpy, []) + }) + }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/contextCommandsProvider.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/contextCommandsProvider.ts index 632360cd67..4a4f5cd4fb 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/contextCommandsProvider.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/context/contextCommandsProvider.ts @@ -12,6 +12,10 @@ import { activeFileCmd } from './additionalContextProvider' export class ContextCommandsProvider implements Disposable { private promptFileWatcher?: FSWatcher private cachedContextCommands?: ContextCommandItem[] + private codeSymbolsPending = true + private filesAndFoldersPending = true + private workspacePending = true + private initialStateSent = false constructor( private readonly logging: Logging, private readonly chat: Chat, @@ -24,12 +28,27 @@ export class ContextCommandsProvider implements Disposable { ) } + onReady() { + if (!this.initialStateSent) { + this.initialStateSent = true + void this.processContextCommandUpdate([]).catch(e => + this.logging.error(`Failed to send initial context commands: ${e}`) + ) + } + } + private async registerContextCommandHandler() { try { const controller = await LocalProjectContextController.getInstance() controller.onContextItemsUpdated = async contextItems => { await this.processContextCommandUpdate(contextItems) } + controller.onIndexingInProgressChanged = (indexingInProgress: boolean) => { + if (this.workspacePending !== indexingInProgress) { + this.workspacePending = indexingInProgress + void this.processContextCommandUpdate(this.cachedContextCommands ?? []) + } + } } catch (e) { this.logging.warn(`Error processing context command update: ${e}`) } @@ -105,6 +124,7 @@ export class ContextCommandsProvider implements Disposable { ], description: 'Add all files in a folder to context', icon: 'folder', + disabledText: this.filesAndFoldersPending ? 'pending' : undefined, } const fileCmds: ContextCommand[] = [activeFileCmd] @@ -118,6 +138,7 @@ export class ContextCommandsProvider implements Disposable { ], description: 'Add a file to context', icon: 'file', + disabledText: this.filesAndFoldersPending ? 'pending' : undefined, } const codeCmds: ContextCommand[] = [] @@ -131,6 +152,7 @@ export class ContextCommandsProvider implements Disposable { ], description: 'Add code to context', icon: 'code-block', + disabledText: this.codeSymbolsPending ? 'pending' : undefined, } const promptCmds: ContextCommand[] = [] @@ -152,10 +174,12 @@ export class ContextCommandsProvider implements Disposable { icon: 'image', placeholder: 'Select an image file', } - const workspaceCmd = { + + const workspaceCmd: ContextCommand = { command: '@workspace', id: '@workspace', description: 'Reference all code in workspace', + disabledText: this.workspacePending ? 'pending' : undefined, } const commands = [workspaceCmd, folderCmdGroup, fileCmdGroup, codeCmdGroup, promptCmdGroup] @@ -209,11 +233,16 @@ export class ContextCommandsProvider implements Disposable { await LocalProjectContextController.getInstance() ).shouldUpdateContextCommandSymbolsOnce() if (needUpdate) { + this.codeSymbolsPending = false const items = await (await LocalProjectContextController.getInstance()).getContextCommandItems() await this.processContextCommandUpdate(items) } } + setFilesAndFoldersPending(value: boolean) { + this.filesAndFoldersPending = value + } + dispose() { void this.promptFileWatcher?.close() } diff --git a/server/aws-lsp-codewhisperer/src/shared/localProjectContextController.ts b/server/aws-lsp-codewhisperer/src/shared/localProjectContextController.ts index 27317e954e..63143f1c75 100644 --- a/server/aws-lsp-codewhisperer/src/shared/localProjectContextController.ts +++ b/server/aws-lsp-codewhisperer/src/shared/localProjectContextController.ts @@ -50,6 +50,8 @@ export interface LocalProjectContextInitializationOptions { export class LocalProjectContextController { // Event handler for context items updated public onContextItemsUpdated: ((contextItems: ContextCommandItem[]) => Promise) | undefined + // Event handler for when index is being built + public onIndexingInProgressChanged: ((enabled: boolean) => void) | undefined private static instance: LocalProjectContextController | undefined private workspaceFolders: WorkspaceFolder[] @@ -214,6 +216,7 @@ export class LocalProjectContextController { } try { this._isIndexingInProgress = true + this.onIndexingInProgressChanged?.(this._isIndexingInProgress) if (this._vecLib) { if (!this.workspaceFolders.length) { this.log.info('skip building index because no workspace folder found') @@ -234,6 +237,7 @@ export class LocalProjectContextController { this.log.error(`Error building index: ${error}`) } finally { this._isIndexingInProgress = false + this.onIndexingInProgressChanged?.(this._isIndexingInProgress) } } From 2c33b384a0e406bcd8d3888a911d5482ce1f38ef Mon Sep 17 00:00:00 2001 From: Na Yue Date: Mon, 20 Oct 2025 13:34:53 -0700 Subject: [PATCH 148/158] feat(amazonq): add user requirement to zipfile for code review tool (#2430) Co-authored-by: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> --- .../tools/qCodeAnalysis/codeReview.test.ts | 13 +++++++++++++ .../agenticChat/tools/qCodeAnalysis/codeReview.ts | 12 +++++++++++- .../tools/qCodeAnalysis/codeReviewSchemas.ts | 6 ++++-- .../tools/qCodeAnalysis/codeReviewTypes.ts | 1 + 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts index 4b53d3a71e..2dc8aca1a0 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.test.ts @@ -104,6 +104,7 @@ describe('CodeReview', () => { folderLevelArtifacts: [], ruleArtifacts: [], scopeOfReview: FULL_REVIEW, + userRequirement: 'Test requirement', modelId: 'claude-4-sonnet', } }) @@ -136,7 +137,9 @@ describe('CodeReview', () => { md5Hash: 'hash123', isCodeDiffPresent: false, programmingLanguages: new Set(['javascript']), + numberOfFilesInCustomerCodeZip: 1, codeDiffFiles: new Set(), + filePathsInZip: new Set(['/test/file.js']), }) sandbox.stub(codeReview as any, 'parseFindings').returns([]) @@ -265,7 +268,9 @@ describe('CodeReview', () => { md5Hash: 'hash123', isCodeDiffPresent: false, programmingLanguages: new Set(['javascript']), + numberOfFilesInCustomerCodeZip: 1, codeDiffFiles: new Set(), + filePathsInZip: new Set(['/test/file.js']), }) sandbox.stub(codeReview as any, 'parseFindings').returns([]) @@ -305,6 +310,7 @@ describe('CodeReview', () => { folderLevelArtifacts: [], ruleArtifacts: [], scopeOfReview: FULL_REVIEW, + userRequirement: 'Test requirement', modelId: 'claude-4-sonnet', } @@ -428,6 +434,7 @@ describe('CodeReview', () => { folderLevelArtifacts: [], ruleArtifacts: [], scopeOfReview: FULL_REVIEW, + userRequirement: 'Test requirement', modelId: 'claude-4-sonnet', } @@ -453,6 +460,7 @@ describe('CodeReview', () => { folderLevelArtifacts: [{ path: '/test/folder' }], ruleArtifacts: [], scopeOfReview: CODE_DIFF_REVIEW, + userRequirement: 'Test requirement', modelId: 'claude-4-sonnet', } @@ -488,6 +496,7 @@ describe('CodeReview', () => { const ruleArtifacts: any[] = [] const result = await (codeReview as any).prepareFilesAndFoldersForUpload( + 'Test requirement', fileArtifacts, folderArtifacts, ruleArtifacts, @@ -507,6 +516,7 @@ describe('CodeReview', () => { sandbox.stub(CodeReviewUtils, 'processArtifactWithDiff').resolves('diff content\n') const result = await (codeReview as any).prepareFilesAndFoldersForUpload( + 'Test requirement', fileArtifacts, folderArtifacts, ruleArtifacts, @@ -526,6 +536,7 @@ describe('CodeReview', () => { try { await (codeReview as any).prepareFilesAndFoldersForUpload( + 'Test requirement', fileArtifacts, folderArtifacts, ruleArtifacts, @@ -554,6 +565,7 @@ describe('CodeReview', () => { sandbox.stub(require('crypto'), 'randomUUID').returns('test-uuid-123') await (codeReview as any).prepareFilesAndFoldersForUpload( + 'Test requirement', fileArtifacts, folderArtifacts, ruleArtifacts, @@ -767,6 +779,7 @@ describe('CodeReview', () => { folderLevelArtifacts: [], ruleArtifacts: [], scopeOfReview: FULL_REVIEW, + userRequirement: 'Test requirement', modelId: 'claude-4-sonnet', } diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts index 7efd71c171..902b7e2882 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReview.ts @@ -39,6 +39,7 @@ export class CodeReview { private static readonly CODE_ARTIFACT_PATH = 'code_artifact' private static readonly CUSTOMER_CODE_ZIP_NAME = 'customerCode.zip' private static readonly CODE_DIFF_PATH = 'code_artifact/codeDiff/customerCodeDiff.diff' + private static readonly USER_REQUIREMENT_PATH = 'code_artifact/userRequirement/userRequirement.txt' private static readonly RULE_ARTIFACT_PATH = '.amazonq/rules' private static readonly MAX_POLLING_ATTEMPTS = 90 // 90 * POLLING_INTERVAL_MS (10000) = 15 mins private static readonly MID_POLLING_ATTEMPTS = 20 @@ -176,6 +177,7 @@ export class CodeReview { // parse input const validatedInput = Z_CODE_REVIEW_INPUT_SCHEMA.parse(input) + const userRequirement = validatedInput.userRequirement const fileArtifacts = validatedInput.fileLevelArtifacts || [] const folderArtifacts = validatedInput.folderLevelArtifacts || [] const ruleArtifacts = validatedInput.ruleArtifacts || [] @@ -204,9 +206,12 @@ export class CodeReview { const programmingLanguage = 'java' const scanName = 'Standard-' + randomUUID() - this.logging.info(`Agentic scan name: ${scanName} selectedModel: ${modelId}`) + this.logging.info( + `Agentic scan name: ${scanName} selectedModel: ${modelId} userRequirement: ${userRequirement}` + ) return { + userRequirement, fileArtifacts, folderArtifacts, isFullReviewRequest, @@ -235,6 +240,7 @@ export class CodeReview { codeDiffFiles, filePathsInZip, } = await this.prepareFilesAndFoldersForUpload( + setup.userRequirement, setup.fileArtifacts, setup.folderArtifacts, setup.ruleArtifacts, @@ -603,6 +609,7 @@ export class CodeReview { * @returns An object containing the zip file buffer and its MD5 hash */ private async prepareFilesAndFoldersForUpload( + userRequirement: string, fileArtifacts: FileArtifacts, folderArtifacts: FolderArtifacts, ruleArtifacts: RuleArtifacts, @@ -660,6 +667,9 @@ export class CodeReview { codeArtifactZip.file(CodeReview.CODE_DIFF_PATH, codeDiff) } + // Add user requirement + codeArtifactZip.file(CodeReview.USER_REQUIREMENT_PATH, userRequirement) + // Generate the final code artifact zip const zipBuffer = await CodeReviewUtils.generateZipBuffer(codeArtifactZip) CodeReviewUtils.logZipStructure(codeArtifactZip, 'Code artifact', this.logging) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewSchemas.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewSchemas.ts index 3b230ae116..34df1f56c2 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewSchemas.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewSchemas.ts @@ -12,8 +12,9 @@ import { FINDING_SEVERITY, SCOPE_OF_CODE_REVIEW } from './codeReviewConstants' export const CODE_REVIEW_INPUT_SCHEMA = { type: 'object', description: [ - '**3 main fields in the tool:**', + '**4 main fields in the tool:**', '- scopeOfReview: CRITICAL - Must be set to either FULL_REVIEW (analyze entire file/folder/project/workspace) or CODE_DIFF_REVIEW (focus only on changes/modifications in the file/folder/project/workspace). This is a required field.', + '- userRequirement: CRITICAL - Must be set as a string to describe the user requirement by analyzing the current conversation and extracting all the related information for code review. This is a required field.', '- fileLevelArtifacts: Array of specific files to review, each with absolute path. Use this when reviewing individual files, not folders. Format: [{"path": "/absolute/path/to/file.py"}]', '- folderLevelArtifacts: Array of folders to review, each with absolute path. Use this when reviewing entire directories, not individual files. Format: [{"path": "/absolute/path/to/folder/"}]', "Note: Either fileLevelArtifacts OR folderLevelArtifacts should be provided based on what's being reviewed, but not both for the same items.", @@ -84,7 +85,7 @@ export const CODE_REVIEW_INPUT_SCHEMA = { }, }, }, - required: ['scopeOfReview'] as const, + required: ['scopeOfReview', 'userRequirement'] as const, } /** @@ -92,6 +93,7 @@ export const CODE_REVIEW_INPUT_SCHEMA = { */ export const Z_CODE_REVIEW_INPUT_SCHEMA = z.object({ scopeOfReview: z.enum(SCOPE_OF_CODE_REVIEW as [string, ...string[]]), + userRequirement: z.string(), fileLevelArtifacts: z .array( z.object({ diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts index 8d1ac616d8..b77855b256 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/qCodeAnalysis/codeReviewTypes.ts @@ -14,6 +14,7 @@ export enum SuccessMetricName { } export type ValidateInputAndSetupResult = { + userRequirement: string fileArtifacts: FileArtifacts folderArtifacts: FolderArtifacts isFullReviewRequest: boolean From 2292bd75fded0848208de9401d15d3399a9c297b Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Tue, 21 Oct 2025 03:44:45 -0700 Subject: [PATCH 149/158] feat: nep auto trigger (#2424) ## Problem The existing edit trigger criteria is too loose (1) non empty right context (2) edit history in the past 20s. ## Solution Build a logistic regression classifier and use users editor state as the features of the formula. ## License By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. --- .../editPredictionAutoTrigger.test.ts | 513 +++++++++++++++++- .../auto-trigger/editPredictionAutoTrigger.ts | 417 +++++++++++++- .../handler/editCompletionHandler.test.ts | 38 +- .../handler/editCompletionHandler.ts | 122 ++--- .../handler/inlineCompletionHandler.ts | 2 +- .../session/sessionManager.ts | 17 + .../utils/triggerUtils.test.ts | 60 +- .../inline-completion/utils/triggerUtils.ts | 66 ++- .../src/shared/codeWhispererService.ts | 93 ++-- 9 files changed, 1192 insertions(+), 136 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.test.ts index 261748468f..15bc689654 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.test.ts @@ -5,10 +5,11 @@ import * as assert from 'assert' import * as sinon from 'sinon' -import { editPredictionAutoTrigger } from './editPredictionAutoTrigger' +import { EditClassifier, editPredictionAutoTrigger } from './editPredictionAutoTrigger' import { EditPredictionConfigManager } from './editPredictionConfig' -import { FileContext } from '../../../shared/codeWhispererService' -import { Position } from '@aws/language-server-runtimes/server-interface' +import { ClientFileContextClss, FileContext, getFileContext } from '../../../shared/codeWhispererService' +import { Logging, Position } from '@aws/language-server-runtimes/server-interface' +import { TextDocument } from 'vscode-languageserver-textdocument' import { CursorTracker } from '../tracker/cursorTracker' import { RecentEditTracker } from '../tracker/codeEditTracker' import { TestScenarios, EditTrackingScenarios, splitCodeAtPosition } from './EditPredictionAutoTriggerTestConstants' @@ -337,3 +338,509 @@ describe('editPredictionAutoTrigger', function () { }) }) }) + +describe('classifier', function () { + const SAMPLE = `public class HelloWorld { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } +}` + + const SAMPLE_FILE_CONTEXT = getFileContext({ + textDocument: TextDocument.create('file:///testfile.java', 'java', 1, SAMPLE), + position: Position.create(2, 18), + inferredLanguageId: 'java', + workspaceFolder: undefined, + }) + + // Create stubs for all methods + const loggingStub = { + error: sinon.stub(), + warn: sinon.stub(), + info: sinon.stub(), + log: sinon.stub(), + debug: sinon.stub(), + } satisfies Logging + + it('test sample', function () { + assert.strictEqual(SAMPLE_FILE_CONTEXT.leftContextAtCurLine, ' System.out') + assert.strictEqual(SAMPLE_FILE_CONTEXT.rightContextAtCurLine, '.println("Hello, World!");') // TODO: Not sure why it doesnt include \n + assert.strictEqual(SAMPLE_FILE_CONTEXT.programmingLanguage.languageName, 'java') + assert.strictEqual( + SAMPLE_FILE_CONTEXT.leftFileContent, + `public class HelloWorld { + public static void main(String[] args) { + System.out` + ) + assert.strictEqual( + SAMPLE_FILE_CONTEXT.rightFileContent, + `.println("Hello, World!"); + } +}` + ) + }) + + describe('constant check', function () { + it('intercept', function () { + assert.strictEqual(EditClassifier.INTERCEPT, -0.2782) + }) + + it('threshold', function () { + assert.strictEqual(EditClassifier.THRESHOLD, 0.53) + }) + + it('process edit history', function () { + const r = + EditClassifier.processEditHistory(`--- file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java 1760647547772 ++++ file:///Volumes/workplace/ide/sample_projects/Calculator-2/src/main/hello/MathUtil.java 1760647547851 +@@ -4,5 +4,5 @@ + return a + b; + } + +- public static int substract ++ public static int substract() + }`) + + assert.strictEqual(r.addedLines, 1) + assert.strictEqual(r.deletedLines, 1) + assert.strictEqual(r.changedCharacters, 2) + }) + + it('process edit history 2', function () { + const r = EditClassifier.processEditHistory(`--- file:///query.sql ++++ file:///query.sql +@@ -1,6 +1,4 @@ + SELECT u.name, u.email, p.title + FROM users u +-LEFT JOIN profiles pr ON u.id = pr.user_id + JOIN posts p ON u.id = p.user_id + WHERE u.active = true +-AND p.published_at >= '2023-01-01' ++AND p.published_date >= '2023-01-01'`) + + assert.strictEqual(r.addedLines, 1) + assert.strictEqual(r.deletedLines, 2) + assert.strictEqual(r.changedCharacters, 45) + }) + + it('edit distance cal', function () { + const r = EditClassifier.editDistance('public static int substract', 'public static int substract()') + assert.strictEqual(r, 2) + }) + }) + + describe('test logistic formula', function () { + function createMockFileContext(leftcontext: string, rightcontext: string) {} + + it('case 1 Python function with keyword', function () { + const document = TextDocument.create( + 'test.py', + 'python', + 1, + `def calculate_sum(a, b): + return a + b + +def main(): + result = calculate_sum(5, 3) + try: + print(f"Result: {result}") + except Exception as e: + print(f"Error: {e}") + +if __name__ == "__main__": + main()` + ) + const filecontext = new ClientFileContextClss({ + textDocument: document, + position: Position.create(5, 7), + inferredLanguageId: 'python', + workspaceFolder: undefined, + }) + + // assert setup is correct + assert.strictEqual( + filecontext.leftFileContent, + `def calculate_sum(a, b): + return a + b + +def main(): + result = calculate_sum(5, 3) + try` + ) + assert.strictEqual( + filecontext.rightFileContent, + `: + print(f"Result: {result}") + except Exception as e: + print(f"Error: {e}") + +if __name__ == "__main__": + main()` + ) + assert.strictEqual(filecontext.programmingLanguage.languageName, 'python') + + // test classifier + const sut = new EditClassifier( + { + fileContext: filecontext, + triggerChar: 'y', + recentEdits: { + isUtg: false, + isProcessTimeout: false, + supplementalContextItems: [ + { + filePath: '', + content: `--- file:///calculator.py ++++ file:///calculator.py +@@ -1,5 +1,7 @@ + def calculate_sum(a, b): + return a + b + ++def calculate_product(a, b): ++ return a * b ++ + def main(): + result = calculate_sum(5, 3)`, + }, + ], + contentsLength: 0, + latency: 0, + strategy: 'recentEdits', + }, + recentDecisions: ['Accept', 'Accept', 'Accept', 'Reject', 'Reject'], // AR = 0.6 + }, + loggingStub + ) + + const actual = sut.score().toPrecision(4) + assert.strictEqual(actual, '0.6998') + }) + + it('case 2 Java method with keyword and deletions', function () { + const document = TextDocument.create( + 'test.java', + 'java', + 1, + `public class Calculator { + private int value; + + public void setValue(int v) { + this.value = v; + } + + public int getValue() { + if (this.value > 0) { + return this.value; + } + return 0; + } +}` + ) + const filecontext = new ClientFileContextClss({ + textDocument: document, + position: Position.create(8, 10), + inferredLanguageId: 'java', + workspaceFolder: undefined, + }) + + // assert setup is correct + assert.strictEqual( + filecontext.leftFileContent, + `public class Calculator { + private int value; + + public void setValue(int v) { + this.value = v; + } + + public int getValue() { + if` + ) + assert.strictEqual( + filecontext.rightFileContent, + ` (this.value > 0) { + return this.value; + } + return 0; + } +}` + ) + assert.strictEqual(filecontext.programmingLanguage.languageName, 'java') + + // test classifier + const sut = new EditClassifier( + { + fileContext: filecontext, + triggerChar: 'f', + recentEdits: { + isUtg: false, + isProcessTimeout: false, + supplementalContextItems: [ + { + filePath: '', + content: `--- file:///Calculator.java ++++ file:///Calculator.java +@@ -1,6 +1,4 @@ + public class Calculator { + private int value; +- private String name; +- private boolean active; + + public void setValue(int v) {`, + }, + ], + contentsLength: 0, + latency: 0, + strategy: 'recentEdits', + }, + recentDecisions: [], // If recentDecision has length 0, will use 0.3 as AR + }, + loggingStub + ) + + const actual = sut.score().toPrecision(4) + assert.strictEqual(actual, '0.5374') + }) + + it('case 3 JavaScript without keyword, with deletions', function () { + const document = TextDocument.create( + 'test.js', + 'javascript', + 1, + `const users = [ + { name: 'Alice', age: 25 }, + { name: 'Bob', age: 30 } +]; + +const getNames = () => { + return users.map(user => user.fullName); +}; + +console.log(getNames());` + ) + const filecontext = new ClientFileContextClss({ + textDocument: document, + position: Position.create(6, 42), + inferredLanguageId: 'javascript', + workspaceFolder: undefined, + }) + + // assert setup is correct + assert.strictEqual( + filecontext.leftFileContent, + `const users = [ + { name: 'Alice', age: 25 }, + { name: 'Bob', age: 30 } +]; + +const getNames = () => { + return users.map(user => user.fullName` + ) + assert.strictEqual( + filecontext.rightFileContent, + `); +}; + +console.log(getNames());` + ) + assert.strictEqual(filecontext.programmingLanguage.languageName, 'javascript') + + // test classifier + const sut = new EditClassifier( + { + fileContext: filecontext, + triggerChar: 'e', + recentEdits: { + isUtg: false, + isProcessTimeout: false, + supplementalContextItems: [ + { + filePath: '', + content: `--- file:///users.js ++++ file:///users.js +@@ -1,6 +1,4 @@ + const users = [ + { name: 'Alice', age: 25 }, +- { name: 'Bob', age: 30 }, +- { name: 'Charlie', age: 35 } ++ { name: 'Bob', age: 30 } + ];`, + }, + ], + contentsLength: 0, + latency: 0, + strategy: 'recentEdits', + }, + recentDecisions: ['Reject', 'Reject', 'Reject', 'Reject', 'Reject'], // AR 0 + }, + loggingStub + ) + + const actual = sut.score().toPrecision(4) + assert.strictEqual(actual, '0.4085') + }) + + it('case 4 C++ without keyword, with similar line changes', function () { + const document = TextDocument.create( + 'test.cpp', + 'cpp', + 1, + `#include +#include + +template +void printVector(const std::vector& vec) { + for (const auto& item : vec) { + std::cout << item << " "; + } + std::cout << std::newline; +} + +int main() { + std::vector numbers = {1, 2, 3, 4, 5}; + printVector(numbers); + return 0; +}` + ) + const filecontext = new ClientFileContextClss({ + textDocument: document, + position: Position.create(8, 29), + inferredLanguageId: 'cpp', + workspaceFolder: undefined, + }) + + // assert setup is correct + assert.strictEqual( + filecontext.leftFileContent, + `#include +#include + +template +void printVector(const std::vector& vec) { + for (const auto& item : vec) { + std::cout << item << " "; + } + std::cout << std::newline` + ) + assert.strictEqual( + filecontext.rightFileContent, + `; +} + +int main() { + std::vector numbers = {1, 2, 3, 4, 5}; + printVector(numbers); + return 0; +}` + ) + assert.strictEqual(filecontext.programmingLanguage.languageName, 'cpp') + + // test classifier + const sut = new EditClassifier( + { + fileContext: filecontext, + triggerChar: 'e', + recentEdits: { + isUtg: false, + isProcessTimeout: false, + supplementalContextItems: [ + { + filePath: '', + content: `--- file:///vector_print.cpp ++++ file:///vector_print.cpp +@@ -5,7 +5,7 @@ + for (const auto& item : vec) { + std::cout << item << " "; + } +- std::cout << std::endl; ++ std::cout << std::newline; + }`, + }, + ], + contentsLength: 0, + latency: 0, + strategy: 'recentEdits', + }, + recentDecisions: ['Accept', 'Accept', 'Reject', 'Reject', 'Reject'], // AR 0.4 + }, + loggingStub + ) + + const actual = sut.score().toPrecision(4) + assert.strictEqual(actual, '0.3954') + }) + + it('case 5 SQL without keyword, with similar line changes and deletions', function () { + const document = TextDocument.create( + 'test.sql', + 'sql', + 1, + `SELECT u.name, u.email, p.title +FROM users u +JOIN posts p ON u.id = p.user_id +WHERE u.active = true +AND p.published_date >= '2023-01-01' +ORDER BY p.published_date DESC +LIMIT 10;` + ) + const filecontext = new ClientFileContextClss({ + textDocument: document, + position: Position.create(4, 23), + inferredLanguageId: 'sql', + workspaceFolder: undefined, + }) + + // assert setup is correct + assert.strictEqual( + filecontext.leftFileContent, + `SELECT u.name, u.email, p.title +FROM users u +JOIN posts p ON u.id = p.user_id +WHERE u.active = true +AND p.published_date >=` + ) + assert.strictEqual( + filecontext.rightFileContent, + ` '2023-01-01' +ORDER BY p.published_date DESC +LIMIT 10;` + ) + assert.strictEqual(filecontext.programmingLanguage.languageName, 'sql') + + // test classifier + const sut = new EditClassifier( + { + fileContext: filecontext, + triggerChar: '', + recentEdits: { + isUtg: false, + isProcessTimeout: false, + supplementalContextItems: [ + { + filePath: '', + content: `--- file:///query.sql ++++ file:///query.sql +@@ -1,6 +1,4 @@ + SELECT u.name, u.email, p.title + FROM users u +-LEFT JOIN profiles pr ON u.id = pr.user_id + JOIN posts p ON u.id = p.user_id + WHERE u.active = true +-AND p.published_at >= '2023-01-01' ++AND p.published_date >= '2023-01-01'`, + }, + ], + contentsLength: 0, + latency: 0, + strategy: 'recentEdits', + }, + recentDecisions: ['Accept', 'Reject', 'Reject', 'Reject', 'Reject'], // AR 0.2 + }, + loggingStub + ) + + const actual = sut.score().toPrecision(4) + assert.strictEqual(actual, '0.4031') + }) + }) +}) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.ts index eee9edbdcb..215ae9abd0 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.ts @@ -3,12 +3,18 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { FileContext } from '../../../shared/codeWhispererService' -import { Position } from '@aws/language-server-runtimes/server-interface' +import { ClientFileContextClss, FileContext } from '../../../shared/codeWhispererService' import { CursorTracker } from '../tracker/cursorTracker' import { RecentEditTracker } from '../tracker/codeEditTracker' -import { LanguageDetectorFactory } from './languageDetector' import { EditPredictionConfigManager } from './editPredictionConfig' +import { CodeWhispererSupplementalContext } from '../../../shared/models/model' +import { UserTriggerDecision } from '../session/sessionManager' +import { Logging } from '@aws/language-server-runtimes/server-interface' + +// The sigmoid function to clamp the auto-trigger result to the (0, 1) range +const sigmoid = (x: number) => { + return 1 / (1 + Math.exp(-x)) +} /** * Parameters for the edit prediction auto-trigger @@ -65,3 +71,408 @@ export const editPredictionAutoTrigger = ({ return { shouldTrigger } } + +const keyWordCoefficients: Record = { + get: 1.171, + const: -0.7697, + try: 0.7182, + number: 0.6706, + this: 0.6271, + return: -0.3991, + from: -0.3515, + None: -0.3409, + True: -0.3653, + true: -0.2502, + async: -0.3212, + false: 0.3478, + else: 0.3154, + type: -0.2662, + null: -0.1576, + if: -0.1276, + in: -0.0905, + void: 0.1712, + any: 0.1663, + as: 0.139, + import: 0.1424, + for: 0.0252, + is: 0.1023, + string: 0.0691, +} + +const lastCharCoefficients: Record = { + // alphabet + a: 0.0773, + c: 0.1191, + d: -0.0938, + e: -0.1517, + f: 0.4246, + i: 0.154, + l: 0.2188, + m: -0.3026, + n: -0.0324, + o: 0.196, + p: -0.2283, + Q: -0.0205, + r: 0.1418, + s: 0.0387, + S: 0.3369, + t: 0.1863, + u: 0.3599, + y: 0.0456, + // numbers + '0': 0.0415, + '1': -0.1826, + '2': -0.1085, + // special chars + '(': 0.0539, + ')': 0.0996, + '{': 0.2644, + '}': 0.1122, + ';': 0.2225, + '/': -0.0745, + '>': -0.0378, + '.': 0.0244, + ',': -0.0274, + '\n': 0.1023, + ' ': -0.066, + _: 0.0781, + "'": -0.036, + '"': 0.0629, +} + +const languageCoefficients: Record = { + c: 0.1013, + cpp: -0.1371, + sql: -0.1509, + java: 0.0564, + javascript: 0.1183, + json: 0.0811, + kotlin: -0.3022, + python: 0.0914, + rust: -0.1024, + scala: 0.1648, + shell: 0.1292, + tf: -0.3823, + typescript: 0.0928, + yaml: -0.2578, +} + +const leftContextLineCountCoeffecients = { + lte25: -0.0417, +} + +// No rightContextLineCountCoefficients, leave it 0 for now +const rightContextLineCountCoefficients = { + lte3: 0, + gte_4_lte6: 0, + gte7: 0, +} + +const editHistoryCoefficients = { + changedCharsNorm: 0.0194, + linesDeletedNorm: -0.084, + linesAddedNorm: 0.0594, +} + +const lastLineLengthCoefficients = { + lte4: 0.0293, + gte_5_lte12: -0.0012, +} + +const arCoefficients = { + previous5: 0.4723, +} + +type EditAutoTriggerInput = { + fileContext: ClientFileContextClss + triggerChar: string + recentEdits: CodeWhispererSupplementalContext + recentDecisions: UserTriggerDecision[] +} + +type EditClassifierFeatures = { + lastCharacter: string + lastLineLength: number + leftContextLineCount: number + rightContextLineCount: number + normalizedEditHistory: EditHistoryFeature | undefined + language: string + keyword: string + userAR: number +} + +type EditHistoryFeature = { + changedCharacters: number + addedLines: number + deletedLines: number +} + +export class EditClassifier { + static THRESHOLD = 0.53 + static INTERCEPT = -0.2782 + + private _score: number | undefined + private features: EditClassifierFeatures + constructor( + params: EditAutoTriggerInput, + readonly logging: Logging + ) { + this.features = this.prepareFeatures(params) + } + + shouldTriggerNep(): { shouldTrigger: boolean; threshold: number; score: number } { + const s = this.score() + return { + score: s, + threshold: EditClassifier.THRESHOLD, + shouldTrigger: s > EditClassifier.THRESHOLD, + } + } + + score() { + if (this._score !== undefined) { + return this._score + } + // 1. Last Character + const lastChar = this.features.lastCharacter + const myLastCharCoef = lastCharCoefficients[lastChar] ?? 0 + + // 2. Last Line Length + const lastLineLength = this.features.lastLineLength + let myLastLineLengthCoef = 0 + if (lastLineLength <= 4) { + myLastLineLengthCoef = lastLineLengthCoefficients.lte4 + } else if (lastLineLength >= 5 && lastLineLength <= 12) { + myLastLineLengthCoef = lastLineLengthCoefficients.gte_5_lte12 + } + + // 3. Left Context Line Count + const leftContextLineCount = this.features.leftContextLineCount + const myLeftContextLineCountCoef = leftContextLineCount <= 25 ? leftContextLineCountCoeffecients.lte25 : 0 + + // 4. Right Context Line Count + const rightContextLineCount = this.features.rightContextLineCount + let myRightContextLineCountCoef = 0 + if (rightContextLineCount <= 3) { + myRightContextLineCountCoef = rightContextLineCountCoefficients.lte3 + } else if (rightContextLineCount >= 4 && rightContextLineCount <= 6) { + myRightContextLineCountCoef = rightContextLineCountCoefficients.gte_4_lte6 + } else { + myRightContextLineCountCoef = rightContextLineCountCoefficients.gte7 + } + + // 5. Edit History (only using oldest) + const editH = this.features.normalizedEditHistory + const myAdded = (editH?.addedLines ?? 0) * editHistoryCoefficients.linesAddedNorm + const myDeleted = (editH?.deletedLines ?? 0) * editHistoryCoefficients.linesDeletedNorm + const myChanged = (editH?.changedCharacters ?? 0) * editHistoryCoefficients.changedCharsNorm + + // 6. Language + const lang = this.features.language + const myLangCoef = languageCoefficients[lang] ?? 0 + + // 7. Keyword + const kw = this.features.keyword + const myKeywordCoef = keyWordCoefficients[kw] ?? 0 + + // 8. AR + const myArCoef = arCoefficients.previous5 * this.features.userAR + + // Linear combination result + const logit = + myLastCharCoef + + myLastLineLengthCoef + + myLeftContextLineCountCoef + + myRightContextLineCountCoef + + myAdded + + myDeleted + + myChanged + + myLangCoef + + myKeywordCoef + + myArCoef + + EditClassifier.INTERCEPT + + const probability = sigmoid(logit) + + this.logging.log(`classifier: +"logit": ${logit}, +"probability": ${probability}, +"threshold": ${EditClassifier.THRESHOLD}, +@@features@@ +${JSON.stringify(this.features, undefined, 2)} +@@linear combination of features@@ +${JSON.stringify( + { + lastChar: myLastCharCoef, + lastLineLength: myLastLineLengthCoef, + leftContextLineCount: myLeftContextLineCountCoef, + rightContextLineCount: myRightContextLineCountCoef, + addedLines: myAdded, + deletedLines: myDeleted, + changedChars: myChanged, + language: myLangCoef, + keyword: myKeywordCoef, + ar: myArCoef, + intercept: EditClassifier.INTERCEPT, + }, + undefined, + 2 +)}`) + + return probability + } + + prepareFeatures(params: EditAutoTriggerInput): EditClassifierFeatures { + // 1. Last Character + const lastCharacter = params.triggerChar + + // 2. Last Line Length + const lastLineLength = params.fileContext.leftContextAtCurLine.length + + // 3. Left Context Line Count + const leftContextLineCount = params.fileContext.leftFileContent.split('\n').length + + // 4. Right Context Line Count + const rightContextLineCount = params.fileContext.rightFileContent.split('\n').length + + // 5. Edit History (only using olderst) + const oldest = + params.recentEdits.supplementalContextItems[params.recentEdits.supplementalContextItems.length - 1] // nullable + + const editHistory = oldest ? EditClassifier.processEditHistory(oldest.content) : undefined + const normalizedEditHistory = editHistory ? EditClassifier.normalizedRecentEdit(editHistory) : undefined + + this.logging.log(`lastLineFileContext: +${params.fileContext.leftContextAtCurLine} +recent decisions: +${JSON.stringify(params.recentDecisions)} +recent edits: +@@raw oldest edit@@ +${oldest.content} +@@raw numbers@@ +${JSON.stringify(editHistory, undefined, 2)} +@@normalized numbers@@ +${JSON.stringify(normalizedEditHistory, undefined, 2)} +@@edits array@@ +${params.recentEdits.supplementalContextItems.map(it => it.content)}`) + + // 6. Language + const lang = params.fileContext.programmingLanguage + + // 7. Keywords + const tokens = params.fileContext.leftContextAtCurLine.trim().split(' ') // split(' ') Not strict enough? + const lastToken = tokens[tokens.length - 1] + + // 8. User AR for last 5 + // Cold start we assume 0.3 for AR + const ar = + params.recentDecisions.length === 0 + ? 0.3 + : params.recentDecisions.reduce((acc: number, cur: UserTriggerDecision) => { + if (cur === 'Accept') { + return acc + 1 + } else { + return acc + } + }, 0) / params.recentDecisions.length + + return { + lastCharacter: lastCharacter, + lastLineLength: lastLineLength, + leftContextLineCount: leftContextLineCount, + rightContextLineCount: rightContextLineCount, + normalizedEditHistory: normalizedEditHistory, + language: lang.languageName, + userAR: ar, + keyword: lastToken, + } + } + + static processEditHistory(udiff: string): EditHistoryFeature { + const lines = udiff.split('\n') + const addedLines = lines + .filter(line => line.startsWith('+') && !line.startsWith('+++')) + .map(line => line.substring(1)) + const deletedLines = lines + .filter(line => line.startsWith('-') && !line.startsWith('---')) + .map(line => line.substring(1)) + + const deletedText = deletedLines.join('\n') + const addedText = addedLines.join('\n') + + const historyChangedChars = EditClassifier.editDistance(deletedText, addedText) + const historyLineAdded = addedLines.length + const historyLineDeleted = deletedLines.length + + return { + changedCharacters: historyChangedChars, + addedLines: historyLineAdded, + deletedLines: historyLineDeleted, + } + } + + static normalizedRecentEdit(edit: EditHistoryFeature): EditHistoryFeature { + // Apply min-max normalization using training data min/max values + const { changedCharacters, addedLines, deletedLines } = edit + + const trainingCharsChangedMin = 0 + const trainingCharsChangedMax = 261 + const normalizedChangedCharacters = + (changedCharacters - trainingCharsChangedMin) / (trainingCharsChangedMax - trainingCharsChangedMin) + + const trainingLineAddedMin = 0 + const trainingLineAddedMax = 7 + const normalizedAddedLines = (addedLines - trainingLineAddedMin) / (trainingLineAddedMax - trainingLineAddedMin) + + const trainingLineDeletedMin = 0 + const trainingLineDeletedMax = 6 + const normalizedDeletedLines = + (deletedLines - trainingLineDeletedMin) / (trainingLineDeletedMax - trainingLineDeletedMin) + + return { + changedCharacters: normalizedChangedCharacters, + addedLines: normalizedAddedLines, + deletedLines: normalizedDeletedLines, + } + } + + // TODO: Maybe consider reusing same logic across the entire repo or 3rd party edit distance function, we have too many different variants of such + static editDistance(s1: string, s2: string): number { + if (s1.length === 0) return s2.length + if (s2.length === 0) return s1.length + + // Create matrix + const rows: number = s1.length + 1 + const cols: number = s2.length + 1 + const dp: number[][] = Array(rows) + .fill(0) + .map(() => Array(cols).fill(0)) + + // Initialize first row and column + for (let i = 0; i < rows; i++) { + dp[i][0] = i + } + for (let j = 0; j < cols; j++) { + dp[0][j] = j + } + + // Fill the matrix + for (let i = 1; i < rows; i++) { + for (let j = 1; j < cols; j++) { + if (s1[i - 1] === s2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + } else { + dp[i][j] = + 1 + + Math.min( + dp[i - 1][j], // deletion + dp[i][j - 1], // insertion + dp[i - 1][j - 1] // substitution + ) + } + } + } + + return dp[rows - 1][cols - 1] + } +} diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.test.ts index 171158b543..ebf4e14380 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.test.ts @@ -6,6 +6,7 @@ import * as sinon from 'sinon' import { CodeWhispererSession, SessionData, SessionManager } from '../session/sessionManager' import { HELLO_WORLD_IN_CSHARP } from '../../../shared/testUtils' import { CodeWhispererServiceToken } from '../../../shared/codeWhispererService' +import * as EditAutotrigger from '../auto-trigger/editPredictionAutoTrigger' describe('EditCompletionHandler', () => { let handler: EditCompletionHandler @@ -54,7 +55,7 @@ describe('EditCompletionHandler', () => { } amazonQServiceManager = { getCodewhispererService: sinon.stub().returns(codeWhispererService) } cursorTracker = { trackPosition: sinon.stub() } - recentEditsTracker = {} + recentEditsTracker = { generateEditBasedContext: sinon.stub() } rejectedEditTracker = { isSimilarToRejected: sinon.stub().returns(false) } telemetry = { emitMetric: sinon.stub() } telemetryService = { emitUserTriggerDecision: sinon.stub() } @@ -225,7 +226,7 @@ describe('EditCompletionHandler', () => { }) }) - describe('documentChanged', () => { + describe.skip('documentChanged', () => { it('should set hasDocumentChangedSinceInvocation when waiting', () => { handler['debounceTimeout'] = setTimeout(() => {}, 1000) as any handler['isWaiting'] = true @@ -337,12 +338,23 @@ describe('EditCompletionHandler', () => { position: { line: 0, character: 0 }, context: { triggerKind: InlineCompletionTriggerKind.Automatic }, } + + afterEach('teardown', function () { + sinon.restore() + }) + + function aTriggerStub(flag: boolean): EditAutotrigger.EditClassifier { + return { + shouldTriggerNep: sinon + .stub() + .returns({ score: 0, threshold: EditAutotrigger.EditClassifier.THRESHOLD, shouldTrigger: flag }), + } as any as EditAutotrigger.EditClassifier + } + it('should return empty result when shouldTriggerEdits returns false', async () => { workspace.getWorkspaceFolder.returns(undefined) - const shouldTriggerEditsStub = sinon - .stub(require('../utils/triggerUtils'), 'shouldTriggerEdits') - .returns(false) + sinon.stub(EditAutotrigger, 'EditClassifier').returns(aTriggerStub(false)) const result = await handler._invoke( params as any, @@ -354,15 +366,12 @@ describe('EditCompletionHandler', () => { ) assert.deepEqual(result, EMPTY_RESULT) - shouldTriggerEditsStub.restore() }) it('should create session and call generateSuggestions when trigger is valid', async () => { workspace.getWorkspaceFolder.returns(undefined) - const shouldTriggerEditsStub = sinon - .stub(require('../utils/triggerUtils'), 'shouldTriggerEdits') - .returns(true) + sinon.stub(EditAutotrigger, 'EditClassifier').returns(aTriggerStub(true)) codeWhispererService.constructSupplementalContext.resolves(null) codeWhispererService.generateSuggestions.resolves({ suggestions: [{ itemId: 'item-1', content: 'test content' }], @@ -380,7 +389,6 @@ describe('EditCompletionHandler', () => { assert.strictEqual(result.items.length, 1) sinon.assert.called(codeWhispererService.generateSuggestions) - shouldTriggerEditsStub.restore() }) it('should handle active session and emit telemetry', async () => { @@ -391,9 +399,7 @@ describe('EditCompletionHandler', () => { if (currentSession) { sessionManager.activateSession(currentSession) } - const shouldTriggerEditsStub = sinon - .stub(require('../utils/triggerUtils'), 'shouldTriggerEdits') - .returns(true) + sinon.stub(EditAutotrigger, 'EditClassifier').returns(aTriggerStub(true)) codeWhispererService.constructSupplementalContext.resolves(null) codeWhispererService.generateSuggestions.resolves({ suggestions: [{ itemId: 'item-1', content: 'test content' }], @@ -410,15 +416,12 @@ describe('EditCompletionHandler', () => { ) assert.strictEqual(currentSession?.state, 'DISCARD') - shouldTriggerEditsStub.restore() }) it('should handle supplemental context when available', async () => { workspace.getWorkspaceFolder.returns(undefined) - const shouldTriggerEditsStub = sinon - .stub(require('../utils/triggerUtils'), 'shouldTriggerEdits') - .returns(true) + sinon.stub(EditAutotrigger, 'EditClassifier').returns(aTriggerStub(true)) codeWhispererService.constructSupplementalContext.resolves({ items: [{ content: 'context', filePath: 'file.ts' }], supContextData: { isUtg: false }, @@ -438,7 +441,6 @@ describe('EditCompletionHandler', () => { ) sinon.assert.calledWith(codeWhispererService.generateSuggestions, sinon.match.has('supplementalContexts')) - shouldTriggerEditsStub.restore() }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts index 2ea75f00dc..1f030c2892 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts @@ -22,7 +22,7 @@ import { CodeWhispererSession, SessionManager } from '../session/sessionManager' import { CursorTracker } from '../tracker/cursorTracker' import { CodewhispererLanguage, getSupportedLanguageId } from '../../../shared/languageDetection' import { WorkspaceFolderManager } from '../../workspaceContext/workspaceFolderManager' -import { shouldTriggerEdits } from '../utils/triggerUtils' +import { inferTriggerChar } from '../utils/triggerUtils' import { emitEmptyUserTriggerDecisionTelemetry, emitServiceInvocationFailure, @@ -36,9 +36,10 @@ import { RejectedEditTracker } from '../tracker/rejectedEditTracker' import { getErrorMessage, hasConnectionExpired } from '../../../shared/utils' import { AmazonQError, AmazonQServiceConnectionExpiredError } from '../../../shared/amazonQServiceManager/errors' import { DocumentChangedListener } from '../documentChangedListener' -import { EMPTY_RESULT, EDIT_DEBOUNCE_INTERVAL_MS } from '../contants/constants' +import { EMPTY_RESULT } from '../contants/constants' import { StreakTracker } from '../tracker/streakTracker' import { processEditSuggestion } from '../utils/diffUtils' +import { EditClassifier } from '../auto-trigger/editPredictionAutoTrigger' export class EditCompletionHandler { private readonly editsEnabled: boolean @@ -79,14 +80,15 @@ export class EditCompletionHandler { * Also as a followup, ideally it should be a message/event publish/subscribe pattern instead of manual invocation like this */ documentChanged() { - if (this.debounceTimeout) { - if (this.isWaiting) { - this.hasDocumentChangedSinceInvocation = true - } else { - this.logging.info(`refresh and debounce edits suggestion for another ${EDIT_DEBOUNCE_INTERVAL_MS}`) - this.debounceTimeout.refresh() - } - } + // TODO: Remove this entirely once we are sure we dont need debounce + // if (this.debounceTimeout) { + // if (this.isWaiting) { + // this.hasDocumentChangedSinceInvocation = true + // } else { + // this.logging.info(`refresh and debounce edits suggestion for another ${EDIT_DEBOUNCE_INTERVAL_MS}`) + // this.debounceTimeout.refresh() + // } + // } } async onEditCompletion( @@ -171,40 +173,18 @@ export class EditCompletionHandler { } } - return new Promise(async resolve => { - this.debounceTimeout = setTimeout(async () => { - try { - this.isWaiting = true - const result = await this._invoke( - params, - startPreprocessTimestamp, - token, - textDocument, - inferredLanguageId, - currentSession - ).finally(() => { - this.isWaiting = false - }) - if (this.hasDocumentChangedSinceInvocation) { - this.logging.info( - 'EditCompletionHandler - Document changed during execution, resolving empty result' - ) - resolve({ - sessionId: SessionManager.getInstance('EDITS').getActiveSession()?.id ?? '', - items: [], - }) - } else { - this.logging.info('EditCompletionHandler - No document changes, resolving result') - resolve(result) - } - } finally { - this.debounceTimeout = undefined - this.hasDocumentChangedSinceInvocation = false - } - }, EDIT_DEBOUNCE_INTERVAL_MS) - }).finally(() => { + try { + return await this._invoke( + params, + startPreprocessTimestamp, + token, + textDocument, + inferredLanguageId, + currentSession + ) + } finally { this.isInProgress = false - }) + } } async _invoke( @@ -218,53 +198,57 @@ export class EditCompletionHandler { // Build request context const isAutomaticLspTriggerKind = params.context.triggerKind == InlineCompletionTriggerKind.Automatic const maxResults = isAutomaticLspTriggerKind ? 1 : 5 - const fileContext = getFileContext({ + const fileContextClss = getFileContext({ textDocument, inferredLanguageId, position: params.position, workspaceFolder: this.workspace.getWorkspaceFolder(textDocument.uri), }) + // TODO: Parametrize these to a util function, duplicate code as inineCompletionHandler + const triggerCharacters = inferTriggerChar(fileContextClss, params.documentChangeParams) + const workspaceState = WorkspaceFolderManager.getInstance()?.getWorkspaceState() const workspaceId = workspaceState?.webSocketClient?.isConnected() ? workspaceState.workspaceId : undefined - const qEditsTrigger = shouldTriggerEdits( - this.codeWhispererService, - fileContext, - params, - this.cursorTracker, - this.recentEditsTracker, - this.sessionManager, - true + const recentEdits = await this.recentEditsTracker.generateEditBasedContext(textDocument) + const classifier = new EditClassifier( + { + fileContext: fileContextClss, + triggerChar: triggerCharacters, + recentEdits: recentEdits, + recentDecisions: this.sessionManager.userDecisionLog.map(it => it.decision), + }, + this.logging ) - if (!qEditsTrigger) { + const qEditsTrigger = classifier.shouldTriggerNep() + + if (!qEditsTrigger.shouldTrigger) { return EMPTY_RESULT } const generateCompletionReq: GenerateSuggestionsRequest = { - fileContext: fileContext, + fileContext: fileContextClss.toServiceModel(), maxResults: maxResults, predictionTypes: ['EDITS'], workspaceId: workspaceId, } - if (qEditsTrigger) { - generateCompletionReq.editorState = { - document: { - relativeFilePath: textDocument.uri, - programmingLanguage: { - languageName: generateCompletionReq.fileContext?.programmingLanguage?.languageName, - }, - text: textDocument.getText(), + generateCompletionReq.editorState = { + document: { + relativeFilePath: textDocument.uri, + programmingLanguage: { + languageName: generateCompletionReq.fileContext?.programmingLanguage?.languageName, }, - cursorState: { - position: { - line: params.position.line, - character: params.position.character, - }, + text: textDocument.getText(), + }, + cursorState: { + position: { + line: params.position.line, + character: params.position.character, }, - } + }, } const supplementalContext = await this.codeWhispererService.constructSupplementalContext( @@ -306,7 +290,7 @@ export class EditCompletionHandler { startPreprocessTimestamp: startPreprocessTimestamp, startPosition: params.position, triggerType: isAutomaticLspTriggerKind ? 'AutoTrigger' : 'OnDemand', - language: fileContext.programmingLanguage.languageName, + language: fileContextClss.programmingLanguage.languageName, requestContext: generateCompletionReq, autoTriggerType: undefined, triggerCharacter: '', diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts index 720f70389c..233b9ceb35 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/inlineCompletionHandler.ts @@ -191,7 +191,7 @@ export class InlineCompletionHandler { inferredLanguageId, position: params.position, workspaceFolder: this.workspace.getWorkspaceFolder(textDocument.uri), - }) + }).toServiceModel() } const workspaceState = WorkspaceFolderManager.getInstance()?.getWorkspaceState() diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts index cdeb441f80..5a0d61a736 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/session/sessionManager.ts @@ -309,6 +309,10 @@ export class SessionManager { private sessionsLog: CodeWhispererSession[] = [] private maxHistorySize = 5 // TODO, for user decision telemetry: accepted suggestions (not necessarily the full corresponding session) should be stored for 5 minutes + private _userDecisionLog: { sessionId: string; decision: UserTriggerDecision }[] = [] + get userDecisionLog() { + return [...this._userDecisionLog] + } private constructor() {} @@ -352,6 +356,19 @@ export class SessionManager { closeSession(session: CodeWhispererSession) { session.close() + + // Note: it has to be called after session.close() as getAggregatedUserTriggerDecision() will return undefined if getAggregatedUserTriggerDecision() is called before session is closed + const decision = session.getAggregatedUserTriggerDecision() + // As we only care about AR here, pushing Accept/Reject only + if (decision === 'Accept' || decision === 'Reject') { + if (this._userDecisionLog.length === 5) { + this._userDecisionLog.shift() + } + this._userDecisionLog.push({ + sessionId: session.codewhispererSessionId ?? 'undefined', + decision: decision, + }) + } } discardSession(session: CodeWhispererSession) { diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.test.ts index 5683d50f1d..a8c6c540ac 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.test.ts @@ -1,14 +1,10 @@ import * as assert from 'assert' import * as sinon from 'sinon' -import { shouldTriggerEdits, NepTrigger } from './triggerUtils' +import { shouldTriggerEdits, NepTrigger, isDocumentChangedFromNewLine } from './triggerUtils' import { SessionManager } from '../session/sessionManager' import { CursorTracker } from '../tracker/cursorTracker' import { RecentEditTracker } from '../tracker/codeEditTracker' -import { - CodeWhispererServiceToken, - CodeWhispererServiceIAM, - ClientFileContext, -} from '../../../shared/codeWhispererService' +import { CodeWhispererServiceToken, CodeWhispererServiceIAM, FileContext } from '../../../shared/codeWhispererService' import * as editPredictionAutoTrigger from '../auto-trigger/editPredictionAutoTrigger' import { InlineCompletionWithReferencesParams } from '@aws/language-server-runtimes/server-interface' @@ -25,7 +21,7 @@ describe('triggerUtils', () => { rightFileContent: '', filename: 'test.ts', programmingLanguage: { languageName: 'typescript' }, - } as ClientFileContext + } as FileContext const inlineParams = { textDocument: { uri: 'file:///test.ts' }, @@ -49,6 +45,56 @@ describe('triggerUtils', () => { sinon.restore() }) + describe('isDocumentChangedFromNewLine', function () { + interface TestCase { + input: string + expected: boolean + } + + const cases: TestCase[] = [ + { + input: '\n ', + expected: true, + }, + { + input: '\n\t\t\t', + expected: true, + }, + { + input: '\n ', + expected: true, + }, + { + input: '\n ', + expected: true, + }, + { + input: '\n def', + expected: false, + }, + { + input: ' \n ', + expected: false, + }, + { + input: '\t\n ', + expected: false, + }, + { + input: ' def\n\t', + expected: false, + }, + ] + + for (let i = 0; i < cases.length; i++) { + const c = cases[i] + it(`case ${i}`, function () { + const actual = isDocumentChangedFromNewLine(c.input) + assert.strictEqual(actual, c.expected) + }) + } + }) + describe('shouldTriggerEdits', () => { it('should return undefined when edits not enabled', () => { const result = shouldTriggerEdits( diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.ts index ce113143ae..42494f74fa 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.ts @@ -1,19 +1,23 @@ import { SessionManager } from '../session/sessionManager' -import { InlineCompletionWithReferencesParams } from '@aws/language-server-runtimes/protocol' +import { + DidChangeTextDocumentParams, + InlineCompletionWithReferencesParams, +} from '@aws/language-server-runtimes/protocol' import { editPredictionAutoTrigger } from '../auto-trigger/editPredictionAutoTrigger' import { CursorTracker } from '../tracker/cursorTracker' import { RecentEditTracker } from '../tracker/codeEditTracker' import { + ClientFileContextClss, CodeWhispererServiceBase, CodeWhispererServiceToken, - ClientFileContext, + FileContext, } from '../../../shared/codeWhispererService' export class NepTrigger {} export function shouldTriggerEdits( service: CodeWhispererServiceBase, - fileContext: ClientFileContext, + fileContext: FileContext, inlineParams: InlineCompletionWithReferencesParams, cursorTracker: CursorTracker, recentEditsTracker: RecentEditTracker, @@ -55,3 +59,59 @@ export function shouldTriggerEdits( return undefined } } + +export function inferTriggerChar( + fileContext: ClientFileContextClss, + changes: DidChangeTextDocumentParams | undefined +): string { + if (changes?.contentChanges && changes.contentChanges.length > 0 && changes.contentChanges[0].text !== undefined) { + const chars = changes.contentChanges[0].text + // TODO: A deletion document change will be empty string with non empty range length, however not sure why we can't access TextDocumentContentChangeEvent.rangeLength here + if (chars.length === 0) { + return fileContext.leftFileContent.trim().at(-1) ?? '' + } + + if (chars.length > 1) { + // TODO: monkey patch, should refine these logic + // Users hit newline and IDE or other extensions auto format for users + // For such documentChanges might be '\n ' (newline + 4 space) + if (isDocumentChangedFromNewLine(chars)) { + return '\n' + } + + if (chars === `''`) { + return `'` + } + + if (chars === `""`) { + return `"` + } + + if (chars === '()') { + return '(' + } + + if (chars === '{}') { + return '{' + } + + if (chars === '[]') { + return '[' + } + } + + return chars + } + + // if the client does not emit document change for the trigger, use left most character. + return fileContext.leftFileContent.trim().at(-1) ?? '' +} + +/** + * A proxy to estimate the provided string is from enter key + * Input = ['\n\t', '\n ', '\n ', ' \ndef '] + * Input = [true, true, true, false] + */ +export function isDocumentChangedFromNewLine(s: string) { + return /^\n[\s\t]+$/.test(s) +} diff --git a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts index 2067708c9d..af9bc78ac7 100644 --- a/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts +++ b/server/aws-lsp-codewhisperer/src/shared/codeWhispererService.ts @@ -140,14 +140,67 @@ export interface GenerateSuggestionsResponse { responseContext: ResponseContext } -export interface ClientFileContext { - leftFileContent: string - rightFileContent: string - filename: string - fileUri: string - programmingLanguage: { +export class ClientFileContextClss { + readonly leftFileContent: string + readonly rightFileContent: string + readonly filename: string + readonly fileUri: string + readonly programmingLanguage: { languageName: CodewhispererLanguage } + readonly leftContextAtCurLine: string + readonly rightContextAtCurLine: string + + constructor(params: { + textDocument: TextDocument + position: Position + inferredLanguageId: CodewhispererLanguage + workspaceFolder: WorkspaceFolder | null | undefined + }) { + const left = params.textDocument.getText({ + start: { line: 0, character: 0 }, + end: params.position, + }) + const trimmedLeft = left.slice(-CONTEXT_CHARACTERS_LIMIT).replaceAll('\r\n', '\n') + + const right = params.textDocument.getText({ + start: params.position, + end: params.textDocument.positionAt(params.textDocument.getText().length), + }) + const trimmedRight = right.slice(0, CONTEXT_CHARACTERS_LIMIT).replaceAll('\r\n', '\n') + + const relativeFilePath = params.workspaceFolder + ? getRelativePath(params.workspaceFolder, params.textDocument.uri) + : path.basename(params.textDocument.uri) + + this.fileUri = params.textDocument.uri.substring(0, FILE_URI_CHARS_LIMIT) + this.filename = relativeFilePath.substring(0, FILENAME_CHARS_LIMIT) + this.programmingLanguage = { + languageName: getRuntimeLanguage(params.inferredLanguageId), + } + this.leftFileContent = trimmedLeft + this.rightFileContent = trimmedRight + + this.leftContextAtCurLine = params.textDocument.getText({ + start: { line: params.position.line, character: 0 }, + end: { line: params.position.line, character: params.position.character }, + }) + + this.rightContextAtCurLine = params.textDocument.getText({ + start: { line: params.position.line, character: params.position.character }, + end: { line: params.position.line, character: Number.MAX_VALUE }, + }) + } + + toServiceModel(): FileContext { + return { + fileUri: this.fileUri, + filename: this.filename, + programmingLanguage: this.programmingLanguage, + leftFileContent: this.leftFileContent, + rightFileContent: this.rightFileContent, + } + } } export function getFileContext(params: { @@ -155,32 +208,8 @@ export function getFileContext(params: { position: Position inferredLanguageId: CodewhispererLanguage workspaceFolder: WorkspaceFolder | null | undefined -}): ClientFileContext { - const left = params.textDocument.getText({ - start: { line: 0, character: 0 }, - end: params.position, - }) - const trimmedLeft = left.slice(-CONTEXT_CHARACTERS_LIMIT).replaceAll('\r\n', '\n') - - const right = params.textDocument.getText({ - start: params.position, - end: params.textDocument.positionAt(params.textDocument.getText().length), - }) - const trimmedRight = right.slice(0, CONTEXT_CHARACTERS_LIMIT).replaceAll('\r\n', '\n') - - const relativeFilePath = params.workspaceFolder - ? getRelativePath(params.workspaceFolder, params.textDocument.uri) - : path.basename(params.textDocument.uri) - - return { - fileUri: params.textDocument.uri.substring(0, FILE_URI_CHARS_LIMIT), - filename: relativeFilePath.substring(0, FILENAME_CHARS_LIMIT), - programmingLanguage: { - languageName: getRuntimeLanguage(params.inferredLanguageId), - }, - leftFileContent: trimmedLeft, - rightFileContent: trimmedRight, - } +}): ClientFileContextClss { + return new ClientFileContextClss(params) } // This abstract class can grow in the future to account for any additional changes across the clients From 7420d591a0fcf5da834f0165696aa50b99fd4d3a Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Tue, 21 Oct 2025 11:12:03 -0700 Subject: [PATCH 150/158] fix: classifier last token sometimes fail to capture the right values (#2434) --- .../auto-trigger/autoTrigger.ts | 4 +- .../auto-trigger/editPredictionAutoTrigger.ts | 4 +- .../utils/triggerUtils.test.ts | 46 ++++++++++++++++++- .../inline-completion/utils/triggerUtils.ts | 14 ++++++ 4 files changed, 63 insertions(+), 5 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts index 4255be11cc..328b2a299e 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/autoTrigger.ts @@ -3,6 +3,7 @@ import { Logging } from '@aws/language-server-runtimes/server-interface' import { FileContext } from '../../../shared/codeWhispererService' import typedCoefficients = require('./coefficients.json') import { TextDocumentContentChangeEvent } from 'vscode-languageserver-textdocument' +import { lastTokenFromString } from '../utils/triggerUtils' type TypedCoefficients = typeof typedCoefficients type Coefficients = TypedCoefficients & { @@ -223,8 +224,7 @@ export const autoTrigger = ( classifierThreshold: TRIGGER_THRESHOLD, } } - const tokens = leftContextAtCurrentLine.trim().split(' ') - const lastToken = tokens[tokens.length - 1] + const lastToken = lastTokenFromString(fileContext.leftFileContent) const keyword = lastToken?.length > 1 ? lastToken : '' diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.ts index 215ae9abd0..93a741b76d 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.ts @@ -10,6 +10,7 @@ import { EditPredictionConfigManager } from './editPredictionConfig' import { CodeWhispererSupplementalContext } from '../../../shared/models/model' import { UserTriggerDecision } from '../session/sessionManager' import { Logging } from '@aws/language-server-runtimes/server-interface' +import { lastTokenFromString } from '../utils/triggerUtils' // The sigmoid function to clamp the auto-trigger result to the (0, 1) range const sigmoid = (x: number) => { @@ -360,8 +361,7 @@ ${params.recentEdits.supplementalContextItems.map(it => it.content)}`) const lang = params.fileContext.programmingLanguage // 7. Keywords - const tokens = params.fileContext.leftContextAtCurLine.trim().split(' ') // split(' ') Not strict enough? - const lastToken = tokens[tokens.length - 1] + const lastToken = lastTokenFromString(params.fileContext.leftFileContent) // 8. User AR for last 5 // Cold start we assume 0.3 for AR diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.test.ts index a8c6c540ac..4fc4ed559a 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.test.ts @@ -1,6 +1,6 @@ import * as assert from 'assert' import * as sinon from 'sinon' -import { shouldTriggerEdits, NepTrigger, isDocumentChangedFromNewLine } from './triggerUtils' +import { shouldTriggerEdits, NepTrigger, isDocumentChangedFromNewLine, lastTokenFromString } from './triggerUtils' import { SessionManager } from '../session/sessionManager' import { CursorTracker } from '../tracker/cursorTracker' import { RecentEditTracker } from '../tracker/codeEditTracker' @@ -45,6 +45,50 @@ describe('triggerUtils', () => { sinon.restore() }) + describe('lastTokenFromString', function () { + interface TestCase { + input: string + expected: string + } + + const cases: TestCase[] = [ + { + input: `line=str`, + expected: `str`, + }, + { + input: `public class Main `, + expected: `Main`, + }, + { + input: `const foo = 5`, + expected: `5`, + }, + { + input: `const fooString = 'foo'`, + expected: `foo`, + }, + { + input: `main(`, + expected: `main`, + }, + { + input: `public class Main { + // print foo + `, + expected: `foo`, + }, + ] + + for (let i = 0; i < cases.length; i++) { + const c = cases[i] + it(`case ${i}`, function () { + const actual = lastTokenFromString(c.input) + assert.strictEqual(actual, c.expected) + }) + } + }) + describe('isDocumentChangedFromNewLine', function () { interface TestCase { input: string diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.ts index 42494f74fa..1ec8f9ae00 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/utils/triggerUtils.ts @@ -115,3 +115,17 @@ export function inferTriggerChar( export function isDocumentChangedFromNewLine(s: string) { return /^\n[\s\t]+$/.test(s) } + +// TODO: Should refine the logic +export function lastTokenFromString(str: string): string { + const tokens = str.trim().split(/\s+/) + if (tokens.length === 0) { + return '' + } + + // This step can filter out most naive case however doesnt work for `line=str` such style without empty space + const candidate = tokens[tokens.length - 1] + // Only run regex against a small portion of string instead of the entire str + const finalCandate = candidate.match(/\w+/g) || [] + return finalCandate.at(-1) ?? '' +} From 7cf19e6700f370d65ce223889547d40194273cbd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 12:03:31 -0700 Subject: [PATCH 151/158] chore(release): release packages from branch main (#2429) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .release-please-manifest.json | 4 ++-- chat-client/CHANGELOG.md | 7 +++++++ chat-client/package.json | 2 +- package-lock.json | 4 ++-- server/aws-lsp-codewhisperer/CHANGELOG.md | 14 ++++++++++++++ server/aws-lsp-codewhisperer/package.json | 2 +- 6 files changed, 27 insertions(+), 6 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index aad7c2b66d..cf83ed5387 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,8 +1,8 @@ { - "chat-client": "0.1.39", + "chat-client": "0.1.40", "core/aws-lsp-core": "0.0.16", "server/aws-lsp-antlr4": "0.1.20", - "server/aws-lsp-codewhisperer": "0.0.86", + "server/aws-lsp-codewhisperer": "0.0.87", "server/aws-lsp-json": "0.1.21", "server/aws-lsp-partiql": "0.0.18", "server/aws-lsp-yaml": "0.1.21" diff --git a/chat-client/CHANGELOG.md b/chat-client/CHANGELOG.md index 4451ffb5fe..52c8aef308 100644 --- a/chat-client/CHANGELOG.md +++ b/chat-client/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.1.40](https://github.com/aws/language-servers/compare/chat-client/v0.1.39...chat-client/v0.1.40) (2025-10-21) + + +### Features + +* send pinned context button immediately with pending state ([#2353](https://github.com/aws/language-servers/issues/2353)) ([bee5cad](https://github.com/aws/language-servers/commit/bee5cadeaf8840a8af08acfe8b58442aac7ad567)) + ## [0.1.39](https://github.com/aws/language-servers/compare/chat-client/v0.1.38...chat-client/v0.1.39) (2025-10-09) diff --git a/chat-client/package.json b/chat-client/package.json index 0639c785ec..6a43de457e 100644 --- a/chat-client/package.json +++ b/chat-client/package.json @@ -1,6 +1,6 @@ { "name": "@aws/chat-client", - "version": "0.1.39", + "version": "0.1.40", "description": "AWS Chat Client", "main": "out/index.js", "repository": { diff --git a/package-lock.json b/package-lock.json index e8d1927351..1bb28757e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -256,7 +256,7 @@ }, "chat-client": { "name": "@aws/chat-client", - "version": "0.1.39", + "version": "0.1.40", "license": "Apache-2.0", "dependencies": { "@aws/chat-client-ui-types": "^0.1.63", @@ -28193,7 +28193,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.86", + "version": "0.0.87", "bundleDependencies": [ "@amzn/codewhisperer", "@amzn/codewhisperer-runtime", diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index 2fbe94a439..7485e9edc0 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [0.0.87](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.86...lsp-codewhisperer/v0.0.87) (2025-10-21) + + +### Features + +* **amazonq:** add user requirement to zipfile for code review tool ([#2430](https://github.com/aws/language-servers/issues/2430)) ([2c33b38](https://github.com/aws/language-servers/commit/2c33b384a0e406bcd8d3888a911d5482ce1f38ef)) +* nep auto trigger ([#2424](https://github.com/aws/language-servers/issues/2424)) ([2292bd7](https://github.com/aws/language-servers/commit/2292bd75fded0848208de9401d15d3399a9c297b)) +* send pinned context button immediately with pending state ([#2353](https://github.com/aws/language-servers/issues/2353)) ([bee5cad](https://github.com/aws/language-servers/commit/bee5cadeaf8840a8af08acfe8b58442aac7ad567)) + + +### Bug Fixes + +* classifier last token sometimes fail to capture the right values ([#2434](https://github.com/aws/language-servers/issues/2434)) ([7420d59](https://github.com/aws/language-servers/commit/7420d591a0fcf5da834f0165696aa50b99fd4d3a)) + ## [0.0.86](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.85...lsp-codewhisperer/v0.0.86) (2025-10-15) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index a0c6bac08f..0f48aa1bfe 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.86", + "version": "0.0.87", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { From a53d14ed838464aa1c6306660e8168d1b2572632 Mon Sep 17 00:00:00 2001 From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> Date: Tue, 21 Oct 2025 18:19:52 -0700 Subject: [PATCH 152/158] chore: bump agentic version: 1.41.0 (#2435) Co-authored-by: aws-toolkit-automation <> --- app/aws-lsp-codewhisperer-runtimes/src/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/src/version.json b/app/aws-lsp-codewhisperer-runtimes/src/version.json index 7638b8c43d..d796f43568 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/version.json +++ b/app/aws-lsp-codewhisperer-runtimes/src/version.json @@ -1,3 +1,3 @@ { - "agenticChat": "1.40.0" + "agenticChat": "1.41.0" } From d030288a2508356db337dfa34ee64c8be1deb8e9 Mon Sep 17 00:00:00 2001 From: Sherry Lu <75588211+XiaoxuanLu@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:40:40 -0700 Subject: [PATCH 153/158] fix: add venv in the common gitignore patterns (#2445) --- server/aws-lsp-codewhisperer/src/shared/constants.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/aws-lsp-codewhisperer/src/shared/constants.ts b/server/aws-lsp-codewhisperer/src/shared/constants.ts index 33f61a079f..47bd84c3f5 100644 --- a/server/aws-lsp-codewhisperer/src/shared/constants.ts +++ b/server/aws-lsp-codewhisperer/src/shared/constants.ts @@ -190,4 +190,8 @@ export const COMMON_GITIGNORE_PATTERNS = [ '**/.vercel/**', '**/node_repl_history', '**/php_errorlog', + + // Python Specific + '.venv', + 'venv', ] From 82e2340cf86a5eba20f8d18f1293c136c0022dd9 Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Tue, 28 Oct 2025 11:14:57 -0700 Subject: [PATCH 154/158] fix: strenghen NEP trigger conditions (#2438) ## Problem Bring the code we removed previously back https://github.com/aws/language-servers/pull/2424/files#diff-10a12088df160c3eec8bb5eedd826e4ee475614c9b3a544fa2393cdeed92bc24L231-L238 and make the trigger criteria more strict. 1. Non empty right context starting next line 2. Recent edits in the past 20 seconds 3. Classifier result is greater than the threshold ## Solution ## License By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. --- .../auto-trigger/editPredictionAutoTrigger.ts | 2 +- .../handler/editCompletionHandler.test.ts | 21 ++++++++++++++++++- .../handler/editCompletionHandler.ts | 20 +++++++++++++++--- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.ts index 93a741b76d..ad02864bed 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/auto-trigger/editPredictionAutoTrigger.ts @@ -221,7 +221,7 @@ export class EditClassifier { this.features = this.prepareFeatures(params) } - shouldTriggerNep(): { shouldTrigger: boolean; threshold: number; score: number } { + shouldTriggerEdits(): { shouldTrigger: boolean; threshold: number; score: number } { const s = this.score() return { score: s, diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.test.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.test.ts index ebf4e14380..ae6663a3a1 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.test.ts @@ -345,7 +345,7 @@ describe('EditCompletionHandler', () => { function aTriggerStub(flag: boolean): EditAutotrigger.EditClassifier { return { - shouldTriggerNep: sinon + shouldTriggerEdits: sinon .stub() .returns({ score: 0, threshold: EditAutotrigger.EditClassifier.THRESHOLD, shouldTrigger: flag }), } as any as EditAutotrigger.EditClassifier @@ -354,6 +354,9 @@ describe('EditCompletionHandler', () => { it('should return empty result when shouldTriggerEdits returns false', async () => { workspace.getWorkspaceFolder.returns(undefined) + const shouldTriggerEditsStub = sinon + .stub(require('../utils/triggerUtils'), 'shouldTriggerEdits') + .returns(false) sinon.stub(EditAutotrigger, 'EditClassifier').returns(aTriggerStub(false)) const result = await handler._invoke( @@ -366,12 +369,16 @@ describe('EditCompletionHandler', () => { ) assert.deepEqual(result, EMPTY_RESULT) + shouldTriggerEditsStub.restore() }) it('should create session and call generateSuggestions when trigger is valid', async () => { workspace.getWorkspaceFolder.returns(undefined) sinon.stub(EditAutotrigger, 'EditClassifier').returns(aTriggerStub(true)) + const shouldTriggerEditsStub = sinon + .stub(require('../utils/triggerUtils'), 'shouldTriggerEdits') + .returns(true) codeWhispererService.constructSupplementalContext.resolves(null) codeWhispererService.generateSuggestions.resolves({ suggestions: [{ itemId: 'item-1', content: 'test content' }], @@ -389,6 +396,8 @@ describe('EditCompletionHandler', () => { assert.strictEqual(result.items.length, 1) sinon.assert.called(codeWhispererService.generateSuggestions) + + shouldTriggerEditsStub.restore() }) it('should handle active session and emit telemetry', async () => { @@ -399,6 +408,9 @@ describe('EditCompletionHandler', () => { if (currentSession) { sessionManager.activateSession(currentSession) } + const shouldTriggerEditsStub = sinon + .stub(require('../utils/triggerUtils'), 'shouldTriggerEdits') + .returns(true) sinon.stub(EditAutotrigger, 'EditClassifier').returns(aTriggerStub(true)) codeWhispererService.constructSupplementalContext.resolves(null) codeWhispererService.generateSuggestions.resolves({ @@ -416,11 +428,16 @@ describe('EditCompletionHandler', () => { ) assert.strictEqual(currentSession?.state, 'DISCARD') + + shouldTriggerEditsStub.restore() }) it('should handle supplemental context when available', async () => { workspace.getWorkspaceFolder.returns(undefined) + const shouldTriggerEditsStub = sinon + .stub(require('../utils/triggerUtils'), 'shouldTriggerEdits') + .returns(true) sinon.stub(EditAutotrigger, 'EditClassifier').returns(aTriggerStub(true)) codeWhispererService.constructSupplementalContext.resolves({ items: [{ content: 'context', filePath: 'file.ts' }], @@ -441,6 +458,8 @@ describe('EditCompletionHandler', () => { ) sinon.assert.calledWith(codeWhispererService.generateSuggestions, sinon.match.has('supplementalContexts')) + + shouldTriggerEditsStub.restore() }) }) diff --git a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts index 1f030c2892..d852dac1d1 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts @@ -22,7 +22,7 @@ import { CodeWhispererSession, SessionManager } from '../session/sessionManager' import { CursorTracker } from '../tracker/cursorTracker' import { CodewhispererLanguage, getSupportedLanguageId } from '../../../shared/languageDetection' import { WorkspaceFolderManager } from '../../workspaceContext/workspaceFolderManager' -import { inferTriggerChar } from '../utils/triggerUtils' +import { inferTriggerChar, shouldTriggerEdits } from '../utils/triggerUtils' import { emitEmptyUserTriggerDecisionTelemetry, emitServiceInvocationFailure, @@ -212,6 +212,8 @@ export class EditCompletionHandler { const workspaceId = workspaceState?.webSocketClient?.isConnected() ? workspaceState.workspaceId : undefined const recentEdits = await this.recentEditsTracker.generateEditBasedContext(textDocument) + + // TODO: Refactor and merge these 2 shouldTrigger into single one const classifier = new EditClassifier( { fileContext: fileContextClss, @@ -221,10 +223,22 @@ export class EditCompletionHandler { }, this.logging ) + const classifierBasedTrigger = classifier.shouldTriggerEdits() + + const ruleBasedTrigger = shouldTriggerEdits( + this.codeWhispererService, + fileContextClss.toServiceModel(), + params, + this.cursorTracker, + this.recentEditsTracker, + this.sessionManager, + true + ) - const qEditsTrigger = classifier.shouldTriggerNep() + // Both classifier and rule based conditions need to evaluate to true otherwise we wont fire Edits requests + const shouldFire = classifierBasedTrigger.shouldTrigger && ruleBasedTrigger !== undefined - if (!qEditsTrigger.shouldTrigger) { + if (!shouldFire) { return EMPTY_RESULT } From 6663f87e68c9645af6ffb004eaf725e5102fe5ab Mon Sep 17 00:00:00 2001 From: invictus <149003065+ashishrp-aws@users.noreply.github.com> Date: Tue, 28 Oct 2025 12:01:11 -0700 Subject: [PATCH 155/158] fix: enforce MAX_TOOL_NAME_LENGTH check in createNamespacedToolName (#2447) --- .../agenticChat/tools/mcp/mcpUtils.test.ts | 11 +++++++++++ .../language-server/agenticChat/tools/mcp/mcpUtils.ts | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts index 4d1f953d79..045d760d2e 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.test.ts @@ -543,6 +543,17 @@ describe('createNamespacedToolName', () => { toolName: longTool, }) }) + + it('truncates tool name and adds suffix when it exceeds MAX_TOOL_NAME_LENGTH', () => { + const longTool = 'Smartanalyzerthatreadssummariescreatesmappingrulesandupdatespayloads' + const result = createNamespacedToolName('ConnectiveRx', longTool, tools, toolNameMapping) + expect(result.length).to.equal(MAX_TOOL_NAME_LENGTH) + expect(tools.has(result)).to.be.true + expect(toolNameMapping.get(result)).to.deep.equal({ + serverName: 'ConnectiveRx', + toolName: longTool, + }) + }) }) describe('normalizePathFromUri', () => { diff --git a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts index 8ca2aff48a..3a318ce41f 100644 --- a/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts +++ b/server/aws-lsp-codewhisperer/src/language-server/agenticChat/tools/mcp/mcpUtils.ts @@ -1168,8 +1168,8 @@ export function createNamespacedToolName( // Sanitize the tool name const sanitizedToolName = sanitizeName(toolName) - // First try to use just the tool name if it's not already in use - if (!allNamespacedTools.has(sanitizedToolName)) { + // First try to use just the tool name if it's not already in use and fits within length limit + if (sanitizedToolName.length <= MAX_TOOL_NAME_LENGTH && !allNamespacedTools.has(sanitizedToolName)) { allNamespacedTools.add(sanitizedToolName) toolNameMapping.set(sanitizedToolName, { serverName, toolName }) return sanitizedToolName From db777f82c9c2ea12b1886418f828d008270f4b0a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 28 Oct 2025 12:13:39 -0700 Subject: [PATCH 156/158] chore(release): release packages from branch main (#2446) :robot: I have created a release *beep* *boop* ---
lsp-codewhisperer: 0.0.88 ## [0.0.88](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.87...lsp-codewhisperer/v0.0.88) (2025-10-28) ### Bug Fixes * add venv in the common gitignore patterns ([#2445](https://github.com/aws/language-servers/issues/2445)) ([d030288](https://github.com/aws/language-servers/commit/d030288a2508356db337dfa34ee64c8be1deb8e9)) * enforce MAX_TOOL_NAME_LENGTH check in createNamespacedToolName ([#2447](https://github.com/aws/language-servers/issues/2447)) ([6663f87](https://github.com/aws/language-servers/commit/6663f87e68c9645af6ffb004eaf725e5102fe5ab)) * strenghen NEP trigger conditions ([#2438](https://github.com/aws/language-servers/issues/2438)) ([82e2340](https://github.com/aws/language-servers/commit/82e2340cf86a5eba20f8d18f1293c136c0022dd9))
--- This PR was generated with [Release Please](https://github.com/googleapis/release-please) bot. When you are ready to release these changes, merge this PR. **Blocking GitHub Checks Issue:** if GitHub checks do not run, close and immediately re-open this PR manually. --- .release-please-manifest.json | 2 +- package-lock.json | 2 +- server/aws-lsp-codewhisperer/CHANGELOG.md | 9 +++++++++ server/aws-lsp-codewhisperer/package.json | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index cf83ed5387..cc727d85a6 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -2,7 +2,7 @@ "chat-client": "0.1.40", "core/aws-lsp-core": "0.0.16", "server/aws-lsp-antlr4": "0.1.20", - "server/aws-lsp-codewhisperer": "0.0.87", + "server/aws-lsp-codewhisperer": "0.0.88", "server/aws-lsp-json": "0.1.21", "server/aws-lsp-partiql": "0.0.18", "server/aws-lsp-yaml": "0.1.21" diff --git a/package-lock.json b/package-lock.json index 1bb28757e8..cded37cce6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28193,7 +28193,7 @@ }, "server/aws-lsp-codewhisperer": { "name": "@aws/lsp-codewhisperer", - "version": "0.0.87", + "version": "0.0.88", "bundleDependencies": [ "@amzn/codewhisperer", "@amzn/codewhisperer-runtime", diff --git a/server/aws-lsp-codewhisperer/CHANGELOG.md b/server/aws-lsp-codewhisperer/CHANGELOG.md index 7485e9edc0..bc8b15cb21 100644 --- a/server/aws-lsp-codewhisperer/CHANGELOG.md +++ b/server/aws-lsp-codewhisperer/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## [0.0.88](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.87...lsp-codewhisperer/v0.0.88) (2025-10-28) + + +### Bug Fixes + +* add venv in the common gitignore patterns ([#2445](https://github.com/aws/language-servers/issues/2445)) ([d030288](https://github.com/aws/language-servers/commit/d030288a2508356db337dfa34ee64c8be1deb8e9)) +* enforce MAX_TOOL_NAME_LENGTH check in createNamespacedToolName ([#2447](https://github.com/aws/language-servers/issues/2447)) ([6663f87](https://github.com/aws/language-servers/commit/6663f87e68c9645af6ffb004eaf725e5102fe5ab)) +* strenghen NEP trigger conditions ([#2438](https://github.com/aws/language-servers/issues/2438)) ([82e2340](https://github.com/aws/language-servers/commit/82e2340cf86a5eba20f8d18f1293c136c0022dd9)) + ## [0.0.87](https://github.com/aws/language-servers/compare/lsp-codewhisperer/v0.0.86...lsp-codewhisperer/v0.0.87) (2025-10-21) diff --git a/server/aws-lsp-codewhisperer/package.json b/server/aws-lsp-codewhisperer/package.json index 0f48aa1bfe..6680066db1 100644 --- a/server/aws-lsp-codewhisperer/package.json +++ b/server/aws-lsp-codewhisperer/package.json @@ -1,6 +1,6 @@ { "name": "@aws/lsp-codewhisperer", - "version": "0.0.87", + "version": "0.0.88", "description": "CodeWhisperer Language Server", "main": "out/index.js", "repository": { From 550e0ea9279aed6ede80663e883d0da965b868a4 Mon Sep 17 00:00:00 2001 From: Will Lo <96078566+Will-ShaoHua@users.noreply.github.com> Date: Wed, 29 Oct 2025 15:13:50 -0700 Subject: [PATCH 157/158] chore: bump agentic version: 1.42.0 (#2451) Co-authored-by: aws-toolkit-automation <> --- app/aws-lsp-codewhisperer-runtimes/src/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/aws-lsp-codewhisperer-runtimes/src/version.json b/app/aws-lsp-codewhisperer-runtimes/src/version.json index d796f43568..14a063ffd1 100644 --- a/app/aws-lsp-codewhisperer-runtimes/src/version.json +++ b/app/aws-lsp-codewhisperer-runtimes/src/version.json @@ -1,3 +1,3 @@ { - "agenticChat": "1.41.0" + "agenticChat": "1.42.0" } From 11900ca371adee2611698427dbec7c9323ef8e01 Mon Sep 17 00:00:00 2001 From: Laxman Reddy <141967714+laileni-aws@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:46:19 -0700 Subject: [PATCH 158/158] fix(amazonq): mcp tool panel blocks amazon q chat interface when using right-click context menu (#2442) --- chat-client/src/client/mcpMynahUi.ts | 10 ++++++++-- chat-client/src/client/mynahUi.ts | 6 ++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/chat-client/src/client/mcpMynahUi.ts b/chat-client/src/client/mcpMynahUi.ts index 5cdae85da1..0ee418e925 100644 --- a/chat-client/src/client/mcpMynahUi.ts +++ b/chat-client/src/client/mcpMynahUi.ts @@ -81,12 +81,17 @@ export class McpMynahUi { private mynahUi: MynahUI private messager: Messager private isMcpServersListActive = false + private mcpDetailedList: { close: () => void } | undefined constructor(mynahUi: MynahUI, messager: Messager) { this.mynahUi = mynahUi this.messager = messager } + close() { + this.mcpDetailedList?.close() + } + /** * Processes filter options by converting icons to Mynah icons */ @@ -397,7 +402,7 @@ export class McpMynahUi { ;(detailedList.filterOptions[0] as any).autoFocus = true } - const mcpSheet = this.mynahUi.openDetailedList({ + this.mcpDetailedList = this.mynahUi.openDetailedList({ detailedList: detailedList, events: { onFilterValueChange: (filterValues: Record) => { @@ -405,7 +410,7 @@ export class McpMynahUi { }, onKeyPress: (e: KeyboardEvent) => { if (e.key === 'Escape') { - mcpSheet.close() + this.mcpDetailedList?.close() } }, onItemSelect: (item: DetailedListItem) => { @@ -426,6 +431,7 @@ export class McpMynahUi { }, onClose: () => { this.isMcpServersListActive = false + this.mcpDetailedList = undefined }, onTitleActionClick: button => { this.messager.onMcpServerClick(button.id) diff --git a/chat-client/src/client/mynahUi.ts b/chat-client/src/client/mynahUi.ts index 63995c6bc8..90b0e1a8d2 100644 --- a/chat-client/src/client/mynahUi.ts +++ b/chat-client/src/client/mynahUi.ts @@ -1417,7 +1417,8 @@ export const createMynahUi = ( const sendToPrompt = (params: SendToPromptParams) => { const tabId = getOrCreateTabId() if (!tabId) return - + chatHistoryList.close() + mcpMynahUi.close() if (params.autoSubmit && params.prompt) { messager.onChatPrompt({ prompt: params.prompt, tabId, context: undefined }, 'contextMenu') initializeChatResponse(mynahUi, tabId, params.prompt.prompt, agenticMode) @@ -1431,7 +1432,8 @@ export const createMynahUi = ( let tabId = getOrCreateTabId() if (!tabId) return - + chatHistoryList.close() + mcpMynahUi.close() // send to a new tab if the current tab is loading if (getTabStore(tabId)?.loadingChat) { tabId = createTabId()