From fdf145d0c0262195edb5c3edda70c467a2a79ab9 Mon Sep 17 00:00:00 2001 From: Hweinstock <42325418+Hweinstock@users.noreply.github.com> Date: Wed, 13 May 2026 19:01:51 -0400 Subject: [PATCH 1/5] feat: instrument telemetry for dev command (#1223) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: instrument telemetry for dev command Add telemetry recording to the dev command across all execution paths: - Invoke: wrapped with withCommandRunTelemetry, emits on success/failure - Exec: wrapped with withCommandRunTelemetry for container exec - Server modes (--logs, --no-browser, browser): emit on SIGINT/exit Schema changes: - Expand Action enum to include 'exec' - Add UiMode enum ('browser' | 'terminal') - Add 'agui' to Protocol enum - Add ui_mode field to DevAttrs Refactored invoke helpers to throw instead of process.exit(1) so telemetry wrapper can record failures before exit. Attributes emitted: action, ui_mode, has_stream, protocol, invoke_count * refactor: use typed errors in dev command helpers + emit browser telemetry eagerly Error classification: - ConnectionError for connection-refused (new class in lib/errors/types.ts) - ValidationError for invalid user input (missing --tool, bad JSON, unknown command) - ResourceNotFoundError for missing container runtime Browser mode telemetry: - Emit telemetry eagerly via TelemetryClientAccessor before the blocking runBrowserMode call (which never returns). Do not copy this pattern — prefer withCommandRunTelemetry for commands that return. --- integ-tests/dev-server.test.ts | 30 +- src/cli/commands/dev/command.tsx | 294 +++++++++++------- .../schemas/__tests__/command-run.test.ts | 57 ++++ src/cli/telemetry/schemas/command-run.ts | 2 + src/cli/telemetry/schemas/common-shapes.ts | 5 +- src/lib/errors/types.ts | 10 + 6 files changed, 289 insertions(+), 109 deletions(-) diff --git a/integ-tests/dev-server.test.ts b/integ-tests/dev-server.test.ts index 4b07b7284..36bb90684 100644 --- a/integ-tests/dev-server.test.ts +++ b/integ-tests/dev-server.test.ts @@ -1,4 +1,4 @@ -import { runCLI } from '../src/test-utils/index.js'; +import { createTelemetryHelper, runCLI } from '../src/test-utils/index.js'; import { type ChildProcess, execSync, spawn } from 'node:child_process'; import { randomUUID } from 'node:crypto'; import { mkdir, rm } from 'node:fs/promises'; @@ -38,6 +38,8 @@ describe('integration: dev server', () => { let projectPath: string; let devProcess: ChildProcess | null = null; + const telemetry = createTelemetryHelper(); + beforeAll(async () => { testDir = join(tmpdir(), `agentcore-integ-dev-${randomUUID()}`); await mkdir(testDir, { recursive: true }); @@ -81,6 +83,7 @@ describe('integration: dev server', () => { if (devProcess) { devProcess.kill('SIGKILL'); } + telemetry.destroy(); await rm(testDir, { recursive: true, force: true }); }); @@ -101,6 +104,31 @@ describe('integration: dev server', () => { const serverReady = await waitForServer(port, 20000); expect(serverReady, 'Dev server should respond to ping within 20s').toBeTruthy(); + // Invoke the running server and verify telemetry + const invokeResult = await runCLI(['dev', 'hello', '--port', String(port)], projectPath, { + env: telemetry.env, + }); + expect(invokeResult.exitCode).toBe(0); + + telemetry.assertMetricEmitted({ + command: 'dev', + action: 'invoke', + ui_mode: 'terminal', + exit_reason: 'success', + protocol: 'http', + }); + + // Verify failure telemetry when invoking a non-running port + telemetry.clearEntries(); + const failResult = await runCLI(['dev', 'hello', '--port', '19999'], projectPath, { env: telemetry.env }); + expect(failResult.exitCode).toBe(1); + + telemetry.assertMetricEmitted({ + command: 'dev', + action: 'invoke', + exit_reason: 'failure', + }); + // Clean shutdown devProcess.kill('SIGTERM'); devProcess = null; diff --git a/src/cli/commands/dev/command.tsx b/src/cli/commands/dev/command.tsx index eac485d8c..21be78174 100644 --- a/src/cli/commands/dev/command.tsx +++ b/src/cli/commands/dev/command.tsx @@ -1,4 +1,11 @@ -import { findConfigRoot, getWorkingDirectory } from '../../../lib'; +import { + ConnectionError, + ResourceNotFoundError, + type Result, + ValidationError, + findConfigRoot, + getWorkingDirectory, +} from '../../../lib'; import { getErrorMessage } from '../../errors'; import { detectContainerRuntime } from '../../external-requirements'; import { ExecLogger } from '../../logging'; @@ -18,6 +25,9 @@ import { loadProjectConfig, } from '../../operations/dev'; import { OtelCollector, startOtelCollector } from '../../operations/dev/otel'; +import { withCommandRunTelemetry } from '../../telemetry/cli-command-run.js'; +import { TelemetryClientAccessor } from '../../telemetry/client-accessor.js'; +import { Protocol, standardize } from '../../telemetry/schemas/common-shapes.js'; import { FatalError } from '../../tui/components'; import { LayoutProvider } from '../../tui/context'; import { COMMAND_DESCRIPTIONS } from '../../tui/copy'; @@ -26,7 +36,7 @@ import { parseHeaderFlags } from '../shared/header-utils'; import { runBrowserMode } from './browser-mode'; import type { Command } from '@commander-js/extra-typings'; import { spawn } from 'child_process'; -import { Text, render } from 'ink'; +import { render } from 'ink'; import path from 'node:path'; import React from 'react'; @@ -43,7 +53,6 @@ async function invokeDevServer( ): Promise { try { if (stream) { - // Stream response to stdout for await (const chunk of invokeAgentStreaming({ port, message: prompt, headers })) { process.stdout.write(chunk); } @@ -53,13 +62,11 @@ async function invokeDevServer( console.log(response); } } catch (err) { - if (isConnectionRefused(err)) { - console.error(`Error: Dev server not running on port ${port}`); - console.error('Start it with: agentcore dev --logs'); - } else { - console.error(`Error: ${err instanceof Error ? err.message : String(err)}`); - } - process.exit(1); + throw isConnectionRefused(err) + ? new ConnectionError(`Dev server not running on port ${port}. Start it with: agentcore dev --logs`, { + cause: err, + }) + : err; } } @@ -70,13 +77,11 @@ async function invokeA2ADevServer(port: number, prompt: string, headers?: Record } process.stdout.write('\n'); } catch (err) { - if (isConnectionRefused(err)) { - console.error(`Error: Dev server not running on port ${port}`); - console.error('Start it with: agentcore dev --logs'); - } else { - console.error(`Error: ${err instanceof Error ? err.message : String(err)}`); - } - process.exit(1); + throw isConnectionRefused(err) + ? new ConnectionError(`Dev server not running on port ${port}. Start it with: agentcore dev --logs`, { + cause: err, + }) + : err; } } @@ -109,47 +114,39 @@ async function handleMcpInvoke( } } else if (invokeValue === 'call-tool') { if (!toolName) { - console.error('Error: --tool is required with call-tool'); - console.error('Usage: agentcore dev call-tool --tool --input \'{"arg": "value"}\''); - process.exit(1); + throw new ValidationError( + '--tool is required with call-tool. Usage: agentcore dev call-tool --tool --input \'{"arg": "value"}\'' + ); } - // Initialize session first, then call tool with the session ID const { sessionId } = await listMcpTools(port, undefined, headers); let args: Record = {}; if (input) { try { args = JSON.parse(input) as Record; } catch { - console.error(`Error: Invalid JSON for --input: ${input}`); - console.error('Expected format: --input \'{"key": "value"}\''); - process.exit(1); + throw new ValidationError(`Invalid JSON for --input: ${input}. Expected format: --input '{"key": "value"}'`); } } const result = await callMcpTool(port, toolName, args, sessionId, undefined, headers); console.log(result); } else { - console.error(`Error: Unknown MCP invoke command "${invokeValue}"`); - console.error('Usage:'); - console.error(' agentcore dev list-tools'); - console.error(' agentcore dev call-tool --tool --input \'{"arg": "value"}\''); - process.exit(1); + throw new ValidationError( + `Unknown MCP invoke command "${invokeValue}". Usage: agentcore dev list-tools | agentcore dev call-tool --tool ` + ); } } catch (err) { - if (isConnectionRefused(err)) { - console.error(`Error: Dev server not running on port ${port}`); - console.error('Start it with: agentcore dev --logs'); - } else { - console.error(`Error: ${err instanceof Error ? err.message : String(err)}`); - } - process.exit(1); + throw isConnectionRefused(err) + ? new ConnectionError(`Dev server not running on port ${port}. Start it with: agentcore dev --logs`, { + cause: err, + }) + : err; } } async function execInContainer(command: string, containerName: string): Promise { const detection = await detectContainerRuntime(); if (!detection.runtime) { - console.error('Error: No container runtime found (docker, podman, or finch required)'); - process.exit(1); + throw new ResourceNotFoundError('No container runtime found (docker, podman, or finch required)'); } return new Promise((resolve, reject) => { const child = spawn(detection.runtime!.binary, ['exec', containerName, 'bash', '-c', command], { @@ -158,9 +155,10 @@ async function execInContainer(command: string, containerName: string): Promise< child.on('error', reject); child.on('close', code => { if (code !== 0 && code !== null) { - process.exit(code); + reject(new Error(`Container exec exited with code ${code}`)); + } else { + resolve(); } - resolve(); }); }); } @@ -213,7 +211,21 @@ export const registerDev = (program: Command) => { process.exit(1); } const containerName = `agentcore-dev-${agentName}`.toLowerCase(); - await execInContainer(positionalPrompt, containerName); + const execResult = await withCommandRunTelemetry( + 'dev', + { + action: 'exec' as const, + ui_mode: 'terminal' as const, + has_stream: false, + protocol: standardize(Protocol, (targetAgent?.protocol ?? 'http').toLowerCase()), + invoke_count: 0, + }, + async (): Promise => { + await execInContainer(positionalPrompt, containerName); + return { success: true }; + } + ); + if (!execResult.success) throw execResult.error; return; } @@ -242,19 +254,37 @@ export const registerDev = (program: Command) => { if (protocol === 'A2A') invokePort = 9000; else if (protocol === 'MCP') invokePort = 8000; - // Protocol-aware dispatch - if (protocol === 'MCP') { - await handleMcpInvoke(invokePort, invokePrompt, opts.tool, opts.input, headers); - } else if (protocol === 'A2A') { - await invokeA2ADevServer(invokePort, invokePrompt, headers); - } else if (protocol === 'AGUI') { - for await (const chunk of invokeForProtocol('AGUI', { port: invokePort, message: invokePrompt, headers })) { - process.stdout.write(chunk); + const invokeResult = await withCommandRunTelemetry( + 'dev', + { + action: 'invoke' as const, + ui_mode: 'terminal' as const, + has_stream: opts.stream ?? false, + protocol: standardize(Protocol, protocol.toLowerCase()), + invoke_count: 1, + }, + async (): Promise => { + // Protocol-aware dispatch + if (protocol === 'MCP') { + await handleMcpInvoke(invokePort, invokePrompt, opts.tool, opts.input, headers); + } else if (protocol === 'A2A') { + await invokeA2ADevServer(invokePort, invokePrompt, headers); + } else if (protocol === 'AGUI') { + for await (const chunk of invokeForProtocol('AGUI', { + port: invokePort, + message: invokePrompt, + headers, + })) { + process.stdout.write(chunk); + } + process.stdout.write('\n'); + } else { + await invokeDevServer(invokePort, invokePrompt, opts.stream ?? false, headers); + } + return { success: true }; } - process.stdout.write('\n'); - } else { - await invokeDevServer(invokePort, invokePrompt, opts.stream ?? false, headers); - } + ); + if (!invokeResult.success) throw invokeResult.error; return; } @@ -353,32 +383,52 @@ export const registerDev = (program: Command) => { console.log(`Log: ${logger.getRelativeLogPath()}`); console.log(`Press Ctrl+C to stop\n`); - const devCallbacks = { - onLog: (level: string, msg: string) => { - const prefix = level === 'error' ? '❌' : level === 'warn' ? '⚠️' : '→'; - console.log(`${prefix} ${msg}`); - logger.log(msg, level === 'error' ? 'error' : 'info'); - }, - onExit: (code: number | null) => { - console.log(`\nServer exited with code ${code ?? 0}`); - logger.finalize(code === 0); - process.exit(code ?? 0); + const devResult = await withCommandRunTelemetry( + 'dev', + { + action: 'server' as const, + ui_mode: 'terminal' as const, + has_stream: false, + protocol: standardize(Protocol, (config.protocol ?? 'http').toLowerCase()), + invoke_count: 0, }, - }; - - const server = createDevServer(config, { port: actualPort, envVars: mergedEnvVars, callbacks: devCallbacks }); - await server.start(); - - // Handle Ctrl+C — use server.kill() for proper container cleanup - process.on('SIGINT', () => { - console.log('\nStopping server...'); - collector?.stop(); - server.kill(); - }); - - // Keep process alive - // eslint-disable-next-line @typescript-eslint/no-empty-function - await new Promise(() => {}); + async (): Promise => { + await new Promise((resolve, reject) => { + const devCallbacks = { + onLog: (level: string, msg: string) => { + const prefix = level === 'error' ? '❌' : level === 'warn' ? '⚠️' : '→'; + console.log(`${prefix} ${msg}`); + logger.log(msg, level === 'error' ? 'error' : 'info'); + }, + onExit: (code: number | null) => { + console.log(`\nServer exited with code ${code ?? 0}`); + logger.finalize(code === 0); + if (code !== 0 && code !== null) { + reject(new Error(`Server exited with code ${code}`)); + } else { + resolve(); + } + }, + }; + + const server = createDevServer(config, { + port: actualPort, + envVars: mergedEnvVars, + callbacks: devCallbacks, + }); + server.start().catch(reject); + + process.once('SIGINT', () => { + console.log('\nStopping server...'); + collector?.stop(); + server.kill(); + }); + }); + return { success: true as const }; + } + ); + if (!devResult.success) throw devResult.error; + process.exit(0); } // If --no-browser provided, launch terminal TUI mode @@ -392,39 +442,71 @@ export const registerDev = (program: Command) => { process.stdout.write(SHOW_CURSOR); }; - const { DevScreen } = await import('../../tui/screens/dev/DevScreen'); - const { unmount, waitUntilExit } = render( - - { - exitAltScreen(); - unmount(); - process.exit(0); - }} - workingDir={workingDir} - port={port} - agentName={opts.runtime} - headers={headers} - /> - + const tuiResult = await withCommandRunTelemetry( + 'dev', + { + action: 'server' as const, + ui_mode: 'terminal' as const, + has_stream: false, + protocol: standardize(Protocol, (targetDevAgent?.protocol ?? 'http').toLowerCase()), + invoke_count: 0, + }, + async (): Promise => { + const { DevScreen } = await import('../../tui/screens/dev/DevScreen'); + const { unmount, waitUntilExit } = render( + + { + exitAltScreen(); + unmount(); + }} + workingDir={workingDir} + port={port} + agentName={opts.runtime} + headers={headers} + /> + + ); + + await waitUntilExit(); + exitAltScreen(); + return { success: true }; + } ); - - await waitUntilExit(); - exitAltScreen(); - return; + if (!tuiResult.success) throw tuiResult.error; + collector?.stop(); + process.exit(0); } // Default: launch web UI in browser - await runBrowserMode({ - workingDir, - project, - port, - agentName: opts.runtime, - otelEnvVars, - collector, - }); + // NOTE: Do not copy this pattern. runBrowserMode blocks forever (internal + // await new Promise(() => {})) so we cannot use withCommandRunTelemetry here. + // We emit telemetry eagerly before the blocking call. If startup fails, the + // error propagates to the outer catch. Prefer withCommandRunTelemetry for + // commands that return. + { + const client = await TelemetryClientAccessor.get().catch(() => undefined); + const devAttrs = { + action: 'server' as const, + ui_mode: 'browser' as const, + has_stream: false, + protocol: standardize(Protocol, (targetDevAgent?.protocol ?? 'http').toLowerCase()), + invoke_count: 0, + }; + if (client) { + await client.withCommandRun('dev', () => devAttrs); + } + await runBrowserMode({ + workingDir, + project, + port, + agentName: opts.runtime, + otelEnvVars, + collector, + }); + } } catch (error) { - render(Error: {getErrorMessage(error)}); + console.error(`Error: ${getErrorMessage(error)}`); process.exit(1); } }); diff --git a/src/cli/telemetry/schemas/__tests__/command-run.test.ts b/src/cli/telemetry/schemas/__tests__/command-run.test.ts index 2df12d271..eae73cabc 100644 --- a/src/cli/telemetry/schemas/__tests__/command-run.test.ts +++ b/src/cli/telemetry/schemas/__tests__/command-run.test.ts @@ -120,6 +120,63 @@ describe('COMMAND_SCHEMAS', () => { it('no-attrs commands accept empty object', () => { expect(COMMAND_SCHEMAS['telemetry.disable'].parse({})).toEqual({}); }); + + it('accepts valid dev invoke attrs', () => { + const attrs = { + action: 'invoke', + ui_mode: 'terminal', + has_stream: true, + protocol: 'http', + invoke_count: 1, + }; + expect(COMMAND_SCHEMAS.dev.parse(attrs)).toEqual(attrs); + }); + + it('accepts valid dev server browser attrs', () => { + const attrs = { + action: 'server', + ui_mode: 'browser', + has_stream: false, + protocol: 'mcp', + invoke_count: 12, + }; + expect(COMMAND_SCHEMAS.dev.parse(attrs)).toEqual(attrs); + }); + + it('accepts dev exec attrs', () => { + const attrs = { + action: 'exec', + ui_mode: 'terminal', + has_stream: false, + protocol: 'http', + invoke_count: 1, + }; + expect(COMMAND_SCHEMAS.dev.parse(attrs)).toEqual(attrs); + }); + + it('rejects dev attrs with invalid action', () => { + expect(() => + COMMAND_SCHEMAS.dev.parse({ + action: 'unknown', + ui_mode: 'terminal', + has_stream: false, + protocol: 'http', + invoke_count: 0, + }) + ).toThrow(); + }); + + it('rejects dev attrs with invalid ui_mode', () => { + expect(() => + COMMAND_SCHEMAS.dev.parse({ + action: 'server', + ui_mode: 'headless', + has_stream: false, + protocol: 'http', + invoke_count: 0, + }) + ).toThrow(); + }); }); describe('deriveCommandGroup', () => { diff --git a/src/cli/telemetry/schemas/command-run.ts b/src/cli/telemetry/schemas/command-run.ts index bf79f42eb..fae8f8394 100644 --- a/src/cli/telemetry/schemas/command-run.ts +++ b/src/cli/telemetry/schemas/command-run.ts @@ -24,6 +24,7 @@ import { RefType, ResourceType, SourceType, + UiMode, ValidationMode, safeSchema, } from './common-shapes.js'; @@ -105,6 +106,7 @@ const DeployAttrs = safeSchema({ const DevAttrs = safeSchema({ action: Action, + ui_mode: UiMode, has_stream: z.boolean(), protocol: Protocol, invoke_count: Count, diff --git a/src/cli/telemetry/schemas/common-shapes.ts b/src/cli/telemetry/schemas/common-shapes.ts index 4624883cd..429716096 100644 --- a/src/cli/telemetry/schemas/common-shapes.ts +++ b/src/cli/telemetry/schemas/common-shapes.ts @@ -46,7 +46,8 @@ export function standardize>(schema: T, value: string | export const Count = z.number().int().nonnegative(); // Shared enums — alphabetical, one per attribute name from the metric shape spec -export const Action = z.enum(['server', 'invoke']); +export const Action = z.enum(['server', 'invoke', 'exec']); +export const UiMode = z.enum(['browser', 'terminal']); export const AgentType = z.enum(['create', 'byo', 'import']); export const AttachMode = z.enum(['log_only', 'enforce']); export const AuthType = z.enum(['sigv4', 'bearer_token']); @@ -94,7 +95,7 @@ export const ModelProvider = z.enum(['bedrock', 'anthropic', 'openai', 'gemini'] export const NetworkMode = z.enum(['public', 'vpc']); export const OutboundAuth = z.enum(['oauth', 'api-key', 'none']); export const PolicyEngineMode = z.enum(['log_only', 'enforce']); -export const Protocol = z.enum(['http', 'mcp', 'a2a']); +export const Protocol = z.enum(['http', 'mcp', 'a2a', 'agui']); export const RefType = z.enum(['arn', 'name']); export const ResourceType = z.enum(['gateway', 'agent']); export const SourceType = z.enum(['file', 'statement', 'generate']); diff --git a/src/lib/errors/types.ts b/src/lib/errors/types.ts index f0a05106c..ca6bfded5 100644 --- a/src/lib/errors/types.ts +++ b/src/lib/errors/types.ts @@ -65,6 +65,16 @@ export class ValidationError extends Error { } } +/** + * Error indicating a network connection failure (e.g., server not reachable). + */ +export class ConnectionError extends Error { + constructor(message: string, options?: ErrorOptions) { + super(message, options); + this.name = 'ConnectionError'; + } +} + /** * Converts an unknown thrown value to an Error instance. * Use in catch blocks to ensure the error field is always an Error object. From 196bf6c76cf6a7c975cecd04fb86581115a6ece4 Mon Sep 17 00:00:00 2001 From: Harrison Weinstock Date: Thu, 14 May 2026 16:34:42 +0000 Subject: [PATCH 2/5] fix: regen package-lock to avoid https://github.com/aws/aws-cdk/issues/37870 --- package-lock.json | 1403 +++------------------------------------------ 1 file changed, 81 insertions(+), 1322 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6bd313ee4..d6791de03 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2342,469 +2342,10 @@ "commander": "~14.0.0" } }, - "node_modules/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", - "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", - "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", - "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", - "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", - "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", - "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", - "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", - "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", - "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", - "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", - "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", - "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", - "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", - "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", - "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", - "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", - "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", - "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", - "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", - "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", - "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", - "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", - "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", - "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", - "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { + "node_modules/@esbuild/linux-x64": { "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", - "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", + "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", "cpu": [ "x64" ], @@ -2812,7 +2353,7 @@ "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { "node": ">=18" @@ -3131,19 +2672,6 @@ } } }, - "node_modules/@napi-rs/wasm-runtime": { - "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.10.0" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3678,315 +3206,56 @@ } }, "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.41.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.41.1.tgz", - "integrity": "sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.130.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.130.0.tgz", - "integrity": "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" - } - }, - "node_modules/@playwright/test": { - "version": "1.60.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz", - "integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "playwright": "1.60.0" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.1.tgz", - "integrity": "sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.1.tgz", - "integrity": "sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.1.tgz", - "integrity": "sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.1.tgz", - "integrity": "sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.1.tgz", - "integrity": "sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.1.tgz", - "integrity": "sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.1.tgz", - "integrity": "sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.1.tgz", - "integrity": "sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.1.tgz", - "integrity": "sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.1.tgz", - "integrity": "sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.1.tgz", - "integrity": "sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.1.tgz", - "integrity": "sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], + "version": "1.41.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.41.1.tgz", + "integrity": "sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==", + "license": "Apache-2.0", "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=14" } }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.1.tgz", - "integrity": "sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==", - "cpu": [ - "wasm32" - ], + "node_modules/@oxc-project/types": { + "version": "0.130.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.130.0.tgz", + "integrity": "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==", "dev": true, "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" + "funding": { + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", - "dev": true, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.1" + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" + "url": "https://opencollective.com/pkgr" } }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.1.tgz", - "integrity": "sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==", - "cpu": [ - "arm64" - ], + "node_modules/@playwright/test": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz", + "integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.60.0" + }, + "bin": { + "playwright": "cli.js" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=18" } }, - "node_modules/@rolldown/binding-win32-x64-msvc": { + "node_modules/@rolldown/binding-linux-x64-gnu": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.1.tgz", - "integrity": "sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.1.tgz", + "integrity": "sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==", "cpu": [ "x64" ], @@ -3994,7 +3263,7 @@ "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { "node": "^20.19.0 || >=22.12.0" @@ -4546,17 +3815,6 @@ } } }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", - "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@types/chai": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", @@ -4868,301 +4126,46 @@ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.59.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.3.tgz", - "integrity": "sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==", - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.59.3", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", - "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", - "license": "ISC" - }, - "node_modules/@unrs/resolver-binding-android-arm-eabi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", - "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@unrs/resolver-binding-android-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", - "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", - "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", - "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", - "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", - "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", - "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", - "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", - "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", - "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", - "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", - "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", - "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", - "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", - "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", - "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", - "cpu": [ - "wasm32" - ], - "dev": true, + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.59.3", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.3.tgz", + "integrity": "sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==", "license": "MIT", - "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.11" + "@typescript-eslint/types": "8.59.3", + "eslint-visitor-keys": "^5.0.0" }, "engines": { - "node": ">=14.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", - "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, - "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", - "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "node_modules/@ungap/structured-clone": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", + "license": "ISC" }, - "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", - "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", "cpu": [ "x64" ], @@ -5170,7 +4173,7 @@ "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ] }, "node_modules/@vitest/coverage-v8": { @@ -5784,6 +4787,17 @@ "@aws-cdk/cloud-assembly-schema": ">=53.21.0" } }, + "node_modules/aws-cdk-lib/node_modules/@aws-cdk/cloud-assembly-api/node_modules/jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/aws-cdk-lib/node_modules/@balena/dockerignore": { "version": "1.0.2", "dev": true, @@ -8344,21 +7358,6 @@ "node": ">=14.14" } }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -9965,153 +8964,6 @@ "lightningcss-win32-x64-msvc": "1.32.0" } }, - "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/lightningcss-linux-x64-gnu": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", @@ -10133,69 +8985,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/lint-staged": { "version": "16.4.0", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.4.0.tgz", @@ -14053,21 +12842,6 @@ "fsevents": "~2.3.3" } }, - "node_modules/tsx/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -14628,21 +13402,6 @@ } } }, - "node_modules/vite/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/vitest": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.6.tgz", From 3a4b747157f9a0a4cad45e5e73abe30da064fb6a Mon Sep 17 00:00:00 2001 From: Harrison Weinstock Date: Thu, 14 May 2026 17:12:17 +0000 Subject: [PATCH 3/5] fix: update tests to consume new result shape --- src/cli/commands/deploy/command.tsx | 8 ++++- .../mcp/__tests__/create-mcp-utils.test.ts | 5 +++- .../memory/__tests__/create-memory.test.ts | 7 +++-- .../remove/__tests__/remove-agent-ops.test.ts | 10 +++++-- .../__tests__/remove-gateway-ops.test.ts | 10 +++++-- .../__tests__/remove-identity-ops.test.ts | 10 +++++-- .../__tests__/remove-memory-ops.test.ts | 10 +++++-- src/cli/primitives/ABTestPrimitive.ts | 2 +- src/cli/primitives/BasePrimitive.ts | 2 +- src/cli/primitives/GatewayPrimitive.ts | 2 +- src/cli/primitives/GatewayTargetPrimitive.ts | 2 +- src/cli/primitives/PolicyEnginePrimitive.ts | 2 +- src/cli/primitives/PolicyPrimitive.ts | 2 +- .../primitives/RuntimeEndpointPrimitive.ts | 2 +- .../__tests__/ABTestPrimitive.test.ts | 19 ++++++++---- .../__tests__/EvaluatorPrimitive.test.ts | 19 +++++++----- .../__tests__/HarnessPrimitive.test.ts | 10 +++---- .../OnlineEvalConfigPrimitive.test.ts | 15 ++++++---- .../RuntimeEndpointPrimitive.test.ts | 29 +++++++++++++++---- .../__tests__/DeployStatus.test.tsx | 8 +++-- .../components/__tests__/LogPanel.test.tsx | 2 +- .../components/__tests__/SecretInput.test.tsx | 5 +++- .../tui/hooks/__tests__/useDevDeploy.test.tsx | 1 - 23 files changed, 129 insertions(+), 53 deletions(-) diff --git a/src/cli/commands/deploy/command.tsx b/src/cli/commands/deploy/command.tsx index d3c314f6e..dc4a9f498 100644 --- a/src/cli/commands/deploy/command.tsx +++ b/src/cli/commands/deploy/command.tsx @@ -64,7 +64,13 @@ async function handleDeployCLI(options: DeployOptions): Promise { // ALL output happens here, after telemetry if (!executeDeployResult.success) { if (options.json) { - console.log(JSON.stringify(executeDeployResult)); + console.log( + JSON.stringify({ + ...executeDeployResult.deployResult, + success: false, + error: executeDeployResult.error.message, + }) + ); } else { console.error(executeDeployResult.error.message); if (executeDeployResult.deployResult.logPath) { diff --git a/src/cli/operations/mcp/__tests__/create-mcp-utils.test.ts b/src/cli/operations/mcp/__tests__/create-mcp-utils.test.ts index 19cb635a1..45dfc1169 100644 --- a/src/cli/operations/mcp/__tests__/create-mcp-utils.test.ts +++ b/src/cli/operations/mcp/__tests__/create-mcp-utils.test.ts @@ -200,7 +200,10 @@ describe('GatewayPrimitive.add (createGateway)', () => { }); expect(result).toEqual( - expect.objectContaining({ success: false, error: expect.stringContaining('Gateway "dup-gw" already exists') }) + expect.objectContaining({ + success: false, + error: expect.objectContaining({ message: expect.stringContaining('Gateway "dup-gw" already exists') }), + }) ); }); diff --git a/src/cli/operations/memory/__tests__/create-memory.test.ts b/src/cli/operations/memory/__tests__/create-memory.test.ts index a0b8077c4..09c827ac0 100644 --- a/src/cli/operations/memory/__tests__/create-memory.test.ts +++ b/src/cli/operations/memory/__tests__/create-memory.test.ts @@ -86,7 +86,7 @@ describe('add', () => { expiry: 30, }); - expect(result).toEqual(expect.objectContaining({ success: false, error: expect.any(String) })); + expect(result).toEqual(expect.objectContaining({ success: false, error: expect.any(Error) })); expect(mockWriteProjectSpec).not.toHaveBeenCalled(); }); @@ -96,7 +96,10 @@ describe('add', () => { const result = await primitive.add({ name: 'Existing', strategies: '', expiry: 30 }); expect(result).toEqual( - expect.objectContaining({ success: false, error: expect.stringContaining('Memory "Existing" already exists') }) + expect.objectContaining({ + success: false, + error: expect.objectContaining({ message: expect.stringContaining('Memory "Existing" already exists') }), + }) ); }); }); diff --git a/src/cli/operations/remove/__tests__/remove-agent-ops.test.ts b/src/cli/operations/remove/__tests__/remove-agent-ops.test.ts index fb2b9fedc..40e8a1185 100644 --- a/src/cli/operations/remove/__tests__/remove-agent-ops.test.ts +++ b/src/cli/operations/remove/__tests__/remove-agent-ops.test.ts @@ -87,7 +87,10 @@ describe('remove', () => { const result = await primitive.remove('Missing'); - expect(result).toEqual({ success: false, error: 'Agent "Missing" not found.' }); + expect(result).toEqual({ + success: false, + error: expect.objectContaining({ message: 'Agent "Missing" not found.' }), + }); }); it('returns error on exception', async () => { @@ -95,6 +98,9 @@ describe('remove', () => { const result = await primitive.remove('Agent1'); - expect(result).toEqual({ success: false, error: 'read fail' }); + expect(result).toEqual({ + success: false, + error: expect.objectContaining({ message: 'read fail' }), + }); }); }); diff --git a/src/cli/operations/remove/__tests__/remove-gateway-ops.test.ts b/src/cli/operations/remove/__tests__/remove-gateway-ops.test.ts index 54293df5a..f22266e05 100644 --- a/src/cli/operations/remove/__tests__/remove-gateway-ops.test.ts +++ b/src/cli/operations/remove/__tests__/remove-gateway-ops.test.ts @@ -101,7 +101,10 @@ describe('remove', () => { const result = await primitive.remove('missing'); - expect(result).toEqual({ success: false, error: 'Gateway "missing" not found.' }); + expect(result).toEqual({ + success: false, + error: expect.objectContaining({ message: 'Gateway "missing" not found.' }), + }); }); it('returns error on exception', async () => { @@ -109,6 +112,9 @@ describe('remove', () => { const result = await primitive.remove('gw1'); - expect(result).toEqual({ success: false, error: 'read fail' }); + expect(result).toEqual({ + success: false, + error: expect.objectContaining({ message: 'read fail' }), + }); }); }); diff --git a/src/cli/operations/remove/__tests__/remove-identity-ops.test.ts b/src/cli/operations/remove/__tests__/remove-identity-ops.test.ts index 1b1bbb8e7..30ad41def 100644 --- a/src/cli/operations/remove/__tests__/remove-identity-ops.test.ts +++ b/src/cli/operations/remove/__tests__/remove-identity-ops.test.ts @@ -93,7 +93,10 @@ describe('remove', () => { const result = await primitive.remove('Missing'); - expect(result).toEqual({ success: false, error: 'Credential "Missing" not found.' }); + expect(result).toEqual({ + success: false, + error: expect.objectContaining({ message: 'Credential "Missing" not found.' }), + }); }); it('returns error on exception', async () => { @@ -101,6 +104,9 @@ describe('remove', () => { const result = await primitive.remove('Cred1'); - expect(result).toEqual({ success: false, error: 'read fail' }); + expect(result).toEqual({ + success: false, + error: expect.objectContaining({ message: 'read fail' }), + }); }); }); diff --git a/src/cli/operations/remove/__tests__/remove-memory-ops.test.ts b/src/cli/operations/remove/__tests__/remove-memory-ops.test.ts index d42bedb94..aa2c70c8f 100644 --- a/src/cli/operations/remove/__tests__/remove-memory-ops.test.ts +++ b/src/cli/operations/remove/__tests__/remove-memory-ops.test.ts @@ -84,7 +84,10 @@ describe('remove', () => { const result = await primitive.remove('Missing'); - expect(result).toEqual({ success: false, error: 'Memory "Missing" not found.' }); + expect(result).toEqual({ + success: false, + error: expect.objectContaining({ message: 'Memory "Missing" not found.' }), + }); }); it('returns error on exception', async () => { @@ -92,6 +95,9 @@ describe('remove', () => { const result = await primitive.remove('Mem1'); - expect(result).toEqual({ success: false, error: 'read fail' }); + expect(result).toEqual({ + success: false, + error: expect.objectContaining({ message: 'read fail' }), + }); }); }); diff --git a/src/cli/primitives/ABTestPrimitive.ts b/src/cli/primitives/ABTestPrimitive.ts index 34b98d319..a09ba1e02 100644 --- a/src/cli/primitives/ABTestPrimitive.ts +++ b/src/cli/primitives/ABTestPrimitive.ts @@ -479,7 +479,7 @@ Target-Based Mode (--mode target-based) resourceType: this.kind, resourceName: cliOptions.name, message: result.success ? `Removed ${this.label.toLowerCase()} '${cliOptions.name}'` : undefined, - error: !result.success ? result.error : undefined, + error: !result.success ? getErrorMessage(result.error) : undefined, }) ); process.exit(result.success ? 0 : 1); diff --git a/src/cli/primitives/BasePrimitive.ts b/src/cli/primitives/BasePrimitive.ts index c8a296eee..e8ae07000 100644 --- a/src/cli/primitives/BasePrimitive.ts +++ b/src/cli/primitives/BasePrimitive.ts @@ -128,7 +128,7 @@ export abstract class BasePrimitive< resourceName: cliOptions.name, message: result.success ? `Removed ${this.label.toLowerCase()} '${cliOptions.name}'` : undefined, note: result.success ? SOURCE_CODE_NOTE : undefined, - error: !result.success ? result.error : undefined, + error: !result.success ? getErrorMessage(result.error) : undefined, }) ); process.exit(result.success ? 0 : 1); diff --git a/src/cli/primitives/GatewayPrimitive.ts b/src/cli/primitives/GatewayPrimitive.ts index ae1d390ee..8e019771b 100644 --- a/src/cli/primitives/GatewayPrimitive.ts +++ b/src/cli/primitives/GatewayPrimitive.ts @@ -270,7 +270,7 @@ export class GatewayPrimitive extends BasePrimitive { const result = await primitive.add(validOptions); expect(result).toEqual( - expect.objectContaining({ success: false, error: expect.stringContaining('already exists') }) + expect.objectContaining({ + success: false, + error: expect.objectContaining({ message: expect.stringContaining('already exists') }), + }) ); }); @@ -130,7 +133,9 @@ describe('ABTestPrimitive', () => { const result = await primitive.add(validOptions); - expect(result).toEqual(expect.objectContaining({ success: false, error: 'disk read error' })); + expect(result).toEqual( + expect.objectContaining({ success: false, error: expect.objectContaining({ message: 'disk read error' }) }) + ); }); it('returns error when writeProjectSpec fails', async () => { @@ -139,7 +144,9 @@ describe('ABTestPrimitive', () => { const result = await primitive.add(validOptions); - expect(result).toEqual(expect.objectContaining({ success: false, error: 'disk write error' })); + expect(result).toEqual( + expect.objectContaining({ success: false, error: expect.objectContaining({ message: 'disk write error' }) }) + ); }); it('returns error when variant weights do not sum to 100', async () => { @@ -175,8 +182,8 @@ describe('ABTestPrimitive', () => { expect(result.success).toBe(false); if (!result.success) { - expect(result.error).toContain('NonExistent'); - expect(result.error).toContain('not found'); + expect(result.error.message).toContain('NonExistent'); + expect(result.error.message).toContain('not found'); } }); @@ -187,7 +194,7 @@ describe('ABTestPrimitive', () => { expect(result.success).toBe(false); if (!result.success) { - expect(result.error).toBe('io error'); + expect(result.error.message).toBe('io error'); } }); diff --git a/src/cli/primitives/__tests__/EvaluatorPrimitive.test.ts b/src/cli/primitives/__tests__/EvaluatorPrimitive.test.ts index b41545d20..bd48394ef 100644 --- a/src/cli/primitives/__tests__/EvaluatorPrimitive.test.ts +++ b/src/cli/primitives/__tests__/EvaluatorPrimitive.test.ts @@ -108,7 +108,10 @@ describe('EvaluatorPrimitive', () => { }); expect(result).toEqual( - expect.objectContaining({ success: false, error: expect.stringContaining('already exists') }) + expect.objectContaining({ + success: false, + error: expect.objectContaining({ message: expect.stringContaining('already exists') }), + }) ); }); @@ -121,7 +124,9 @@ describe('EvaluatorPrimitive', () => { config: validConfig, }); - expect(result).toEqual(expect.objectContaining({ success: false, error: 'disk read error' })); + expect(result).toEqual( + expect.objectContaining({ success: false, error: expect.objectContaining({ message: 'disk read error' }) }) + ); }); }); @@ -145,8 +150,8 @@ describe('EvaluatorPrimitive', () => { expect(result.success).toBe(false); if (!result.success) { - expect(result.error).toContain('NonExistent'); - expect(result.error).toContain('not found'); + expect(result.error.message).toContain('NonExistent'); + expect(result.error.message).toContain('not found'); } }); @@ -159,8 +164,8 @@ describe('EvaluatorPrimitive', () => { expect(result.success).toBe(false); if (!result.success) { - expect(result.error).toContain('referenced by online eval config'); - expect(result.error).toContain('MyOnlineConfig'); + expect(result.error.message).toContain('referenced by online eval config'); + expect(result.error.message).toContain('MyOnlineConfig'); } expect(mockWriteProjectSpec).not.toHaveBeenCalled(); }); @@ -172,7 +177,7 @@ describe('EvaluatorPrimitive', () => { expect(result.success).toBe(false); if (!result.success) { - expect(result.error).toBe('io error'); + expect(result.error.message).toBe('io error'); } }); }); diff --git a/src/cli/primitives/__tests__/HarnessPrimitive.test.ts b/src/cli/primitives/__tests__/HarnessPrimitive.test.ts index b37c58733..1a4216d95 100644 --- a/src/cli/primitives/__tests__/HarnessPrimitive.test.ts +++ b/src/cli/primitives/__tests__/HarnessPrimitive.test.ts @@ -1,5 +1,5 @@ import { setEnvVar } from '../../../lib'; -import type { AgentCoreProjectSpec, NetworkMode } from '../../../schema'; +import type { AgentCoreProjectSpec } from '../../../schema'; import { DEFAULT_EPISODIC_REFLECTION_NAMESPACES, DEFAULT_STRATEGY_NAMESPACES } from '../../../schema'; import { HarnessPrimitive } from '../HarnessPrimitive'; import { beforeEach, describe, expect, it, vi } from 'vitest'; @@ -161,7 +161,7 @@ describe('HarnessPrimitive', () => { expect(result.success).toBe(false); if (!result.success) { - expect(result.error).toContain('already exists'); + expect(result.error.message).toContain('already exists'); } }); @@ -234,7 +234,7 @@ describe('HarnessPrimitive', () => { name: 'testHarness', modelProvider: 'bedrock', modelId: 'anthropic.claude-3-5-sonnet-20240620-v1:0', - networkMode: 'VPC' as NetworkMode, + networkMode: 'VPC', subnets: ['subnet-123', 'subnet-456'], securityGroups: ['sg-789'], }); @@ -486,7 +486,7 @@ describe('HarnessPrimitive', () => { }); expect(result.success).toBe(false); - expect(!result.success && result.error).toContain('Dockerfile not found at'); + expect(!result.success && result.error.message).toContain('Dockerfile not found at'); }); it('includes authorizerType AWS_IAM in harness spec', async () => { @@ -654,7 +654,7 @@ describe('HarnessPrimitive', () => { expect(result.success).toBe(false); if (!result.success) { - expect(result.error).toContain('not found'); + expect(result.error.message).toContain('not found'); } }); }); diff --git a/src/cli/primitives/__tests__/OnlineEvalConfigPrimitive.test.ts b/src/cli/primitives/__tests__/OnlineEvalConfigPrimitive.test.ts index c81160a6c..ced4db9ce 100644 --- a/src/cli/primitives/__tests__/OnlineEvalConfigPrimitive.test.ts +++ b/src/cli/primitives/__tests__/OnlineEvalConfigPrimitive.test.ts @@ -126,7 +126,10 @@ describe('OnlineEvalConfigPrimitive', () => { }); expect(result).toEqual( - expect.objectContaining({ success: false, error: expect.stringContaining('already exists') }) + expect.objectContaining({ + success: false, + error: expect.objectContaining({ message: expect.stringContaining('already exists') }), + }) ); }); @@ -140,7 +143,9 @@ describe('OnlineEvalConfigPrimitive', () => { samplingRate: 10, }); - expect(result).toEqual(expect.objectContaining({ success: false, error: 'no project' })); + expect(result).toEqual( + expect.objectContaining({ success: false, error: expect.objectContaining({ message: 'no project' }) }) + ); }); }); @@ -169,8 +174,8 @@ describe('OnlineEvalConfigPrimitive', () => { expect(result.success).toBe(false); if (!result.success) { - expect(result.error).toContain('NonExistent'); - expect(result.error).toContain('not found'); + expect(result.error.message).toContain('NonExistent'); + expect(result.error.message).toContain('not found'); } }); @@ -181,7 +186,7 @@ describe('OnlineEvalConfigPrimitive', () => { expect(result.success).toBe(false); if (!result.success) { - expect(result.error).toBe('io error'); + expect(result.error.message).toBe('io error'); } }); }); diff --git a/src/cli/primitives/__tests__/RuntimeEndpointPrimitive.test.ts b/src/cli/primitives/__tests__/RuntimeEndpointPrimitive.test.ts index 46fe426f5..433d0c0e2 100644 --- a/src/cli/primitives/__tests__/RuntimeEndpointPrimitive.test.ts +++ b/src/cli/primitives/__tests__/RuntimeEndpointPrimitive.test.ts @@ -87,7 +87,12 @@ describe('RuntimeEndpointPrimitive', () => { endpoint: 'prod', }); - expect(result).toEqual(expect.objectContaining({ success: false, error: expect.stringContaining('not found') })); + expect(result).toEqual( + expect.objectContaining({ + success: false, + error: expect.objectContaining({ message: expect.stringContaining('not found') }), + }) + ); }); it('returns error when endpoint already exists', async () => { @@ -100,7 +105,10 @@ describe('RuntimeEndpointPrimitive', () => { }); expect(result).toEqual( - expect.objectContaining({ success: false, error: expect.stringContaining('already exists') }) + expect.objectContaining({ + success: false, + error: expect.objectContaining({ message: expect.stringContaining('already exists') }), + }) ); }); @@ -134,7 +142,10 @@ describe('RuntimeEndpointPrimitive', () => { }); expect(result).toEqual( - expect.objectContaining({ success: false, error: expect.stringContaining('positive integer') }) + expect.objectContaining({ + success: false, + error: expect.objectContaining({ message: expect.stringContaining('positive integer') }), + }) ); }); @@ -181,7 +192,10 @@ describe('RuntimeEndpointPrimitive', () => { }); expect(result).toEqual( - expect.objectContaining({ success: false, error: expect.stringContaining('exceeds latest deployed version') }) + expect.objectContaining({ + success: false, + error: expect.objectContaining({ message: expect.stringContaining('exceeds latest deployed version') }), + }) ); }); }); @@ -223,7 +237,12 @@ describe('RuntimeEndpointPrimitive', () => { const result = await primitive.remove('MyRuntime/nonexistent'); - expect(result).toEqual(expect.objectContaining({ success: false, error: expect.stringContaining('not found') })); + expect(result).toEqual( + expect.objectContaining({ + success: false, + error: expect.objectContaining({ message: expect.stringContaining('not found') }), + }) + ); }); it('cleans up empty endpoints dict after removing last endpoint', async () => { diff --git a/src/cli/tui/components/__tests__/DeployStatus.test.tsx b/src/cli/tui/components/__tests__/DeployStatus.test.tsx index fedca8e1a..4abc0d857 100644 --- a/src/cli/tui/components/__tests__/DeployStatus.test.tsx +++ b/src/cli/tui/components/__tests__/DeployStatus.test.tsx @@ -1,9 +1,11 @@ import type { DeployMessage } from '../../../cdk/toolkit-lib/index.js'; import { DeployStatus } from '../DeployStatus.js'; import { render } from 'ink-testing-library'; -import React from 'react'; import { describe, expect, it } from 'vitest'; +// eslint-disable-next-line no-control-regex +const stripAnsi = (s: string) => s.replace(/\u001b\[[0-9;]*m/g, ''); + function makeMsg( message: string, code = 'CDK_TOOLKIT_I5502', @@ -28,7 +30,7 @@ describe('DeployStatus', () => { it('shows "Deploying to AWS" when not complete', () => { const { lastFrame } = render(); - expect(lastFrame()).toContain('Deploying to AWS'); + expect(stripAnsi(lastFrame()!)).toContain('Deploying to AWS'); }); it('shows success message when complete without error', () => { @@ -90,7 +92,7 @@ describe('DeployStatus', () => { const { lastFrame } = render(); // Should show deploying text but no resource lines - expect(lastFrame()).toContain('Deploying to AWS'); + expect(stripAnsi(lastFrame()!)).toContain('Deploying to AWS'); expect(lastFrame()).not.toContain('Some general info'); }); diff --git a/src/cli/tui/components/__tests__/LogPanel.test.tsx b/src/cli/tui/components/__tests__/LogPanel.test.tsx index e7e445e48..307934f2e 100644 --- a/src/cli/tui/components/__tests__/LogPanel.test.tsx +++ b/src/cli/tui/components/__tests__/LogPanel.test.tsx @@ -19,7 +19,7 @@ describe('LogPanel', () => { describe('empty state', () => { it('renders "No output yet" with no other content', () => { const { lastFrame } = render(); - expect(lastFrame()).toBe('No output yet'); + expect(lastFrame()).toContain('No output yet'); }); }); diff --git a/src/cli/tui/components/__tests__/SecretInput.test.tsx b/src/cli/tui/components/__tests__/SecretInput.test.tsx index 3b326ea2a..3c51b4232 100644 --- a/src/cli/tui/components/__tests__/SecretInput.test.tsx +++ b/src/cli/tui/components/__tests__/SecretInput.test.tsx @@ -12,6 +12,9 @@ function delay(ms = 50) { return new Promise(resolve => setTimeout(resolve, ms)); } +// eslint-disable-next-line no-control-regex +const stripAnsi = (s: string) => s.replace(/\u001b\[[0-9;]*m/g, ''); + afterEach(() => vi.restoreAllMocks()); describe('SecretInput', () => { @@ -34,7 +37,7 @@ describe('SecretInput', () => { ); - expect(lastFrame()).toContain('sk-...'); + expect(stripAnsi(lastFrame()!)).toContain('sk-...'); }); it('masks input with default * character', async () => { diff --git a/src/cli/tui/hooks/__tests__/useDevDeploy.test.tsx b/src/cli/tui/hooks/__tests__/useDevDeploy.test.tsx index ff8434a8e..de56d0e29 100644 --- a/src/cli/tui/hooks/__tests__/useDevDeploy.test.tsx +++ b/src/cli/tui/hooks/__tests__/useDevDeploy.test.tsx @@ -1,7 +1,6 @@ import { useDevDeploy } from '../useDevDeploy.js'; import { Text } from 'ink'; import { render } from 'ink-testing-library'; -import React from 'react'; import { afterEach, describe, expect, it, vi } from 'vitest'; const mockHandleDeploy = vi.fn(); From c792733a02470273a3ae6f4363b81d04366b9f89 Mon Sep 17 00:00:00 2001 From: Harrison Weinstock Date: Thu, 14 May 2026 17:54:38 +0000 Subject: [PATCH 4/5] fix: reapply telemetry change to get integ test to pass --- src/cli/primitives/ABTestPrimitive.ts | 10 +++++----- src/cli/primitives/ConfigBundlePrimitive.ts | 4 ++-- src/cli/telemetry/cli-command-run.ts | 20 +++++++++++++------- src/cli/telemetry/client.ts | 11 ++++------- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/cli/primitives/ABTestPrimitive.ts b/src/cli/primitives/ABTestPrimitive.ts index a09ba1e02..603e98b09 100644 --- a/src/cli/primitives/ABTestPrimitive.ts +++ b/src/cli/primitives/ABTestPrimitive.ts @@ -1,4 +1,4 @@ -import { type Result, findConfigRoot } from '../../lib'; +import { type Result, findConfigRoot, serializeResult } from '../../lib'; import type { ABTest } from '../../schema/schemas/primitives/ab-test'; import { ABTestSchema } from '../../schema/schemas/primitives/ab-test'; import { getErrorMessage } from '../errors'; @@ -366,11 +366,11 @@ Target-Based Mode (--mode target-based) }); if (cliOptions.json) { - console.log(JSON.stringify(result)); + console.log(JSON.stringify(serializeResult(result))); } else if (result.success) { console.log(`Added target-based AB test '${result.abTestName}'`); } else { - console.error(result.error); + console.error(result.error.message); } process.exit(result.success ? 0 : 1); return; @@ -413,11 +413,11 @@ Target-Based Mode (--mode target-based) }); if (cliOptions.json) { - console.log(JSON.stringify(result)); + console.log(JSON.stringify(serializeResult(result))); } else if (result.success) { console.log(`Added AB test '${result.abTestName}'`); } else { - console.error(result.error); + console.error(result.error.message); } process.exit(result.success ? 0 : 1); } else { diff --git a/src/cli/primitives/ConfigBundlePrimitive.ts b/src/cli/primitives/ConfigBundlePrimitive.ts index bd46b40b8..17b152ebb 100644 --- a/src/cli/primitives/ConfigBundlePrimitive.ts +++ b/src/cli/primitives/ConfigBundlePrimitive.ts @@ -1,4 +1,4 @@ -import { type Result, findConfigRoot } from '../../lib'; +import { type Result, findConfigRoot, serializeResult } from '../../lib'; import type { ConfigBundle } from '../../schema'; import { ConfigBundleSchema } from '../../schema'; import { getErrorMessage } from '../errors'; @@ -171,7 +171,7 @@ export class ConfigBundlePrimitive extends BasePrimitive { - result = await fn(); - if (!result.success) throw result.error; - return attrs; - }); + await client.withCommandRun( + command, + async () => { + result = await fn(); + if (!result.success) throw result.error; + return attrs; + }, + attrs + ); } catch (e) { // withCommandRun re-throws after recording failure telemetry. // If result was set, fn() returned a failure result — return it directly. @@ -50,11 +54,13 @@ export async function withCommandRunTelemetry( command: C, json: boolean, - fn: () => Promise> + fn: () => Promise>, + knownAttrs?: Partial> ): Promise { try { const client = await getTelemetryClient(); @@ -62,7 +68,7 @@ export async function runCliCommand( await fn(); process.exit(0); } - await client.withCommandRun(command, fn); + await client.withCommandRun(command, fn, knownAttrs); process.exit(0); } catch (error) { if (json) { diff --git a/src/cli/telemetry/client.ts b/src/cli/telemetry/client.ts index 91dffd94f..cbb0b296f 100644 --- a/src/cli/telemetry/client.ts +++ b/src/cli/telemetry/client.ts @@ -26,7 +26,8 @@ export class TelemetryClient { */ async withCommandRun( command: C, - fn: () => CommandAttrs | typeof CANCELLED | Promise | typeof CANCELLED> + fn: () => CommandAttrs | typeof CANCELLED | Promise | typeof CANCELLED>, + fallbackAttrs?: Partial> ): Promise { const start = performance.now(); try { @@ -43,7 +44,7 @@ export class TelemetryClient { error_name: classifyError(err), is_user_error: isUserError(err), }; - this.recordCommandRun(command, failureResult, {}, Math.round(performance.now() - start)); + this.recordCommandRun(command, failureResult, fallbackAttrs ?? {}, Math.round(performance.now() - start)); throw err; } finally { try { @@ -75,11 +76,7 @@ export class TelemetryClient { // Validate command attrs resiliently: invalid fields default to 'unknown' // instead of dropping the entire metric. - // On failure/cancel the callback attrs are empty so validation is skipped. - const validatedAttrs = - result.exit_reason !== 'failure' && result.exit_reason !== 'cancel' - ? resilientParse(COMMAND_SCHEMAS[command], attrs as Record) - : attrs; + const validatedAttrs = Object.keys(attrs).length > 0 ? resilientParse(COMMAND_SCHEMAS[command], attrs) : attrs; const otelAttrs: Record = { command_group: deriveCommandGroup(command), From fbb4b5bcc5f20a3904c5396f05d7db31b6e799e1 Mon Sep 17 00:00:00 2001 From: Harrison Weinstock Date: Thu, 14 May 2026 18:21:53 +0000 Subject: [PATCH 5/5] fix: address eslint errors --- src/cli/aws/agentcore-control.ts | 2 +- src/cli/aws/agentcore.ts | 4 +- src/cli/aws/bedrock-import.ts | 2 +- src/cli/cdk/toolkit-lib/wrapper.ts | 2 +- src/cli/commands/add/validate.ts | 8 +-- .../commands/create/__tests__/create.test.ts | 4 ++ src/cli/commands/deploy/actions.ts | 17 ++--- .../__tests__/import-gateway-spec.test.ts | 1 - .../__tests__/import-gateway-targets.test.ts | 6 -- src/cli/commands/import/import-runtime.ts | 2 +- src/cli/commands/import/yaml-parser.ts | 8 +-- src/cli/logging/invoke-logger.ts | 4 +- .../agent/import/langgraph-translator.ts | 2 +- .../agent/import/strands-translator.ts | 2 +- .../__tests__/post-deploy-ab-tests.test.ts | 2 +- .../post-deploy-config-bundles.test.ts | 4 +- .../deploy/__tests__/teardown-utils.test.ts | 9 ++- .../imperative/deployers/harness-mapper.ts | 2 +- .../operations/deploy/post-deploy-ab-tests.ts | 6 +- .../deploy/post-deploy-config-bundles.ts | 7 +- .../__tests__/container-dev-server.test.ts | 2 +- src/cli/operations/dev/invoke.ts | 6 +- .../__tests__/cloudwatch-traces.test.ts | 2 +- .../__tests__/harness-invocation.test.ts | 4 +- .../__tests__/harness-tool-response.test.ts | 4 +- .../dev/web-ui/__tests__/mcp-proxy.test.ts | 2 +- .../__tests__/resolve-ui-dist-dir.test.ts | 3 +- .../dev/web-ui/__tests__/status.test.ts | 8 +-- .../dev/web-ui/handlers/resources.ts | 16 ++--- .../eval/__tests__/run-eval.test.ts | 6 +- src/cli/operations/eval/run-eval.ts | 2 +- .../identity/__tests__/credential-ops.test.ts | 29 ++------ .../recommendation/apply-to-bundle.ts | 2 +- .../__tests__/ResourceGraph.test.tsx | 2 +- .../__tests__/usePanelNavigation.test.tsx | 1 + src/cli/tui/hooks/useCdkPreflight.ts | 2 +- src/cli/tui/hooks/useDevDeploy.ts | 6 +- .../tui/screens/ab-test/AddABTestScreen.tsx | 3 +- .../ab-test/TargetBasedABTestScreen.tsx | 2 + src/cli/tui/screens/agent/AddAgentScreen.tsx | 26 +++---- .../VersionHistoryScreen.tsx | 71 ++++++++++--------- src/cli/tui/screens/deploy/useDeployFlow.ts | 5 +- src/cli/tui/screens/home/HelpScreen.tsx | 37 +++++----- .../screens/mcp/AddGatewayTargetScreen.tsx | 3 +- .../online-eval/AddOnlineEvalScreen.tsx | 2 +- .../screens/schema/AgentCoreGuidedEditor.tsx | 21 +++--- src/lib/errors/__tests__/config.test.ts | 2 +- src/lib/packaging/__tests__/node.test.ts | 6 +- src/lib/packaging/__tests__/python.test.ts | 10 +-- src/lib/packaging/index.ts | 2 +- src/schema/schemas/primitives/harness.ts | 4 +- src/tui-harness/mcp/server.ts | 2 + 52 files changed, 180 insertions(+), 207 deletions(-) diff --git a/src/cli/aws/agentcore-control.ts b/src/cli/aws/agentcore-control.ts index 8a8569cf0..ef463cef4 100644 --- a/src/cli/aws/agentcore-control.ts +++ b/src/cli/aws/agentcore-control.ts @@ -544,7 +544,7 @@ export async function getEvaluator(options: GetEvaluatorOptions): Promise toolkit.synth(source, { validateStacks: true })); // Store synth result - it may hold locks - this.synthResult = result as SynthResult; + this.synthResult = result; // Produce the assembly to get the directory and stack info const assembly = await result.produce(); diff --git a/src/cli/commands/add/validate.ts b/src/cli/commands/add/validate.ts index 32f858c0f..d3127a22a 100644 --- a/src/cli/commands/add/validate.ts +++ b/src/cli/commands/add/validate.ts @@ -140,7 +140,7 @@ export function validateAddAgentOptions(options: AddAgentOptions): ValidationRes if (!options.memory) { return { valid: false, error: '--memory is required for import path' }; } - if (!MEMORY_OPTIONS.includes(options.memory as (typeof MEMORY_OPTIONS)[number])) { + if (!MEMORY_OPTIONS.includes(options.memory)) { return { valid: false, error: `Invalid memory option: ${options.memory}. Use none, shortTerm, or longAndShortTerm`, @@ -153,8 +153,8 @@ export function validateAddAgentOptions(options: AddAgentOptions): ValidationRes if (lcResult.maxLifetime !== undefined) options.maxLifetime = lcResult.maxLifetime; // Force import defaults - options.modelProvider = 'Bedrock' as typeof options.modelProvider; - options.language = 'Python' as typeof options.language; + options.modelProvider = 'Bedrock'; + options.language = 'Python'; return { valid: true }; } @@ -248,7 +248,7 @@ export function validateAddAgentOptions(options: AddAgentOptions): ValidationRes return { valid: false, error: '--memory is required for create path' }; } - if (!MEMORY_OPTIONS.includes(options.memory as (typeof MEMORY_OPTIONS)[number])) { + if (!MEMORY_OPTIONS.includes(options.memory)) { return { valid: false, error: `Invalid memory option: ${options.memory}. Use none, shortTerm, or longAndShortTerm`, diff --git a/src/cli/commands/create/__tests__/create.test.ts b/src/cli/commands/create/__tests__/create.test.ts index 729cce707..cf112f30a 100644 --- a/src/cli/commands/create/__tests__/create.test.ts +++ b/src/cli/commands/create/__tests__/create.test.ts @@ -47,6 +47,7 @@ describe('create command', () => { const json = JSON.parse(result.stdout); expect(json.success).toBe(true); + // eslint-disable-next-line security/detect-non-literal-regexp -- test assertion with safe variable expect(json.projectPath).toMatch(new RegExp(`/${projectName}$`)); expect(await exists(join(json.projectPath, 'agentcore'))).toBeTruthy(); }); @@ -187,6 +188,7 @@ describe('create command', () => { const json = JSON.parse(result.stdout); expect(json.success).toBe(true); + // eslint-disable-next-line security/detect-non-literal-regexp -- test assertion with safe variable expect(json.projectPath).toMatch(new RegExp(`/${projectName}$`)); expect(json.agentName).toBe(agentName); expect(await exists(join(json.projectPath, 'app', agentName))).toBeTruthy(); @@ -210,6 +212,7 @@ describe('create command', () => { const json = JSON.parse(result.stdout); expect(json.success).toBe(true); + // eslint-disable-next-line security/detect-non-literal-regexp -- test assertion with safe variable expect(json.projectPath).toMatch(new RegExp(`/${projectName}$`)); expect(await exists(join(json.projectPath, 'app', harnessName, 'harness.json'))).toBeTruthy(); @@ -282,6 +285,7 @@ describe('create command', () => { expect(result.exitCode).toBe(0); const json = JSON.parse(result.stdout); + // eslint-disable-next-line security/detect-non-literal-regexp -- test assertion with safe variable expect(json.projectPath).toMatch(new RegExp(`/${projectName}$`)); expect(json.wouldCreate).toContain(`${json.projectPath}/app/${agentName}/`); expect(await exists(join(testDir, projectName)), 'Should not create directory').toBe(false); diff --git a/src/cli/commands/deploy/actions.ts b/src/cli/commands/deploy/actions.ts index f7210a9b2..bfe12b2fd 100644 --- a/src/cli/commands/deploy/actions.ts +++ b/src/cli/commands/deploy/actions.ts @@ -225,7 +225,7 @@ export async function handleDeploy(options: ValidatedDeployOptions): Promise 0) { - const existingPreSynthState = await configIO.readDeployedState().catch(() => ({ targets: {} }) as DeployedState); + const existingPreSynthState: DeployedState = await configIO.readDeployedState().catch(() => ({ targets: {} })); const targetState = existingPreSynthState.targets?.[target.name] ?? { resources: {} }; targetState.resources ??= {}; targetState.resources.credentials = deployedCredentials; @@ -374,7 +374,7 @@ export async function handleDeploy(options: ValidatedDeployOptions): Promise ({ targets: {} }) as DeployedState); + const existingTeardownState: DeployedState = await configIO.readDeployedState().catch(() => ({ targets: {} })); const teardownContext = { projectSpec: context.projectSpec, target, @@ -478,13 +478,10 @@ export async function handleDeploy(options: ValidatedDeployOptions): Promise { - acc[gateway.name] = gateway; - return acc; - }, - {} as Record - ) ?? {}; + mcpSpec?.agentCoreGateways?.reduce>((acc, gateway) => { + acc[gateway.name] = gateway; + return acc; + }, {}) ?? {}; const gateways = parseGatewayOutputs(outputs, gatewaySpecs); endStep('success'); @@ -492,7 +489,7 @@ export async function handleDeploy(options: ValidatedDeployOptions): Promise | undefined; const imperativeManager = createDeploymentManager(); - const existingState = await configIO.readDeployedState().catch(() => ({ targets: {} }) as DeployedState); + const existingState: DeployedState = await configIO.readDeployedState().catch(() => ({ targets: {} })); const imperativeContext = { projectSpec: context.projectSpec, target, diff --git a/src/cli/commands/import/__tests__/import-gateway-spec.test.ts b/src/cli/commands/import/__tests__/import-gateway-spec.test.ts index 7c2963edf..b6ebbeeb6 100644 --- a/src/cli/commands/import/__tests__/import-gateway-spec.test.ts +++ b/src/cli/commands/import/__tests__/import-gateway-spec.test.ts @@ -141,7 +141,6 @@ describe('toGatewaySpec – authorizer type mapping', () => { it('missing authorizerType: defaults to NONE', () => { const gw = makeGateway(); // Simulate undefined authorizerType by deleting after construction - // eslint-disable-next-line @typescript-eslint/no-explicit-any delete (gw as any).authorizerType; const result = toGatewaySpec(gw, emptyTargets, 'my_gw'); diff --git a/src/cli/commands/import/__tests__/import-gateway-targets.test.ts b/src/cli/commands/import/__tests__/import-gateway-targets.test.ts index 3624ce545..b2eed2b32 100644 --- a/src/cli/commands/import/__tests__/import-gateway-targets.test.ts +++ b/src/cli/commands/import/__tests__/import-gateway-targets.test.ts @@ -52,7 +52,6 @@ describe('toGatewayTargetSpec — apiGateway', () => { expect(result!.name).toBe('test_target'); expect(result!.targetType).toBe('apiGateway'); - // eslint-disable-next-line @typescript-eslint/no-explicit-any const apigw = (result as any).apiGateway; expect(apigw.restApiId).toBe('abc123'); expect(apigw.stage).toBe('prod'); @@ -84,7 +83,6 @@ describe('toGatewayTargetSpec — apiGateway', () => { const onProgress = vi.fn(); const result = toGatewayTargetSpec(detail, new Map(), onProgress); - // eslint-disable-next-line @typescript-eslint/no-explicit-any const apigw = (result as any).apiGateway; expect(apigw.apiGatewayToolConfiguration.toolOverrides).toEqual([ { name: 'listPets', path: '/pets', method: 'GET', description: 'List all pets' }, @@ -110,7 +108,6 @@ describe('toGatewayTargetSpec — apiGateway', () => { const onProgress = vi.fn(); const result = toGatewayTargetSpec(detail, new Map(), onProgress); - // eslint-disable-next-line @typescript-eslint/no-explicit-any const apigw = (result as any).apiGateway; expect(apigw.apiGatewayToolConfiguration.toolOverrides).toBeUndefined(); }); @@ -176,7 +173,6 @@ describe('toGatewayTargetSpec — openApiSchema', () => { expect(result!.name).toBe('test_target'); expect(result!.targetType).toBe('openApiSchema'); - // eslint-disable-next-line @typescript-eslint/no-explicit-any const schemaSource = (result as any).schemaSource; expect(schemaSource.s3.uri).toBe('s3://my-bucket/schema.yaml'); expect(schemaSource.s3.bucketOwnerAccountId).toBe('123456789012'); @@ -222,7 +218,6 @@ describe('toGatewayTargetSpec — smithyModel', () => { expect(result!.name).toBe('test_target'); expect(result!.targetType).toBe('smithyModel'); - // eslint-disable-next-line @typescript-eslint/no-explicit-any const schemaSource = (result as any).schemaSource; expect(schemaSource.s3.uri).toBe('s3://models-bucket/model.json'); expect(schemaSource.s3.bucketOwnerAccountId).toBeUndefined(); @@ -269,7 +264,6 @@ describe('toGatewayTargetSpec — lambda', () => { expect(result!.name).toBe('test_target'); expect(result!.targetType).toBe('lambdaFunctionArn'); - // eslint-disable-next-line @typescript-eslint/no-explicit-any const lambdaConfig = (result as any).lambdaFunctionArn; expect(lambdaConfig.lambdaArn).toBe('arn:aws:lambda:us-west-2:123456789012:function:my-func'); expect(lambdaConfig.toolSchemaFile).toBe('s3://schemas/tools.json'); diff --git a/src/cli/commands/import/import-runtime.ts b/src/cli/commands/import/import-runtime.ts index b1921d546..25b8fc077 100644 --- a/src/cli/commands/import/import-runtime.ts +++ b/src/cli/commands/import/import-runtime.ts @@ -57,7 +57,7 @@ function toAgentEnvSpec( spec.authorizerType = runtime.authorizerType as AgentEnvSpec['authorizerType']; } if (runtime.authorizerConfiguration) { - spec.authorizerConfiguration = runtime.authorizerConfiguration as AgentEnvSpec['authorizerConfiguration']; + spec.authorizerConfiguration = runtime.authorizerConfiguration; } if (runtime.environmentVariables && Object.keys(runtime.environmentVariables).length > 0) { diff --git a/src/cli/commands/import/yaml-parser.ts b/src/cli/commands/import/yaml-parser.ts index 3002416d7..f9e41acb6 100644 --- a/src/cli/commands/import/yaml-parser.ts +++ b/src/cli/commands/import/yaml-parser.ts @@ -1,4 +1,4 @@ -import type { AuthorizerConfig, CustomClaimValidation, RuntimeAuthorizerType } from '../../../schema'; +import type { AuthorizerConfig, CustomClaimValidation } from '../../../schema'; import { ProtocolModeSchema } from '../../../schema'; import { RUNTIME_TYPE_MAP } from './constants'; import type { @@ -149,7 +149,7 @@ function extractAuthorizerConfig( }; return { - authorizerType: 'CUSTOM_JWT' as RuntimeAuthorizerType, + authorizerType: 'CUSTOM_JWT', authorizerConfiguration: { customJwtAuthorizer }, }; } @@ -210,9 +210,7 @@ export function parseStarterToolkitYaml(filePath: string): ParsedStarterToolkitC build, runtimeVersion, language: (agentConfig.language as 'python' | 'typescript') ?? 'python', - sourcePath: agentConfig.source_path - ? path.resolve(yamlDir, String(agentConfig.source_path as string)) - : undefined, + sourcePath: agentConfig.source_path ? path.resolve(yamlDir, agentConfig.source_path as string) : undefined, networkMode, networkConfig: networkMode === 'VPC' && networkModeConfig diff --git a/src/cli/logging/invoke-logger.ts b/src/cli/logging/invoke-logger.ts index 97928f983..2ff959713 100644 --- a/src/cli/logging/invoke-logger.ts +++ b/src/cli/logging/invoke-logger.ts @@ -241,7 +241,9 @@ ${separator} } else if (value === null || value === undefined) { stringValue = ''; } else { - stringValue = String(value as string | number | boolean); + // value is a primitive here (object/null/undefined handled above) + // eslint-disable-next-line @typescript-eslint/no-base-to-string, @typescript-eslint/restrict-template-expressions + stringValue = `${value}`; } this.appendLine(`[${timestamp}] ERROR.${key}: ${stringValue}`); if (responseLog.error?.metadata) { diff --git a/src/cli/operations/agent/import/langgraph-translator.ts b/src/cli/operations/agent/import/langgraph-translator.ts index 89436e92a..24c8e5b05 100644 --- a/src/cli/operations/agent/import/langgraph-translator.ts +++ b/src/cli/operations/agent/import/langgraph-translator.ts @@ -166,7 +166,7 @@ retriever_tool_${kbName} = retriever_${kbName}.as_tool(name="kb_${kbName}", desc const fileName = `langchain_collaborator_${collabName}`; // Recursively translate collaborator - const collabTranslator = new LangGraphTranslator(collaborator as unknown as BedrockAgentConfig, this.options, { + const collabTranslator = new LangGraphTranslator(collaborator, this.options, { name: collabName, instruction: collaborator.collaborationInstruction ?? '', relayHistory: collaborator.relayConversationHistory ?? 'DISABLED', diff --git a/src/cli/operations/agent/import/strands-translator.ts b/src/cli/operations/agent/import/strands-translator.ts index fff4a5274..ccea17932 100644 --- a/src/cli/operations/agent/import/strands-translator.ts +++ b/src/cli/operations/agent/import/strands-translator.ts @@ -143,7 +143,7 @@ def retrieve_${kbName}(query: str): const fileName = `strands_collaborator_${collabName}`; // Recursively translate collaborator - const collabTranslator = new StrandsTranslator(collaborator as unknown as BedrockAgentConfig, this.options, { + const collabTranslator = new StrandsTranslator(collaborator, this.options, { name: collabName, instruction: collaborator.collaborationInstruction ?? '', relayHistory: collaborator.relayConversationHistory ?? 'DISABLED', diff --git a/src/cli/operations/deploy/__tests__/post-deploy-ab-tests.test.ts b/src/cli/operations/deploy/__tests__/post-deploy-ab-tests.test.ts index 5e30115c0..93df632a0 100644 --- a/src/cli/operations/deploy/__tests__/post-deploy-ab-tests.test.ts +++ b/src/cli/operations/deploy/__tests__/post-deploy-ab-tests.test.ts @@ -272,7 +272,7 @@ describe('setupABTests', () => { gatewayArn: 'arn:aws:bedrock-agentcore:us-east-1:123:httpgateway/httpgw-001', }, }, - } as unknown as DeployedResourceState, + }, }); expect(mockCreateABTest.mock.calls[0]![0].gatewayArn).toBe( diff --git a/src/cli/operations/deploy/__tests__/post-deploy-config-bundles.test.ts b/src/cli/operations/deploy/__tests__/post-deploy-config-bundles.test.ts index 34be18b88..52347776f 100644 --- a/src/cli/operations/deploy/__tests__/post-deploy-config-bundles.test.ts +++ b/src/cli/operations/deploy/__tests__/post-deploy-config-bundles.test.ts @@ -516,14 +516,14 @@ describe('resolveConfigBundleComponentKeys', () => { targets: { [targetName]: { resources }, }, - } as unknown as DeployedState; + }; } it('returns projectSpec unchanged when target has no resources', () => { const spec = makeFullProjectSpec([ { name: 'b1', components: { '{{runtime:my-rt}}': { configuration: { k: 'v' } } } } as any, ]); - const deployedState = { targets: {} } as unknown as DeployedState; + const deployedState = { targets: {} }; const result = resolveConfigBundleComponentKeys(spec, deployedState, 'missing-target'); expect(result).toBe(spec); // same reference — no transformation diff --git a/src/cli/operations/deploy/__tests__/teardown-utils.test.ts b/src/cli/operations/deploy/__tests__/teardown-utils.test.ts index 911487463..6949ad0de 100644 --- a/src/cli/operations/deploy/__tests__/teardown-utils.test.ts +++ b/src/cli/operations/deploy/__tests__/teardown-utils.test.ts @@ -116,11 +116,10 @@ describe('discoverDeployedTargets', () => { describe('destroyTarget', () => { afterEach(() => vi.clearAllMocks()); - const makeTarget = (name: string, stackName: string): DeployedTarget => - ({ - target: { name, account: '123456789012', region: 'us-east-1' }, - stack: { stackName, stackArn: `arn:aws:cf:us-east-1:123:stack/${stackName}/id`, targetName: name }, - }) as DeployedTarget; + const makeTarget = (name: string, stackName: string): DeployedTarget => ({ + target: { name, account: '123456789012', region: 'us-east-1' }, + stack: { stackName, stackArn: `arn:aws:cf:us-east-1:123:stack/${stackName}/id`, targetName: name }, + }); it('throws when CDK project dir does not exist', async () => { mockExistsSync.mockReturnValue(false); diff --git a/src/cli/operations/deploy/imperative/deployers/harness-mapper.ts b/src/cli/operations/deploy/imperative/deployers/harness-mapper.ts index e1321914d..71f61e8bc 100644 --- a/src/cli/operations/deploy/imperative/deployers/harness-mapper.ts +++ b/src/cli/operations/deploy/imperative/deployers/harness-mapper.ts @@ -249,7 +249,7 @@ function mapTools(tools: HarnessSpec['tools']): HarnessTool[] { return tools.map(tool => ({ type: tool.type, name: tool.name, - ...(tool.config && { config: tool.config as unknown as Record }), + ...(tool.config && { config: tool.config }), })); } diff --git a/src/cli/operations/deploy/post-deploy-ab-tests.ts b/src/cli/operations/deploy/post-deploy-ab-tests.ts index 9c5481d93..ad4154509 100644 --- a/src/cli/operations/deploy/post-deploy-ab-tests.ts +++ b/src/cli/operations/deploy/post-deploy-ab-tests.ts @@ -184,7 +184,7 @@ export async function setupABTests(options: SetupABTestsOptions): Promise = {}): RouteContext agentErrors: new Map(), setCorsHeaders: vi.fn(), readBody: vi.fn(), - } as RouteContext; + }; } describe('handleListCloudWatchTraces', () => { diff --git a/src/cli/operations/dev/web-ui/__tests__/harness-invocation.test.ts b/src/cli/operations/dev/web-ui/__tests__/harness-invocation.test.ts index 98d537d53..f0a4f72af 100644 --- a/src/cli/operations/dev/web-ui/__tests__/harness-invocation.test.ts +++ b/src/cli/operations/dev/web-ui/__tests__/harness-invocation.test.ts @@ -60,14 +60,14 @@ function mockCtx(overrides: Partial = {}): RouteContext { }, ], uiPort: 8081, - } as RouteContext['options'], + }, runningAgents: new Map(), startingAgents: new Map(), agentErrors: new Map(), setCorsHeaders: vi.fn(), readBody: vi.fn(), ...overrides, - } as unknown as RouteContext; + }; } async function* fakeStream(events: HarnessStreamEvent[]): AsyncGenerator { diff --git a/src/cli/operations/dev/web-ui/__tests__/harness-tool-response.test.ts b/src/cli/operations/dev/web-ui/__tests__/harness-tool-response.test.ts index 028806fcd..3a1234f05 100644 --- a/src/cli/operations/dev/web-ui/__tests__/harness-tool-response.test.ts +++ b/src/cli/operations/dev/web-ui/__tests__/harness-tool-response.test.ts @@ -64,14 +64,14 @@ function mockCtx(overrides: Partial = {}): RouteContext { }, ], uiPort: 8081, - } as RouteContext['options'], + }, runningAgents: new Map(), startingAgents: new Map(), agentErrors: new Map(), setCorsHeaders: vi.fn(), readBody: vi.fn(), ...overrides, - } as unknown as RouteContext; + }; } async function* fakeStream(events: HarnessStreamEvent[]): AsyncGenerator { diff --git a/src/cli/operations/dev/web-ui/__tests__/mcp-proxy.test.ts b/src/cli/operations/dev/web-ui/__tests__/mcp-proxy.test.ts index c2dcfc615..2cd813c56 100644 --- a/src/cli/operations/dev/web-ui/__tests__/mcp-proxy.test.ts +++ b/src/cli/operations/dev/web-ui/__tests__/mcp-proxy.test.ts @@ -36,7 +36,7 @@ function mockCtx(overrides: Partial = {}): RouteContext { setCorsHeaders: vi.fn(), readBody: vi.fn(), ...overrides, - } as unknown as RouteContext; + }; } describe('handleMcpProxy', () => { diff --git a/src/cli/operations/dev/web-ui/__tests__/resolve-ui-dist-dir.test.ts b/src/cli/operations/dev/web-ui/__tests__/resolve-ui-dist-dir.test.ts index 6308a1f24..200f59f78 100644 --- a/src/cli/operations/dev/web-ui/__tests__/resolve-ui-dist-dir.test.ts +++ b/src/cli/operations/dev/web-ui/__tests__/resolve-ui-dist-dir.test.ts @@ -1,6 +1,5 @@ import { resolveUIDistDir } from '../web-server.js'; -import fs from 'node:fs'; -import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import fs, { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; diff --git a/src/cli/operations/dev/web-ui/__tests__/status.test.ts b/src/cli/operations/dev/web-ui/__tests__/status.test.ts index 81e019a5b..1ecd2ff4e 100644 --- a/src/cli/operations/dev/web-ui/__tests__/status.test.ts +++ b/src/cli/operations/dev/web-ui/__tests__/status.test.ts @@ -30,14 +30,14 @@ function mockCtx(overrides: Partial = {}): RouteContext { agents: [], harnesses: [], uiPort: 8081, - } as RouteContext['options'], + }, runningAgents: new Map(), startingAgents: new Map(), agentErrors: new Map(), setCorsHeaders: vi.fn(), readBody: vi.fn(), ...overrides, - } as unknown as RouteContext; + }; } describe('handleStatus', () => { @@ -68,7 +68,7 @@ describe('handleStatus', () => { }, ], uiPort: 8081, - } as RouteContext['options'], + }, }); const res = mockRes(); @@ -94,7 +94,7 @@ describe('handleStatus', () => { { name: 'harness-2', harnessArn: 'arn:2', region: 'us-west-2' }, ], uiPort: 8081, - } as RouteContext['options'], + }, runningAgents: agents, agentErrors, }); diff --git a/src/cli/operations/dev/web-ui/handlers/resources.ts b/src/cli/operations/dev/web-ui/handlers/resources.ts index a65ac3e21..73eae009e 100644 --- a/src/cli/operations/dev/web-ui/handlers/resources.ts +++ b/src/cli/operations/dev/web-ui/handlers/resources.ts @@ -97,7 +97,7 @@ export async function handleResources(ctx: RouteContext, res: ServerResponse, or networkMode: '', protocol: '', envVars: [], - deploymentStatus: 'pending-removal' as ResourceDeploymentStatus, + deploymentStatus: 'pending-removal', deployed, invocationUrl: deployed.runtimeArn && targetRegion @@ -137,7 +137,7 @@ export async function handleResources(ctx: RouteContext, res: ServerResponse, or name, model: '', tools: [], - deploymentStatus: 'pending-removal' as ResourceDeploymentStatus, + deploymentStatus: 'pending-removal', deployed: { harnessId: deployed.harnessId, harnessArn: deployed.harnessArn }, }); } @@ -163,7 +163,7 @@ export async function handleResources(ctx: RouteContext, res: ServerResponse, or name, strategies: [], expiryDays: undefined, - deploymentStatus: 'pending-removal' as ResourceDeploymentStatus, + deploymentStatus: 'pending-removal', deployed, }); } @@ -184,7 +184,7 @@ export async function handleResources(ctx: RouteContext, res: ServerResponse, or credentials.push({ name, type: '', - deploymentStatus: 'pending-removal' as ResourceDeploymentStatus, + deploymentStatus: 'pending-removal', deployed, }); } @@ -208,7 +208,7 @@ export async function handleResources(ctx: RouteContext, res: ServerResponse, or gateways.push({ name, targets: [], - deploymentStatus: 'pending-removal' as ResourceDeploymentStatus, + deploymentStatus: 'pending-removal', deployed, }); } @@ -238,7 +238,7 @@ export async function handleResources(ctx: RouteContext, res: ServerResponse, or level: '', description: undefined, configType: 'llm-as-a-judge' as const, - deploymentStatus: 'pending-removal' as ResourceDeploymentStatus, + deploymentStatus: 'pending-removal', deployed, }); } @@ -265,7 +265,7 @@ export async function handleResources(ctx: RouteContext, res: ServerResponse, or evaluators: [], samplingRate: 0, description: undefined, - deploymentStatus: 'pending-removal' as ResourceDeploymentStatus, + deploymentStatus: 'pending-removal', deployed, }); } @@ -293,7 +293,7 @@ export async function handleResources(ctx: RouteContext, res: ServerResponse, or name, description: undefined, policies: [], - deploymentStatus: 'pending-removal' as ResourceDeploymentStatus, + deploymentStatus: 'pending-removal', deployed, }); } diff --git a/src/cli/operations/eval/__tests__/run-eval.test.ts b/src/cli/operations/eval/__tests__/run-eval.test.ts index 39314af69..780918a19 100644 --- a/src/cli/operations/eval/__tests__/run-eval.test.ts +++ b/src/cli/operations/eval/__tests__/run-eval.test.ts @@ -57,11 +57,7 @@ vi.mock('@aws-sdk/client-cloudwatch-logs', () => ({ // ─── Helpers ────────────────────────────────────────────────────────────────── -function makeDeployedContext({ - agentName = 'my-agent', - runtimeId = 'rt-123', - evaluators = {} as Record, -} = {}) { +function makeDeployedContext({ agentName = 'my-agent', runtimeId = 'rt-123', evaluators = {} } = {}) { return { project: { runtimes: [{ name: agentName }], diff --git a/src/cli/operations/eval/run-eval.ts b/src/cli/operations/eval/run-eval.ts index 90cd519c7..03863d1cc 100644 --- a/src/cli/operations/eval/run-eval.ts +++ b/src/cli/operations/eval/run-eval.ts @@ -208,7 +208,7 @@ async function resolveEvaluatorLevels(evaluatorIds: string[], region: string): P // Custom evaluator — fetch level from API try { const evaluator = await getEvaluator({ region, evaluatorId: id }); - levels.set(id, (evaluator.level as EvaluatorLevel) ?? 'SESSION'); + levels.set(id, evaluator.level ?? 'SESSION'); } catch { // If we can't determine the level, default to SESSION (most permissive) levels.set(id, 'SESSION'); diff --git a/src/cli/operations/identity/__tests__/credential-ops.test.ts b/src/cli/operations/identity/__tests__/credential-ops.test.ts index 32568765b..81ba2383b 100644 --- a/src/cli/operations/identity/__tests__/credential-ops.test.ts +++ b/src/cli/operations/identity/__tests__/credential-ops.test.ts @@ -86,14 +86,7 @@ describe('resolveCredentialStrategy', () => { }); it('returns no credential when no API key', async () => { - const result = await primitive.resolveCredentialStrategy( - 'Proj', - 'Agent', - 'Anthropic' as any, - undefined, - '/base', - [] - ); + const result = await primitive.resolveCredentialStrategy('Proj', 'Agent', 'Anthropic', undefined, '/base', []); expect(result.credentialName).toBe(''); }); @@ -104,7 +97,7 @@ describe('resolveCredentialStrategy', () => { const result = await primitive.resolveCredentialStrategy( 'Proj', 'Agent', - 'Anthropic' as any, + 'Anthropic', 'my-api-key', '/base', creds @@ -115,14 +108,7 @@ describe('resolveCredentialStrategy', () => { }); it('creates project-scoped credential when no existing', async () => { - const result = await primitive.resolveCredentialStrategy( - 'Proj', - 'Agent', - 'Anthropic' as any, - 'new-key', - '/base', - [] - ); + const result = await primitive.resolveCredentialStrategy('Proj', 'Agent', 'Anthropic', 'new-key', '/base', []); expect(result.reuse).toBe(false); expect(result.credentialName).toBe('ProjAnthropic'); @@ -133,14 +119,7 @@ describe('resolveCredentialStrategy', () => { mockGetEnvVar.mockResolvedValue('different-key'); const creds = [{ name: 'ProjAnthropic', authorizerType: 'ApiKeyCredentialProvider' as const }]; - const result = await primitive.resolveCredentialStrategy( - 'Proj', - 'Agent', - 'Anthropic' as any, - 'new-key', - '/base', - creds - ); + const result = await primitive.resolveCredentialStrategy('Proj', 'Agent', 'Anthropic', 'new-key', '/base', creds); expect(result.reuse).toBe(false); expect(result.credentialName).toBe('ProjAgentAnthropic'); diff --git a/src/cli/operations/recommendation/apply-to-bundle.ts b/src/cli/operations/recommendation/apply-to-bundle.ts index bf9060d10..7be7e6cec 100644 --- a/src/cli/operations/recommendation/apply-to-bundle.ts +++ b/src/cli/operations/recommendation/apply-to-bundle.ts @@ -112,7 +112,7 @@ export async function applyRecommendationToBundle( } // Update local bundle components to match the server's new version - bundle.components = newVersion.components as typeof bundle.components; + bundle.components = newVersion.components; // Update commit message from lineage metadata if available if (newVersion.lineageMetadata?.commitMessage) { diff --git a/src/cli/tui/components/__tests__/ResourceGraph.test.tsx b/src/cli/tui/components/__tests__/ResourceGraph.test.tsx index b6eb34dfa..bd8788a1e 100644 --- a/src/cli/tui/components/__tests__/ResourceGraph.test.tsx +++ b/src/cli/tui/components/__tests__/ResourceGraph.test.tsx @@ -201,7 +201,7 @@ describe('ResourceGraph', () => { const mcp: AgentCoreMcpSpec = { agentCoreGateways: [], unassignedTargets: [], - } as unknown as AgentCoreMcpSpec; + }; const { lastFrame } = render(); diff --git a/src/cli/tui/hooks/__tests__/usePanelNavigation.test.tsx b/src/cli/tui/hooks/__tests__/usePanelNavigation.test.tsx index 89182b2e5..a140c6956 100644 --- a/src/cli/tui/hooks/__tests__/usePanelNavigation.test.tsx +++ b/src/cli/tui/hooks/__tests__/usePanelNavigation.test.tsx @@ -212,6 +212,7 @@ describe('usePanelNavigation', () => { if (nav.position.layer === 'active') { nav.deactivate(); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [nav.position.layer, nav.position.column, nav.position.field, nav.deactivate]); return ( diff --git a/src/cli/tui/hooks/useCdkPreflight.ts b/src/cli/tui/hooks/useCdkPreflight.ts index 062da752f..496515eb4 100644 --- a/src/cli/tui/hooks/useCdkPreflight.ts +++ b/src/cli/tui/hooks/useCdkPreflight.ts @@ -770,7 +770,7 @@ export function useCdkPreflight(options: PreflightOptions): PreflightResult { setAllCredentials(deployedCredentials); const configIO = new ConfigIO(); const target = context.awsTargets[0]; - const existingState = await configIO.readDeployedState().catch(() => ({ targets: {} }) as DeployedState); + const existingState = await configIO.readDeployedState().catch((): DeployedState => ({ targets: {} })); const targetState = existingState.targets?.[target!.name] ?? { resources: {} }; targetState.resources ??= {}; targetState.resources.credentials = deployedCredentials; diff --git a/src/cli/tui/hooks/useDevDeploy.ts b/src/cli/tui/hooks/useDevDeploy.ts index d4dfaca09..e081a4eec 100644 --- a/src/cli/tui/hooks/useDevDeploy.ts +++ b/src/cli/tui/hooks/useDevDeploy.ts @@ -4,7 +4,7 @@ import type { DeployMessage } from '../../cdk/toolkit-lib'; import { handleDeploy } from '../../commands/deploy/actions'; import { getErrorMessage } from '../../errors'; import { canSkipDeploy } from '../../operations/deploy/change-detection'; -import type { Step, StepStatus } from '../components/StepProgress'; +import type { Step } from '../components/StepProgress'; import { useCallback, useEffect, useRef, useState } from 'react'; export interface UseDevDeployOptions { @@ -31,9 +31,9 @@ export function useDevDeploy({ skip, ready = true }: UseDevDeployOptions = {}): const onProgress = useCallback((stepName: string, status: 'start' | 'success' | 'error') => { setSteps(prev => { if (status === 'start') { - return [...prev, { label: stepName, status: 'running' as StepStatus }]; + return [...prev, { label: stepName, status: 'running' }]; } - return prev.map(s => (s.label === stepName ? { ...s, status: status as StepStatus } : s)); + return prev.map(s => (s.label === stepName ? { ...s, status: status } : s)); }); }, []); diff --git a/src/cli/tui/screens/ab-test/AddABTestScreen.tsx b/src/cli/tui/screens/ab-test/AddABTestScreen.tsx index 3306ce86c..b70f48aed 100644 --- a/src/cli/tui/screens/ab-test/AddABTestScreen.tsx +++ b/src/cli/tui/screens/ab-test/AddABTestScreen.tsx @@ -235,7 +235,8 @@ export function AddABTestScreen({ useEffect(() => { wizard.setSkipCheck(shouldSkipStep); - }, [shouldSkipStep]); // wizard.setSkipCheck is stable (useCallback with no deps) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [shouldSkipStep, wizard.setSkipCheck]); // Mode selection items const modeItems: SelectableItem[] = useMemo( diff --git a/src/cli/tui/screens/ab-test/TargetBasedABTestScreen.tsx b/src/cli/tui/screens/ab-test/TargetBasedABTestScreen.tsx index 60b92dd45..cca390698 100644 --- a/src/cli/tui/screens/ab-test/TargetBasedABTestScreen.tsx +++ b/src/cli/tui/screens/ab-test/TargetBasedABTestScreen.tsx @@ -354,12 +354,14 @@ export function TargetBasedABTestScreen({ if (wizard.config.controlTargetInfo && controlEvalItems.length === 1 && !wizard.config.controlOnlineEval) { wizard.setControlEval(controlEvalItems[0]!.id); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [wizard.config.controlTargetInfo, controlEvalItems, wizard.config.controlOnlineEval, wizard.setControlEval]); useEffect(() => { if (wizard.config.treatmentTargetInfo && treatmentEvalItems.length === 1 && !wizard.config.treatmentOnlineEval) { wizard.setTreatmentEval(treatmentEvalItems[0]!.id); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [ wizard.config.treatmentTargetInfo, treatmentEvalItems, diff --git a/src/cli/tui/screens/agent/AddAgentScreen.tsx b/src/cli/tui/screens/agent/AddAgentScreen.tsx index 5072e8ccb..5c4f00468 100644 --- a/src/cli/tui/screens/agent/AddAgentScreen.tsx +++ b/src/cli/tui/screens/agent/AddAgentScreen.tsx @@ -175,16 +175,16 @@ export function AddAgentScreen({ existingAgentNames, onComplete, onExit }: AddAg codeLocation: '', entrypoint: DEFAULT_ENTRYPOINT, buildType: 'CodeZip' as BuildType, - dockerfile: '' as string, + dockerfile: '', modelProvider: 'Bedrock' as ModelProvider, apiKey: undefined as string | undefined, networkMode: 'PUBLIC' as NetworkMode, - subnets: '' as string, - securityGroups: '' as string, - requestHeaderAllowlist: '' as string, - idleTimeout: '' as string, - maxLifetime: '' as string, - sessionStorageMountPath: '' as string, + subnets: '', + securityGroups: '', + requestHeaderAllowlist: '', + idleTimeout: '', + maxLifetime: '', + sessionStorageMountPath: '', withConfigBundle: undefined as boolean | undefined, }); const [byoAdvancedSettings, setByoAdvancedSettings] = useState>(new Set()); @@ -334,7 +334,6 @@ export function AddAgentScreen({ existingAgentNames, onComplete, onExit }: AddAg // ───────────────────────────────────────────────────────────────────────────── // BYO steps filtering (apiKey for Bedrock, advanced sub-steps based on multi-select, jwtConfig for CUSTOM_JWT) - const byoAdvancedActive = byoAdvancedSettings.size > 0; const byoSteps = useMemo( () => computeByoSteps({ @@ -344,14 +343,7 @@ export function AddAgentScreen({ existingAgentNames, onComplete, onExit }: AddAg authorizerType: byoAuthorizerType, advancedSettings: byoAdvancedSettings, }), - [ - byoConfig.buildType, - byoConfig.modelProvider, - byoConfig.networkMode, - byoAdvancedActive, - byoAdvancedSettings, - byoAuthorizerType, - ] + [byoConfig.buildType, byoConfig.modelProvider, byoConfig.networkMode, byoAdvancedSettings, byoAuthorizerType] ); const byoCurrentIndex = byoSteps.indexOf(byoStep); @@ -490,7 +482,7 @@ export function AddAgentScreen({ existingAgentNames, onComplete, onExit }: AddAg setByoConfig(c => ({ ...c, dockerfile: '', - networkMode: 'PUBLIC' as NetworkMode, + networkMode: 'PUBLIC', subnets: '', securityGroups: '', requestHeaderAllowlist: '', diff --git a/src/cli/tui/screens/config-bundle-hub/VersionHistoryScreen.tsx b/src/cli/tui/screens/config-bundle-hub/VersionHistoryScreen.tsx index 56e161c85..b35038cce 100644 --- a/src/cli/tui/screens/config-bundle-hub/VersionHistoryScreen.tsx +++ b/src/cli/tui/screens/config-bundle-hub/VersionHistoryScreen.tsx @@ -8,7 +8,7 @@ import { Panel, Screen } from '../../components'; import type { BundleWithMeta } from './useConfigBundleHub'; import { useVersionHistory } from './useConfigBundleHub'; import { Box, Text, useInput } from 'ink'; -import React, { useMemo, useState } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; function formatTimestamp(epochSeconds: string): string { const num = Number(epochSeconds); @@ -49,6 +49,42 @@ export function VersionHistoryScreen({ bundle, region, onViewDiff, onExit }: Ver return map; }, [versions]); + const loadDetail = useCallback( + async (versionId: string) => { + try { + const detail = await getConfigurationBundleVersion({ + region, + bundleId: bundle.bundleId, + versionId, + }); + const lines: string[] = []; + lines.push(`Version: ${detail.versionId}`); + if (detail.description) lines.push(`Description: ${detail.description}`); + if (detail.lineageMetadata?.branchName) lines.push(`Branch: ${detail.lineageMetadata.branchName}`); + if (detail.lineageMetadata?.commitMessage) lines.push(`Message: ${detail.lineageMetadata.commitMessage}`); + if (detail.lineageMetadata?.createdBy) { + const cb = detail.lineageMetadata.createdBy; + lines.push(`Created by: ${cb.name}${cb.arn ? ` (${cb.arn})` : ''}`); + } + if (detail.lineageMetadata?.parentVersionIds?.length) { + lines.push(`Parent: ${detail.lineageMetadata.parentVersionIds.map(id => id).join(', ')}`); + } + lines.push(`Created: ${formatTimestamp(detail.versionCreatedAt)}`); + lines.push(''); + lines.push('Components:'); + for (const [arn, comp] of Object.entries(detail.components)) { + lines.push(` ${arn}`); + lines.push(` ${JSON.stringify(comp.configuration, null, 2).split('\n').join('\n ')}`); + lines.push(''); + } + setDetailText(lines.join('\n')); + } catch (err) { + setDetailText(`Error loading version: ${err instanceof Error ? err.message : String(err)}`); + } + }, + [region, bundle.bundleId] + ); + useInput( (input, key) => { if (isLoading || flatVersions.length === 0) return; @@ -109,39 +145,6 @@ export function VersionHistoryScreen({ bundle, region, onViewDiff, onExit }: Ver { isActive: !isLoading } ); - async function loadDetail(versionId: string) { - try { - const detail = await getConfigurationBundleVersion({ - region, - bundleId: bundle.bundleId, - versionId, - }); - const lines: string[] = []; - lines.push(`Version: ${detail.versionId}`); - if (detail.description) lines.push(`Description: ${detail.description}`); - if (detail.lineageMetadata?.branchName) lines.push(`Branch: ${detail.lineageMetadata.branchName}`); - if (detail.lineageMetadata?.commitMessage) lines.push(`Message: ${detail.lineageMetadata.commitMessage}`); - if (detail.lineageMetadata?.createdBy) { - const cb = detail.lineageMetadata.createdBy; - lines.push(`Created by: ${cb.name}${cb.arn ? ` (${cb.arn})` : ''}`); - } - if (detail.lineageMetadata?.parentVersionIds?.length) { - lines.push(`Parent: ${detail.lineageMetadata.parentVersionIds.map(id => id).join(', ')}`); - } - lines.push(`Created: ${formatTimestamp(detail.versionCreatedAt)}`); - lines.push(''); - lines.push('Components:'); - for (const [arn, comp] of Object.entries(detail.components)) { - lines.push(` ${arn}`); - lines.push(` ${JSON.stringify(comp.configuration, null, 2).split('\n').join('\n ')}`); - lines.push(''); - } - setDetailText(lines.join('\n')); - } catch (err) { - setDetailText(`Error loading version: ${err instanceof Error ? err.message : String(err)}`); - } - } - if (isLoading) { return ( diff --git a/src/cli/tui/screens/deploy/useDeployFlow.ts b/src/cli/tui/screens/deploy/useDeployFlow.ts index c57d5adfa..0628e014d 100644 --- a/src/cli/tui/screens/deploy/useDeployFlow.ts +++ b/src/cli/tui/screens/deploy/useDeployFlow.ts @@ -806,9 +806,7 @@ export function useDeployFlow(options: DeployFlowOptions = {}): DeployFlowState shouldStartDeploy, persistDeployedState, switchableIoHost, - context?.isTeardownDeploy, - context?.awsTargets, - context?.projectSpec.runtimes, + context, diffMode, ]); @@ -878,6 +876,7 @@ export function useDeployFlow(options: DeployFlowOptions = {}): DeployFlowState skipPreflight, shouldStartDeploy, switchableIoHost, + context, ]); // Finalize logger and dispose toolkit when preflight fails diff --git a/src/cli/tui/screens/home/HelpScreen.tsx b/src/cli/tui/screens/home/HelpScreen.tsx index e9f3c23be..6e0a3aae4 100644 --- a/src/cli/tui/screens/home/HelpScreen.tsx +++ b/src/cli/tui/screens/home/HelpScreen.tsx @@ -3,7 +3,7 @@ import { HINTS } from '../../copy'; import { useTextInput } from '../../hooks'; import type { CommandMeta } from '../../utils/commands'; import { Box, Text, useInput, useStdout } from 'ink'; -import React, { useEffect, useMemo, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; function truncateDescription(desc: string, maxLen: number): string { if (desc.length <= maxLen) return desc; @@ -208,25 +208,28 @@ export function HelpScreen(props: { excludeChars: ['/'], }); - function filterCommand(cmd: CommandMeta): DisplayItem[] { - if (cmd.disabled) return []; - if (!query) return [{ command: cmd }]; + const filterCommand = useCallback( + (cmd: CommandMeta): DisplayItem[] => { + if (cmd.disabled) return []; + if (!query) return [{ command: cmd }]; - const q = query.toLowerCase(); - const matchesCommand = cmd.id.toLowerCase().includes(q); - const matchingSubcommands = cmd.subcommands.filter(sub => sub.toLowerCase().includes(q)); + const q = query.toLowerCase(); + const matchesCommand = cmd.id.toLowerCase().includes(q); + const matchingSubcommands = cmd.subcommands.filter(sub => sub.toLowerCase().includes(q)); - const results: DisplayItem[] = []; - if (matchesCommand) { - results.push({ command: cmd }); - } - for (const sub of matchingSubcommands) { - if (!matchesCommand) { - results.push({ command: cmd, matchedSubcommand: sub }); + const results: DisplayItem[] = []; + if (matchesCommand) { + results.push({ command: cmd }); } - } - return results; - } + for (const sub of matchingSubcommands) { + if (!matchesCommand) { + results.push({ command: cmd, matchedSubcommand: sub }); + } + } + return results; + }, + [query] + ); const interactiveItems = useMemo((): DisplayItem[] => { return commands.filter(cmd => !cmd.cliOnly).flatMap(filterCommand); diff --git a/src/cli/tui/screens/mcp/AddGatewayTargetScreen.tsx b/src/cli/tui/screens/mcp/AddGatewayTargetScreen.tsx index fa022b4f7..cb9ba8269 100644 --- a/src/cli/tui/screens/mcp/AddGatewayTargetScreen.tsx +++ b/src/cli/tui/screens/mcp/AddGatewayTargetScreen.tsx @@ -10,7 +10,6 @@ import type { AddGatewayTargetStep, ApiGatewayTargetConfig, GatewayTargetWizardState, - SchemaBasedTargetConfig, } from './types'; import { API_GATEWAY_AUTH_OPTIONS, MCP_TOOL_STEP_LABELS, TARGET_TYPE_OPTIONS, getOutboundAuthOptions } from './types'; import { useAddGatewayTargetWizard } from './useAddGatewayTargetWizard'; @@ -236,7 +235,7 @@ export function AddGatewayTargetScreen({ name: c.name, gateway: c.gateway!, schemaSource: c.schemaSource!, - outboundAuth: c.outboundAuth as SchemaBasedTargetConfig['outboundAuth'], + outboundAuth: c.outboundAuth, }); } else if (c.targetType === 'lambdaFunctionArn') { onComplete({ diff --git a/src/cli/tui/screens/online-eval/AddOnlineEvalScreen.tsx b/src/cli/tui/screens/online-eval/AddOnlineEvalScreen.tsx index fd5fafcf6..b164463b9 100644 --- a/src/cli/tui/screens/online-eval/AddOnlineEvalScreen.tsx +++ b/src/cli/tui/screens/online-eval/AddOnlineEvalScreen.tsx @@ -71,7 +71,7 @@ export function AddOnlineEvalScreen({ useEffect(() => { wizard.setSkipCheck(shouldSkipStep); - }, [shouldSkipStep]); // wizard.setSkipCheck is stable (useCallback with no deps) + }, [shouldSkipStep, wizard]); // Build endpoint picker items: DEFAULT (plain) + each endpoint const endpointItems: SelectableItem[] = useMemo(() => { diff --git a/src/cli/tui/screens/schema/AgentCoreGuidedEditor.tsx b/src/cli/tui/screens/schema/AgentCoreGuidedEditor.tsx index a0141d546..0808d8ba8 100644 --- a/src/cli/tui/screens/schema/AgentCoreGuidedEditor.tsx +++ b/src/cli/tui/screens/schema/AgentCoreGuidedEditor.tsx @@ -223,21 +223,26 @@ function AgentCoreGuidedEditorBody(props: { const agentIndex = Math.min(activeAgentIndex, Math.max(0, draft.runtimes.length - 1)); const agentCount = draft.runtimes.length; - const { tabs, fieldErrors, runtimeArtifact, issues } = useMemo(() => { + const { tabs, fieldErrors, runtimeArtifact, issues } = useMemo((): { + tabs: TabDef[]; + fieldErrors: FieldErrorMap; + runtimeArtifact: string; + issues: IssueEntry[]; + } => { if (!draft || draft.runtimes.length === 0) { return { - tabs: [] as TabDef[], - fieldErrors: {} as FieldErrorMap, + tabs: [], + fieldErrors: {}, runtimeArtifact: '', - issues: [] as IssueEntry[], + issues: [], }; } const agent = draft.runtimes[agentIndex]; if (!agent) { return { - tabs: [] as TabDef[], - fieldErrors: {} as FieldErrorMap, + tabs: [], + fieldErrors: {}, runtimeArtifact: '', issues: [] as IssueEntry[], }; @@ -326,7 +331,7 @@ function AgentCoreGuidedEditorBody(props: { { id: 'runtime-python-version', label: 'Python Version', - type: 'enum' as FieldType, + type: 'enum', path: ['runtimes', agentIndex, 'runtime', 'pythonVersion'], enumValues: PythonRuntimeSchema.options, }, @@ -335,7 +340,7 @@ function AgentCoreGuidedEditorBody(props: { { id: 'runtime-image-uri', label: 'Image Uri', - type: 'string' as FieldType, + type: 'string', path: ['runtimes', agentIndex, 'runtime', 'imageUri'], }, ] as FieldDef[])), diff --git a/src/lib/errors/__tests__/config.test.ts b/src/lib/errors/__tests__/config.test.ts index 365afc7f5..11f2e5667 100644 --- a/src/lib/errors/__tests__/config.test.ts +++ b/src/lib/errors/__tests__/config.test.ts @@ -137,7 +137,7 @@ describe('ConfigValidationError', () => { path: ['field'], message: 'Expected string', expected: 'string', - } as any, + }, ]); const err = new ConfigValidationError('/path', 'project', zodError); expect(err.message).toContain('field'); diff --git a/src/lib/packaging/__tests__/node.test.ts b/src/lib/packaging/__tests__/node.test.ts index c1551aa6d..b9dc5505b 100644 --- a/src/lib/packaging/__tests__/node.test.ts +++ b/src/lib/packaging/__tests__/node.test.ts @@ -4,15 +4,15 @@ import { describe, expect, it } from 'vitest'; describe('extractNodeVersion', () => { it('extracts 18 from NODE_18', () => { - expect(extractNodeVersion('NODE_18' as NodeRuntime)).toBe('18'); + expect(extractNodeVersion('NODE_18')).toBe('18'); }); it('extracts 20 from NODE_20', () => { - expect(extractNodeVersion('NODE_20' as NodeRuntime)).toBe('20'); + expect(extractNodeVersion('NODE_20')).toBe('20'); }); it('extracts 22 from NODE_22', () => { - expect(extractNodeVersion('NODE_22' as NodeRuntime)).toBe('22'); + expect(extractNodeVersion('NODE_22')).toBe('22'); }); it('throws for unsupported runtime string', () => { diff --git a/src/lib/packaging/__tests__/python.test.ts b/src/lib/packaging/__tests__/python.test.ts index 1640e9581..5834cdd9b 100644 --- a/src/lib/packaging/__tests__/python.test.ts +++ b/src/lib/packaging/__tests__/python.test.ts @@ -4,23 +4,23 @@ import { describe, expect, it } from 'vitest'; describe('extractPythonVersion', () => { it('extracts 3.10 from PYTHON_3_10', () => { - expect(extractPythonVersion('PYTHON_3_10' as PythonRuntime)).toBe('3.10'); + expect(extractPythonVersion('PYTHON_3_10')).toBe('3.10'); }); it('extracts 3.11 from PYTHON_3_11', () => { - expect(extractPythonVersion('PYTHON_3_11' as PythonRuntime)).toBe('3.11'); + expect(extractPythonVersion('PYTHON_3_11')).toBe('3.11'); }); it('extracts 3.12 from PYTHON_3_12', () => { - expect(extractPythonVersion('PYTHON_3_12' as PythonRuntime)).toBe('3.12'); + expect(extractPythonVersion('PYTHON_3_12')).toBe('3.12'); }); it('extracts 3.13 from PYTHON_3_13', () => { - expect(extractPythonVersion('PYTHON_3_13' as PythonRuntime)).toBe('3.13'); + expect(extractPythonVersion('PYTHON_3_13')).toBe('3.13'); }); it('extracts 3.14 from PYTHON_3_14', () => { - expect(extractPythonVersion('PYTHON_3_14' as PythonRuntime)).toBe('3.14'); + expect(extractPythonVersion('PYTHON_3_14')).toBe('3.14'); }); it('throws for unsupported runtime string', () => { diff --git a/src/lib/packaging/index.ts b/src/lib/packaging/index.ts index a281bbdbb..fd4cf68b5 100644 --- a/src/lib/packaging/index.ts +++ b/src/lib/packaging/index.ts @@ -81,7 +81,7 @@ export async function packRuntime(spec: AgentEnvSpec, options?: PackageOptions): export function packCodeZipSync(config: CodeBundleConfig | AgentEnvSpec, options?: PackageOptions): ArtifactResult { const runtimeVersion = config.runtimeVersion ?? DEFAULT_PYTHON_VERSION; const packager = getCodeZipPackager(runtimeVersion); - return packager.packCodeZip(config as AgentEnvSpec, options); + return packager.packCodeZip(config, options); } export type { diff --git a/src/schema/schemas/primitives/harness.ts b/src/schema/schemas/primitives/harness.ts index 823d75d82..accf8055b 100644 --- a/src/schema/schemas/primitives/harness.ts +++ b/src/schema/schemas/primitives/harness.ts @@ -1,6 +1,5 @@ import { NetworkModeSchema } from '../../constants'; -import { NetworkConfigSchema } from '../agent-env'; -import { LifecycleConfigurationSchema } from '../agent-env'; +import { LifecycleConfigurationSchema, NetworkConfigSchema } from '../agent-env'; import { AuthorizerConfigSchema, RuntimeAuthorizerTypeSchema } from '../auth'; import { uniqueBy } from '../zod-util'; import { TagsSchema } from './tags'; @@ -229,6 +228,7 @@ export const AllowedToolSchema = z .string() .min(1) .max(64) + // eslint-disable-next-line security/detect-unsafe-regex -- safe: input is bounded to 64 chars by .max(64) .regex(/^(\*|@?[^/]+(\/[^/]+)?)$/, 'Must be "*" or a tool name pattern (max 64 chars)'); // ============================================================================ diff --git a/src/tui-harness/mcp/server.ts b/src/tui-harness/mcp/server.ts index 8c4f4c85d..e64716291 100644 --- a/src/tui-harness/mcp/server.ts +++ b/src/tui-harness/mcp/server.ts @@ -229,6 +229,7 @@ async function handleAction(args: { let resolvedPattern: string | RegExp; if (isRegex) { try { + // eslint-disable-next-line security/detect-non-literal-regexp -- user-provided regex pattern is intentional resolvedPattern = new RegExp(pattern); } catch (err) { return errorResponse( @@ -319,6 +320,7 @@ async function handleWaitFor(args: { sessionId: string; pattern: string; timeout let pattern: string | RegExp; if (isRegex) { try { + // eslint-disable-next-line security/detect-non-literal-regexp -- user-provided regex pattern is intentional pattern = new RegExp(patternStr); } catch (err) { return errorResponse(