diff --git a/esbuild.config.mjs b/esbuild.config.mjs index 2cbd5b81f..fc4e1d9ac 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -48,6 +48,7 @@ await esbuild.build({ platform: 'node', format: 'esm', minify: true, + keepNames: true, jsx: 'automatic', // Inject require shim for ESM compatibility with CommonJS dependencies banner: { diff --git a/integ-tests/add-remove-resources.test.ts b/integ-tests/add-remove-resources.test.ts index 11d763bbd..c2098da36 100644 --- a/integ-tests/add-remove-resources.test.ts +++ b/integ-tests/add-remove-resources.test.ts @@ -197,6 +197,23 @@ describe('integration: add and remove resources', () => { }); }); + describe('add validation failure telemetry', () => { + it('emits ValidationError for add memory with missing --name', async () => { + telemetry.clearEntries(); + const result = await runCLI(['add', 'memory', '--strategies', 'SEMANTIC', '--json'], project.projectPath, { + env: telemetry.env, + }); + + expect(result.exitCode).toBe(1); + telemetry.assertMetricEmitted({ + command: 'add.memory', + exit_reason: 'failure', + error_name: 'ValidationError', + error_source: 'user', + }); + }); + }); + describe('remove all', () => { it('resets all schemas and emits telemetry', async () => { const result = await runCLI(['remove', 'all', '--yes', '--json'], project.projectPath, { diff --git a/integ-tests/create-edge-cases.test.ts b/integ-tests/create-edge-cases.test.ts index 84376c27c..e001a7926 100644 --- a/integ-tests/create-edge-cases.test.ts +++ b/integ-tests/create-edge-cases.test.ts @@ -38,6 +38,8 @@ describe.skipIf(!prereqs.npm || !prereqs.git)('integration: create edge cases', telemetry.assertMetricEmitted({ command: 'create', exit_reason: 'failure', + error_name: 'ValidationError', + error_source: 'user', agent_language: 'python', has_agent: 'true', }); diff --git a/src/cli/commands/create/command.tsx b/src/cli/commands/create/command.tsx index 534e2e412..e9a58f520 100644 --- a/src/cli/commands/create/command.tsx +++ b/src/cli/commands/create/command.tsx @@ -1,4 +1,4 @@ -import { getWorkingDirectory, serializeResult } from '../../../lib'; +import { ValidationError, getWorkingDirectory, serializeResult } from '../../../lib'; import type { BuildType, ModelProvider, @@ -132,7 +132,7 @@ async function handleCreateCLI(options: CreateOptions): Promise { async () => { const validation = validateCreateOptions(options, cwd); if (!validation.valid) { - throw new Error(validation.error); + throw new ValidationError(validation.error!); } const green = '\x1b[32m'; const reset = '\x1b[0m'; diff --git a/src/cli/primitives/AgentPrimitive.tsx b/src/cli/primitives/AgentPrimitive.tsx index d4e9fc341..d6927f85e 100644 --- a/src/cli/primitives/AgentPrimitive.tsx +++ b/src/cli/primitives/AgentPrimitive.tsx @@ -4,6 +4,7 @@ import { ConflictError, NoProjectError, ResourceNotFoundError, + ValidationError, findConfigRoot, serializeResult, setEnvVar, @@ -301,7 +302,7 @@ export class AgentPrimitive extends BasePrimitive { const validation = validateAddAgentOptions(cliOptions); if (!validation.valid) { - throw new Error(validation.error); + throw new ValidationError(validation.error!); } // Parse custom claims JSON if provided (already validated by validateAddAgentOptions) diff --git a/src/cli/primitives/CredentialPrimitive.tsx b/src/cli/primitives/CredentialPrimitive.tsx index 4b858f324..5034c1c2c 100644 --- a/src/cli/primitives/CredentialPrimitive.tsx +++ b/src/cli/primitives/CredentialPrimitive.tsx @@ -1,6 +1,7 @@ import { ConflictError, ResourceNotFoundError, + ValidationError, findConfigRoot, getEnvVar, serializeResult, @@ -315,7 +316,7 @@ export class CredentialPrimitive extends BasePrimitive { const validation = validateAddGatewayOptions(cliOptions); if (!validation.valid) { - throw new Error(validation.error); + throw new ValidationError(validation.error!); } // Parse custom claims JSON if provided (already validated) diff --git a/src/cli/primitives/GatewayTargetPrimitive.ts b/src/cli/primitives/GatewayTargetPrimitive.ts index 67991df7c..6ef4bf598 100644 --- a/src/cli/primitives/GatewayTargetPrimitive.ts +++ b/src/cli/primitives/GatewayTargetPrimitive.ts @@ -2,6 +2,7 @@ import { APP_DIR, MCP_APP_SUBDIR, ResourceNotFoundError, + ValidationError, findConfigRoot, requireConfigRoot, serializeResult, @@ -323,7 +324,7 @@ export class GatewayTargetPrimitive extends BasePrimitive { const validation = await validateAddGatewayTargetOptions(cliOptions); if (!validation.valid) { - throw new Error(validation.error); + throw new ValidationError(validation.error!); } // Map CLI flag values to internal types diff --git a/src/cli/primitives/MemoryPrimitive.tsx b/src/cli/primitives/MemoryPrimitive.tsx index 6f02941bc..8080010b0 100644 --- a/src/cli/primitives/MemoryPrimitive.tsx +++ b/src/cli/primitives/MemoryPrimitive.tsx @@ -1,4 +1,4 @@ -import { ResourceNotFoundError, findConfigRoot, serializeResult, toError } from '../../lib'; +import { ResourceNotFoundError, ValidationError, findConfigRoot, serializeResult, toError } from '../../lib'; import type { Result } from '../../lib/result'; import type { Memory, @@ -204,7 +204,7 @@ export class MemoryPrimitive extends BasePrimitive