From a9e4af78d64b2f0e68f10faa2bb25f4f2dc17ca5 Mon Sep 17 00:00:00 2001
From: Aidan Daly <aidandal@amazon.com>
Date: Thu, 29 Jan 2026 13:59:15 -0500
Subject: [PATCH 01/15] test: add unit tests for validation, update, errors,
 and zod-util
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- src/cli/commands/add/validate.test.ts
- src/cli/commands/update/update.test.ts
- src/cli/errors.test.ts
- src/schema/schemas/zod-util.test.ts

🤖 Assisted by Amazon Q Developer
---
 src/cli/commands/add/validate.test.ts  | 371 +++++++++++++++++++++++++
 src/cli/commands/update/update.test.ts |  37 +++
 src/cli/errors.test.ts                 | 180 ++++++++++++
 src/schema/schemas/zod-util.test.ts    | 115 ++++++++
 4 files changed, 703 insertions(+)
 create mode 100644 src/cli/commands/add/validate.test.ts
 create mode 100644 src/cli/commands/update/update.test.ts
 create mode 100644 src/cli/errors.test.ts
 create mode 100644 src/schema/schemas/zod-util.test.ts

diff --git a/src/cli/commands/add/validate.test.ts b/src/cli/commands/add/validate.test.ts
new file mode 100644
index 000000000..e0847eb64
--- /dev/null
+++ b/src/cli/commands/add/validate.test.ts
@@ -0,0 +1,371 @@
+import { describe, it } from 'bun:test';
+import assert from 'node:assert';
+import {
+  validateAddAgentOptions,
+  validateAddGatewayOptions,
+  validateAddMcpToolOptions,
+  validateAddMemoryOptions,
+  validateAddIdentityOptions,
+} from './validate.js';
+import type {
+  AddAgentOptions,
+  AddGatewayOptions,
+  AddMcpToolOptions,
+  AddMemoryOptions,
+  AddIdentityOptions,
+} from './types.js';
+
+// Helper: valid base options for each type
+const validAgentOptionsByo: AddAgentOptions = {
+  name: 'TestAgent',
+  type: 'byo',
+  language: 'Python',
+  framework: 'Strands',
+  modelProvider: 'Bedrock',
+  codeLocation: '/path/to/code',
+};
+
+const validAgentOptionsCreate: AddAgentOptions = {
+  name: 'TestAgent',
+  type: 'create',
+  language: 'Python',
+  framework: 'Strands',
+  modelProvider: 'Bedrock',
+  memory: 'none',
+};
+
+const validGatewayOptionsNone: AddGatewayOptions = {
+  name: 'test-gateway',
+  authorizerType: 'NONE',
+};
+
+const validGatewayOptionsJwt: AddGatewayOptions = {
+  name: 'test-gateway',
+  authorizerType: 'CUSTOM_JWT',
+  discoveryUrl: 'https://example.com/.well-known/openid-configuration',
+  allowedAudience: 'aud1,aud2',
+  allowedClients: 'client1,client2',
+};
+
+const validMcpToolOptionsMcpRuntime: AddMcpToolOptions = {
+  name: 'test-tool',
+  language: 'Python',
+  exposure: 'mcp-runtime',
+  agents: 'Agent1,Agent2',
+};
+
+const validMcpToolOptionsBehindGateway: AddMcpToolOptions = {
+  name: 'test-tool',
+  language: 'Python',
+  exposure: 'behind-gateway',
+  gateway: 'my-gateway',
+  host: 'Lambda',
+};
+
+const validMemoryOptions: AddMemoryOptions = {
+  name: 'test-memory',
+  strategies: 'SEMANTIC,SUMMARIZATION',
+  owner: 'TestAgent',
+};
+
+const validIdentityOptions: AddIdentityOptions = {
+  name: 'test-identity',
+  type: 'ApiKeyCredentialProvider',
+  apiKey: 'test-key',
+  owner: 'TestAgent',
+};
+
+describe('validate', () => {
+  describe('validateAddAgentOptions', () => {
+    // AC1: All required fields validated
+    it('returns error for missing required fields', () => {
+      const requiredFields: Array<{ field: keyof AddAgentOptions; error: string }> = [
+        { field: 'name', error: '--name is required' },
+        { field: 'framework', error: '--framework is required' },
+        { field: 'modelProvider', error: '--model-provider is required' },
+        { field: 'language', error: '--language is required' },
+      ];
+
+      for (const { field, error } of requiredFields) {
+        const opts = { ...validAgentOptionsByo, [field]: undefined };
+        const result = validateAddAgentOptions(opts);
+        assert.strictEqual(result.valid, false, `Should fail for missing ${field}`);
+        assert.strictEqual(result.error, error);
+      }
+    });
+
+    // AC2: Invalid schema values rejected
+    it('returns error for invalid schema values', () => {
+      // Invalid name
+      let result = validateAddAgentOptions({ ...validAgentOptionsByo, name: '123invalid' });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('begin with') || result.error?.includes('letter'));
+
+      // Invalid framework
+      result = validateAddAgentOptions({ ...validAgentOptionsByo, framework: 'InvalidFW' as any });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('Invalid framework'));
+
+      // Invalid modelProvider
+      result = validateAddAgentOptions({ ...validAgentOptionsByo, modelProvider: 'InvalidMP' as any });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('Invalid model provider'));
+
+      // Invalid language
+      result = validateAddAgentOptions({ ...validAgentOptionsByo, language: 'InvalidLang' as any });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('Invalid language'));
+    });
+
+    // AC3: Framework/model provider compatibility
+    it('returns error for incompatible framework and model provider', () => {
+      const result = validateAddAgentOptions({
+        ...validAgentOptionsByo,
+        framework: 'GoogleADK',
+        modelProvider: 'Bedrock',
+      });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('does not support'));
+    });
+
+    // AC4: BYO path requires codeLocation
+    it('returns error for BYO path without codeLocation', () => {
+      const result = validateAddAgentOptions({
+        ...validAgentOptionsByo,
+        type: 'byo',
+        codeLocation: undefined,
+      });
+      assert.strictEqual(result.valid, false);
+      assert.strictEqual(result.error, '--code-location is required for BYO path');
+    });
+
+    // AC5: Create path language restrictions
+    it('returns error for create path with TypeScript or Other', () => {
+      let result = validateAddAgentOptions({ ...validAgentOptionsCreate, language: 'TypeScript' });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('Python'));
+
+      result = validateAddAgentOptions({ ...validAgentOptionsCreate, language: 'Other' });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('Python'));
+    });
+
+    // AC6: Create path requires memory
+    it('returns error for create path without memory or invalid memory', () => {
+      let result = validateAddAgentOptions({ ...validAgentOptionsCreate, memory: undefined });
+      assert.strictEqual(result.valid, false);
+      assert.strictEqual(result.error, '--memory is required for create path');
+
+      result = validateAddAgentOptions({ ...validAgentOptionsCreate, memory: 'invalid' as any });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('Invalid memory option'));
+    });
+
+    // AC7: Valid options pass
+    it('passes for valid options', () => {
+      assert.deepStrictEqual(validateAddAgentOptions(validAgentOptionsByo), { valid: true });
+      assert.deepStrictEqual(validateAddAgentOptions(validAgentOptionsCreate), { valid: true });
+    });
+  });
+
+  describe('validateAddGatewayOptions', () => {
+    // AC8: Required fields validated
+    it('returns error for missing name', () => {
+      const result = validateAddGatewayOptions({ ...validGatewayOptionsNone, name: undefined });
+      assert.strictEqual(result.valid, false);
+      assert.strictEqual(result.error, '--name is required');
+    });
+
+    // AC9: Invalid name rejected
+    it('returns error for invalid gateway name', () => {
+      const result = validateAddGatewayOptions({ ...validGatewayOptionsNone, name: 'INVALID_NAME!' });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error);
+    });
+
+    // AC10: Invalid authorizerType rejected
+    it('returns error for invalid authorizerType', () => {
+      const result = validateAddGatewayOptions({ ...validGatewayOptionsNone, authorizerType: 'INVALID' as any });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('Invalid authorizer type'));
+    });
+
+    // AC11: CUSTOM_JWT requires all fields
+    it('returns error for CUSTOM_JWT missing required fields', () => {
+      const jwtFields: Array<{ field: keyof AddGatewayOptions; error: string }> = [
+        { field: 'discoveryUrl', error: '--discovery-url is required for CUSTOM_JWT authorizer' },
+        { field: 'allowedAudience', error: '--allowed-audience is required for CUSTOM_JWT authorizer' },
+        { field: 'allowedClients', error: '--allowed-clients is required for CUSTOM_JWT authorizer' },
+      ];
+
+      for (const { field, error } of jwtFields) {
+        const opts = { ...validGatewayOptionsJwt, [field]: undefined };
+        const result = validateAddGatewayOptions(opts);
+        assert.strictEqual(result.valid, false, `Should fail for missing ${field}`);
+        assert.strictEqual(result.error, error);
+      }
+    });
+
+    // AC12: discoveryUrl validation
+    it('returns error for invalid discoveryUrl', () => {
+      // Invalid URL format
+      let result = validateAddGatewayOptions({ ...validGatewayOptionsJwt, discoveryUrl: 'not-a-url' });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('valid URL'));
+
+      // Missing well-known suffix
+      result = validateAddGatewayOptions({ ...validGatewayOptionsJwt, discoveryUrl: 'https://example.com/oauth' });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('.well-known/openid-configuration'));
+    });
+
+    // AC13: Empty comma-separated values rejected
+    it('returns error for empty audience or clients', () => {
+      let result = validateAddGatewayOptions({ ...validGatewayOptionsJwt, allowedAudience: ',,,' });
+      assert.strictEqual(result.valid, false);
+      assert.strictEqual(result.error, 'At least one audience value is required');
+
+      result = validateAddGatewayOptions({ ...validGatewayOptionsJwt, allowedClients: '  ,  ' });
+      assert.strictEqual(result.valid, false);
+      assert.strictEqual(result.error, 'At least one client value is required');
+    });
+
+    // AC14: Valid options pass
+    it('passes for valid options', () => {
+      assert.deepStrictEqual(validateAddGatewayOptions(validGatewayOptionsNone), { valid: true });
+      assert.deepStrictEqual(validateAddGatewayOptions(validGatewayOptionsJwt), { valid: true });
+    });
+  });
+
+  describe('validateAddMcpToolOptions', () => {
+    // AC15: Required fields validated
+    it('returns error for missing required fields', () => {
+      const requiredFields: Array<{ field: keyof AddMcpToolOptions; error: string }> = [
+        { field: 'name', error: '--name is required' },
+        { field: 'language', error: '--language is required' },
+        { field: 'exposure', error: '--exposure is required' },
+      ];
+
+      for (const { field, error } of requiredFields) {
+        const opts = { ...validMcpToolOptionsMcpRuntime, [field]: undefined };
+        const result = validateAddMcpToolOptions(opts);
+        assert.strictEqual(result.valid, false, `Should fail for missing ${field}`);
+        assert.strictEqual(result.error, error);
+      }
+    });
+
+    // AC16: Invalid values rejected
+    it('returns error for invalid values', () => {
+      let result = validateAddMcpToolOptions({ ...validMcpToolOptionsMcpRuntime, language: 'Java' as any });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('Invalid language'));
+
+      result = validateAddMcpToolOptions({ ...validMcpToolOptionsMcpRuntime, exposure: 'invalid' as any });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('Invalid exposure'));
+    });
+
+    // AC17: mcp-runtime exposure requires agents
+    it('returns error for mcp-runtime without agents', () => {
+      let result = validateAddMcpToolOptions({ ...validMcpToolOptionsMcpRuntime, agents: undefined });
+      assert.strictEqual(result.valid, false);
+      assert.strictEqual(result.error, '--agents is required for mcp-runtime exposure');
+
+      result = validateAddMcpToolOptions({ ...validMcpToolOptionsMcpRuntime, agents: ',,,' });
+      assert.strictEqual(result.valid, false);
+      assert.strictEqual(result.error, 'At least one agent is required');
+    });
+
+    // AC18: behind-gateway exposure requires gateway and host
+    it('returns error for behind-gateway missing gateway, host, or invalid host', () => {
+      let result = validateAddMcpToolOptions({ ...validMcpToolOptionsBehindGateway, gateway: undefined });
+      assert.strictEqual(result.valid, false);
+      assert.strictEqual(result.error, '--gateway is required for behind-gateway exposure');
+
+      result = validateAddMcpToolOptions({ ...validMcpToolOptionsBehindGateway, host: undefined });
+      assert.strictEqual(result.valid, false);
+      assert.strictEqual(result.error, '--host is required for behind-gateway exposure');
+
+      result = validateAddMcpToolOptions({ ...validMcpToolOptionsBehindGateway, host: 'InvalidHost' as any });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('Invalid host'));
+    });
+
+    // AC19: Valid options pass
+    it('passes for valid options', () => {
+      assert.deepStrictEqual(validateAddMcpToolOptions(validMcpToolOptionsMcpRuntime), { valid: true });
+      assert.deepStrictEqual(validateAddMcpToolOptions(validMcpToolOptionsBehindGateway), { valid: true });
+    });
+  });
+
+  describe('validateAddMemoryOptions', () => {
+    // AC20: Required fields validated
+    it('returns error for missing required fields', () => {
+      const requiredFields: Array<{ field: keyof AddMemoryOptions; error: string }> = [
+        { field: 'name', error: '--name is required' },
+        { field: 'strategies', error: '--strategies is required' },
+        { field: 'owner', error: '--owner is required' },
+      ];
+
+      for (const { field, error } of requiredFields) {
+        const opts = { ...validMemoryOptions, [field]: undefined };
+        const result = validateAddMemoryOptions(opts);
+        assert.strictEqual(result.valid, false, `Should fail for missing ${field}`);
+        assert.strictEqual(result.error, error);
+      }
+    });
+
+    // AC21: Invalid/empty strategies rejected
+    it('returns error for invalid or empty strategies', () => {
+      let result = validateAddMemoryOptions({ ...validMemoryOptions, strategies: 'INVALID' });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('Invalid strategy'));
+      assert.ok(result.error?.includes('SEMANTIC'));
+
+      result = validateAddMemoryOptions({ ...validMemoryOptions, strategies: ',,,' });
+      assert.strictEqual(result.valid, false);
+      assert.strictEqual(result.error, 'At least one strategy is required');
+    });
+
+    // AC22: Valid options pass
+    it('passes for valid options', () => {
+      assert.deepStrictEqual(validateAddMemoryOptions(validMemoryOptions), { valid: true });
+      // Test all valid strategies
+      assert.deepStrictEqual(
+        validateAddMemoryOptions({ ...validMemoryOptions, strategies: 'SEMANTIC,SUMMARIZATION,USER_PREFERENCE,CUSTOM' }),
+        { valid: true }
+      );
+    });
+  });
+
+  describe('validateAddIdentityOptions', () => {
+    // AC23: Required fields validated
+    it('returns error for missing required fields', () => {
+      const requiredFields: Array<{ field: keyof AddIdentityOptions; error: string }> = [
+        { field: 'name', error: '--name is required' },
+        { field: 'type', error: '--type is required' },
+        { field: 'apiKey', error: '--api-key is required' },
+        { field: 'owner', error: '--owner is required' },
+      ];
+
+      for (const { field, error } of requiredFields) {
+        const opts = { ...validIdentityOptions, [field]: undefined };
+        const result = validateAddIdentityOptions(opts);
+        assert.strictEqual(result.valid, false, `Should fail for missing ${field}`);
+        assert.strictEqual(result.error, error);
+      }
+    });
+
+    // AC24: Only ApiKeyCredentialProvider supported
+    it('returns error for unsupported type', () => {
+      const result = validateAddIdentityOptions({ ...validIdentityOptions, type: 'OtherType' });
+      assert.strictEqual(result.valid, false);
+      assert.ok(result.error?.includes('Only ApiKeyCredentialProvider is supported'));
+    });
+
+    // AC25: Valid options pass
+    it('passes for valid options', () => {
+      assert.deepStrictEqual(validateAddIdentityOptions(validIdentityOptions), { valid: true });
+    });
+  });
+});
diff --git a/src/cli/commands/update/update.test.ts b/src/cli/commands/update/update.test.ts
new file mode 100644
index 000000000..a104861fd
--- /dev/null
+++ b/src/cli/commands/update/update.test.ts
@@ -0,0 +1,37 @@
+import { describe, it } from 'bun:test';
+import assert from 'node:assert';
+import { compareVersions } from './action.js';
+
+describe('update', () => {
+  describe('compareVersions', () => {
+    it('returns 0 for equal versions', () => {
+      assert.strictEqual(compareVersions('1.0.0', '1.0.0'), 0);
+      assert.strictEqual(compareVersions('2.5.3', '2.5.3'), 0);
+    });
+
+    it('returns 1 when latest is newer (update available)', () => {
+      assert.strictEqual(compareVersions('1.0.0', '1.0.1'), 1);
+      assert.strictEqual(compareVersions('1.0.0', '1.1.0'), 1);
+      assert.strictEqual(compareVersions('1.0.0', '2.0.0'), 1);
+      assert.strictEqual(compareVersions('1.9.9', '2.0.0'), 1);
+    });
+
+    it('returns -1 when current is newer (local ahead)', () => {
+      assert.strictEqual(compareVersions('1.0.1', '1.0.0'), -1);
+      assert.strictEqual(compareVersions('1.1.0', '1.0.0'), -1);
+      assert.strictEqual(compareVersions('2.0.0', '1.0.0'), -1);
+      assert.strictEqual(compareVersions('2.0.0', '1.9.9'), -1);
+    });
+
+    it('handles missing patch version', () => {
+      assert.strictEqual(compareVersions('1.0', '1.0.0'), 0);
+      assert.strictEqual(compareVersions('1.0.0', '1.0'), 0);
+      assert.strictEqual(compareVersions('1.0', '1.0.1'), 1);
+    });
+
+    it('compares major version first', () => {
+      assert.strictEqual(compareVersions('1.9.9', '2.0.0'), 1);
+      assert.strictEqual(compareVersions('2.0.0', '1.9.9'), -1);
+    });
+  });
+});
diff --git a/src/cli/errors.test.ts b/src/cli/errors.test.ts
new file mode 100644
index 000000000..8002aade1
--- /dev/null
+++ b/src/cli/errors.test.ts
@@ -0,0 +1,180 @@
+import { describe, it } from 'bun:test';
+import assert from 'node:assert';
+import {
+  getErrorMessage,
+  isExpiredTokenError,
+  isNoCredentialsError,
+  isStackInProgressError,
+} from './errors.js';
+
+describe('errors', () => {
+  describe('getErrorMessage', () => {
+    it('returns message from Error instance', () => {
+      const err = new Error('test error');
+      assert.strictEqual(getErrorMessage(err), 'test error');
+    });
+
+    it('returns string for non-Error values', () => {
+      assert.strictEqual(getErrorMessage('raw error'), 'raw error');
+      assert.strictEqual(getErrorMessage(123), '123');
+      assert.strictEqual(getErrorMessage(null), 'null');
+      assert.strictEqual(getErrorMessage(undefined), 'undefined');
+    });
+  });
+
+  describe('isExpiredTokenError', () => {
+    // Test ALL error codes in EXPIRED_TOKEN_ERROR_CODES via error.name
+    const allErrorCodes = [
+      'ExpiredToken',
+      'ExpiredTokenException',
+      'TokenRefreshRequired',
+      'CredentialsExpired',
+      'InvalidIdentityToken',
+      'UnauthorizedAccess',
+      'AccessDenied',
+      'AccessDeniedException',
+      'InvalidClientTokenId',
+      'SignatureDoesNotMatch',
+      'RequestExpired',
+    ];
+
+    it('returns true for all SDK v3 error names', () => {
+      for (const code of allErrorCodes) {
+        assert.strictEqual(
+          isExpiredTokenError({ name: code }),
+          true,
+          `Should detect error.name: ${code}`
+        );
+      }
+    });
+
+    it('returns true for all error Code properties', () => {
+      for (const code of allErrorCodes) {
+        assert.strictEqual(
+          isExpiredTokenError({ Code: code }),
+          true,
+          `Should detect error.Code: ${code}`
+        );
+      }
+    });
+
+    it('returns true for nested cause with error name', () => {
+      assert.strictEqual(isExpiredTokenError({ cause: { name: 'ExpiredToken' } }), true);
+    });
+
+    it('returns true for double-nested cause', () => {
+      assert.strictEqual(isExpiredTokenError({ cause: { cause: { name: 'ExpiredToken' } } }), true);
+    });
+
+    it('returns true for nested cause with Code', () => {
+      assert.strictEqual(isExpiredTokenError({ cause: { Code: 'AccessDenied' } }), true);
+    });
+
+    it('returns true for message patterns', () => {
+      const patterns = [
+        'expired token',
+        'token has expired',
+        'credentials have expired',
+        'security token included in the request is expired',
+        'the security token included in the request is invalid',
+      ];
+      for (const pattern of patterns) {
+        assert.strictEqual(
+          isExpiredTokenError(new Error(pattern)),
+          true,
+          `Should detect message: ${pattern}`
+        );
+      }
+    });
+
+    it('returns false for non-expired errors', () => {
+      assert.strictEqual(isExpiredTokenError({ name: 'ValidationError' }), false);
+      assert.strictEqual(isExpiredTokenError({ Code: 'ResourceNotFound' }), false);
+      assert.strictEqual(isExpiredTokenError(new Error('some other error')), false);
+    });
+
+    it('returns false for edge cases', () => {
+      assert.strictEqual(isExpiredTokenError(null), false);
+      assert.strictEqual(isExpiredTokenError(undefined), false);
+      assert.strictEqual(isExpiredTokenError('string'), false);
+      assert.strictEqual(isExpiredTokenError(123), false);
+      assert.strictEqual(isExpiredTokenError({}), false);
+      assert.strictEqual(isExpiredTokenError({ name: 123 }), false); // non-string name
+      assert.strictEqual(isExpiredTokenError({ Code: 123 }), false); // non-string Code
+    });
+  });
+
+  describe('isNoCredentialsError', () => {
+    it('returns true for AwsCredentialsError', () => {
+      assert.strictEqual(isNoCredentialsError({ name: 'AwsCredentialsError' }), true);
+    });
+
+    it('returns true for message patterns', () => {
+      const patterns = [
+        'no aws credentials found',
+        'could not load credentials',
+        'credentials not found',
+      ];
+      for (const pattern of patterns) {
+        assert.strictEqual(
+          isNoCredentialsError(new Error(pattern)),
+          true,
+          `Should detect message: ${pattern}`
+        );
+      }
+    });
+
+    it('returns false for other errors', () => {
+      assert.strictEqual(isNoCredentialsError({ name: 'ExpiredTokenException' }), false);
+      assert.strictEqual(isNoCredentialsError(new Error('some other error')), false);
+    });
+
+    it('returns false for edge cases', () => {
+      assert.strictEqual(isNoCredentialsError(null), false);
+      assert.strictEqual(isNoCredentialsError(undefined), false);
+      assert.strictEqual(isNoCredentialsError('string'), false);
+      assert.strictEqual(isNoCredentialsError(123), false);
+      assert.strictEqual(isNoCredentialsError({}), false);
+    });
+  });
+
+  describe('isStackInProgressError', () => {
+    it('returns true for in-progress states', () => {
+      const states = [
+        'UPDATE_IN_PROGRESS',
+        'CREATE_IN_PROGRESS',
+        'DELETE_IN_PROGRESS',
+        'ROLLBACK_IN_PROGRESS',
+      ];
+      for (const state of states) {
+        assert.strictEqual(
+          isStackInProgressError(new Error(`Stack is in ${state} state`)),
+          true,
+          `Should detect state: ${state}`
+        );
+      }
+    });
+
+    it('returns true for state and cannot be updated pattern', () => {
+      assert.strictEqual(
+        isStackInProgressError(new Error('Stack is in UPDATE_ROLLBACK_IN_PROGRESS state and cannot be updated')),
+        true
+      );
+    });
+
+    it('returns true for currently being updated', () => {
+      assert.strictEqual(isStackInProgressError(new Error('stack is currently being updated')), true);
+    });
+
+    it('returns false for other errors', () => {
+      assert.strictEqual(isStackInProgressError(new Error('Stack not found')), false);
+      assert.strictEqual(isStackInProgressError(new Error('some other error')), false);
+    });
+
+    it('returns false for edge cases', () => {
+      assert.strictEqual(isStackInProgressError(null), false);
+      assert.strictEqual(isStackInProgressError(undefined), false);
+      assert.strictEqual(isStackInProgressError({}), false);
+    });
+  });
+});
diff --git a/src/schema/schemas/zod-util.test.ts b/src/schema/schemas/zod-util.test.ts
new file mode 100644
index 000000000..d37e1dd04
--- /dev/null
+++ b/src/schema/schemas/zod-util.test.ts
@@ -0,0 +1,115 @@
+import { describe, it } from 'bun:test';
+import assert from 'node:assert';
+import { z } from 'zod';
+import { uniqueBy } from './zod-util.js';
+
+describe('zod-util', () => {
+  describe('uniqueBy', () => {
+    // Helper schema for testing
+    const createSchema = (errorMsg: (key: string) => string = (k) => `Duplicate: ${k}`) =>
+      z.array(z.object({ name: z.string() })).superRefine(uniqueBy((x) => x.name, errorMsg));
+
+    // AC1: Unique array passes validation
+    it('passes validation for unique arrays', () => {
+      const schema = createSchema();
+      const result = schema.safeParse([{ name: 'a' }, { name: 'b' }, { name: 'c' }]);
+      assert.strictEqual(result.success, true);
+    });
+
+    // AC2: Duplicate detected at correct index (NOT first occurrence)
+    it('detects duplicate at correct index', () => {
+      const schema = createSchema();
+      const result = schema.safeParse([{ name: 'a' }, { name: 'b' }, { name: 'a' }]);
+      assert.strictEqual(result.success, false);
+      if (!result.success) {
+        assert.strictEqual(result.error.issues.length, 1);
+        assert.deepStrictEqual(result.error.issues[0].path, [2]);
+      }
+    });
+
+    // AC3: Custom error message used
+    it('uses custom error message', () => {
+      const schema = createSchema((key) => `Duplicate name: ${key}`);
+      const result = schema.safeParse([{ name: 'foo' }, { name: 'foo' }]);
+      assert.strictEqual(result.success, false);
+      if (!result.success) {
+        assert.strictEqual(result.error.issues[0].message, 'Duplicate name: foo');
+      }
+    });
+
+    // AC4: Empty array passes
+    it('passes validation for empty array', () => {
+      const schema = createSchema();
+      const result = schema.safeParse([]);
+      assert.strictEqual(result.success, true);
+    });
+
+    // AC5: Single element passes
+    it('passes validation for single element', () => {
+      const schema = createSchema();
+      const result = schema.safeParse([{ name: 'a' }]);
+      assert.strictEqual(result.success, true);
+    });
+
+    // AC6: Multiple duplicates of same key flagged at each occurrence
+    it('flags multiple duplicates at each subsequent occurrence', () => {
+      const schema = createSchema();
+      const result = schema.safeParse([
+        { name: 'a' },  // index 0 - first, not flagged
+        { name: 'b' },  // index 1 - unique
+        { name: 'a' },  // index 2 - duplicate, flagged
+        { name: 'c' },  // index 3 - unique
+        { name: 'a' },  // index 4 - duplicate, flagged
+      ]);
+      assert.strictEqual(result.success, false);
+      if (!result.success) {
+        assert.strictEqual(result.error.issues.length, 2);
+        const paths = result.error.issues.map((i) => i.path[0]);
+        assert.ok(paths.includes(2), 'Should flag index 2');
+        assert.ok(paths.includes(4), 'Should flag index 4');
+        assert.ok(!paths.includes(0), 'Should NOT flag index 0 (first occurrence)');
+      }
+    });
+
+    // AC7: First occurrence is never flagged
+    it('never flags first occurrence', () => {
+      const schema = createSchema();
+      const result = schema.safeParse([{ name: 'a' }, { name: 'a' }]);
+      assert.strictEqual(result.success, false);
+      if (!result.success) {
+        const paths = result.error.issues.map((i) => i.path[0]);
+        assert.ok(!paths.includes(0), 'First occurrence should not be flagged');
+        assert.ok(paths.includes(1), 'Second occurrence should be flagged');
+      }
+    });
+
+    // AC8: Different key functions work
+    it('works with different key functions', () => {
+      const idSchema = z
+        .array(z.object({ id: z.string() }))
+        .superRefine(uniqueBy((x) => x.id, (k) => `Duplicate id: ${k}`));
+
+      const result = idSchema.safeParse([{ id: '1' }, { id: '2' }, { id: '1' }]);
+      assert.strictEqual(result.success, false);
+      if (!result.success) {
+        assert.strictEqual(result.error.issues.length, 1);
+        assert.deepStrictEqual(result.error.issues[0].path, [2]);
+        assert.strictEqual(result.error.issues[0].message, 'Duplicate id: 1');
+      }
+    });
+
+    // AC9: All elements same key
+    it('flags all subsequent occurrences when all elements have same key', () => {
+      const schema = createSchema();
+      const result = schema.safeParse([{ name: 'a' }, { name: 'a' }, { name: 'a' }]);
+      assert.strictEqual(result.success, false);
+      if (!result.success) {
+        assert.strictEqual(result.error.issues.length, 2);
+        const paths = result.error.issues.map((i) => i.path[0]);
+        assert.ok(!paths.includes(0), 'Index 0 should NOT be flagged');
+        assert.ok(paths.includes(1), 'Index 1 should be flagged');
+        assert.ok(paths.includes(2), 'Index 2 should be flagged');
+      }
+    });
+  });
+});

From b33d24c6aebe8587b29c1a0b7d42c689295ad856 Mon Sep 17 00:00:00 2001
From: Aidan Daly <aidandal@amazon.com>
Date: Thu, 29 Jan 2026 14:18:54 -0500
Subject: [PATCH 02/15] refactor: move CLI integration tests from __tests__ to
 integ-tests

- Move help.test.ts and json-output.test.ts to integ-tests/
- Fix import paths for test-utils
- Remove empty src/cli/__tests__/ directory

These tests run the CLI as a black box and belong with other
integration tests, not colocated with source files.
---
 {src/cli/__tests__ => integ-tests}/help.test.ts        | 2 +-
 {src/cli/__tests__ => integ-tests}/json-output.test.ts | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
 rename {src/cli/__tests__ => integ-tests}/help.test.ts (95%)
 rename {src/cli/__tests__ => integ-tests}/json-output.test.ts (98%)

diff --git a/src/cli/__tests__/help.test.ts b/integ-tests/help.test.ts
similarity index 95%
rename from src/cli/__tests__/help.test.ts
rename to integ-tests/help.test.ts
index a116ec482..66463638e 100644
--- a/src/cli/__tests__/help.test.ts
+++ b/integ-tests/help.test.ts
@@ -1,6 +1,6 @@
 import { describe, it } from 'bun:test';
 import assert from 'node:assert';
-import { runCLI } from '../../test-utils/index.js';
+import { runCLI } from '../src/test-utils/index.js';
 
 const COMMANDS = [
   'create',
diff --git a/src/cli/__tests__/json-output.test.ts b/integ-tests/json-output.test.ts
similarity index 98%
rename from src/cli/__tests__/json-output.test.ts
rename to integ-tests/json-output.test.ts
index c6bed123a..605aa28f2 100644
--- a/src/cli/__tests__/json-output.test.ts
+++ b/integ-tests/json-output.test.ts
@@ -4,7 +4,7 @@ import { rm, mkdir } from 'node:fs/promises';
 import { join } from 'node:path';
 import { tmpdir } from 'node:os';
 import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../test-utils/index.js';
+import { runCLI } from '../src/test-utils/index.js';
 
 describe('JSON output structure', () => {
   let testDir: string;

From 5f55f81050f6cfdff8eba6cb40f684339b396ce5 Mon Sep 17 00:00:00 2001
From: Aidan Daly <aidandal@amazon.com>
Date: Fri, 30 Jan 2026 14:48:44 -0500
Subject: [PATCH 03/15] refactor: migrate from bun to
 esbuild/tsx/vitest\n\nBuild system:\n- Replace bun bundler with esbuild
 (esbuild.config.mjs)\n- Delete bun.build.ts\n\nRuntime:\n- Replace bun with
 tsx for TypeScript execution\n- Update dev server to use npx tsx watch\n-
 Update test runner to use node with built bundle\n\nTesting:\n- Replace
 bun:test with vitest\n- Migrate all assertions from node:assert to vitest
 expect\n- Move 29 test files to __tests__/ directories\n- Add
 vitest.config.ts with text-loader plugin\n\nDependencies:\n- Add: esbuild,
 tsx, vitest\n- Remove: @types/bun\n\nDocumentation:\n- Update CONTRIBUTING.md
 (remove bun prereq, add Testing section)\n- Update integ-tests/README.md
 (vitest commands/imports)\n- Add docs/TESTING.md\n\nConfig:\n- Update
 tsconfig.build.json to exclude test files\n- Add test and test:watch npm
 scripts

---
 CONTRIBUTING.md                               |   10 +-
 docs/TESTING.md                               |  116 +
 bun.build.ts => esbuild.config.mjs            |   27 +-
 integ-tests/README.md                         |    8 +-
 integ-tests/create-no-agent.test.ts           |   16 +-
 integ-tests/create-with-agent.test.ts         |   17 +-
 integ-tests/deploy.test.ts                    |   14 +-
 integ-tests/dev-server.test.ts                |    8 +-
 integ-tests/help.test.ts                      |   18 +-
 integ-tests/invoke-agent.test.ts              |    8 +-
 integ-tests/json-output.test.ts               |   72 +-
 package-lock.json                             | 2065 ++++++++++++++---
 package.json                                  |   14 +-
 src/cli/__tests__/errors.test.ts              |  146 ++
 src/cli/aws/account.ts                        |    4 +-
 src/cli/cli.ts                                |    2 +-
 src/cli/cloudformation/outputs.ts             |    2 +-
 .../commands/add/__tests__/add-agent.test.ts  |  273 +++
 .../add/__tests__/add-gateway.test.ts         |  154 ++
 .../add/__tests__/add-identity.test.ts        |  200 ++
 .../add/__tests__/add-mcp-tool.test.ts        |  311 +++
 .../commands/add/__tests__/add-memory.test.ts |  231 ++
 .../commands/add/__tests__/add-target.test.ts |  104 +
 .../add/{ => __tests__}/validate.test.ts      |  182 +-
 src/cli/commands/add/actions.ts               |   65 +-
 src/cli/commands/add/add-agent.test.ts        |  205 --
 src/cli/commands/add/add-gateway.test.ts      |  158 --
 src/cli/commands/add/add-identity.test.ts     |  179 --
 src/cli/commands/add/add-mcp-tool.test.ts     |  249 --
 src/cli/commands/add/add-memory.test.ts       |  203 --
 src/cli/commands/add/add-target.test.ts       |  111 -
 src/cli/commands/add/command.tsx              |   14 +-
 src/cli/commands/add/target-action.ts         |    2 +-
 src/cli/commands/add/validate.ts              |   31 +-
 .../attach/__tests__/attach-agent.test.ts     |  157 ++
 .../{ => __tests__}/attach-gateway.test.ts    |  100 +-
 .../attach/__tests__/attach-identity.test.ts  |  153 ++
 .../__tests__/attach-mcp-runtime.test.ts      |  163 ++
 .../attach/__tests__/attach-memory.test.ts    |  175 ++
 src/cli/commands/attach/actions.ts            |   20 +-
 src/cli/commands/attach/attach-agent.test.ts  |  153 --
 .../commands/attach/attach-identity.test.ts   |  133 --
 .../attach/attach-mcp-runtime.test.ts         |  148 --
 src/cli/commands/attach/attach-memory.test.ts |  178 --
 src/cli/commands/attach/command.tsx           |   26 +-
 src/cli/commands/attach/validate.ts           |    8 +-
 .../commands/create/__tests__/create.test.ts  |  155 ++
 src/cli/commands/create/action.ts             |   16 +-
 src/cli/commands/create/command.tsx           |   15 +-
 src/cli/commands/create/create.test.ts        |  135 --
 src/cli/commands/create/validate.ts           |   23 +-
 .../deploy/{ => __tests__}/deploy.test.ts     |   75 +-
 src/cli/commands/deploy/actions.ts            |   33 +-
 src/cli/commands/deploy/command.tsx           |   52 +-
 .../destroy/{ => __tests__}/destroy.test.ts   |   87 +-
 src/cli/commands/destroy/actions.ts           |    2 +-
 src/cli/commands/dev/__tests__/dev.test.ts    |   52 +
 src/cli/commands/dev/command.tsx              |   22 +-
 src/cli/commands/dev/dev.test.ts              |   54 -
 .../invoke/{ => __tests__}/invoke.test.ts     |  105 +-
 src/cli/commands/invoke/command.tsx           |   85 +-
 .../plan/{ => __tests__}/plan.test.ts         |   87 +-
 src/cli/commands/plan/actions.ts              |   12 +-
 .../__tests__/agent-removal-cascade.test.ts   |  189 ++
 .../__tests__/removal-policy-cascade.test.ts  |  192 ++
 .../__tests__/removal-policy-restrict.test.ts |  321 +++
 .../{ => __tests__}/remove-gateway.test.ts    |   78 +-
 .../{ => __tests__}/remove-identity.test.ts   |  147 +-
 .../{ => __tests__}/remove-mcp-tool.test.ts   |  166 +-
 .../{ => __tests__}/remove-memory.test.ts     |  121 +-
 .../remove/{ => __tests__}/remove.test.ts     |   75 +-
 src/cli/commands/remove/actions.ts            |   24 +-
 .../remove/agent-removal-cascade.test.ts      |  154 --
 src/cli/commands/remove/command.tsx           |    9 +-
 .../remove/removal-policy-cascade.test.ts     |  111 -
 .../remove/removal-policy-restrict.test.ts    |  165 --
 src/cli/commands/remove/validate.ts           |    2 +-
 .../commands/update/__tests__/update.test.ts  |   36 +
 src/cli/commands/update/update.test.ts        |   37 -
 src/cli/errors.test.ts                        |  180 --
 src/cli/operations/dev/server.ts              |    4 +-
 src/cli/tui/screens/attach/AttachFlow.tsx     |   22 +-
 src/cli/tui/utils/__tests__/process.test.ts   |   81 +
 src/schema/schemas/__tests__/zod-util.test.ts |  117 +
 src/schema/schemas/zod-util.test.ts           |  115 -
 src/test-utils/cli-runner.ts                  |    8 +-
 test-output.txt                               |  830 +++++++
 tsconfig.build.json                           |    9 +-
 tsconfig.json                                 |    6 +-
 vitest.config.ts                              |   42 +
 90 files changed, 7034 insertions(+), 3850 deletions(-)
 create mode 100644 docs/TESTING.md
 rename bun.build.ts => esbuild.config.mjs (65%)
 create mode 100644 src/cli/__tests__/errors.test.ts
 create mode 100644 src/cli/commands/add/__tests__/add-agent.test.ts
 create mode 100644 src/cli/commands/add/__tests__/add-gateway.test.ts
 create mode 100644 src/cli/commands/add/__tests__/add-identity.test.ts
 create mode 100644 src/cli/commands/add/__tests__/add-mcp-tool.test.ts
 create mode 100644 src/cli/commands/add/__tests__/add-memory.test.ts
 create mode 100644 src/cli/commands/add/__tests__/add-target.test.ts
 rename src/cli/commands/add/{ => __tests__}/validate.test.ts (65%)
 delete mode 100644 src/cli/commands/add/add-agent.test.ts
 delete mode 100644 src/cli/commands/add/add-gateway.test.ts
 delete mode 100644 src/cli/commands/add/add-identity.test.ts
 delete mode 100644 src/cli/commands/add/add-mcp-tool.test.ts
 delete mode 100644 src/cli/commands/add/add-memory.test.ts
 delete mode 100644 src/cli/commands/add/add-target.test.ts
 create mode 100644 src/cli/commands/attach/__tests__/attach-agent.test.ts
 rename src/cli/commands/attach/{ => __tests__}/attach-gateway.test.ts (51%)
 create mode 100644 src/cli/commands/attach/__tests__/attach-identity.test.ts
 create mode 100644 src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts
 create mode 100644 src/cli/commands/attach/__tests__/attach-memory.test.ts
 delete mode 100644 src/cli/commands/attach/attach-agent.test.ts
 delete mode 100644 src/cli/commands/attach/attach-identity.test.ts
 delete mode 100644 src/cli/commands/attach/attach-mcp-runtime.test.ts
 delete mode 100644 src/cli/commands/attach/attach-memory.test.ts
 create mode 100644 src/cli/commands/create/__tests__/create.test.ts
 delete mode 100644 src/cli/commands/create/create.test.ts
 rename src/cli/commands/deploy/{ => __tests__}/deploy.test.ts (58%)
 rename src/cli/commands/destroy/{ => __tests__}/destroy.test.ts (64%)
 create mode 100644 src/cli/commands/dev/__tests__/dev.test.ts
 delete mode 100644 src/cli/commands/dev/dev.test.ts
 rename src/cli/commands/invoke/{ => __tests__}/invoke.test.ts (61%)
 rename src/cli/commands/plan/{ => __tests__}/plan.test.ts (62%)
 create mode 100644 src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts
 create mode 100644 src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts
 create mode 100644 src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts
 rename src/cli/commands/remove/{ => __tests__}/remove-gateway.test.ts (63%)
 rename src/cli/commands/remove/{ => __tests__}/remove-identity.test.ts (54%)
 rename src/cli/commands/remove/{ => __tests__}/remove-mcp-tool.test.ts (59%)
 rename src/cli/commands/remove/{ => __tests__}/remove-memory.test.ts (57%)
 rename src/cli/commands/remove/{ => __tests__}/remove.test.ts (64%)
 delete mode 100644 src/cli/commands/remove/agent-removal-cascade.test.ts
 delete mode 100644 src/cli/commands/remove/removal-policy-cascade.test.ts
 delete mode 100644 src/cli/commands/remove/removal-policy-restrict.test.ts
 create mode 100644 src/cli/commands/update/__tests__/update.test.ts
 delete mode 100644 src/cli/commands/update/update.test.ts
 delete mode 100644 src/cli/errors.test.ts
 create mode 100644 src/cli/tui/utils/__tests__/process.test.ts
 create mode 100644 src/schema/schemas/__tests__/zod-util.test.ts
 delete mode 100644 src/schema/schemas/zod-util.test.ts
 create mode 100644 test-output.txt
 create mode 100644 vitest.config.ts

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7f85722cd..9f581d774 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -63,7 +63,6 @@ public github issue.
 ### Prerequisites
 
 - Node.js 20+
-- Bun (for CLI bundling)
 - npm
 
 ### Building
@@ -73,6 +72,15 @@ npm install
 npm run build
 ```
 
+### Testing
+
+```bash
+npm test           # Run all tests
+npm run test:watch # Run tests in watch mode
+```
+
+See [docs/TESTING.md](docs/TESTING.md) for detailed testing guidelines.
+
 ### Local Development with CDK Package
 
 If you're also developing the CDK package (`@aws/agentcore-l3-cdk-constructs`):
diff --git a/docs/TESTING.md b/docs/TESTING.md
new file mode 100644
index 000000000..79bc3d440
--- /dev/null
+++ b/docs/TESTING.md
@@ -0,0 +1,116 @@
+# Testing Guide
+
+## Quick Start
+
+```bash
+npm test           # Run all tests
+npm run test:watch # Run tests in watch mode
+```
+
+## Test Organization
+
+### Unit Tests
+
+Unit tests are co-located with source files in `__tests__/` directories:
+
+```
+src/cli/commands/add/
+├── action.ts
+├── command.ts
+└── __tests__/
+    └── add.test.ts
+```
+
+### Integration Tests
+
+Integration tests live in `integ-tests/`:
+
+```
+integ-tests/
+├── create-no-agent.test.ts
+├── create-with-agent.test.ts
+├── deploy.test.ts
+└── ...
+```
+
+See [integ-tests/README.md](../integ-tests/README.md) for integration test details.
+
+## Writing Tests
+
+### Imports
+
+Use vitest for all test utilities:
+
+```typescript
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
+```
+
+### Assertions
+
+Use `expect` assertions:
+
+```typescript
+// Equality
+expect(result).toBe('expected');
+expect(obj).toEqual({ key: 'value' });
+
+// Truthiness
+expect(value).toBeTruthy();
+expect(value).toBeFalsy();
+
+// Errors
+expect(() => fn()).toThrow();
+expect(() => fn()).toThrow('message');
+```
+
+### Mocking
+
+Use `vi` for mocks:
+
+```typescript
+// Mock functions
+const mockFn = vi.fn();
+mockFn.mockReturnValue('value');
+mockFn.mockResolvedValue('async value');
+
+// Spies
+vi.spyOn(module, 'method');
+
+// Module mocks
+vi.mock('./module');
+```
+
+## Test Utilities
+
+### CLI Runner
+
+`src/test-utils/cli-runner.ts` runs CLI commands in tests:
+
+```typescript
+import { runCLI } from '../src/test-utils/cli-runner';
+
+const result = await runCLI(['create', '--name', 'test'], tempDir);
+expect(result.exitCode).toBe(0);
+```
+
+## Configuration
+
+Test configuration is in `vitest.config.ts`:
+
+- Test timeout: 15 seconds
+- Hook timeout: 60 seconds
+- Test patterns: `src/**/*.test.ts`, `integ-tests/**/*.test.ts`
+
+## Integration Tests
+
+Integration tests require:
+
+- AWS credentials configured
+- IAM permissions for CloudFormation operations
+- Dedicated test AWS account (recommended)
+
+Run integration tests:
+
+```bash
+npm run test:integ
+```
diff --git a/bun.build.ts b/esbuild.config.mjs
similarity index 65%
rename from bun.build.ts
rename to esbuild.config.mjs
index 686cbdf60..efa62e4ca 100644
--- a/bun.build.ts
+++ b/esbuild.config.mjs
@@ -1,9 +1,11 @@
+import * as esbuild from 'esbuild';
 import * as fs from 'fs';
+import { createRequire } from 'module';
 
 // Stub plugin for optional dev dependencies
 const optionalDepsPlugin = {
   name: 'optional-deps',
-  setup(build: Parameters<Parameters<typeof Bun.build>[0]['plugins'][number]['setup']>[0]) {
+  setup(build) {
     // Stub react-devtools-core (only used when DEV=true)
     build.onResolve({ filter: /^react-devtools-core$/ }, () => ({
       path: 'react-devtools-core',
@@ -19,17 +21,18 @@ const optionalDepsPlugin = {
 // Text loader plugin for embedding files
 const textLoaderPlugin = {
   name: 'text-loader',
-  setup(build: Parameters<Parameters<typeof Bun.build>[0]['plugins'][number]['setup']>[0]) {
+  setup(build) {
+    // Handle .md and .txt files as text
     build.onLoad({ filter: /\.(md|txt)$/ }, async args => {
-      const text = await Bun.file(args.path).text();
+      const text = await fs.promises.readFile(args.path, 'utf8');
       return {
         contents: `export default ${JSON.stringify(text)};`,
         loader: 'js',
       };
     });
-    // Handle .ts files in llm-compacted as text (use platform-agnostic pattern)
+    // Handle .ts files in llm-compacted as text
     build.onLoad({ filter: /llm-compacted[/\\].*\.ts$/ }, async args => {
-      const text = await Bun.file(args.path).text();
+      const text = await fs.promises.readFile(args.path, 'utf8');
       return {
         contents: `export default ${JSON.stringify(text)};`,
         loader: 'js',
@@ -38,13 +41,17 @@ const textLoaderPlugin = {
   },
 };
 
-await Bun.build({
-  entrypoints: ['./src/cli/index.ts'],
-  outdir: './dist/cli',
-  target: 'node',
+await esbuild.build({
+  entryPoints: ['./src/cli/index.ts'],
+  outfile: './dist/cli/index.mjs',
+  bundle: true,
+  platform: 'node',
   format: 'esm',
   minify: true,
-  naming: '[dir]/[name].mjs',
+  // Inject require shim for ESM compatibility with CommonJS dependencies
+  banner: {
+    js: `import { createRequire } from 'module'; const require = createRequire(import.meta.url);`,
+  },
   external: ['fsevents', '@aws-cdk/toolkit-lib'],
   plugins: [optionalDepsPlugin, textLoaderPlugin],
 });
diff --git a/integ-tests/README.md b/integ-tests/README.md
index 09f89cc44..729977988 100644
--- a/integ-tests/README.md
+++ b/integ-tests/README.md
@@ -15,7 +15,7 @@ This directory contains real AWS integration tests that actually deploy resource
 npm run test:integ
 
 # Run a specific test
-bun test --timeout 300000 integ-tests/integ.deploy.ts
+npx vitest run integ-tests/deploy.test.ts --testTimeout=300000
 ```
 
 ## Test Naming Convention
@@ -38,14 +38,14 @@ Integration tests are NOT run automatically on every PR. They can be triggered:
 ## Writing Integration Tests
 
 ```typescript
-import { runCLI } from '../src/test-utils';
-import { after, before, describe, it } from 'node:test';
+import { runCLI } from '../src/test-utils/cli-runner';
+import { afterAll, describe, expect, it } from 'vitest';
 
 describe('integ: deploy', () => {
   // Use unique stack names to avoid conflicts
   const stackName = `test-${Date.now()}`;
 
-  after(async () => {
+  afterAll(async () => {
     // ALWAYS clean up - destroy the stack
     await runCLI(['destroy', '--target', stackName, '--force'], projectDir);
   });
diff --git a/integ-tests/create-no-agent.test.ts b/integ-tests/create-no-agent.test.ts
index c76de7cee..2ba964e2a 100644
--- a/integ-tests/create-no-agent.test.ts
+++ b/integ-tests/create-no-agent.test.ts
@@ -1,11 +1,11 @@
 import { exists, runCLI } from '../src/test-utils/index.js';
-import { afterAll, beforeAll, describe, it } from 'bun:test';
-import assert from 'node:assert';
 import { execSync } from 'node:child_process';
 import { randomUUID } from 'node:crypto';
 import { mkdir, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it } from 'vitest';
+import { expect } from 'vitest';
 
 function hasCommand(cmd: string): boolean {
   try {
@@ -35,22 +35,22 @@ describe('integration: create without agent', () => {
     const name = `IntegNoAgent${Date.now()}`;
     const result = await runCLI(['create', '--name', name, '--no-agent', '--json'], testDir, false);
 
-    assert.strictEqual(result.exitCode, 0, `stderr: ${result.stderr}`);
+    expect(result.exitCode, `stderr: ${result.stderr}`).toBe(0);
 
     const json = JSON.parse(result.stdout);
-    assert.strictEqual(json.success, true);
+    expect(json.success).toBe(true);
 
     // Verify npm install ran (in CDK project directory)
-    assert.ok(
+    expect(
       await exists(join(json.projectPath, 'agentcore', 'cdk', 'node_modules')),
       'agentcore/cdk/node_modules/ should exist'
-    );
+    ).toBeTruthy();
 
     // Verify git init ran
-    assert.ok(await exists(join(json.projectPath, '.git')), '.git/ should exist');
+    expect(await exists(join(json.projectPath, '.git')), '.git/ should exist').toBeTruthy();
 
     // Verify at least one commit
     const gitLog = execSync('git log --oneline', { cwd: json.projectPath, encoding: 'utf-8' });
-    assert.ok(gitLog.trim().length > 0, 'Should have at least one commit');
+    expect(gitLog.trim().length > 0, 'Should have at least one commit').toBeTruthy();
   });
 });
diff --git a/integ-tests/create-with-agent.test.ts b/integ-tests/create-with-agent.test.ts
index 382886586..591d63732 100644
--- a/integ-tests/create-with-agent.test.ts
+++ b/integ-tests/create-with-agent.test.ts
@@ -1,11 +1,11 @@
 import { exists, runCLI } from '../src/test-utils/index.js';
-import { afterAll, beforeAll, describe, it } from 'bun:test';
-import assert from 'node:assert';
 import { execSync } from 'node:child_process';
 import { randomUUID } from 'node:crypto';
 import { mkdir, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it } from 'vitest';
+import { expect } from 'vitest';
 
 function hasCommand(cmd: string): boolean {
   try {
@@ -53,19 +53,22 @@ describe('integration: create with Python agent', () => {
       false
     );
 
-    assert.strictEqual(result.exitCode, 0, `stderr: ${result.stderr}`);
+    expect(result.exitCode, `stderr: ${result.stderr}`).toBe(0);
 
     const json = JSON.parse(result.stdout);
-    assert.strictEqual(json.success, true);
+    expect(json.success).toBe(true);
 
     // Verify npm install ran
-    assert.ok(await exists(join(json.projectPath, 'agentcore', 'cdk', 'node_modules')), 'node_modules/ should exist');
+    expect(
+      await exists(join(json.projectPath, 'agentcore', 'cdk', 'node_modules')),
+      'node_modules/ should exist'
+    ).toBeTruthy();
 
     // Verify git init ran
-    assert.ok(await exists(join(json.projectPath, '.git')), '.git/ should exist');
+    expect(await exists(join(json.projectPath, '.git')), '.git/ should exist').toBeTruthy();
 
     // Verify uv venv ran - .venv in app/{agentName} directory
     const agentDir = join(json.projectPath, 'app', json.agentName || name);
-    assert.ok(await exists(join(agentDir, '.venv')), '.venv/ should exist in agent directory');
+    expect(await exists(join(agentDir, '.venv')), '.venv/ should exist in agent directory').toBeTruthy();
   });
 });
diff --git a/integ-tests/deploy.test.ts b/integ-tests/deploy.test.ts
index 573641a1a..4230d78db 100644
--- a/integ-tests/deploy.test.ts
+++ b/integ-tests/deploy.test.ts
@@ -1,11 +1,11 @@
 import { runCLI } from '../src/test-utils/index.js';
-import { afterAll, beforeAll, describe, it } from 'bun:test';
-import assert from 'node:assert';
 import { execSync } from 'node:child_process';
 import { randomUUID } from 'node:crypto';
 import { mkdir, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it } from 'vitest';
+import { expect } from 'vitest';
 
 function hasCommand(cmd: string): boolean {
   try {
@@ -89,9 +89,9 @@ describe('integration: deploy', () => {
       const result = await runCLI(['destroy', '--target', targetName, '--yes', '--json'], projectPath, false);
 
       // Assert destroy succeeded
-      assert.strictEqual(result.exitCode, 0, `Destroy failed: ${result.stderr}`);
+      expect(result.exitCode, `Destroy failed: ${result.stderr}`).toBe(0);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true, 'Destroy should report success');
+      expect(json.success, 'Destroy should report success').toBe(true);
     }
     await rm(testDir, { recursive: true, force: true });
   }, 120000);
@@ -99,7 +99,7 @@ describe('integration: deploy', () => {
   it.skipIf(!hasNpm || !hasGit || !hasUv || !hasAws)(
     'deploys to AWS successfully',
     async () => {
-      assert.ok(projectPath, 'Project should have been created');
+      expect(projectPath, 'Project should have been created').toBeTruthy();
 
       const result = await runCLI(['deploy', '--target', targetName, '--yes', '--json'], projectPath, false);
 
@@ -108,10 +108,10 @@ describe('integration: deploy', () => {
         console.log('Deploy stderr:', result.stderr);
       }
 
-      assert.strictEqual(result.exitCode, 0, `Deploy failed: ${result.stderr}`);
+      expect(result.exitCode, `Deploy failed: ${result.stderr}`).toBe(0);
 
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true, 'Deploy should report success');
+      expect(json.success, 'Deploy should report success').toBe(true);
     },
     180000
   );
diff --git a/integ-tests/dev-server.test.ts b/integ-tests/dev-server.test.ts
index f323a1e20..9f461a478 100644
--- a/integ-tests/dev-server.test.ts
+++ b/integ-tests/dev-server.test.ts
@@ -1,11 +1,11 @@
 import { exists, runCLI } from '../src/test-utils/index.js';
-import { afterAll, afterEach, beforeAll, describe, it } from 'bun:test';
-import assert from 'node:assert';
 import { type ChildProcess, execSync, spawn } from 'node:child_process';
 import { randomUUID } from 'node:crypto';
 import { mkdir, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
+import { afterAll, afterEach, beforeAll, describe, it } from 'vitest';
+import { expect } from 'vitest';
 
 function hasCommand(cmd: string): boolean {
   try {
@@ -88,7 +88,7 @@ describe('integration: dev server', () => {
   it.skipIf(!hasNpm || !hasGit || !hasUv)(
     'starts dev server and responds to health check',
     async () => {
-      assert.ok(projectPath, 'Project should have been created');
+      expect(projectPath, 'Project should have been created').toBeTruthy();
 
       const cliPath = join(__dirname, '..', 'src', 'cli', 'index.ts');
       const port = 8000 + Math.floor(Math.random() * 1000);
@@ -99,7 +99,7 @@ describe('integration: dev server', () => {
       });
 
       const serverReady = await waitForServer(port, 20000);
-      assert.ok(serverReady, 'Dev server should respond to ping within 20s');
+      expect(serverReady, 'Dev server should respond to ping within 20s').toBeTruthy();
 
       // Clean shutdown
       devProcess.kill('SIGTERM');
diff --git a/integ-tests/help.test.ts b/integ-tests/help.test.ts
index 66463638e..43e437e8b 100644
--- a/integ-tests/help.test.ts
+++ b/integ-tests/help.test.ts
@@ -1,6 +1,6 @@
-import { describe, it } from 'bun:test';
-import assert from 'node:assert';
 import { runCLI } from '../src/test-utils/index.js';
+import { describe, it } from 'vitest';
+import { expect } from 'vitest';
 
 const COMMANDS = [
   'create',
@@ -24,10 +24,10 @@ describe('CLI help', () => {
   describe('main help', () => {
     it('shows all commands', async () => {
       const result = await runCLI(['--help']);
-      
-      assert.strictEqual(result.exitCode, 0);
-      assert.ok(result.stdout.includes('Usage:'), 'Should show usage');
-      assert.ok(result.stdout.includes('Commands:'), 'Should list commands');
+
+      expect(result.exitCode).toBe(0);
+      expect(result.stdout.includes('Usage:'), 'Should show usage').toBeTruthy();
+      expect(result.stdout.includes('Commands:'), 'Should list commands').toBeTruthy();
     });
   });
 
@@ -35,9 +35,9 @@ describe('CLI help', () => {
     for (const cmd of COMMANDS) {
       it(`${cmd} --help exits 0`, async () => {
         const result = await runCLI([cmd, '--help']);
-        
-        assert.strictEqual(result.exitCode, 0, `${cmd} --help failed: ${result.stderr}`);
-        assert.ok(result.stdout.includes('Usage:'), `${cmd} should show usage`);
+
+        expect(result.exitCode, `${cmd} --help failed: ${result.stderr}`).toBe(0);
+        expect(result.stdout.includes('Usage:'), `${cmd} should show usage`).toBeTruthy();
       });
     }
   });
diff --git a/integ-tests/invoke-agent.test.ts b/integ-tests/invoke-agent.test.ts
index a82163fad..0a294bf0a 100644
--- a/integ-tests/invoke-agent.test.ts
+++ b/integ-tests/invoke-agent.test.ts
@@ -1,11 +1,11 @@
 import { runCLI } from '../src/test-utils/index.js';
-import { afterAll, beforeAll, describe, it } from 'bun:test';
-import assert from 'node:assert';
 import { execSync } from 'node:child_process';
 import { randomUUID } from 'node:crypto';
 import { mkdir, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it } from 'vitest';
+import { expect } from 'vitest';
 
 function hasCommand(cmd: string): boolean {
   try {
@@ -64,7 +64,7 @@ describe('integration: invoke agent', () => {
   it.skipIf(!hasNpm || !hasGit || !hasUv)(
     'invokes agent and receives response',
     async () => {
-      assert.ok(projectPath, 'Project should have been created');
+      expect(projectPath, 'Project should have been created').toBeTruthy();
 
       const result = await runCLI(
         ['invoke', '--agent', agentName, '--prompt', 'Say hello', '--json'],
@@ -74,7 +74,7 @@ describe('integration: invoke agent', () => {
 
       // Invoke may fail if no AWS credentials, but should at least attempt
       // For now, just verify the command runs and produces output
-      assert.ok(result.stdout.length > 0 || result.stderr.length > 0, 'Should produce some output');
+      expect(result.stdout.length > 0 || result.stderr.length > 0, 'Should produce some output').toBeTruthy();
     },
     60000
   );
diff --git a/integ-tests/json-output.test.ts b/integ-tests/json-output.test.ts
index 605aa28f2..44a974756 100644
--- a/integ-tests/json-output.test.ts
+++ b/integ-tests/json-output.test.ts
@@ -1,10 +1,10 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
-import { randomUUID } from 'node:crypto';
 import { runCLI } from '../src/test-utils/index.js';
+import { randomUUID } from 'node:crypto';
+import { mkdir, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it } from 'vitest';
+import { expect } from 'vitest';
 
 describe('JSON output structure', () => {
   let testDir: string;
@@ -22,50 +22,58 @@ describe('JSON output structure', () => {
     it('error response has success:false and error string', async () => {
       // 'Test' is a reserved name, so this will fail validation
       const result = await runCLI(['create', '--name', 'Test', '--json'], testDir);
-      
-      assert.strictEqual(result.exitCode, 1);
+
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false, 'success should be false');
-      assert.strictEqual(typeof json.error, 'string', 'error should be a string');
-      assert.ok(json.error.length > 0, 'error should not be empty');
+      expect(json.success, 'success should be false').toBe(false);
+      expect(typeof json.error, 'error should be a string').toBe('string');
+      expect(json.error.length > 0, 'error should not be empty').toBeTruthy();
     });
 
     it('validation error mentions the issue', async () => {
       const result = await runCLI(['create', '--name', 'Test', '--json'], testDir);
       const json = JSON.parse(result.stdout);
-      
+
       // Error should mention why 'Test' is invalid (reserved/conflicts)
-      assert.ok(
-        json.error.toLowerCase().includes('reserved') || 
-        json.error.toLowerCase().includes('conflict'),
+      expect(
+        json.error.toLowerCase().includes('reserved') || json.error.toLowerCase().includes('conflict'),
         `Error should explain the issue: ${json.error}`
-      );
+      ).toBeTruthy();
     });
 
     it('missing required options returns error JSON', async () => {
       // Missing --language, --framework, etc without --no-agent
       const result = await runCLI(['create', '--name', 'ValidName', '--json'], testDir);
-      
-      assert.strictEqual(result.exitCode, 1);
+
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.strictEqual(typeof json.error, 'string');
+      expect(json.success).toBe(false);
+      expect(typeof json.error).toBe('string');
     });
 
     it('invalid framework returns error JSON', async () => {
-      const result = await runCLI([
-        'create', '--name', 'TestProj',
-        '--language', 'Python',
-        '--framework', 'InvalidFramework',
-        '--model-provider', 'Bedrock',
-        '--memory', 'none',
-        '--json'
-      ], testDir);
-      
-      assert.strictEqual(result.exitCode, 1);
+      const result = await runCLI(
+        [
+          'create',
+          '--name',
+          'TestProj',
+          '--language',
+          'Python',
+          '--framework',
+          'InvalidFramework',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        testDir
+      );
+
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('framework'));
+      expect(json.success).toBe(false);
+      expect(json.error.toLowerCase().includes('framework')).toBeTruthy();
     });
   });
 
diff --git a/package-lock.json b/package-lock.json
index de207cd11..895b2c479 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -35,13 +35,13 @@
         "@eslint/js": "^9.39.2",
         "@secretlint/secretlint-rule-preset-recommend": "^11.3.0",
         "@trivago/prettier-plugin-sort-imports": "6.0.0",
-        "@types/bun": "^1.2.14",
         "@types/node": "^25.0.3",
         "@types/react": "^19.2.7",
         "@typescript-eslint/eslint-plugin": "^8.50.0",
         "@typescript-eslint/parser": "^8.50.0",
         "aws-cdk-lib": "^2.234.1",
         "constructs": "^10.4.4",
+        "esbuild": "^0.27.2",
         "eslint": "^9.39.2",
         "eslint-config-prettier": "^10.1.8",
         "eslint-import-resolver-typescript": "^4.4.4",
@@ -54,8 +54,10 @@
         "lint-staged": "^16.2.7",
         "prettier": "^3.7.4",
         "secretlint": "^11.3.0",
+        "tsx": "^4.21.0",
         "typescript": "^5",
-        "typescript-eslint": "^8.50.1"
+        "typescript-eslint": "^8.50.1",
+        "vitest": "^4.0.18"
       },
       "engines": {
         "node": ">=20"
@@ -2996,447 +2998,1239 @@
         "tslib": "^2.4.0"
       }
     },
-    "node_modules/@eslint-community/eslint-utils": {
-      "version": "4.9.1",
-      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
-      "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
+    "node_modules/@esbuild/aix-ppc64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz",
+      "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==",
+      "cpu": [
+        "ppc64"
+      ],
       "dev": true,
       "license": "MIT",
-      "dependencies": {
-        "eslint-visitor-keys": "^3.4.3"
-      },
+      "optional": true,
+      "os": [
+        "aix"
+      ],
       "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/eslint"
-      },
-      "peerDependencies": {
-        "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+        "node": ">=18"
       }
     },
-    "node_modules/@eslint-community/regexpp": {
-      "version": "4.12.2",
-      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
-      "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
+    "node_modules/@esbuild/android-arm": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz",
+      "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==",
+      "cpu": [
+        "arm"
+      ],
       "dev": true,
       "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
       "engines": {
-        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+        "node": ">=18"
       }
     },
-    "node_modules/@eslint/config-array": {
-      "version": "0.21.1",
-      "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
-      "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
+    "node_modules/@esbuild/android-arm64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz",
+      "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==",
+      "cpu": [
+        "arm64"
+      ],
       "dev": true,
-      "license": "Apache-2.0",
-      "dependencies": {
-        "@eslint/object-schema": "^2.1.7",
-        "debug": "^4.3.1",
-        "minimatch": "^3.1.2"
-      },
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
       "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+        "node": ">=18"
       }
     },
-    "node_modules/@eslint/config-array/node_modules/brace-expansion": {
-      "version": "1.1.12",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
-      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+    "node_modules/@esbuild/android-x64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz",
+      "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==",
+      "cpu": [
+        "x64"
+      ],
       "dev": true,
       "license": "MIT",
-      "dependencies": {
-        "balanced-match": "^1.0.0",
-        "concat-map": "0.0.1"
-      }
-    },
-    "node_modules/@eslint/config-array/node_modules/minimatch": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
-      "dev": true,
-      "license": "ISC",
-      "dependencies": {
-        "brace-expansion": "^1.1.7"
-      },
+      "optional": true,
+      "os": [
+        "android"
+      ],
       "engines": {
-        "node": "*"
+        "node": ">=18"
       }
     },
-    "node_modules/@eslint/config-helpers": {
-      "version": "0.4.2",
-      "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
-      "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
+    "node_modules/@esbuild/darwin-arm64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz",
+      "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==",
+      "cpu": [
+        "arm64"
+      ],
       "dev": true,
-      "license": "Apache-2.0",
-      "dependencies": {
-        "@eslint/core": "^0.17.0"
-      },
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
       "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+        "node": ">=18"
       }
     },
-    "node_modules/@eslint/core": {
-      "version": "0.17.0",
-      "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
-      "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
+    "node_modules/@esbuild/darwin-x64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz",
+      "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==",
+      "cpu": [
+        "x64"
+      ],
       "dev": true,
-      "license": "Apache-2.0",
-      "dependencies": {
-        "@types/json-schema": "^7.0.15"
-      },
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
       "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+        "node": ">=18"
       }
     },
-    "node_modules/@eslint/eslintrc": {
-      "version": "3.3.3",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz",
-      "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==",
+    "node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz",
+      "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==",
+      "cpu": [
+        "arm64"
+      ],
       "dev": true,
       "license": "MIT",
-      "dependencies": {
-        "ajv": "^6.12.4",
-        "debug": "^4.3.2",
-        "espree": "^10.0.1",
-        "globals": "^14.0.0",
-        "ignore": "^5.2.0",
-        "import-fresh": "^3.2.1",
-        "js-yaml": "^4.1.1",
-        "minimatch": "^3.1.2",
-        "strip-json-comments": "^3.1.1"
-      },
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
       "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "url": "https://opencollective.com/eslint"
+        "node": ">=18"
       }
     },
-    "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
-      "version": "1.1.12",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
-      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+    "node_modules/@esbuild/freebsd-x64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz",
+      "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==",
+      "cpu": [
+        "x64"
+      ],
       "dev": true,
       "license": "MIT",
-      "dependencies": {
-        "balanced-match": "^1.0.0",
-        "concat-map": "0.0.1"
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
       }
     },
-    "node_modules/@eslint/eslintrc/node_modules/ignore": {
-      "version": "5.3.2",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
-      "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+    "node_modules/@esbuild/linux-arm": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz",
+      "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==",
+      "cpu": [
+        "arm"
+      ],
       "dev": true,
       "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
       "engines": {
-        "node": ">= 4"
+        "node": ">=18"
       }
     },
-    "node_modules/@eslint/eslintrc/node_modules/minimatch": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+    "node_modules/@esbuild/linux-arm64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz",
+      "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==",
+      "cpu": [
+        "arm64"
+      ],
       "dev": true,
-      "license": "ISC",
-      "dependencies": {
-        "brace-expansion": "^1.1.7"
-      },
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
       "engines": {
-        "node": "*"
+        "node": ">=18"
       }
     },
-    "node_modules/@eslint/js": {
-      "version": "9.39.2",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz",
-      "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==",
+    "node_modules/@esbuild/linux-ia32": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz",
+      "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==",
+      "cpu": [
+        "ia32"
+      ],
       "dev": true,
       "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
       "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
-      },
-      "funding": {
-        "url": "https://eslint.org/donate"
+        "node": ">=18"
       }
     },
-    "node_modules/@eslint/object-schema": {
-      "version": "2.1.7",
-      "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
-      "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
+    "node_modules/@esbuild/linux-loong64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz",
+      "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==",
+      "cpu": [
+        "loong64"
+      ],
       "dev": true,
-      "license": "Apache-2.0",
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
       "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+        "node": ">=18"
       }
     },
-    "node_modules/@eslint/plugin-kit": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
-      "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
+    "node_modules/@esbuild/linux-mips64el": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz",
+      "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==",
+      "cpu": [
+        "mips64el"
+      ],
       "dev": true,
-      "license": "Apache-2.0",
-      "dependencies": {
-        "@eslint/core": "^0.17.0",
-        "levn": "^0.4.1"
-      },
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
       "engines": {
-        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+        "node": ">=18"
       }
     },
-    "node_modules/@humanfs/core": {
-      "version": "0.19.1",
-      "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
-      "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+    "node_modules/@esbuild/linux-ppc64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz",
+      "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==",
+      "cpu": [
+        "ppc64"
+      ],
       "dev": true,
-      "license": "Apache-2.0",
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
       "engines": {
-        "node": ">=18.18.0"
+        "node": ">=18"
       }
     },
-    "node_modules/@humanfs/node": {
-      "version": "0.16.7",
-      "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
-      "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
+    "node_modules/@esbuild/linux-riscv64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz",
+      "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==",
+      "cpu": [
+        "riscv64"
+      ],
       "dev": true,
-      "license": "Apache-2.0",
-      "dependencies": {
-        "@humanfs/core": "^0.19.1",
-        "@humanwhocodes/retry": "^0.4.0"
-      },
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
       "engines": {
-        "node": ">=18.18.0"
+        "node": ">=18"
       }
     },
-    "node_modules/@humanwhocodes/module-importer": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
-      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+    "node_modules/@esbuild/linux-s390x": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz",
+      "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==",
+      "cpu": [
+        "s390x"
+      ],
       "dev": true,
-      "license": "Apache-2.0",
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
       "engines": {
-        "node": ">=12.22"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/nzakas"
+        "node": ">=18"
       }
     },
-    "node_modules/@humanwhocodes/retry": {
-      "version": "0.4.3",
-      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
-      "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+    "node_modules/@esbuild/linux-x64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz",
+      "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==",
+      "cpu": [
+        "x64"
+      ],
       "dev": true,
-      "license": "Apache-2.0",
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
       "engines": {
-        "node": ">=18.18"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/nzakas"
+        "node": ">=18"
       }
     },
-    "node_modules/@isaacs/balanced-match": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
-      "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
+    "node_modules/@esbuild/netbsd-arm64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz",
+      "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/netbsd-x64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz",
+      "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
       "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
       "engines": {
-        "node": "20 || >=22"
+        "node": ">=18"
       }
     },
-    "node_modules/@isaacs/brace-expansion": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
-      "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
+    "node_modules/@esbuild/openbsd-arm64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz",
+      "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
       "license": "MIT",
-      "dependencies": {
-        "@isaacs/balanced-match": "^4.0.1"
-      },
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
       "engines": {
-        "node": "20 || >=22"
+        "node": ">=18"
       }
     },
-    "node_modules/@isaacs/cliui": {
-      "version": "8.0.2",
-      "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
-      "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
-      "license": "ISC",
+    "node_modules/@esbuild/openbsd-x64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz",
+      "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openharmony-arm64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz",
+      "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/sunos-x64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz",
+      "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-arm64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz",
+      "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-ia32": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz",
+      "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-x64": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz",
+      "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@eslint-community/eslint-utils": {
+      "version": "4.9.1",
+      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+      "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
+      "dev": true,
+      "license": "MIT",
       "dependencies": {
-        "string-width": "^5.1.2",
-        "string-width-cjs": "npm:string-width@^4.2.0",
-        "strip-ansi": "^7.0.1",
-        "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
-        "wrap-ansi": "^8.1.0",
-        "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+        "eslint-visitor-keys": "^3.4.3"
       },
       "engines": {
-        "node": ">=12"
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
       }
     },
-    "node_modules/@isaacs/cliui/node_modules/ansi-styles": {
-      "version": "6.2.3",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
-      "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+    "node_modules/@eslint-community/regexpp": {
+      "version": "4.12.2",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
+      "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
+      "dev": true,
       "license": "MIT",
       "engines": {
-        "node": ">=12"
+        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@eslint/config-array": {
+      "version": "0.21.1",
+      "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
+      "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@eslint/object-schema": "^2.1.7",
+        "debug": "^4.3.1",
+        "minimatch": "^3.1.2"
       },
-      "funding": {
-        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
       }
     },
-    "node_modules/@isaacs/cliui/node_modules/emoji-regex": {
-      "version": "9.2.2",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
-      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
-      "license": "MIT"
+    "node_modules/@eslint/config-array/node_modules/brace-expansion": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
     },
-    "node_modules/@isaacs/cliui/node_modules/string-width": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
-      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+    "node_modules/@eslint/config-array/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/@eslint/config-helpers": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
+      "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@eslint/core": "^0.17.0"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/core": {
+      "version": "0.17.0",
+      "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
+      "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@types/json-schema": "^7.0.15"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/eslintrc": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz",
+      "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^10.0.1",
+        "globals": "^14.0.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.1",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/ignore": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+      "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/@eslint/js": {
+      "version": "9.39.2",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz",
+      "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      },
+      "funding": {
+        "url": "https://eslint.org/donate"
+      }
+    },
+    "node_modules/@eslint/object-schema": {
+      "version": "2.1.7",
+      "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
+      "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@eslint/plugin-kit": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
+      "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@eslint/core": "^0.17.0",
+        "levn": "^0.4.1"
+      },
+      "engines": {
+        "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+      }
+    },
+    "node_modules/@humanfs/core": {
+      "version": "0.19.1",
+      "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+      "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanfs/node": {
+      "version": "0.16.7",
+      "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
+      "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@humanfs/core": "^0.19.1",
+        "@humanwhocodes/retry": "^0.4.0"
+      },
+      "engines": {
+        "node": ">=18.18.0"
+      }
+    },
+    "node_modules/@humanwhocodes/module-importer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=12.22"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@humanwhocodes/retry": {
+      "version": "0.4.3",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+      "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=18.18"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@isaacs/balanced-match": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
+      "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
+      "license": "MIT",
+      "engines": {
+        "node": "20 || >=22"
+      }
+    },
+    "node_modules/@isaacs/brace-expansion": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
+      "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
+      "license": "MIT",
+      "dependencies": {
+        "@isaacs/balanced-match": "^4.0.1"
+      },
+      "engines": {
+        "node": "20 || >=22"
+      }
+    },
+    "node_modules/@isaacs/cliui": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+      "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^5.1.2",
+        "string-width-cjs": "npm:string-width@^4.2.0",
+        "strip-ansi": "^7.0.1",
+        "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+        "wrap-ansi": "^8.1.0",
+        "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@isaacs/cliui/node_modules/ansi-styles": {
+      "version": "6.2.3",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+      "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/@isaacs/cliui/node_modules/emoji-regex": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+      "license": "MIT"
+    },
+    "node_modules/@isaacs/cliui/node_modules/string-width": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+      "license": "MIT",
+      "dependencies": {
+        "eastasianwidth": "^0.2.0",
+        "emoji-regex": "^9.2.2",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+      "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^6.1.0",
+        "string-width": "^5.0.1",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.13",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+      "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.0",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      }
+    },
+    "node_modules/@jridgewell/remapping": {
+      "version": "2.3.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+      "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.5",
+        "@jridgewell/trace-mapping": "^0.3.24"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+      "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.31",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+      "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.1.0",
+        "@jridgewell/sourcemap-codec": "^1.4.14"
+      }
+    },
+    "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",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@pkgjs/parseargs": {
+      "version": "0.11.0",
+      "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+      "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=14"
+      }
+    },
+    "node_modules/@rollup/rollup-android-arm-eabi": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz",
+      "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-android-arm64": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz",
+      "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-arm64": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz",
+      "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-x64": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz",
+      "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-arm64": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz",
+      "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-x64": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz",
+      "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz",
+      "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz",
+      "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-gnu": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz",
+      "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-musl": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz",
+      "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-loong64-gnu": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz",
+      "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-loong64-musl": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz",
+      "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz",
+      "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-ppc64-musl": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz",
+      "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
       "license": "MIT",
-      "dependencies": {
-        "eastasianwidth": "^0.2.0",
-        "emoji-regex": "^9.2.2",
-        "strip-ansi": "^7.0.1"
-      },
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
+      "optional": true,
+      "os": [
+        "linux"
+      ]
     },
-    "node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
-      "version": "8.1.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
-      "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+    "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz",
+      "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
       "license": "MIT",
-      "dependencies": {
-        "ansi-styles": "^6.1.0",
-        "string-width": "^5.0.1",
-        "strip-ansi": "^7.0.1"
-      },
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
-      }
+      "optional": true,
+      "os": [
+        "linux"
+      ]
     },
-    "node_modules/@jridgewell/gen-mapping": {
-      "version": "0.3.13",
-      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
-      "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+    "node_modules/@rollup/rollup-linux-riscv64-musl": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz",
+      "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==",
+      "cpu": [
+        "riscv64"
+      ],
       "dev": true,
       "license": "MIT",
-      "dependencies": {
-        "@jridgewell/sourcemap-codec": "^1.5.0",
-        "@jridgewell/trace-mapping": "^0.3.24"
-      }
+      "optional": true,
+      "os": [
+        "linux"
+      ]
     },
-    "node_modules/@jridgewell/remapping": {
-      "version": "2.3.5",
-      "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
-      "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+    "node_modules/@rollup/rollup-linux-s390x-gnu": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz",
+      "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==",
+      "cpu": [
+        "s390x"
+      ],
       "dev": true,
       "license": "MIT",
-      "dependencies": {
-        "@jridgewell/gen-mapping": "^0.3.5",
-        "@jridgewell/trace-mapping": "^0.3.24"
-      }
+      "optional": true,
+      "os": [
+        "linux"
+      ]
     },
-    "node_modules/@jridgewell/resolve-uri": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
-      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+    "node_modules/@rollup/rollup-linux-x64-gnu": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz",
+      "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==",
+      "cpu": [
+        "x64"
+      ],
       "dev": true,
       "license": "MIT",
-      "engines": {
-        "node": ">=6.0.0"
-      }
+      "optional": true,
+      "os": [
+        "linux"
+      ]
     },
-    "node_modules/@jridgewell/sourcemap-codec": {
-      "version": "1.5.5",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
-      "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+    "node_modules/@rollup/rollup-linux-x64-musl": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz",
+      "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==",
+      "cpu": [
+        "x64"
+      ],
       "dev": true,
-      "license": "MIT"
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
     },
-    "node_modules/@jridgewell/trace-mapping": {
-      "version": "0.3.31",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
-      "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+    "node_modules/@rollup/rollup-openbsd-x64": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz",
+      "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==",
+      "cpu": [
+        "x64"
+      ],
       "dev": true,
       "license": "MIT",
-      "dependencies": {
-        "@jridgewell/resolve-uri": "^3.1.0",
-        "@jridgewell/sourcemap-codec": "^1.4.14"
-      }
+      "optional": true,
+      "os": [
+        "openbsd"
+      ]
     },
-    "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==",
+    "node_modules/@rollup/rollup-openharmony-arm64": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz",
+      "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==",
+      "cpu": [
+        "arm64"
+      ],
       "dev": true,
       "license": "MIT",
       "optional": true,
-      "dependencies": {
-        "@emnapi/core": "^1.4.3",
-        "@emnapi/runtime": "^1.4.3",
-        "@tybys/wasm-util": "^0.10.0"
-      }
+      "os": [
+        "openharmony"
+      ]
     },
-    "node_modules/@nodelib/fs.scandir": {
-      "version": "2.1.5",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
-      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+    "node_modules/@rollup/rollup-win32-arm64-msvc": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz",
+      "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==",
+      "cpu": [
+        "arm64"
+      ],
       "dev": true,
       "license": "MIT",
-      "dependencies": {
-        "@nodelib/fs.stat": "2.0.5",
-        "run-parallel": "^1.1.9"
-      },
-      "engines": {
-        "node": ">= 8"
-      }
+      "optional": true,
+      "os": [
+        "win32"
+      ]
     },
-    "node_modules/@nodelib/fs.stat": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
-      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+    "node_modules/@rollup/rollup-win32-ia32-msvc": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz",
+      "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==",
+      "cpu": [
+        "ia32"
+      ],
       "dev": true,
       "license": "MIT",
-      "engines": {
-        "node": ">= 8"
-      }
+      "optional": true,
+      "os": [
+        "win32"
+      ]
     },
-    "node_modules/@nodelib/fs.walk": {
-      "version": "1.2.8",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
-      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+    "node_modules/@rollup/rollup-win32-x64-gnu": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz",
+      "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==",
+      "cpu": [
+        "x64"
+      ],
       "dev": true,
       "license": "MIT",
-      "dependencies": {
-        "@nodelib/fs.scandir": "2.1.5",
-        "fastq": "^1.6.0"
-      },
-      "engines": {
-        "node": ">= 8"
-      }
+      "optional": true,
+      "os": [
+        "win32"
+      ]
     },
-    "node_modules/@pkgjs/parseargs": {
-      "version": "0.11.0",
-      "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
-      "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+    "node_modules/@rollup/rollup-win32-x64-msvc": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz",
+      "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
       "license": "MIT",
       "optional": true,
-      "engines": {
-        "node": ">=14"
-      }
+      "os": [
+        "win32"
+      ]
     },
     "node_modules/@rtsao/scc": {
       "version": "1.1.0",
@@ -4399,6 +5193,13 @@
         "node": ">=18.0.0"
       }
     },
+    "node_modules/@standard-schema/spec": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
+      "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/@textlint/ast-node-types": {
       "version": "15.5.1",
       "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.5.1.tgz",
@@ -4551,16 +5352,24 @@
         "tslib": "^2.4.0"
       }
     },
-    "node_modules/@types/bun": {
-      "version": "1.3.6",
-      "resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.3.6.tgz",
-      "integrity": "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA==",
+    "node_modules/@types/chai": {
+      "version": "5.2.3",
+      "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
+      "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "bun-types": "1.3.6"
+        "@types/deep-eql": "*",
+        "assertion-error": "^2.0.1"
       }
     },
+    "node_modules/@types/deep-eql": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
+      "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/@types/estree": {
       "version": "1.0.8",
       "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -5127,6 +5936,90 @@
         "win32"
       ]
     },
+    "node_modules/@vitest/expect": {
+      "version": "4.0.18",
+      "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz",
+      "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@standard-schema/spec": "^1.0.0",
+        "@types/chai": "^5.2.2",
+        "@vitest/spy": "4.0.18",
+        "@vitest/utils": "4.0.18",
+        "chai": "^6.2.1",
+        "tinyrainbow": "^3.0.3"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/pretty-format": {
+      "version": "4.0.18",
+      "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz",
+      "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tinyrainbow": "^3.0.3"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/runner": {
+      "version": "4.0.18",
+      "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz",
+      "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/utils": "4.0.18",
+        "pathe": "^2.0.3"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/snapshot": {
+      "version": "4.0.18",
+      "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz",
+      "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/pretty-format": "4.0.18",
+        "magic-string": "^0.30.21",
+        "pathe": "^2.0.3"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/spy": {
+      "version": "4.0.18",
+      "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz",
+      "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==",
+      "dev": true,
+      "license": "MIT",
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
+    "node_modules/@vitest/utils": {
+      "version": "4.0.18",
+      "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz",
+      "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/pretty-format": "4.0.18",
+        "tinyrainbow": "^3.0.3"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      }
+    },
     "node_modules/abort-controller": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
@@ -5496,6 +6389,16 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/assertion-error": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+      "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/astral-regex": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
@@ -6150,16 +7053,6 @@
         "node": ">=8.0.0"
       }
     },
-    "node_modules/bun-types": {
-      "version": "1.3.6",
-      "resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.3.6.tgz",
-      "integrity": "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@types/node": "*"
-      }
-    },
     "node_modules/call-bind": {
       "version": "1.0.8",
       "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
@@ -6247,6 +7140,16 @@
       "integrity": "sha512-k2gr6iA1WC6MKO8tJzNA603Ov+jAXGmYSJHJtTrMNFpoiCDNSvWixB8gDJ8bsnFnha5oAq68siTz1Ia/eixbcQ==",
       "license": "MIT OR Apache-2.0"
     },
+    "node_modules/chai": {
+      "version": "6.2.2",
+      "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
+      "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
     "node_modules/chalk": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -6822,6 +7725,13 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/es-module-lexer": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
+      "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/es-object-atoms": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
@@ -6892,6 +7802,48 @@
         "benchmarks"
       ]
     },
+    "node_modules/esbuild": {
+      "version": "0.27.2",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz",
+      "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "optionalDependencies": {
+        "@esbuild/aix-ppc64": "0.27.2",
+        "@esbuild/android-arm": "0.27.2",
+        "@esbuild/android-arm64": "0.27.2",
+        "@esbuild/android-x64": "0.27.2",
+        "@esbuild/darwin-arm64": "0.27.2",
+        "@esbuild/darwin-x64": "0.27.2",
+        "@esbuild/freebsd-arm64": "0.27.2",
+        "@esbuild/freebsd-x64": "0.27.2",
+        "@esbuild/linux-arm": "0.27.2",
+        "@esbuild/linux-arm64": "0.27.2",
+        "@esbuild/linux-ia32": "0.27.2",
+        "@esbuild/linux-loong64": "0.27.2",
+        "@esbuild/linux-mips64el": "0.27.2",
+        "@esbuild/linux-ppc64": "0.27.2",
+        "@esbuild/linux-riscv64": "0.27.2",
+        "@esbuild/linux-s390x": "0.27.2",
+        "@esbuild/linux-x64": "0.27.2",
+        "@esbuild/netbsd-arm64": "0.27.2",
+        "@esbuild/netbsd-x64": "0.27.2",
+        "@esbuild/openbsd-arm64": "0.27.2",
+        "@esbuild/openbsd-x64": "0.27.2",
+        "@esbuild/openharmony-arm64": "0.27.2",
+        "@esbuild/sunos-x64": "0.27.2",
+        "@esbuild/win32-arm64": "0.27.2",
+        "@esbuild/win32-ia32": "0.27.2",
+        "@esbuild/win32-x64": "0.27.2"
+      }
+    },
     "node_modules/escalade": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
@@ -7454,6 +8406,16 @@
         "node": ">=4.0"
       }
     },
+    "node_modules/estree-walker": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+      "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "^1.0.0"
+      }
+    },
     "node_modules/esutils": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@@ -7498,6 +8460,16 @@
         "bare-events": "^2.7.0"
       }
     },
+    "node_modules/expect-type": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz",
+      "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
     "node_modules/fast-deep-equal": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -7733,6 +8705,21 @@
         "node": ">=10"
       }
     },
+    "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/function-bind": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -9421,6 +10408,16 @@
         "yallist": "^3.0.2"
       }
     },
+    "node_modules/magic-string": {
+      "version": "0.30.21",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+      "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.5"
+      }
+    },
     "node_modules/math-intrinsics": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@@ -9555,6 +10552,25 @@
         "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1"
       }
     },
+    "node_modules/nanoid": {
+      "version": "3.3.11",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+      "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
     "node_modules/napi-postinstall": {
       "version": "0.3.4",
       "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz",
@@ -9738,6 +10754,17 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/obug": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz",
+      "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==",
+      "dev": true,
+      "funding": [
+        "https://github.com/sponsors/sxzz",
+        "https://opencollective.com/debug"
+      ],
+      "license": "MIT"
+    },
     "node_modules/onetime": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
@@ -9960,6 +10987,13 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/pathe": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+      "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/picocolors": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -10013,6 +11047,35 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/postcss": {
+      "version": "8.5.6",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+      "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "nanoid": "^3.3.11",
+        "picocolors": "^1.1.1",
+        "source-map-js": "^1.2.1"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
     "node_modules/prelude-ls": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -10392,6 +11455,51 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/rollup": {
+      "version": "4.57.1",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz",
+      "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "1.0.8"
+      },
+      "bin": {
+        "rollup": "dist/bin/rollup"
+      },
+      "engines": {
+        "node": ">=18.0.0",
+        "npm": ">=8.0.0"
+      },
+      "optionalDependencies": {
+        "@rollup/rollup-android-arm-eabi": "4.57.1",
+        "@rollup/rollup-android-arm64": "4.57.1",
+        "@rollup/rollup-darwin-arm64": "4.57.1",
+        "@rollup/rollup-darwin-x64": "4.57.1",
+        "@rollup/rollup-freebsd-arm64": "4.57.1",
+        "@rollup/rollup-freebsd-x64": "4.57.1",
+        "@rollup/rollup-linux-arm-gnueabihf": "4.57.1",
+        "@rollup/rollup-linux-arm-musleabihf": "4.57.1",
+        "@rollup/rollup-linux-arm64-gnu": "4.57.1",
+        "@rollup/rollup-linux-arm64-musl": "4.57.1",
+        "@rollup/rollup-linux-loong64-gnu": "4.57.1",
+        "@rollup/rollup-linux-loong64-musl": "4.57.1",
+        "@rollup/rollup-linux-ppc64-gnu": "4.57.1",
+        "@rollup/rollup-linux-ppc64-musl": "4.57.1",
+        "@rollup/rollup-linux-riscv64-gnu": "4.57.1",
+        "@rollup/rollup-linux-riscv64-musl": "4.57.1",
+        "@rollup/rollup-linux-s390x-gnu": "4.57.1",
+        "@rollup/rollup-linux-x64-gnu": "4.57.1",
+        "@rollup/rollup-linux-x64-musl": "4.57.1",
+        "@rollup/rollup-openbsd-x64": "4.57.1",
+        "@rollup/rollup-openharmony-arm64": "4.57.1",
+        "@rollup/rollup-win32-arm64-msvc": "4.57.1",
+        "@rollup/rollup-win32-ia32-msvc": "4.57.1",
+        "@rollup/rollup-win32-x64-gnu": "4.57.1",
+        "@rollup/rollup-win32-x64-msvc": "4.57.1",
+        "fsevents": "~2.3.2"
+      }
+    },
     "node_modules/run-parallel": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -10688,6 +11796,13 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/siginfo": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+      "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
+      "dev": true,
+      "license": "ISC"
+    },
     "node_modules/signal-exit": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
@@ -10750,6 +11865,16 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/source-map-js": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/spdx-correct": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
@@ -10826,6 +11951,20 @@
         "node": ">=8"
       }
     },
+    "node_modules/stackback": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
+      "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/std-env": {
+      "version": "3.10.0",
+      "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz",
+      "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/stop-iteration-iterator": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
@@ -11372,6 +12511,23 @@
         "url": "https://bevry.me/fund"
       }
     },
+    "node_modules/tinybench": {
+      "version": "2.9.0",
+      "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
+      "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/tinyexec": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz",
+      "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
     "node_modules/tinyglobby": {
       "version": "0.2.15",
       "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
@@ -11389,6 +12545,16 @@
         "url": "https://github.com/sponsors/SuperchupuDev"
       }
     },
+    "node_modules/tinyrainbow": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz",
+      "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
     "node_modules/to-regex-range": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -11447,6 +12613,26 @@
       "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
       "license": "0BSD"
     },
+    "node_modules/tsx": {
+      "version": "4.21.0",
+      "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz",
+      "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "esbuild": "~0.27.0",
+        "get-tsconfig": "^4.7.5"
+      },
+      "bin": {
+        "tsx": "dist/cli.mjs"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.3"
+      }
+    },
     "node_modules/type-check": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -11768,6 +12954,204 @@
         "url": "https://bevry.me/fund"
       }
     },
+    "node_modules/vitest": {
+      "version": "4.0.18",
+      "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz",
+      "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/expect": "4.0.18",
+        "@vitest/mocker": "4.0.18",
+        "@vitest/pretty-format": "4.0.18",
+        "@vitest/runner": "4.0.18",
+        "@vitest/snapshot": "4.0.18",
+        "@vitest/spy": "4.0.18",
+        "@vitest/utils": "4.0.18",
+        "es-module-lexer": "^1.7.0",
+        "expect-type": "^1.2.2",
+        "magic-string": "^0.30.21",
+        "obug": "^2.1.1",
+        "pathe": "^2.0.3",
+        "picomatch": "^4.0.3",
+        "std-env": "^3.10.0",
+        "tinybench": "^2.9.0",
+        "tinyexec": "^1.0.2",
+        "tinyglobby": "^0.2.15",
+        "tinyrainbow": "^3.0.3",
+        "vite": "^6.0.0 || ^7.0.0",
+        "why-is-node-running": "^2.3.0"
+      },
+      "bin": {
+        "vitest": "vitest.mjs"
+      },
+      "engines": {
+        "node": "^20.0.0 || ^22.0.0 || >=24.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      },
+      "peerDependencies": {
+        "@edge-runtime/vm": "*",
+        "@opentelemetry/api": "^1.9.0",
+        "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
+        "@vitest/browser-playwright": "4.0.18",
+        "@vitest/browser-preview": "4.0.18",
+        "@vitest/browser-webdriverio": "4.0.18",
+        "@vitest/ui": "4.0.18",
+        "happy-dom": "*",
+        "jsdom": "*"
+      },
+      "peerDependenciesMeta": {
+        "@edge-runtime/vm": {
+          "optional": true
+        },
+        "@opentelemetry/api": {
+          "optional": true
+        },
+        "@types/node": {
+          "optional": true
+        },
+        "@vitest/browser-playwright": {
+          "optional": true
+        },
+        "@vitest/browser-preview": {
+          "optional": true
+        },
+        "@vitest/browser-webdriverio": {
+          "optional": true
+        },
+        "@vitest/ui": {
+          "optional": true
+        },
+        "happy-dom": {
+          "optional": true
+        },
+        "jsdom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vitest/node_modules/@vitest/mocker": {
+      "version": "4.0.18",
+      "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz",
+      "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@vitest/spy": "4.0.18",
+        "estree-walker": "^3.0.3",
+        "magic-string": "^0.30.21"
+      },
+      "funding": {
+        "url": "https://opencollective.com/vitest"
+      },
+      "peerDependencies": {
+        "msw": "^2.4.9",
+        "vite": "^6.0.0 || ^7.0.0-0"
+      },
+      "peerDependenciesMeta": {
+        "msw": {
+          "optional": true
+        },
+        "vite": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vitest/node_modules/vite": {
+      "version": "7.3.1",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
+      "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "esbuild": "^0.27.0",
+        "fdir": "^6.5.0",
+        "picomatch": "^4.0.3",
+        "postcss": "^8.5.6",
+        "rollup": "^4.43.0",
+        "tinyglobby": "^0.2.15"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^20.19.0 || >=22.12.0"
+      },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.3"
+      },
+      "peerDependencies": {
+        "@types/node": "^20.19.0 || >=22.12.0",
+        "jiti": ">=1.21.0",
+        "less": "^4.0.0",
+        "lightningcss": "^1.21.0",
+        "sass": "^1.70.0",
+        "sass-embedded": "^1.70.0",
+        "stylus": ">=0.54.8",
+        "sugarss": "^5.0.0",
+        "terser": "^5.16.0",
+        "tsx": "^4.8.1",
+        "yaml": "^2.4.2"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "jiti": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "lightningcss": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        },
+        "tsx": {
+          "optional": true
+        },
+        "yaml": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vitest/node_modules/yaml": {
+      "version": "2.8.2",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
+      "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
+      "dev": true,
+      "license": "ISC",
+      "optional": true,
+      "peer": true,
+      "bin": {
+        "yaml": "bin.mjs"
+      },
+      "engines": {
+        "node": ">= 14.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/eemeli"
+      }
+    },
     "node_modules/which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -11872,6 +13256,23 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/why-is-node-running": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
+      "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "siginfo": "^2.0.0",
+        "stackback": "0.0.2"
+      },
+      "bin": {
+        "why-is-node-running": "cli.js"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/widest-line": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz",
diff --git a/package.json b/package.json
index 90a51b333..3052c1324 100644
--- a/package.json
+++ b/package.json
@@ -19,9 +19,9 @@
   "scripts": {
     "build": "npm run build:lib && npm run build:cli && npm run build:assets",
     "build:lib": "tsc -p tsconfig.build.json",
-    "build:cli": "bun run bun.build.ts",
+    "build:cli": "node esbuild.config.mjs",
     "build:assets": "rsync -a --exclude='/AGENTS.md' src/assets/ dist/assets/",
-    "cli": "bun run src/cli/index.ts",
+    "cli": "npx tsx src/cli/index.ts",
     "typecheck": "tsc --noEmit",
     "lint": "eslint src/",
     "lint:fix": "eslint src/ --fix",
@@ -30,7 +30,9 @@
     "secrets:check": "secretlint '**/*'",
     "security:audit": "npm audit --audit-level=high",
     "clean": "rm -rf dist",
-    "prepare": "husky"
+    "prepare": "husky",
+    "test": "vitest run",
+    "test:watch": "vitest"
   },
   "dependencies": {
     "@aws-cdk/toolkit-lib": "^1.13.0",
@@ -61,13 +63,13 @@
     "@eslint/js": "^9.39.2",
     "@secretlint/secretlint-rule-preset-recommend": "^11.3.0",
     "@trivago/prettier-plugin-sort-imports": "6.0.0",
-    "@types/bun": "^1.2.14",
     "@types/node": "^25.0.3",
     "@types/react": "^19.2.7",
     "@typescript-eslint/eslint-plugin": "^8.50.0",
     "@typescript-eslint/parser": "^8.50.0",
     "aws-cdk-lib": "^2.234.1",
     "constructs": "^10.4.4",
+    "esbuild": "^0.27.2",
     "eslint": "^9.39.2",
     "eslint-config-prettier": "^10.1.8",
     "eslint-import-resolver-typescript": "^4.4.4",
@@ -80,8 +82,10 @@
     "lint-staged": "^16.2.7",
     "prettier": "^3.7.4",
     "secretlint": "^11.3.0",
+    "tsx": "^4.21.0",
     "typescript": "^5",
-    "typescript-eslint": "^8.50.1"
+    "typescript-eslint": "^8.50.1",
+    "vitest": "^4.0.18"
   },
   "engines": {
     "node": ">=20"
diff --git a/src/cli/__tests__/errors.test.ts b/src/cli/__tests__/errors.test.ts
new file mode 100644
index 000000000..341b28779
--- /dev/null
+++ b/src/cli/__tests__/errors.test.ts
@@ -0,0 +1,146 @@
+import { getErrorMessage, isExpiredTokenError, isNoCredentialsError, isStackInProgressError } from '../errors.js';
+import { describe, it , expect } from 'vitest';
+
+describe('errors', () => {
+  describe('getErrorMessage', () => {
+    it('returns message from Error instance', () => {
+      const err = new Error('test error');
+      expect(getErrorMessage(err)).toBe('test error');
+    });
+
+    it('returns string for non-Error values', () => {
+      expect(getErrorMessage('raw error')).toBe('raw error');
+      expect(getErrorMessage(123)).toBe('123');
+      expect(getErrorMessage(null)).toBe('null');
+      expect(getErrorMessage(undefined)).toBe('undefined');
+    });
+  });
+
+  describe('isExpiredTokenError', () => {
+    // Test ALL error codes in EXPIRED_TOKEN_ERROR_CODES via error.name
+    const allErrorCodes = [
+      'ExpiredToken',
+      'ExpiredTokenException',
+      'TokenRefreshRequired',
+      'CredentialsExpired',
+      'InvalidIdentityToken',
+      'UnauthorizedAccess',
+      'AccessDenied',
+      'AccessDeniedException',
+      'InvalidClientTokenId',
+      'SignatureDoesNotMatch',
+      'RequestExpired',
+    ];
+
+    it('returns true for all SDK v3 error names', () => {
+      for (const code of allErrorCodes) {
+        expect(isExpiredTokenError({ name: code }), `Should detect error.name: ${code}`).toBe(true);
+      }
+    });
+
+    it('returns true for all error Code properties', () => {
+      for (const code of allErrorCodes) {
+        expect(isExpiredTokenError({ Code: code }), `Should detect error.Code: ${code}`).toBe(true);
+      }
+    });
+
+    it('returns true for nested cause with error name', () => {
+      expect(isExpiredTokenError({ cause: { name: 'ExpiredToken' } })).toBe(true);
+    });
+
+    it('returns true for double-nested cause', () => {
+      expect(isExpiredTokenError({ cause: { cause: { name: 'ExpiredToken' } } })).toBe(true);
+    });
+
+    it('returns true for nested cause with Code', () => {
+      expect(isExpiredTokenError({ cause: { Code: 'AccessDenied' } })).toBe(true);
+    });
+
+    it('returns true for message patterns', () => {
+      const patterns = [
+        'expired token',
+        'token has expired',
+        'credentials have expired',
+        'security token included in the request is expired',
+        'the security token included in the request is invalid',
+      ];
+      for (const pattern of patterns) {
+        expect(isExpiredTokenError(new Error(pattern)), `Should detect message: ${pattern}`).toBe(true);
+      }
+    });
+
+    it('returns false for non-expired errors', () => {
+      expect(isExpiredTokenError({ name: 'ValidationError' })).toBe(false);
+      expect(isExpiredTokenError({ Code: 'ResourceNotFound' })).toBe(false);
+      expect(isExpiredTokenError(new Error('some other error'))).toBe(false);
+    });
+
+    it('returns false for edge cases', () => {
+      expect(isExpiredTokenError(null)).toBe(false);
+      expect(isExpiredTokenError(undefined)).toBe(false);
+      expect(isExpiredTokenError('string')).toBe(false);
+      expect(isExpiredTokenError(123)).toBe(false);
+      expect(isExpiredTokenError({})).toBe(false);
+      expect(isExpiredTokenError({ name: 123 })).toBe(false); // non-string name
+      expect(isExpiredTokenError({ Code: 123 })).toBe(false); // non-string Code
+    });
+  });
+
+  describe('isNoCredentialsError', () => {
+    it('returns true for AwsCredentialsError', () => {
+      expect(isNoCredentialsError({ name: 'AwsCredentialsError' })).toBe(true);
+    });
+
+    it('returns true for message patterns', () => {
+      const patterns = ['no aws credentials found', 'could not load credentials', 'credentials not found'];
+      for (const pattern of patterns) {
+        expect(isNoCredentialsError(new Error(pattern)), `Should detect message: ${pattern}`).toBe(true);
+      }
+    });
+
+    it('returns false for other errors', () => {
+      expect(isNoCredentialsError({ name: 'ExpiredTokenException' })).toBe(false);
+      expect(isNoCredentialsError(new Error('some other error'))).toBe(false);
+    });
+
+    it('returns false for edge cases', () => {
+      expect(isNoCredentialsError(null)).toBe(false);
+      expect(isNoCredentialsError(undefined)).toBe(false);
+      expect(isNoCredentialsError('string')).toBe(false);
+      expect(isNoCredentialsError(123)).toBe(false);
+      expect(isNoCredentialsError({})).toBe(false);
+    });
+  });
+
+  describe('isStackInProgressError', () => {
+    it('returns true for in-progress states', () => {
+      const states = ['UPDATE_IN_PROGRESS', 'CREATE_IN_PROGRESS', 'DELETE_IN_PROGRESS', 'ROLLBACK_IN_PROGRESS'];
+      for (const state of states) {
+        expect(isStackInProgressError(new Error(`Stack is in ${state} state`)), `Should detect state: ${state}`).toBe(
+          true
+        );
+      }
+    });
+
+    it('returns true for state and cannot be updated pattern', () => {
+      expect(
+        isStackInProgressError(new Error('Stack is in UPDATE_ROLLBACK_IN_PROGRESS state and cannot be updated'))
+      ).toBe(true);
+    });
+
+    it('returns true for currently being updated', () => {
+      expect(isStackInProgressError(new Error('stack is currently being updated'))).toBe(true);
+    });
+
+    it('returns false for other errors', () => {
+      expect(isStackInProgressError(new Error('Stack not found'))).toBe(false);
+      expect(isStackInProgressError(new Error('some other error'))).toBe(false);
+    });
+
+    it('returns false for edge cases', () => {
+      expect(isStackInProgressError(null)).toBe(false);
+      expect(isStackInProgressError(undefined)).toBe(false);
+      expect(isStackInProgressError({})).toBe(false);
+    });
+  });
+});
diff --git a/src/cli/aws/account.ts b/src/cli/aws/account.ts
index 986d3d5dc..44758e9e1 100644
--- a/src/cli/aws/account.ts
+++ b/src/cli/aws/account.ts
@@ -59,9 +59,7 @@ export async function detectAccount(): Promise<string | null> {
     if (code === 'ExpiredTokenException' || code === 'ExpiredToken') {
       throw new AwsCredentialsError(
         'AWS credentials expired.',
-        'AWS credentials expired.\n\n' +
-          'To fix this:\n' +
-          '  Run: aws login'
+        'AWS credentials expired.\n\n' + 'To fix this:\n' + '  Run: aws login'
       );
     }
 
diff --git a/src/cli/cli.ts b/src/cli/cli.ts
index e95ea77a8..cef57aad2 100644
--- a/src/cli/cli.ts
+++ b/src/cli/cli.ts
@@ -89,7 +89,7 @@ export function createProgram(): Command {
   // Custom help only for main program
   program.addHelpCommand(false); // Disable default help subcommand
   program.helpOption('-h, --help', 'Display help');
-  
+
   // Override help action for main program only
   program.on('option:help', () => {
     renderHelp(program);
diff --git a/src/cli/cloudformation/outputs.ts b/src/cli/cloudformation/outputs.ts
index d7be8ee47..d56aa0693 100644
--- a/src/cli/cloudformation/outputs.ts
+++ b/src/cli/cloudformation/outputs.ts
@@ -1,6 +1,6 @@
-import { toPascalId } from './logical-ids';
 import type { AgentCoreDeployedState, DeployedState, TargetDeployedState } from '../../schema';
 import { getCredentialProvider } from '../aws';
+import { toPascalId } from './logical-ids';
 import { getStackName } from './stack-discovery';
 import { CloudFormationClient, DescribeStacksCommand } from '@aws-sdk/client-cloudformation';
 
diff --git a/src/cli/commands/add/__tests__/add-agent.test.ts b/src/cli/commands/add/__tests__/add-agent.test.ts
new file mode 100644
index 000000000..b313dcedc
--- /dev/null
+++ b/src/cli/commands/add/__tests__/add-agent.test.ts
@@ -0,0 +1,273 @@
+import { exists, runCLI } from '../../../../test-utils/index.js';
+import { randomUUID } from 'node:crypto';
+import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+
+describe('add agent command', () => {
+  let testDir: string;
+  let projectDir: string;
+
+  beforeAll(async () => {
+    testDir = join(tmpdir(), `agentcore-add-agent-${randomUUID()}`);
+    await mkdir(testDir, { recursive: true });
+
+    // Create a project first
+    const projectName = 'TestProj';
+    const result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
+    }
+    projectDir = join(testDir, projectName);
+  });
+
+  afterAll(async () => {
+    await rm(testDir, { recursive: true, force: true });
+  });
+
+  describe('create path', () => {
+    it('creates agent with valid inputs', async () => {
+      const agentName = `Agent${Date.now()}`;
+      const result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          agentName,
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(json.agentName).toBe(agentName);
+
+      // Verify agent code exists
+      expect(await exists(join(projectDir, 'app', agentName)), 'Agent code should exist').toBeTruthy();
+
+      // Verify agent in agentcore.json
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentName);
+      expect(agent, 'Agent should be in agentcore.json').toBeTruthy();
+    });
+
+    it('requires all create path options', async () => {
+      const result = await runCLI(['add', 'agent', '--name', 'Incomplete', '--json'], projectDir);
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('required'), `Error should mention required: ${json.error}`).toBeTruthy();
+    });
+
+    it('validates framework', async () => {
+      const result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'BadFW',
+          '--language',
+          'Python',
+          '--framework',
+          'NotReal',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('Invalid framework'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('rejects TypeScript for create path', async () => {
+      const result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'TSAgent',
+          '--language',
+          'TypeScript',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('Python'), `Error should mention Python: ${json.error}`).toBeTruthy();
+    });
+
+    it('validates framework/model compatibility', async () => {
+      const result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'BadCombo',
+          '--language',
+          'Python',
+          '--framework',
+          'OpenAIAgents',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('does not support'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('rejects duplicate agent name', async () => {
+      const agentName = 'DupeAgent';
+
+      // First creation should succeed
+      const first = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          agentName,
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projectDir
+      );
+      expect(first.exitCode, `First should succeed: ${first.stdout}`).toBe(0);
+
+      // Second creation should fail
+      const second = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          agentName,
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(second.exitCode).toBe(1);
+      const json = JSON.parse(second.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('already exists'), `Error: ${json.error}`).toBeTruthy();
+    });
+  });
+
+  describe('BYO path', () => {
+    it('registers BYO agent', async () => {
+      const agentName = `ByoAgent${Date.now()}`;
+      const codeDir = 'existing-agent';
+
+      // Create existing code directory
+      await mkdir(join(projectDir, codeDir), { recursive: true });
+      await writeFile(join(projectDir, codeDir, 'main.py'), '# existing code\n');
+
+      const result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          agentName,
+          '--type',
+          'byo',
+          '--code-location',
+          codeDir,
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
+
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(json.agentName).toBe(agentName);
+
+      // Verify agent in agentcore.json with correct codeLocation
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentName);
+      expect(agent, 'Agent should be in agentcore.json').toBeTruthy();
+      expect(agent.runtime.codeLocation.includes(codeDir), `codeLocation should reference ${codeDir}`).toBeTruthy();
+    });
+
+    it('requires code-location for BYO path', async () => {
+      const result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'NoByo',
+          '--type',
+          'byo',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('code-location'), `Error: ${json.error}`).toBeTruthy();
+    });
+  });
+});
diff --git a/src/cli/commands/add/__tests__/add-gateway.test.ts b/src/cli/commands/add/__tests__/add-gateway.test.ts
new file mode 100644
index 000000000..fa20150f1
--- /dev/null
+++ b/src/cli/commands/add/__tests__/add-gateway.test.ts
@@ -0,0 +1,154 @@
+import { runCLI } from '../../../../test-utils/index.js';
+import { randomUUID } from 'node:crypto';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+
+describe('add gateway command', () => {
+  let testDir: string;
+  let projectDir: string;
+
+  beforeAll(async () => {
+    testDir = join(tmpdir(), `agentcore-add-gateway-${randomUUID()}`);
+    await mkdir(testDir, { recursive: true });
+
+    // Create a project first
+    const projectName = 'TestProj';
+    const result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
+    }
+    projectDir = join(testDir, projectName);
+  });
+
+  afterAll(async () => {
+    await rm(testDir, { recursive: true, force: true });
+  });
+
+  describe('basic gateway', () => {
+    it('creates gateway with default authorizer', async () => {
+      const gatewayName = `gw-${Date.now()}`;
+      const result = await runCLI(['add', 'gateway', '--name', gatewayName, '--json'], projectDir);
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(json.gatewayName).toBe(gatewayName);
+
+      // Verify gateway in mcp.json
+      const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8'));
+      const gateway = mcpSpec.agentCoreGateways.find((g: { name: string }) => g.name === gatewayName);
+      expect(gateway, 'Gateway should be in mcp.json').toBeTruthy();
+      expect(gateway.authorizerType).toBe('NONE');
+    });
+
+    it('requires name flag', async () => {
+      const result = await runCLI(['add', 'gateway', '--json'], projectDir);
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--name'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('validates gateway name format', async () => {
+      const result = await runCLI(['add', 'gateway', '--name', 'invalid name!', '--json'], projectDir);
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+    });
+
+    it('rejects duplicate gateway name', async () => {
+      const gatewayName = 'dup-gateway';
+
+      // First creation should succeed
+      const first = await runCLI(['add', 'gateway', '--name', gatewayName, '--json'], projectDir);
+      expect(first.exitCode, `First should succeed: ${first.stdout}`).toBe(0);
+
+      // Second creation should fail
+      const second = await runCLI(['add', 'gateway', '--name', gatewayName, '--json'], projectDir);
+
+      expect(second.exitCode).toBe(1);
+      const json = JSON.parse(second.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('already exists'), `Error: ${json.error}`).toBeTruthy();
+    });
+  });
+
+  describe('JWT authorizer', () => {
+    it('creates gateway with CUSTOM_JWT authorizer', async () => {
+      const gatewayName = `jwt-gw-${Date.now()}`;
+      const result = await runCLI(
+        [
+          'add',
+          'gateway',
+          '--name',
+          gatewayName,
+          '--authorizer-type',
+          'CUSTOM_JWT',
+          '--discovery-url',
+          'https://example.com/.well-known/openid-configuration',
+          '--allowed-audience',
+          'aud1,aud2',
+          '--allowed-clients',
+          'client1',
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
+
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+
+      // Verify JWT config in mcp.json
+      const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8'));
+      const gateway = mcpSpec.agentCoreGateways.find((g: { name: string }) => g.name === gatewayName);
+      expect(gateway, 'Gateway should be in mcp.json').toBeTruthy();
+      expect(gateway.authorizerType).toBe('CUSTOM_JWT');
+      expect(gateway.authorizerConfiguration?.customJwtAuthorizer, 'Should have JWT config').toBeTruthy();
+    });
+
+    it('requires JWT fields when CUSTOM_JWT', async () => {
+      const result = await runCLI(
+        ['add', 'gateway', '--name', 'no-jwt', '--authorizer-type', 'CUSTOM_JWT', '--json'],
+        projectDir
+      );
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('discovery-url'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('validates discovery URL format', async () => {
+      const result = await runCLI(
+        [
+          'add',
+          'gateway',
+          '--name',
+          'bad-url',
+          '--authorizer-type',
+          'CUSTOM_JWT',
+          '--discovery-url',
+          'https://example.com/wrong',
+          '--allowed-audience',
+          'aud',
+          '--allowed-clients',
+          'client',
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('well-known'), `Error: ${json.error}`).toBeTruthy();
+    });
+  });
+});
diff --git a/src/cli/commands/add/__tests__/add-identity.test.ts b/src/cli/commands/add/__tests__/add-identity.test.ts
new file mode 100644
index 000000000..5eebfb0c9
--- /dev/null
+++ b/src/cli/commands/add/__tests__/add-identity.test.ts
@@ -0,0 +1,200 @@
+import { runCLI } from '../../../../test-utils/index.js';
+import { randomUUID } from 'node:crypto';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+
+describe('add identity command', () => {
+  let testDir: string;
+  let projectDir: string;
+  const ownerAgent = 'OwnerAgent';
+  const userAgent = 'UserAgent';
+
+  beforeAll(async () => {
+    testDir = join(tmpdir(), `agentcore-add-identity-${randomUUID()}`);
+    await mkdir(testDir, { recursive: true });
+
+    // Create project
+    const projectName = 'IdentityProj';
+    let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
+    }
+    projectDir = join(testDir, projectName);
+
+    // Add owner agent
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        ownerAgent,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create owner agent: ${result.stdout} ${result.stderr}`);
+    }
+
+    // Add user agent
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        userAgent,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create user agent: ${result.stdout} ${result.stderr}`);
+    }
+  });
+
+  afterAll(async () => {
+    await rm(testDir, { recursive: true, force: true });
+  });
+
+  describe('validation', () => {
+    it('requires name flag', async () => {
+      const result = await runCLI(['add', 'identity', '--json'], projectDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--name'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('requires type flag', async () => {
+      const result = await runCLI(['add', 'identity', '--name', 'test', '--json'], projectDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--type'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('validates type value', async () => {
+      const result = await runCLI(
+        ['add', 'identity', '--name', 'test', '--type', 'Invalid', '--api-key', 'xxx', '--owner', ownerAgent, '--json'],
+        projectDir
+      );
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('ApiKeyCredentialProvider'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('requires api-key flag', async () => {
+      const result = await runCLI(
+        ['add', 'identity', '--name', 'test', '--type', 'ApiKeyCredentialProvider', '--json'],
+        projectDir
+      );
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--api-key'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('requires owner flag', async () => {
+      const result = await runCLI(
+        ['add', 'identity', '--name', 'test', '--type', 'ApiKeyCredentialProvider', '--api-key', 'xxx', '--json'],
+        projectDir
+      );
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--owner'), `Error: ${json.error}`).toBeTruthy();
+    });
+  });
+
+  describe('identity creation', () => {
+    it('creates identity with owner', async () => {
+      const identityName = `id${Date.now()}`;
+      const result = await runCLI(
+        [
+          'add',
+          'identity',
+          '--name',
+          identityName,
+          '--type',
+          'ApiKeyCredentialProvider',
+          '--api-key',
+          'test-key-123',
+          '--owner',
+          ownerAgent,
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(json.identityName).toBe(identityName);
+      expect(json.ownerAgent).toBe(ownerAgent);
+
+      // Verify in agentcore.json
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const agent = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
+      const identity = agent?.identityProviders?.find((i: { name: string }) => i.name === identityName);
+      expect(identity, 'Identity should be on owner agent').toBeTruthy();
+      expect(identity.relation).toBe('own');
+    });
+
+    it('creates identity with owner and users', async () => {
+      const identityName = `shared${Date.now()}`;
+      const result = await runCLI(
+        [
+          'add',
+          'identity',
+          '--name',
+          identityName,
+          '--type',
+          'ApiKeyCredentialProvider',
+          '--api-key',
+          'shared-key-456',
+          '--owner',
+          ownerAgent,
+          '--users',
+          userAgent,
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(json.userAgents).toEqual([userAgent]);
+
+      // Verify relations
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+
+      const owner = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
+      const ownerIdentity = owner?.identityProviders?.find((i: { name: string }) => i.name === identityName);
+      expect(ownerIdentity?.relation).toBe('own');
+
+      const user = projectSpec.agents.find((a: { name: string }) => a.name === userAgent);
+      const userIdentity = user?.identityProviders?.find((i: { name: string }) => i.name === identityName);
+      expect(userIdentity?.relation).toBe('use');
+    });
+  });
+});
diff --git a/src/cli/commands/add/__tests__/add-mcp-tool.test.ts b/src/cli/commands/add/__tests__/add-mcp-tool.test.ts
new file mode 100644
index 000000000..56cf9918e
--- /dev/null
+++ b/src/cli/commands/add/__tests__/add-mcp-tool.test.ts
@@ -0,0 +1,311 @@
+import { runCLI } from '../../../../test-utils/index.js';
+import { randomUUID } from 'node:crypto';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+
+describe('add mcp-tool command', () => {
+  let testDir: string;
+  let projectDir: string;
+  const agentName = 'TestAgent';
+  const gatewayName = 'test-gateway';
+
+  beforeAll(async () => {
+    testDir = join(tmpdir(), `agentcore-add-mcp-tool-${randomUUID()}`);
+    await mkdir(testDir, { recursive: true });
+
+    // Create project with agent
+    const projectName = 'McpToolProj';
+    let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
+    }
+    projectDir = join(testDir, projectName);
+
+    // Add agent for mcp-runtime tests
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        agentName,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create agent: ${result.stdout} ${result.stderr}`);
+    }
+
+    // Add gateway for behind-gateway tests
+    result = await runCLI(['add', 'gateway', '--name', gatewayName, '--json'], projectDir);
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create gateway: ${result.stdout} ${result.stderr}`);
+    }
+  });
+
+  afterAll(async () => {
+    await rm(testDir, { recursive: true, force: true });
+  });
+
+  describe('validation', () => {
+    it('requires name flag', async () => {
+      const result = await runCLI(['add', 'mcp-tool', '--json'], projectDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--name'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('requires exposure flag', async () => {
+      const result = await runCLI(['add', 'mcp-tool', '--name', 'test', '--language', 'Python', '--json'], projectDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--exposure'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('validates language', async () => {
+      const result = await runCLI(
+        [
+          'add',
+          'mcp-tool',
+          '--name',
+          'test',
+          '--language',
+          'InvalidLang',
+          '--exposure',
+          'mcp-runtime',
+          '--agents',
+          agentName,
+          '--json',
+        ],
+        projectDir
+      );
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(
+        json.error.toLowerCase().includes('invalid') || json.error.toLowerCase().includes('valid options'),
+        `Error should mention invalid language: ${json.error}`
+      ).toBeTruthy();
+    });
+
+    it('accepts Other as valid language option', async () => {
+      const result = await runCLI(
+        [
+          'add',
+          'mcp-tool',
+          '--name',
+          'container-tool',
+          '--language',
+          'Other',
+          '--exposure',
+          'mcp-runtime',
+          '--agents',
+          agentName,
+          '--json',
+        ],
+        projectDir
+      );
+
+      // Should fail with "not yet supported" error, not validation error
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(
+        json.error.toLowerCase().includes('not yet supported') || json.error.toLowerCase().includes('other'),
+        `Error should mention Other not supported: ${json.error}`
+      ).toBeTruthy();
+    });
+  });
+
+  describe('mcp-runtime', () => {
+    it('creates mcp-runtime tool', async () => {
+      const toolName = `rttool${Date.now()}`;
+      const result = await runCLI(
+        [
+          'add',
+          'mcp-tool',
+          '--name',
+          toolName,
+          '--language',
+          'Python',
+          '--exposure',
+          'mcp-runtime',
+          '--agents',
+          agentName,
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(json.toolName).toBe(toolName);
+
+      // Verify in mcp.json
+      const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8'));
+      const tool = mcpSpec.mcpRuntimeTools?.find((t: { name: string }) => t.name === toolName);
+      expect(tool, 'Tool should be in mcpRuntimeTools').toBeTruthy();
+
+      // Verify agent has remote tool reference
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentName);
+      const hasRef = agent?.remoteTools?.some((rt: { mcpRuntimeName?: string }) => rt.mcpRuntimeName === toolName);
+      expect(hasRef, 'Agent should have remoteTools reference').toBeTruthy();
+    });
+
+    it('requires agents for mcp-runtime', async () => {
+      const result = await runCLI(
+        ['add', 'mcp-tool', '--name', 'no-agents', '--language', 'Python', '--exposure', 'mcp-runtime', '--json'],
+        projectDir
+      );
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--agents'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('returns clear error for Other language with mcp-runtime', async () => {
+      const result = await runCLI(
+        [
+          'add',
+          'mcp-tool',
+          '--name',
+          'runtime-container',
+          '--language',
+          'Other',
+          '--exposure',
+          'mcp-runtime',
+          '--agents',
+          agentName,
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.length > 0, 'Should have error message').toBeTruthy();
+    });
+  });
+
+  describe('behind-gateway', () => {
+    it('creates behind-gateway tool', async () => {
+      const toolName = `gwtool${Date.now()}`;
+      const result = await runCLI(
+        [
+          'add',
+          'mcp-tool',
+          '--name',
+          toolName,
+          '--language',
+          'Python',
+          '--exposure',
+          'behind-gateway',
+          '--gateway',
+          gatewayName,
+          '--host',
+          'Lambda',
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(json.toolName).toBe(toolName);
+
+      // Verify in mcp.json gateway targets
+      const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8'));
+      const gateway = mcpSpec.agentCoreGateways.find((g: { name: string }) => g.name === gatewayName);
+      const target = gateway?.targets?.find((t: { name: string }) => t.name === toolName);
+      expect(target, 'Tool should be in gateway targets').toBeTruthy();
+    });
+
+    it('requires gateway for behind-gateway', async () => {
+      const result = await runCLI(
+        [
+          'add',
+          'mcp-tool',
+          '--name',
+          'no-gw',
+          '--language',
+          'Python',
+          '--exposure',
+          'behind-gateway',
+          '--host',
+          'Lambda',
+          '--json',
+        ],
+        projectDir
+      );
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--gateway'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('requires host for behind-gateway', async () => {
+      const result = await runCLI(
+        [
+          'add',
+          'mcp-tool',
+          '--name',
+          'no-host',
+          '--language',
+          'Python',
+          '--exposure',
+          'behind-gateway',
+          '--gateway',
+          gatewayName,
+          '--json',
+        ],
+        projectDir
+      );
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--host'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('returns clear error for Other language with behind-gateway', async () => {
+      const result = await runCLI(
+        [
+          'add',
+          'mcp-tool',
+          '--name',
+          'gateway-container',
+          '--language',
+          'Other',
+          '--exposure',
+          'behind-gateway',
+          '--gateway',
+          gatewayName,
+          '--host',
+          'Lambda',
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.length > 0, 'Should have error message').toBeTruthy();
+    });
+  });
+});
diff --git a/src/cli/commands/add/__tests__/add-memory.test.ts b/src/cli/commands/add/__tests__/add-memory.test.ts
new file mode 100644
index 000000000..be58d7c5c
--- /dev/null
+++ b/src/cli/commands/add/__tests__/add-memory.test.ts
@@ -0,0 +1,231 @@
+import { runCLI } from '../../../../test-utils/index.js';
+import { randomUUID } from 'node:crypto';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+
+describe('add memory command', () => {
+  let testDir: string;
+  let projectDir: string;
+  const ownerAgent = 'OwnerAgent';
+  const userAgent = 'UserAgent';
+
+  beforeAll(async () => {
+    testDir = join(tmpdir(), `agentcore-add-memory-${randomUUID()}`);
+    await mkdir(testDir, { recursive: true });
+
+    // Create project
+    const projectName = 'MemoryProj';
+    let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
+    }
+    projectDir = join(testDir, projectName);
+
+    // Add owner agent
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        ownerAgent,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create owner agent: ${result.stdout} ${result.stderr}`);
+    }
+
+    // Add user agent
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        userAgent,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create user agent: ${result.stdout} ${result.stderr}`);
+    }
+  });
+
+  afterAll(async () => {
+    await rm(testDir, { recursive: true, force: true });
+  });
+
+  describe('validation', () => {
+    it('requires name flag', async () => {
+      const result = await runCLI(['add', 'memory', '--json'], projectDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--name'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('requires strategies flag', async () => {
+      const result = await runCLI(['add', 'memory', '--name', 'test', '--json'], projectDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--strategies'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('requires owner flag', async () => {
+      const result = await runCLI(
+        ['add', 'memory', '--name', 'test', '--strategies', 'SEMANTIC', '--json'],
+        projectDir
+      );
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--owner'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('validates strategy types', async () => {
+      const result = await runCLI(
+        ['add', 'memory', '--name', 'test', '--strategies', 'INVALID', '--owner', ownerAgent, '--json'],
+        projectDir
+      );
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('INVALID'), `Error: ${json.error}`).toBeTruthy();
+    });
+  });
+
+  describe('memory creation', () => {
+    it('creates memory with owner', async () => {
+      const memoryName = `mem${Date.now()}`;
+      const result = await runCLI(
+        ['add', 'memory', '--name', memoryName, '--strategies', 'SEMANTIC', '--owner', ownerAgent, '--json'],
+        projectDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(json.memoryName).toBe(memoryName);
+      expect(json.ownerAgent).toBe(ownerAgent);
+
+      // Verify in agentcore.json
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const agent = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
+      const memory = agent?.memoryProviders?.find((m: { name: string }) => m.name === memoryName);
+      expect(memory, 'Memory should be on owner agent').toBeTruthy();
+      expect(memory.relation).toBe('own');
+    });
+
+    it('creates memory with owner and users', async () => {
+      const memoryName = `shared${Date.now()}`;
+      const result = await runCLI(
+        [
+          'add',
+          'memory',
+          '--name',
+          memoryName,
+          '--strategies',
+          'SUMMARIZATION',
+          '--owner',
+          ownerAgent,
+          '--users',
+          userAgent,
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(json.userAgents).toEqual([userAgent]);
+
+      // Verify relations
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+
+      const owner = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
+      const ownerMem = owner?.memoryProviders?.find((m: { name: string }) => m.name === memoryName);
+      expect(ownerMem?.relation).toBe('own');
+
+      const user = projectSpec.agents.find((a: { name: string }) => a.name === userAgent);
+      const userMem = user?.memoryProviders?.find((m: { name: string }) => m.name === memoryName);
+      expect(userMem?.relation).toBe('use');
+    });
+
+    it('creates memory with multiple strategies', async () => {
+      const memoryName = `multi${Date.now()}`;
+      const result = await runCLI(
+        [
+          'add',
+          'memory',
+          '--name',
+          memoryName,
+          '--strategies',
+          'SEMANTIC,SUMMARIZATION',
+          '--owner',
+          ownerAgent,
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+
+      // Verify strategies
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const agent = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
+      const memory = agent?.memoryProviders?.find((m: { name: string }) => m.name === memoryName);
+      const strategies = memory?.config?.memoryStrategies?.map((s: { type: string }) => s.type);
+      expect(strategies?.includes('SEMANTIC'), 'Should have SEMANTIC').toBeTruthy();
+      expect(strategies?.includes('SUMMARIZATION'), 'Should have SUMMARIZATION').toBeTruthy();
+    });
+
+    it('creates memory with custom expiry', async () => {
+      const memoryName = `expiry${Date.now()}`;
+      const result = await runCLI(
+        [
+          'add',
+          'memory',
+          '--name',
+          memoryName,
+          '--strategies',
+          'SEMANTIC',
+          '--owner',
+          ownerAgent,
+          '--expiry',
+          '90',
+          '--json',
+        ],
+        projectDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+
+      // Verify expiry
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const agent = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
+      const memory = agent?.memoryProviders?.find((m: { name: string }) => m.name === memoryName);
+      expect(memory?.config?.eventExpiryDuration).toBe(90);
+    });
+  });
+});
diff --git a/src/cli/commands/add/__tests__/add-target.test.ts b/src/cli/commands/add/__tests__/add-target.test.ts
new file mode 100644
index 000000000..b0aa23378
--- /dev/null
+++ b/src/cli/commands/add/__tests__/add-target.test.ts
@@ -0,0 +1,104 @@
+import { runCLI } from '../../../../test-utils/index.js';
+import { randomUUID } from 'node:crypto';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+
+describe('add target command', () => {
+  let testDir: string;
+  let projectDir: string;
+
+  beforeAll(async () => {
+    testDir = join(tmpdir(), `agentcore-add-target-${randomUUID()}`);
+    await mkdir(testDir, { recursive: true });
+
+    // Create a project first
+    const projectName = 'TestProj';
+    const result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
+    }
+    projectDir = join(testDir, projectName);
+  });
+
+  afterAll(async () => {
+    await rm(testDir, { recursive: true, force: true });
+  });
+
+  it('adds target with valid inputs', async () => {
+    const result = await runCLI(
+      ['add', 'target', '--name', 'dev', '--account', '123456789012', '--region', 'us-east-1', '--json'],
+      projectDir
+    );
+
+    expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
+
+    const json = JSON.parse(result.stdout);
+    expect(json.success).toBe(true);
+
+    // Verify target in file
+    const targets = JSON.parse(await readFile(join(projectDir, 'agentcore/aws-targets.json'), 'utf-8'));
+    expect(targets.length).toBe(1);
+    expect(targets[0].name).toBe('dev');
+  });
+
+  it('rejects duplicate target name', async () => {
+    const result = await runCLI(
+      ['add', 'target', '--name', 'dev', '--account', '123456789012', '--region', 'us-west-2', '--json'],
+      projectDir
+    );
+
+    expect(result.exitCode).toBe(1);
+
+    const json = JSON.parse(result.stdout);
+    expect(json.success).toBe(false);
+    expect(json.error.includes('already exists')).toBeTruthy();
+  });
+
+  it('rejects invalid account ID', async () => {
+    const result = await runCLI(
+      ['add', 'target', '--name', 'prod', '--account', 'invalid', '--region', 'us-east-1', '--json'],
+      projectDir
+    );
+
+    expect(result.exitCode).toBe(1);
+
+    const json = JSON.parse(result.stdout);
+    expect(json.success).toBe(false);
+    expect(json.error.includes('12 digits')).toBeTruthy();
+  });
+
+  it('rejects invalid region name', async () => {
+    const result = await runCLI(
+      [
+        'add',
+        'target',
+        '--name',
+        'invalid-region-target',
+        '--account',
+        '123456789012',
+        '--region',
+        'invalid-region-123',
+        '--json',
+      ],
+      projectDir
+    );
+
+    expect(result.exitCode).toBe(1);
+
+    const json = JSON.parse(result.stdout);
+    expect(json.success).toBe(false);
+    expect(json.error.toLowerCase().includes('region'), `Expected region error, got: ${json.error}`).toBeTruthy();
+  });
+
+  it('requires all flags', async () => {
+    const result = await runCLI(['add', 'target', '--name', 'staging', '--json'], projectDir);
+
+    expect(result.exitCode).toBe(1);
+
+    const json = JSON.parse(result.stdout);
+    expect(json.success).toBe(false);
+    expect(json.error.includes('Required')).toBeTruthy();
+  });
+});
diff --git a/src/cli/commands/add/validate.test.ts b/src/cli/commands/add/__tests__/validate.test.ts
similarity index 65%
rename from src/cli/commands/add/validate.test.ts
rename to src/cli/commands/add/__tests__/validate.test.ts
index e0847eb64..ae8881d17 100644
--- a/src/cli/commands/add/validate.test.ts
+++ b/src/cli/commands/add/__tests__/validate.test.ts
@@ -1,19 +1,18 @@
-import { describe, it } from 'bun:test';
-import assert from 'node:assert';
-import {
-  validateAddAgentOptions,
-  validateAddGatewayOptions,
-  validateAddMcpToolOptions,
-  validateAddMemoryOptions,
-  validateAddIdentityOptions,
-} from './validate.js';
 import type {
   AddAgentOptions,
   AddGatewayOptions,
+  AddIdentityOptions,
   AddMcpToolOptions,
   AddMemoryOptions,
-  AddIdentityOptions,
 } from './types.js';
+import {
+  validateAddAgentOptions,
+  validateAddGatewayOptions,
+  validateAddIdentityOptions,
+  validateAddMcpToolOptions,
+  validateAddMemoryOptions,
+} from './validate.js';
+import { describe, it , expect } from 'vitest';
 
 // Helper: valid base options for each type
 const validAgentOptionsByo: AddAgentOptions = {
@@ -79,7 +78,7 @@ describe('validate', () => {
   describe('validateAddAgentOptions', () => {
     // AC1: All required fields validated
     it('returns error for missing required fields', () => {
-      const requiredFields: Array<{ field: keyof AddAgentOptions; error: string }> = [
+      const requiredFields: { field: keyof AddAgentOptions; error: string }[] = [
         { field: 'name', error: '--name is required' },
         { field: 'framework', error: '--framework is required' },
         { field: 'modelProvider', error: '--model-provider is required' },
@@ -89,8 +88,8 @@ describe('validate', () => {
       for (const { field, error } of requiredFields) {
         const opts = { ...validAgentOptionsByo, [field]: undefined };
         const result = validateAddAgentOptions(opts);
-        assert.strictEqual(result.valid, false, `Should fail for missing ${field}`);
-        assert.strictEqual(result.error, error);
+        expect(result.valid, `Should fail for missing ${field}`).toBe(false);
+        expect(result.error).toBe(error);
       }
     });
 
@@ -98,23 +97,23 @@ describe('validate', () => {
     it('returns error for invalid schema values', () => {
       // Invalid name
       let result = validateAddAgentOptions({ ...validAgentOptionsByo, name: '123invalid' });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('begin with') || result.error?.includes('letter'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('begin with') || result.error?.includes('letter')).toBeTruthy();
 
       // Invalid framework
       result = validateAddAgentOptions({ ...validAgentOptionsByo, framework: 'InvalidFW' as any });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('Invalid framework'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('Invalid framework')).toBeTruthy();
 
       // Invalid modelProvider
       result = validateAddAgentOptions({ ...validAgentOptionsByo, modelProvider: 'InvalidMP' as any });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('Invalid model provider'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('Invalid model provider')).toBeTruthy();
 
       // Invalid language
       result = validateAddAgentOptions({ ...validAgentOptionsByo, language: 'InvalidLang' as any });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('Invalid language'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('Invalid language')).toBeTruthy();
     });
 
     // AC3: Framework/model provider compatibility
@@ -124,8 +123,8 @@ describe('validate', () => {
         framework: 'GoogleADK',
         modelProvider: 'Bedrock',
       });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('does not support'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('does not support')).toBeTruthy();
     });
 
     // AC4: BYO path requires codeLocation
@@ -135,36 +134,36 @@ describe('validate', () => {
         type: 'byo',
         codeLocation: undefined,
       });
-      assert.strictEqual(result.valid, false);
-      assert.strictEqual(result.error, '--code-location is required for BYO path');
+      expect(result.valid).toBe(false);
+      expect(result.error).toBe('--code-location is required for BYO path');
     });
 
     // AC5: Create path language restrictions
     it('returns error for create path with TypeScript or Other', () => {
       let result = validateAddAgentOptions({ ...validAgentOptionsCreate, language: 'TypeScript' });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('Python'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('Python')).toBeTruthy();
 
       result = validateAddAgentOptions({ ...validAgentOptionsCreate, language: 'Other' });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('Python'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('Python')).toBeTruthy();
     });
 
     // AC6: Create path requires memory
     it('returns error for create path without memory or invalid memory', () => {
       let result = validateAddAgentOptions({ ...validAgentOptionsCreate, memory: undefined });
-      assert.strictEqual(result.valid, false);
-      assert.strictEqual(result.error, '--memory is required for create path');
+      expect(result.valid).toBe(false);
+      expect(result.error).toBe('--memory is required for create path');
 
       result = validateAddAgentOptions({ ...validAgentOptionsCreate, memory: 'invalid' as any });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('Invalid memory option'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('Invalid memory option')).toBeTruthy();
     });
 
     // AC7: Valid options pass
     it('passes for valid options', () => {
-      assert.deepStrictEqual(validateAddAgentOptions(validAgentOptionsByo), { valid: true });
-      assert.deepStrictEqual(validateAddAgentOptions(validAgentOptionsCreate), { valid: true });
+      expect(validateAddAgentOptions(validAgentOptionsByo)).toEqual({ valid: true });
+      expect(validateAddAgentOptions(validAgentOptionsCreate)).toEqual({ valid: true });
     });
   });
 
@@ -172,27 +171,27 @@ describe('validate', () => {
     // AC8: Required fields validated
     it('returns error for missing name', () => {
       const result = validateAddGatewayOptions({ ...validGatewayOptionsNone, name: undefined });
-      assert.strictEqual(result.valid, false);
-      assert.strictEqual(result.error, '--name is required');
+      expect(result.valid).toBe(false);
+      expect(result.error).toBe('--name is required');
     });
 
     // AC9: Invalid name rejected
     it('returns error for invalid gateway name', () => {
       const result = validateAddGatewayOptions({ ...validGatewayOptionsNone, name: 'INVALID_NAME!' });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error);
+      expect(result.valid).toBe(false);
+      expect(result.error).toBeTruthy();
     });
 
     // AC10: Invalid authorizerType rejected
     it('returns error for invalid authorizerType', () => {
       const result = validateAddGatewayOptions({ ...validGatewayOptionsNone, authorizerType: 'INVALID' as any });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('Invalid authorizer type'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('Invalid authorizer type')).toBeTruthy();
     });
 
     // AC11: CUSTOM_JWT requires all fields
     it('returns error for CUSTOM_JWT missing required fields', () => {
-      const jwtFields: Array<{ field: keyof AddGatewayOptions; error: string }> = [
+      const jwtFields: { field: keyof AddGatewayOptions; error: string }[] = [
         { field: 'discoveryUrl', error: '--discovery-url is required for CUSTOM_JWT authorizer' },
         { field: 'allowedAudience', error: '--allowed-audience is required for CUSTOM_JWT authorizer' },
         { field: 'allowedClients', error: '--allowed-clients is required for CUSTOM_JWT authorizer' },
@@ -201,8 +200,8 @@ describe('validate', () => {
       for (const { field, error } of jwtFields) {
         const opts = { ...validGatewayOptionsJwt, [field]: undefined };
         const result = validateAddGatewayOptions(opts);
-        assert.strictEqual(result.valid, false, `Should fail for missing ${field}`);
-        assert.strictEqual(result.error, error);
+        expect(result.valid, `Should fail for missing ${field}`).toBe(false);
+        expect(result.error).toBe(error);
       }
     });
 
@@ -210,37 +209,37 @@ describe('validate', () => {
     it('returns error for invalid discoveryUrl', () => {
       // Invalid URL format
       let result = validateAddGatewayOptions({ ...validGatewayOptionsJwt, discoveryUrl: 'not-a-url' });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('valid URL'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('valid URL')).toBeTruthy();
 
       // Missing well-known suffix
       result = validateAddGatewayOptions({ ...validGatewayOptionsJwt, discoveryUrl: 'https://example.com/oauth' });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('.well-known/openid-configuration'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('.well-known/openid-configuration')).toBeTruthy();
     });
 
     // AC13: Empty comma-separated values rejected
     it('returns error for empty audience or clients', () => {
       let result = validateAddGatewayOptions({ ...validGatewayOptionsJwt, allowedAudience: ',,,' });
-      assert.strictEqual(result.valid, false);
-      assert.strictEqual(result.error, 'At least one audience value is required');
+      expect(result.valid).toBe(false);
+      expect(result.error).toBe('At least one audience value is required');
 
       result = validateAddGatewayOptions({ ...validGatewayOptionsJwt, allowedClients: '  ,  ' });
-      assert.strictEqual(result.valid, false);
-      assert.strictEqual(result.error, 'At least one client value is required');
+      expect(result.valid).toBe(false);
+      expect(result.error).toBe('At least one client value is required');
     });
 
     // AC14: Valid options pass
     it('passes for valid options', () => {
-      assert.deepStrictEqual(validateAddGatewayOptions(validGatewayOptionsNone), { valid: true });
-      assert.deepStrictEqual(validateAddGatewayOptions(validGatewayOptionsJwt), { valid: true });
+      expect(validateAddGatewayOptions(validGatewayOptionsNone)).toEqual({ valid: true });
+      expect(validateAddGatewayOptions(validGatewayOptionsJwt)).toEqual({ valid: true });
     });
   });
 
   describe('validateAddMcpToolOptions', () => {
     // AC15: Required fields validated
     it('returns error for missing required fields', () => {
-      const requiredFields: Array<{ field: keyof AddMcpToolOptions; error: string }> = [
+      const requiredFields: { field: keyof AddMcpToolOptions; error: string }[] = [
         { field: 'name', error: '--name is required' },
         { field: 'language', error: '--language is required' },
         { field: 'exposure', error: '--exposure is required' },
@@ -249,59 +248,59 @@ describe('validate', () => {
       for (const { field, error } of requiredFields) {
         const opts = { ...validMcpToolOptionsMcpRuntime, [field]: undefined };
         const result = validateAddMcpToolOptions(opts);
-        assert.strictEqual(result.valid, false, `Should fail for missing ${field}`);
-        assert.strictEqual(result.error, error);
+        expect(result.valid, `Should fail for missing ${field}`).toBe(false);
+        expect(result.error).toBe(error);
       }
     });
 
     // AC16: Invalid values rejected
     it('returns error for invalid values', () => {
       let result = validateAddMcpToolOptions({ ...validMcpToolOptionsMcpRuntime, language: 'Java' as any });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('Invalid language'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('Invalid language')).toBeTruthy();
 
       result = validateAddMcpToolOptions({ ...validMcpToolOptionsMcpRuntime, exposure: 'invalid' as any });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('Invalid exposure'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('Invalid exposure')).toBeTruthy();
     });
 
     // AC17: mcp-runtime exposure requires agents
     it('returns error for mcp-runtime without agents', () => {
       let result = validateAddMcpToolOptions({ ...validMcpToolOptionsMcpRuntime, agents: undefined });
-      assert.strictEqual(result.valid, false);
-      assert.strictEqual(result.error, '--agents is required for mcp-runtime exposure');
+      expect(result.valid).toBe(false);
+      expect(result.error).toBe('--agents is required for mcp-runtime exposure');
 
       result = validateAddMcpToolOptions({ ...validMcpToolOptionsMcpRuntime, agents: ',,,' });
-      assert.strictEqual(result.valid, false);
-      assert.strictEqual(result.error, 'At least one agent is required');
+      expect(result.valid).toBe(false);
+      expect(result.error).toBe('At least one agent is required');
     });
 
     // AC18: behind-gateway exposure requires gateway and host
     it('returns error for behind-gateway missing gateway, host, or invalid host', () => {
       let result = validateAddMcpToolOptions({ ...validMcpToolOptionsBehindGateway, gateway: undefined });
-      assert.strictEqual(result.valid, false);
-      assert.strictEqual(result.error, '--gateway is required for behind-gateway exposure');
+      expect(result.valid).toBe(false);
+      expect(result.error).toBe('--gateway is required for behind-gateway exposure');
 
       result = validateAddMcpToolOptions({ ...validMcpToolOptionsBehindGateway, host: undefined });
-      assert.strictEqual(result.valid, false);
-      assert.strictEqual(result.error, '--host is required for behind-gateway exposure');
+      expect(result.valid).toBe(false);
+      expect(result.error).toBe('--host is required for behind-gateway exposure');
 
       result = validateAddMcpToolOptions({ ...validMcpToolOptionsBehindGateway, host: 'InvalidHost' as any });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('Invalid host'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('Invalid host')).toBeTruthy();
     });
 
     // AC19: Valid options pass
     it('passes for valid options', () => {
-      assert.deepStrictEqual(validateAddMcpToolOptions(validMcpToolOptionsMcpRuntime), { valid: true });
-      assert.deepStrictEqual(validateAddMcpToolOptions(validMcpToolOptionsBehindGateway), { valid: true });
+      expect(validateAddMcpToolOptions(validMcpToolOptionsMcpRuntime)).toEqual({ valid: true });
+      expect(validateAddMcpToolOptions(validMcpToolOptionsBehindGateway)).toEqual({ valid: true });
     });
   });
 
   describe('validateAddMemoryOptions', () => {
     // AC20: Required fields validated
     it('returns error for missing required fields', () => {
-      const requiredFields: Array<{ field: keyof AddMemoryOptions; error: string }> = [
+      const requiredFields: { field: keyof AddMemoryOptions; error: string }[] = [
         { field: 'name', error: '--name is required' },
         { field: 'strategies', error: '--strategies is required' },
         { field: 'owner', error: '--owner is required' },
@@ -310,38 +309,37 @@ describe('validate', () => {
       for (const { field, error } of requiredFields) {
         const opts = { ...validMemoryOptions, [field]: undefined };
         const result = validateAddMemoryOptions(opts);
-        assert.strictEqual(result.valid, false, `Should fail for missing ${field}`);
-        assert.strictEqual(result.error, error);
+        expect(result.valid, `Should fail for missing ${field}`).toBe(false);
+        expect(result.error).toBe(error);
       }
     });
 
     // AC21: Invalid/empty strategies rejected
     it('returns error for invalid or empty strategies', () => {
       let result = validateAddMemoryOptions({ ...validMemoryOptions, strategies: 'INVALID' });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('Invalid strategy'));
-      assert.ok(result.error?.includes('SEMANTIC'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('Invalid strategy')).toBeTruthy();
+      expect(result.error?.includes('SEMANTIC')).toBeTruthy();
 
       result = validateAddMemoryOptions({ ...validMemoryOptions, strategies: ',,,' });
-      assert.strictEqual(result.valid, false);
-      assert.strictEqual(result.error, 'At least one strategy is required');
+      expect(result.valid).toBe(false);
+      expect(result.error).toBe('At least one strategy is required');
     });
 
     // AC22: Valid options pass
     it('passes for valid options', () => {
-      assert.deepStrictEqual(validateAddMemoryOptions(validMemoryOptions), { valid: true });
+      expect(validateAddMemoryOptions(validMemoryOptions)).toEqual({ valid: true });
       // Test all valid strategies
-      assert.deepStrictEqual(
-        validateAddMemoryOptions({ ...validMemoryOptions, strategies: 'SEMANTIC,SUMMARIZATION,USER_PREFERENCE,CUSTOM' }),
-        { valid: true }
-      );
+      expect(
+        validateAddMemoryOptions({ ...validMemoryOptions, strategies: 'SEMANTIC,SUMMARIZATION,USER_PREFERENCE,CUSTOM' })
+      ).toEqual({ valid: true });
     });
   });
 
   describe('validateAddIdentityOptions', () => {
     // AC23: Required fields validated
     it('returns error for missing required fields', () => {
-      const requiredFields: Array<{ field: keyof AddIdentityOptions; error: string }> = [
+      const requiredFields: { field: keyof AddIdentityOptions; error: string }[] = [
         { field: 'name', error: '--name is required' },
         { field: 'type', error: '--type is required' },
         { field: 'apiKey', error: '--api-key is required' },
@@ -351,21 +349,21 @@ describe('validate', () => {
       for (const { field, error } of requiredFields) {
         const opts = { ...validIdentityOptions, [field]: undefined };
         const result = validateAddIdentityOptions(opts);
-        assert.strictEqual(result.valid, false, `Should fail for missing ${field}`);
-        assert.strictEqual(result.error, error);
+        expect(result.valid, `Should fail for missing ${field}`).toBe(false);
+        expect(result.error).toBe(error);
       }
     });
 
     // AC24: Only ApiKeyCredentialProvider supported
     it('returns error for unsupported type', () => {
       const result = validateAddIdentityOptions({ ...validIdentityOptions, type: 'OtherType' });
-      assert.strictEqual(result.valid, false);
-      assert.ok(result.error?.includes('Only ApiKeyCredentialProvider is supported'));
+      expect(result.valid).toBe(false);
+      expect(result.error?.includes('Only ApiKeyCredentialProvider is supported')).toBeTruthy();
     });
 
     // AC25: Valid options pass
     it('passes for valid options', () => {
-      assert.deepStrictEqual(validateAddIdentityOptions(validIdentityOptions), { valid: true });
+      expect(validateAddIdentityOptions(validIdentityOptions)).toEqual({ valid: true });
     });
   });
 });
diff --git a/src/cli/commands/add/actions.ts b/src/cli/commands/add/actions.ts
index e6a342c89..9fbc70b50 100644
--- a/src/cli/commands/add/actions.ts
+++ b/src/cli/commands/add/actions.ts
@@ -1,5 +1,4 @@
-import { dirname, join } from 'path';
-import { APP_DIR, ConfigIO, findConfigRoot, MCP_APP_SUBDIR, NoProjectError, setEnvVar } from '../../../lib';
+import { APP_DIR, ConfigIO, MCP_APP_SUBDIR, NoProjectError, findConfigRoot, setEnvVar } from '../../../lib';
 import type {
   AgentEnvSpec,
   DirectoryPath,
@@ -13,9 +12,12 @@ import type {
 } from '../../../schema';
 import { getErrorMessage } from '../../errors';
 import { setupPythonProject } from '../../operations';
-import { mapGenerateConfigToAgentEnvSpec, mapModelProviderToIdentityProviders, writeAgentToProject } from '../../operations/agent/generate';
-import { computeDefaultIdentityEnvVarName } from '../../operations/identity/create-identity';
-import { createIdentityFromWizard } from '../../operations/identity/create-identity';
+import {
+  mapGenerateConfigToAgentEnvSpec,
+  mapModelProviderToIdentityProviders,
+  writeAgentToProject,
+} from '../../operations/agent/generate';
+import { computeDefaultIdentityEnvVarName , createIdentityFromWizard } from '../../operations/identity/create-identity';
 import { createGatewayFromWizard, createToolFromWizard } from '../../operations/mcp/create-mcp';
 import { createMemoryFromWizard } from '../../operations/memory/create-memory';
 import { createRenderer } from '../../templates';
@@ -24,13 +26,8 @@ import type { AddIdentityConfig } from '../../tui/screens/identity/types';
 import type { AddGatewayConfig, AddMcpToolConfig } from '../../tui/screens/mcp/types';
 import type { AddMemoryConfig, AddMemoryStrategyConfig } from '../../tui/screens/memory/types';
 import { DEFAULT_EVENT_EXPIRY } from '../../tui/screens/memory/types';
-import type {
-  AddAgentResult,
-  AddGatewayResult,
-  AddIdentityResult,
-  AddMcpToolResult,
-  AddMemoryResult,
-} from './types';
+import type { AddAgentResult, AddGatewayResult, AddIdentityResult, AddMcpToolResult, AddMemoryResult } from './types';
+import { dirname, join } from 'path';
 
 // Validated option interfaces
 export interface ValidatedAddAgentOptions {
@@ -112,10 +109,7 @@ export async function handleAddAgent(options: ValidatedAddAgentOptions): Promise
   }
 }
 
-async function handleCreatePath(
-  options: ValidatedAddAgentOptions,
-  configBaseDir: string
-): Promise<AddAgentResult> {
+async function handleCreatePath(options: ValidatedAddAgentOptions, configBaseDir: string): Promise<AddAgentResult> {
   const projectRoot = dirname(configBaseDir);
 
   const generateConfig = {
@@ -151,9 +145,7 @@ async function handleByoPath(
   configIO: ConfigIO,
   configBaseDir: string
 ): Promise<AddAgentResult> {
-  const codeLocation = options.codeLocation!.endsWith('/')
-    ? options.codeLocation!
-    : `${options.codeLocation!}/`;
+  const codeLocation = options.codeLocation!.endsWith('/') ? options.codeLocation! : `${options.codeLocation!}/`;
 
   const agentEnvSpec: AgentEnvSpec = {
     name: options.name,
@@ -190,7 +182,10 @@ async function handleByoPath(
 // Gateway handler
 function buildGatewayConfig(options: ValidatedAddGatewayOptions): AddGatewayConfig {
   const agents = options.agents
-    ? options.agents.split(',').map(s => s.trim()).filter(Boolean)
+    ? options.agents
+        .split(',')
+        .map(s => s.trim())
+        .filter(Boolean)
     : [];
 
   const config: AddGatewayConfig = {
@@ -204,8 +199,14 @@ function buildGatewayConfig(options: ValidatedAddGatewayOptions): AddGatewayConf
   if (options.authorizerType === 'CUSTOM_JWT' && options.discoveryUrl) {
     config.jwtConfig = {
       discoveryUrl: options.discoveryUrl,
-      allowedAudience: options.allowedAudience!.split(',').map(s => s.trim()).filter(Boolean),
-      allowedClients: options.allowedClients!.split(',').map(s => s.trim()).filter(Boolean),
+      allowedAudience: options
+        .allowedAudience!.split(',')
+        .map(s => s.trim())
+        .filter(Boolean),
+      allowedClients: options
+        .allowedClients!.split(',')
+        .map(s => s.trim())
+        .filter(Boolean),
     };
   }
 
@@ -239,9 +240,13 @@ function buildMcpToolConfig(options: ValidatedAddMcpToolOptions): AddMcpToolConf
       description,
       inputSchema: { type: 'object' },
     },
-    selectedAgents: options.exposure === 'mcp-runtime'
-      ? options.agents!.split(',').map(s => s.trim()).filter(Boolean)
-      : [],
+    selectedAgents:
+      options.exposure === 'mcp-runtime'
+        ? options
+            .agents!.split(',')
+            .map(s => s.trim())
+            .filter(Boolean)
+        : [],
     gateway: options.exposure === 'behind-gateway' ? options.gateway : undefined,
   };
 }
@@ -259,7 +264,10 @@ export async function handleAddMcpTool(options: ValidatedAddMcpToolOptions): Pro
 // Memory handler
 function buildMemoryConfig(options: ValidatedAddMemoryOptions): AddMemoryConfig {
   const userAgents = options.users
-    ? options.users.split(',').map(s => s.trim()).filter(Boolean)
+    ? options.users
+        .split(',')
+        .map(s => s.trim())
+        .filter(Boolean)
     : [];
 
   const strategies: AddMemoryStrategyConfig[] = options.strategies
@@ -296,7 +304,10 @@ export async function handleAddMemory(options: ValidatedAddMemoryOptions): Promi
 // Identity handler
 function buildIdentityConfig(options: ValidatedAddIdentityOptions): AddIdentityConfig {
   const userAgents = options.users
-    ? options.users.split(',').map(s => s.trim()).filter(Boolean)
+    ? options.users
+        .split(',')
+        .map(s => s.trim())
+        .filter(Boolean)
     : [];
 
   return {
diff --git a/src/cli/commands/add/add-agent.test.ts b/src/cli/commands/add/add-agent.test.ts
deleted file mode 100644
index 45a52967c..000000000
--- a/src/cli/commands/add/add-agent.test.ts
+++ /dev/null
@@ -1,205 +0,0 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile, writeFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
-import { randomUUID } from 'node:crypto';
-import { runCLI, exists } from '../../../test-utils/index.js';
-
-describe('add agent command', () => {
-  let testDir: string;
-  let projectDir: string;
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-add-agent-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-
-    // Create a project first
-    const projectName = 'TestProj';
-    const result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
-    }
-    projectDir = join(testDir, projectName);
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('create path', () => {
-    it('creates agent with valid inputs', async () => {
-      const agentName = `Agent${Date.now()}`;
-      const result = await runCLI([
-        'add', 'agent',
-        '--name', agentName,
-        '--language', 'Python',
-        '--framework', 'Strands',
-        '--model-provider', 'Bedrock',
-        '--memory', 'none',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.strictEqual(json.agentName, agentName);
-
-      // Verify agent code exists
-      assert.ok(await exists(join(projectDir, 'app', agentName)), 'Agent code should exist');
-
-      // Verify agent in agentcore.json
-      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentName);
-      assert.ok(agent, 'Agent should be in agentcore.json');
-    });
-
-    it('requires all create path options', async () => {
-      const result = await runCLI([
-        'add', 'agent',
-        '--name', 'Incomplete',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('required'), `Error should mention required: ${json.error}`);
-    });
-
-    it('validates framework', async () => {
-      const result = await runCLI([
-        'add', 'agent',
-        '--name', 'BadFW',
-        '--language', 'Python',
-        '--framework', 'NotReal',
-        '--model-provider', 'Bedrock',
-        '--memory', 'none',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('Invalid framework'), `Error: ${json.error}`);
-    });
-
-    it('rejects TypeScript for create path', async () => {
-      const result = await runCLI([
-        'add', 'agent',
-        '--name', 'TSAgent',
-        '--language', 'TypeScript',
-        '--framework', 'Strands',
-        '--model-provider', 'Bedrock',
-        '--memory', 'none',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('Python'), `Error should mention Python: ${json.error}`);
-    });
-
-    it('validates framework/model compatibility', async () => {
-      const result = await runCLI([
-        'add', 'agent',
-        '--name', 'BadCombo',
-        '--language', 'Python',
-        '--framework', 'OpenAIAgents',
-        '--model-provider', 'Bedrock',
-        '--memory', 'none',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('does not support'), `Error: ${json.error}`);
-    });
-
-    it('rejects duplicate agent name', async () => {
-      const agentName = 'DupeAgent';
-      
-      // First creation should succeed
-      const first = await runCLI([
-        'add', 'agent',
-        '--name', agentName,
-        '--language', 'Python',
-        '--framework', 'Strands',
-        '--model-provider', 'Bedrock',
-        '--memory', 'none',
-        '--json'
-      ], projectDir);
-      assert.strictEqual(first.exitCode, 0, `First should succeed: ${first.stdout}`);
-
-      // Second creation should fail
-      const second = await runCLI([
-        'add', 'agent',
-        '--name', agentName,
-        '--language', 'Python',
-        '--framework', 'Strands',
-        '--model-provider', 'Bedrock',
-        '--memory', 'none',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(second.exitCode, 1);
-      const json = JSON.parse(second.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('already exists'), `Error: ${json.error}`);
-    });
-  });
-
-  describe('BYO path', () => {
-    it('registers BYO agent', async () => {
-      const agentName = `ByoAgent${Date.now()}`;
-      const codeDir = 'existing-agent';
-      
-      // Create existing code directory
-      await mkdir(join(projectDir, codeDir), { recursive: true });
-      await writeFile(join(projectDir, codeDir, 'main.py'), '# existing code\n');
-
-      const result = await runCLI([
-        'add', 'agent',
-        '--name', agentName,
-        '--type', 'byo',
-        '--code-location', codeDir,
-        '--language', 'Python',
-        '--framework', 'Strands',
-        '--model-provider', 'Bedrock',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}`);
-
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.strictEqual(json.agentName, agentName);
-
-      // Verify agent in agentcore.json with correct codeLocation
-      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentName);
-      assert.ok(agent, 'Agent should be in agentcore.json');
-      assert.ok(agent.runtime.codeLocation.includes(codeDir), `codeLocation should reference ${codeDir}`);
-    });
-
-    it('requires code-location for BYO path', async () => {
-      const result = await runCLI([
-        'add', 'agent',
-        '--name', 'NoByo',
-        '--type', 'byo',
-        '--language', 'Python',
-        '--framework', 'Strands',
-        '--model-provider', 'Bedrock',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('code-location'), `Error: ${json.error}`);
-    });
-  });
-});
diff --git a/src/cli/commands/add/add-gateway.test.ts b/src/cli/commands/add/add-gateway.test.ts
deleted file mode 100644
index 09f60eecd..000000000
--- a/src/cli/commands/add/add-gateway.test.ts
+++ /dev/null
@@ -1,158 +0,0 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
-import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
-
-describe('add gateway command', () => {
-  let testDir: string;
-  let projectDir: string;
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-add-gateway-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-
-    // Create a project first
-    const projectName = 'TestProj';
-    const result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
-    }
-    projectDir = join(testDir, projectName);
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('basic gateway', () => {
-    it('creates gateway with default authorizer', async () => {
-      const gatewayName = `gw-${Date.now()}`;
-      const result = await runCLI([
-        'add', 'gateway',
-        '--name', gatewayName,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.strictEqual(json.gatewayName, gatewayName);
-
-      // Verify gateway in mcp.json
-      const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8'));
-      const gateway = mcpSpec.agentCoreGateways.find((g: { name: string }) => g.name === gatewayName);
-      assert.ok(gateway, 'Gateway should be in mcp.json');
-      assert.strictEqual(gateway.authorizerType, 'NONE');
-    });
-
-    it('requires name flag', async () => {
-      const result = await runCLI([
-        'add', 'gateway',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--name'), `Error: ${json.error}`);
-    });
-
-    it('validates gateway name format', async () => {
-      const result = await runCLI([
-        'add', 'gateway',
-        '--name', 'invalid name!',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-    });
-
-    it('rejects duplicate gateway name', async () => {
-      const gatewayName = 'dup-gateway';
-      
-      // First creation should succeed
-      const first = await runCLI([
-        'add', 'gateway',
-        '--name', gatewayName,
-        '--json'
-      ], projectDir);
-      assert.strictEqual(first.exitCode, 0, `First should succeed: ${first.stdout}`);
-
-      // Second creation should fail
-      const second = await runCLI([
-        'add', 'gateway',
-        '--name', gatewayName,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(second.exitCode, 1);
-      const json = JSON.parse(second.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('already exists'), `Error: ${json.error}`);
-    });
-  });
-
-  describe('JWT authorizer', () => {
-    it('creates gateway with CUSTOM_JWT authorizer', async () => {
-      const gatewayName = `jwt-gw-${Date.now()}`;
-      const result = await runCLI([
-        'add', 'gateway',
-        '--name', gatewayName,
-        '--authorizer-type', 'CUSTOM_JWT',
-        '--discovery-url', 'https://example.com/.well-known/openid-configuration',
-        '--allowed-audience', 'aud1,aud2',
-        '--allowed-clients', 'client1',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}`);
-
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-
-      // Verify JWT config in mcp.json
-      const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8'));
-      const gateway = mcpSpec.agentCoreGateways.find((g: { name: string }) => g.name === gatewayName);
-      assert.ok(gateway, 'Gateway should be in mcp.json');
-      assert.strictEqual(gateway.authorizerType, 'CUSTOM_JWT');
-      assert.ok(gateway.authorizerConfiguration?.customJwtAuthorizer, 'Should have JWT config');
-    });
-
-    it('requires JWT fields when CUSTOM_JWT', async () => {
-      const result = await runCLI([
-        'add', 'gateway',
-        '--name', 'no-jwt',
-        '--authorizer-type', 'CUSTOM_JWT',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('discovery-url'), `Error: ${json.error}`);
-    });
-
-    it('validates discovery URL format', async () => {
-      const result = await runCLI([
-        'add', 'gateway',
-        '--name', 'bad-url',
-        '--authorizer-type', 'CUSTOM_JWT',
-        '--discovery-url', 'https://example.com/wrong',
-        '--allowed-audience', 'aud',
-        '--allowed-clients', 'client',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('well-known'), `Error: ${json.error}`);
-    });
-  });
-});
diff --git a/src/cli/commands/add/add-identity.test.ts b/src/cli/commands/add/add-identity.test.ts
deleted file mode 100644
index 0cda0e852..000000000
--- a/src/cli/commands/add/add-identity.test.ts
+++ /dev/null
@@ -1,179 +0,0 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
-import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
-
-describe('add identity command', () => {
-  let testDir: string;
-  let projectDir: string;
-  const ownerAgent = 'OwnerAgent';
-  const userAgent = 'UserAgent';
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-add-identity-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-
-    // Create project
-    const projectName = 'IdentityProj';
-    let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
-    }
-    projectDir = join(testDir, projectName);
-
-    // Add owner agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', ownerAgent,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create owner agent: ${result.stdout} ${result.stderr}`);
-    }
-
-    // Add user agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', userAgent,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create user agent: ${result.stdout} ${result.stderr}`);
-    }
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('validation', () => {
-    it('requires name flag', async () => {
-      const result = await runCLI(['add', 'identity', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--name'), `Error: ${json.error}`);
-    });
-
-    it('requires type flag', async () => {
-      const result = await runCLI([
-        'add', 'identity',
-        '--name', 'test',
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--type'), `Error: ${json.error}`);
-    });
-
-    it('validates type value', async () => {
-      const result = await runCLI([
-        'add', 'identity',
-        '--name', 'test',
-        '--type', 'Invalid',
-        '--api-key', 'xxx',
-        '--owner', ownerAgent,
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('ApiKeyCredentialProvider'), `Error: ${json.error}`);
-    });
-
-    it('requires api-key flag', async () => {
-      const result = await runCLI([
-        'add', 'identity',
-        '--name', 'test',
-        '--type', 'ApiKeyCredentialProvider',
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--api-key'), `Error: ${json.error}`);
-    });
-
-    it('requires owner flag', async () => {
-      const result = await runCLI([
-        'add', 'identity',
-        '--name', 'test',
-        '--type', 'ApiKeyCredentialProvider',
-        '--api-key', 'xxx',
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--owner'), `Error: ${json.error}`);
-    });
-  });
-
-  describe('identity creation', () => {
-    it('creates identity with owner', async () => {
-      const identityName = `id${Date.now()}`;
-      const result = await runCLI([
-        'add', 'identity',
-        '--name', identityName,
-        '--type', 'ApiKeyCredentialProvider',
-        '--api-key', 'test-key-123',
-        '--owner', ownerAgent,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.strictEqual(json.identityName, identityName);
-      assert.strictEqual(json.ownerAgent, ownerAgent);
-
-      // Verify in agentcore.json
-      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const agent = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
-      const identity = agent?.identityProviders?.find((i: { name: string }) => i.name === identityName);
-      assert.ok(identity, 'Identity should be on owner agent');
-      assert.strictEqual(identity.relation, 'own');
-    });
-
-    it('creates identity with owner and users', async () => {
-      const identityName = `shared${Date.now()}`;
-      const result = await runCLI([
-        'add', 'identity',
-        '--name', identityName,
-        '--type', 'ApiKeyCredentialProvider',
-        '--api-key', 'shared-key-456',
-        '--owner', ownerAgent,
-        '--users', userAgent,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.deepStrictEqual(json.userAgents, [userAgent]);
-
-      // Verify relations
-      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
-      
-      const owner = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
-      const ownerIdentity = owner?.identityProviders?.find((i: { name: string }) => i.name === identityName);
-      assert.strictEqual(ownerIdentity?.relation, 'own');
-
-      const user = projectSpec.agents.find((a: { name: string }) => a.name === userAgent);
-      const userIdentity = user?.identityProviders?.find((i: { name: string }) => i.name === identityName);
-      assert.strictEqual(userIdentity?.relation, 'use');
-    });
-  });
-});
diff --git a/src/cli/commands/add/add-mcp-tool.test.ts b/src/cli/commands/add/add-mcp-tool.test.ts
deleted file mode 100644
index 1040c20b2..000000000
--- a/src/cli/commands/add/add-mcp-tool.test.ts
+++ /dev/null
@@ -1,249 +0,0 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
-import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
-
-describe('add mcp-tool command', () => {
-  let testDir: string;
-  let projectDir: string;
-  const agentName = 'TestAgent';
-  const gatewayName = 'test-gateway';
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-add-mcp-tool-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-
-    // Create project with agent
-    const projectName = 'McpToolProj';
-    let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
-    }
-    projectDir = join(testDir, projectName);
-
-    // Add agent for mcp-runtime tests
-    result = await runCLI([
-      'add', 'agent',
-      '--name', agentName,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create agent: ${result.stdout} ${result.stderr}`);
-    }
-
-    // Add gateway for behind-gateway tests
-    result = await runCLI([
-      'add', 'gateway',
-      '--name', gatewayName,
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create gateway: ${result.stdout} ${result.stderr}`);
-    }
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('validation', () => {
-    it('requires name flag', async () => {
-      const result = await runCLI(['add', 'mcp-tool', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--name'), `Error: ${json.error}`);
-    });
-
-    it('requires exposure flag', async () => {
-      const result = await runCLI([
-        'add', 'mcp-tool',
-        '--name', 'test',
-        '--language', 'Python',
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--exposure'), `Error: ${json.error}`);
-    });
-
-    it('validates language', async () => {
-      const result = await runCLI([
-        'add', 'mcp-tool',
-        '--name', 'test',
-        '--language', 'InvalidLang',
-        '--exposure', 'mcp-runtime',
-        '--agents', agentName,
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(
-        json.error.toLowerCase().includes('invalid') || json.error.toLowerCase().includes('valid options'),
-        `Error should mention invalid language: ${json.error}`
-      );
-    });
-
-    it('accepts Other as valid language option', async () => {
-      const result = await runCLI([
-        'add', 'mcp-tool',
-        '--name', 'container-tool',
-        '--language', 'Other',
-        '--exposure', 'mcp-runtime',
-        '--agents', agentName,
-        '--json'
-      ], projectDir);
-      
-      // Should fail with "not yet supported" error, not validation error
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(
-        json.error.toLowerCase().includes('not yet supported') || json.error.toLowerCase().includes('other'),
-        `Error should mention Other not supported: ${json.error}`
-      );
-    });
-  });
-
-  describe('mcp-runtime', () => {
-    it('creates mcp-runtime tool', async () => {
-      const toolName = `rttool${Date.now()}`;
-      const result = await runCLI([
-        'add', 'mcp-tool',
-        '--name', toolName,
-        '--language', 'Python',
-        '--exposure', 'mcp-runtime',
-        '--agents', agentName,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.strictEqual(json.toolName, toolName);
-
-      // Verify in mcp.json
-      const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8'));
-      const tool = mcpSpec.mcpRuntimeTools?.find((t: { name: string }) => t.name === toolName);
-      assert.ok(tool, 'Tool should be in mcpRuntimeTools');
-
-      // Verify agent has remote tool reference
-      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentName);
-      const hasRef = agent?.remoteTools?.some((rt: { mcpRuntimeName?: string }) => rt.mcpRuntimeName === toolName);
-      assert.ok(hasRef, 'Agent should have remoteTools reference');
-    });
-
-    it('requires agents for mcp-runtime', async () => {
-      const result = await runCLI([
-        'add', 'mcp-tool',
-        '--name', 'no-agents',
-        '--language', 'Python',
-        '--exposure', 'mcp-runtime',
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--agents'), `Error: ${json.error}`);
-    });
-
-    it('returns clear error for Other language with mcp-runtime', async () => {
-      const result = await runCLI([
-        'add', 'mcp-tool',
-        '--name', 'runtime-container',
-        '--language', 'Other',
-        '--exposure', 'mcp-runtime',
-        '--agents', agentName,
-        '--json'
-      ], projectDir);
-      
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.length > 0, 'Should have error message');
-    });
-  });
-
-  describe('behind-gateway', () => {
-    it('creates behind-gateway tool', async () => {
-      const toolName = `gwtool${Date.now()}`;
-      const result = await runCLI([
-        'add', 'mcp-tool',
-        '--name', toolName,
-        '--language', 'Python',
-        '--exposure', 'behind-gateway',
-        '--gateway', gatewayName,
-        '--host', 'Lambda',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.strictEqual(json.toolName, toolName);
-
-      // Verify in mcp.json gateway targets
-      const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8'));
-      const gateway = mcpSpec.agentCoreGateways.find((g: { name: string }) => g.name === gatewayName);
-      const target = gateway?.targets?.find((t: { name: string }) => t.name === toolName);
-      assert.ok(target, 'Tool should be in gateway targets');
-    });
-
-    it('requires gateway for behind-gateway', async () => {
-      const result = await runCLI([
-        'add', 'mcp-tool',
-        '--name', 'no-gw',
-        '--language', 'Python',
-        '--exposure', 'behind-gateway',
-        '--host', 'Lambda',
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--gateway'), `Error: ${json.error}`);
-    });
-
-    it('requires host for behind-gateway', async () => {
-      const result = await runCLI([
-        'add', 'mcp-tool',
-        '--name', 'no-host',
-        '--language', 'Python',
-        '--exposure', 'behind-gateway',
-        '--gateway', gatewayName,
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--host'), `Error: ${json.error}`);
-    });
-
-    it('returns clear error for Other language with behind-gateway', async () => {
-      const result = await runCLI([
-        'add', 'mcp-tool',
-        '--name', 'gateway-container',
-        '--language', 'Other',
-        '--exposure', 'behind-gateway',
-        '--gateway', gatewayName,
-        '--host', 'Lambda',
-        '--json'
-      ], projectDir);
-      
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.length > 0, 'Should have error message');
-    });
-  });
-});
diff --git a/src/cli/commands/add/add-memory.test.ts b/src/cli/commands/add/add-memory.test.ts
deleted file mode 100644
index 6ce9ad298..000000000
--- a/src/cli/commands/add/add-memory.test.ts
+++ /dev/null
@@ -1,203 +0,0 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
-import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
-
-describe('add memory command', () => {
-  let testDir: string;
-  let projectDir: string;
-  const ownerAgent = 'OwnerAgent';
-  const userAgent = 'UserAgent';
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-add-memory-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-
-    // Create project
-    const projectName = 'MemoryProj';
-    let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
-    }
-    projectDir = join(testDir, projectName);
-
-    // Add owner agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', ownerAgent,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create owner agent: ${result.stdout} ${result.stderr}`);
-    }
-
-    // Add user agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', userAgent,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create user agent: ${result.stdout} ${result.stderr}`);
-    }
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('validation', () => {
-    it('requires name flag', async () => {
-      const result = await runCLI(['add', 'memory', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--name'), `Error: ${json.error}`);
-    });
-
-    it('requires strategies flag', async () => {
-      const result = await runCLI([
-        'add', 'memory',
-        '--name', 'test',
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--strategies'), `Error: ${json.error}`);
-    });
-
-    it('requires owner flag', async () => {
-      const result = await runCLI([
-        'add', 'memory',
-        '--name', 'test',
-        '--strategies', 'SEMANTIC',
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--owner'), `Error: ${json.error}`);
-    });
-
-    it('validates strategy types', async () => {
-      const result = await runCLI([
-        'add', 'memory',
-        '--name', 'test',
-        '--strategies', 'INVALID',
-        '--owner', ownerAgent,
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('INVALID'), `Error: ${json.error}`);
-    });
-  });
-
-  describe('memory creation', () => {
-    it('creates memory with owner', async () => {
-      const memoryName = `mem${Date.now()}`;
-      const result = await runCLI([
-        'add', 'memory',
-        '--name', memoryName,
-        '--strategies', 'SEMANTIC',
-        '--owner', ownerAgent,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.strictEqual(json.memoryName, memoryName);
-      assert.strictEqual(json.ownerAgent, ownerAgent);
-
-      // Verify in agentcore.json
-      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const agent = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
-      const memory = agent?.memoryProviders?.find((m: { name: string }) => m.name === memoryName);
-      assert.ok(memory, 'Memory should be on owner agent');
-      assert.strictEqual(memory.relation, 'own');
-    });
-
-    it('creates memory with owner and users', async () => {
-      const memoryName = `shared${Date.now()}`;
-      const result = await runCLI([
-        'add', 'memory',
-        '--name', memoryName,
-        '--strategies', 'SUMMARIZATION',
-        '--owner', ownerAgent,
-        '--users', userAgent,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.deepStrictEqual(json.userAgents, [userAgent]);
-
-      // Verify relations
-      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
-      
-      const owner = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
-      const ownerMem = owner?.memoryProviders?.find((m: { name: string }) => m.name === memoryName);
-      assert.strictEqual(ownerMem?.relation, 'own');
-
-      const user = projectSpec.agents.find((a: { name: string }) => a.name === userAgent);
-      const userMem = user?.memoryProviders?.find((m: { name: string }) => m.name === memoryName);
-      assert.strictEqual(userMem?.relation, 'use');
-    });
-
-    it('creates memory with multiple strategies', async () => {
-      const memoryName = `multi${Date.now()}`;
-      const result = await runCLI([
-        'add', 'memory',
-        '--name', memoryName,
-        '--strategies', 'SEMANTIC,SUMMARIZATION',
-        '--owner', ownerAgent,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-
-      // Verify strategies
-      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const agent = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
-      const memory = agent?.memoryProviders?.find((m: { name: string }) => m.name === memoryName);
-      const strategies = memory?.config?.memoryStrategies?.map((s: { type: string }) => s.type);
-      assert.ok(strategies?.includes('SEMANTIC'), 'Should have SEMANTIC');
-      assert.ok(strategies?.includes('SUMMARIZATION'), 'Should have SUMMARIZATION');
-    });
-
-    it('creates memory with custom expiry', async () => {
-      const memoryName = `expiry${Date.now()}`;
-      const result = await runCLI([
-        'add', 'memory',
-        '--name', memoryName,
-        '--strategies', 'SEMANTIC',
-        '--owner', ownerAgent,
-        '--expiry', '90',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-
-      // Verify expiry
-      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const agent = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
-      const memory = agent?.memoryProviders?.find((m: { name: string }) => m.name === memoryName);
-      assert.strictEqual(memory?.config?.eventExpiryDuration, 90);
-    });
-  });
-});
diff --git a/src/cli/commands/add/add-target.test.ts b/src/cli/commands/add/add-target.test.ts
deleted file mode 100644
index ecac67c53..000000000
--- a/src/cli/commands/add/add-target.test.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
-import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
-
-describe('add target command', () => {
-  let testDir: string;
-  let projectDir: string;
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-add-target-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-
-    // Create a project first
-    const projectName = 'TestProj';
-    const result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
-    }
-    projectDir = join(testDir, projectName);
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  it('adds target with valid inputs', async () => {
-    const result = await runCLI([
-      'add', 'target',
-      '--name', 'dev',
-      '--account', '123456789012',
-      '--region', 'us-east-1',
-      '--json'
-    ], projectDir);
-
-    assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}`);
-
-    const json = JSON.parse(result.stdout);
-    assert.strictEqual(json.success, true);
-
-    // Verify target in file
-    const targets = JSON.parse(await readFile(join(projectDir, 'agentcore/aws-targets.json'), 'utf-8'));
-    assert.strictEqual(targets.length, 1);
-    assert.strictEqual(targets[0].name, 'dev');
-  });
-
-  it('rejects duplicate target name', async () => {
-    const result = await runCLI([
-      'add', 'target',
-      '--name', 'dev',
-      '--account', '123456789012',
-      '--region', 'us-west-2',
-      '--json'
-    ], projectDir);
-
-    assert.strictEqual(result.exitCode, 1);
-
-    const json = JSON.parse(result.stdout);
-    assert.strictEqual(json.success, false);
-    assert.ok(json.error.includes('already exists'));
-  });
-
-  it('rejects invalid account ID', async () => {
-    const result = await runCLI([
-      'add', 'target',
-      '--name', 'prod',
-      '--account', 'invalid',
-      '--region', 'us-east-1',
-      '--json'
-    ], projectDir);
-
-    assert.strictEqual(result.exitCode, 1);
-
-    const json = JSON.parse(result.stdout);
-    assert.strictEqual(json.success, false);
-    assert.ok(json.error.includes('12 digits'));
-  });
-
-  it('rejects invalid region name', async () => {
-    const result = await runCLI([
-      'add', 'target',
-      '--name', 'invalid-region-target',
-      '--account', '123456789012',
-      '--region', 'invalid-region-123',
-      '--json'
-    ], projectDir);
-
-    assert.strictEqual(result.exitCode, 1);
-
-    const json = JSON.parse(result.stdout);
-    assert.strictEqual(json.success, false);
-    assert.ok(json.error.toLowerCase().includes('region'), `Expected region error, got: ${json.error}`);
-  });
-
-  it('requires all flags', async () => {
-    const result = await runCLI([
-      'add', 'target',
-      '--name', 'staging',
-      '--json'
-    ], projectDir);
-
-    assert.strictEqual(result.exitCode, 1);
-
-    const json = JSON.parse(result.stdout);
-    assert.strictEqual(json.success, false);
-    assert.ok(json.error.includes('Required'));
-  });
-});
diff --git a/src/cli/commands/add/command.tsx b/src/cli/commands/add/command.tsx
index 914676817..83a8d4445 100644
--- a/src/cli/commands/add/command.tsx
+++ b/src/cli/commands/add/command.tsx
@@ -1,13 +1,7 @@
 import { COMMAND_DESCRIPTIONS } from '../../tui/copy';
 import { requireProject } from '../../tui/guards';
 import { AddFlow } from '../../tui/screens/add/AddFlow';
-import {
-  handleAddAgent,
-  handleAddGateway,
-  handleAddIdentity,
-  handleAddMcpTool,
-  handleAddMemory,
-} from './actions';
+import { handleAddAgent, handleAddGateway, handleAddIdentity, handleAddMcpTool, handleAddMemory } from './actions';
 import { handleAddTarget } from './target-action';
 import type {
   AddAgentOptions,
@@ -77,7 +71,7 @@ async function handleAddAgentCLI(options: AddAgentOptions): Promise<void> {
 
   const result = await handleAddAgent({
     name: options.name!,
-    type: (options.type as 'create' | 'byo') ?? 'create',
+    type: (options.type!) ?? 'create',
     language: options.language!,
     framework: options.framework!,
     modelProvider: options.modelProvider!,
@@ -148,10 +142,10 @@ async function handleAddMcpToolCLI(options: AddMcpToolOptions): Promise<void> {
     name: options.name!,
     description: options.description,
     language: options.language! as 'Python' | 'TypeScript',
-    exposure: options.exposure! as 'mcp-runtime' | 'behind-gateway',
+    exposure: options.exposure!,
     agents: options.agents,
     gateway: options.gateway,
-    host: options.host as 'Lambda' | 'AgentCoreRuntime' | undefined,
+    host: options.host,
   });
 
   if (options.json) {
diff --git a/src/cli/commands/add/target-action.ts b/src/cli/commands/add/target-action.ts
index 14eb1526f..9e07b58b0 100644
--- a/src/cli/commands/add/target-action.ts
+++ b/src/cli/commands/add/target-action.ts
@@ -1,4 +1,4 @@
-import { ConfigIO, findConfigRoot, NoProjectError } from '../../../lib';
+import { ConfigIO, NoProjectError, findConfigRoot } from '../../../lib';
 import type { AwsDeploymentTarget } from '../../../schema';
 import { AgentCoreRegionSchema, AwsAccountIdSchema, DeploymentTargetNameSchema } from '../../../schema';
 import { getErrorMessage } from '../../errors';
diff --git a/src/cli/commands/add/validate.ts b/src/cli/commands/add/validate.ts
index a63c3d0d7..ef06784cf 100644
--- a/src/cli/commands/add/validate.ts
+++ b/src/cli/commands/add/validate.ts
@@ -1,17 +1,17 @@
 import {
   GatewayNameSchema,
-  getSupportedModelProviders,
   ModelProviderSchema,
   ProviderNameSchema,
   SDKFrameworkSchema,
   TargetLanguageSchema,
+  getSupportedModelProviders,
 } from '../../../schema';
 import type {
   AddAgentOptions,
   AddGatewayOptions,
+  AddIdentityOptions,
   AddMcpToolOptions,
   AddMemoryOptions,
-  AddIdentityOptions,
 } from './types';
 
 export interface ValidationResult {
@@ -85,8 +85,11 @@ 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])) {
-      return { valid: false, error: `Invalid memory option: ${options.memory}. Use none, shortTerm, or longAndShortTerm` };
+    if (!MEMORY_OPTIONS.includes(options.memory as (typeof MEMORY_OPTIONS)[number])) {
+      return {
+        valid: false,
+        error: `Invalid memory option: ${options.memory}. Use none, shortTerm, or longAndShortTerm`,
+      };
     }
   }
 
@@ -127,7 +130,10 @@ export function validateAddGatewayOptions(options: AddGatewayOptions): Validatio
       return { valid: false, error: '--allowed-audience is required for CUSTOM_JWT authorizer' };
     }
 
-    const audiences = options.allowedAudience.split(',').map(s => s.trim()).filter(Boolean);
+    const audiences = options.allowedAudience
+      .split(',')
+      .map(s => s.trim())
+      .filter(Boolean);
     if (audiences.length === 0) {
       return { valid: false, error: 'At least one audience value is required' };
     }
@@ -136,7 +142,10 @@ export function validateAddGatewayOptions(options: AddGatewayOptions): Validatio
       return { valid: false, error: '--allowed-clients is required for CUSTOM_JWT authorizer' };
     }
 
-    const clients = options.allowedClients.split(',').map(s => s.trim()).filter(Boolean);
+    const clients = options.allowedClients
+      .split(',')
+      .map(s => s.trim())
+      .filter(Boolean);
     if (clients.length === 0) {
       return { valid: false, error: 'At least one client value is required' };
     }
@@ -171,7 +180,10 @@ export function validateAddMcpToolOptions(options: AddMcpToolOptions): Validatio
     if (!options.agents) {
       return { valid: false, error: '--agents is required for mcp-runtime exposure' };
     }
-    const agents = options.agents.split(',').map(s => s.trim()).filter(Boolean);
+    const agents = options.agents
+      .split(',')
+      .map(s => s.trim())
+      .filter(Boolean);
     if (agents.length === 0) {
       return { valid: false, error: 'At least one agent is required' };
     }
@@ -200,7 +212,10 @@ export function validateAddMemoryOptions(options: AddMemoryOptions): ValidationR
     return { valid: false, error: '--strategies is required' };
   }
 
-  const strategies = options.strategies.split(',').map(s => s.trim()).filter(Boolean);
+  const strategies = options.strategies
+    .split(',')
+    .map(s => s.trim())
+    .filter(Boolean);
   if (strategies.length === 0) {
     return { valid: false, error: 'At least one strategy is required' };
   }
diff --git a/src/cli/commands/attach/__tests__/attach-agent.test.ts b/src/cli/commands/attach/__tests__/attach-agent.test.ts
new file mode 100644
index 000000000..6edbf3151
--- /dev/null
+++ b/src/cli/commands/attach/__tests__/attach-agent.test.ts
@@ -0,0 +1,157 @@
+import { runCLI } from '../../../../test-utils/index.js';
+import { randomUUID } from 'node:crypto';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+
+describe('attach agent command', () => {
+  let testDir: string;
+  let projectDir: string;
+  const agentA = 'AgentA';
+  const agentB = 'AgentB';
+
+  beforeAll(async () => {
+    testDir = join(tmpdir(), `agentcore-attach-agent-${randomUUID()}`);
+    await mkdir(testDir, { recursive: true });
+
+    // Create project
+    const projectName = 'AttachProj';
+    let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
+    }
+    projectDir = join(testDir, projectName);
+
+    // Add AgentA
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        agentA,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create AgentA: ${result.stdout} ${result.stderr}`);
+    }
+
+    // Add AgentB
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        agentB,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create AgentB: ${result.stdout} ${result.stderr}`);
+    }
+  });
+
+  afterAll(async () => {
+    await rm(testDir, { recursive: true, force: true });
+  });
+
+  describe('validation', () => {
+    it('requires source flag', async () => {
+      const result = await runCLI(['attach', 'agent', '--json'], projectDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--source'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('requires target flag', async () => {
+      const result = await runCLI(['attach', 'agent', '--source', agentA, '--json'], projectDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--target'), `Error: ${json.error}`).toBeTruthy();
+    });
+  });
+
+  describe('attach operations', () => {
+    it('attaches agent to agent', async () => {
+      const result = await runCLI(['attach', 'agent', '--source', agentA, '--target', agentB, '--json'], projectDir);
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(json.sourceAgent).toBe(agentA);
+      expect(json.targetAgent).toBe(agentB);
+
+      // Verify in agentcore.json
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentA);
+      const remoteTool = agent?.remoteTools?.find((t: { name: string }) => t.name === `invoke${agentB}`);
+      expect(remoteTool, 'Remote tool should be on source agent').toBeTruthy();
+      expect(remoteTool.type).toBe('AgentCoreAgentInvocation');
+      expect(remoteTool.targetAgentName).toBe(agentB);
+    });
+
+    it('uses custom name', async () => {
+      const customName = `custom${Date.now()}`;
+      const result = await runCLI(
+        ['attach', 'agent', '--source', agentA, '--target', agentB, '--name', customName, '--json'],
+        projectDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+
+      // Verify custom name
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentA);
+      const remoteTool = agent?.remoteTools?.find((t: { name: string }) => t.name === customName);
+      expect(remoteTool, `Remote tool with name ${customName} should exist`).toBeTruthy();
+    });
+
+    it('rejects self-attachment', async () => {
+      const result = await runCLI(['attach', 'agent', '--source', agentA, '--target', agentA, '--json'], projectDir);
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(
+        json.error.toLowerCase().includes('itself') || json.error.toLowerCase().includes('same'),
+        `Error: ${json.error}`
+      ).toBeTruthy();
+    });
+
+    it('rejects non-existent source', async () => {
+      const result = await runCLI(
+        ['attach', 'agent', '--source', 'NonExistent', '--target', agentB, '--json'],
+        projectDir
+      );
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(
+        json.error.includes('not found') || json.error.includes('NonExistent'),
+        `Error: ${json.error}`
+      ).toBeTruthy();
+    });
+  });
+});
diff --git a/src/cli/commands/attach/attach-gateway.test.ts b/src/cli/commands/attach/__tests__/attach-gateway.test.ts
similarity index 51%
rename from src/cli/commands/attach/attach-gateway.test.ts
rename to src/cli/commands/attach/__tests__/attach-gateway.test.ts
index 7421879a4..a292b98f8 100644
--- a/src/cli/commands/attach/attach-gateway.test.ts
+++ b/src/cli/commands/attach/__tests__/attach-gateway.test.ts
@@ -1,10 +1,9 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
+import { runCLI } from '../../../../test-utils/index.js';
 import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
 
 describe('attach gateway command', () => {
   let testDir: string;
@@ -25,25 +24,30 @@ describe('attach gateway command', () => {
     projectDir = join(testDir, projectName);
 
     // Add agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', agentName,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        agentName,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create agent: ${result.stdout} ${result.stderr}`);
     }
 
     // Add gateway
-    result = await runCLI([
-      'add', 'gateway',
-      '--name', gatewayName,
-      '--json'
-    ], projectDir);
+    result = await runCLI(['add', 'gateway', '--name', gatewayName, '--json'], projectDir);
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create gateway: ${result.stdout} ${result.stderr}`);
     }
@@ -56,60 +60,52 @@ describe('attach gateway command', () => {
   describe('validation', () => {
     it('requires agent flag', async () => {
       const result = await runCLI(['attach', 'gateway', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--agent'), `Error: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--agent'), `Error: ${json.error}`).toBeTruthy();
     });
 
     it('requires gateway flag', async () => {
-      const result = await runCLI([
-        'attach', 'gateway',
-        '--agent', agentName,
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      const result = await runCLI(['attach', 'gateway', '--agent', agentName, '--json'], projectDir);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--gateway'), `Error: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--gateway'), `Error: ${json.error}`).toBeTruthy();
     });
   });
 
   describe('attach operations', () => {
     it('attaches gateway to agent', async () => {
-      const result = await runCLI([
-        'attach', 'gateway',
-        '--agent', agentName,
-        '--gateway', gatewayName,
-        '--json'
-      ], projectDir);
+      const result = await runCLI(
+        ['attach', 'gateway', '--agent', agentName, '--gateway', gatewayName, '--json'],
+        projectDir
+      );
 
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.strictEqual(json.agentName, agentName);
-      assert.strictEqual(json.gatewayName, gatewayName);
+      expect(json.success).toBe(true);
+      expect(json.agentName).toBe(agentName);
+      expect(json.gatewayName).toBe(gatewayName);
 
       // Verify in agentcore.json
       const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
       const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentName);
       const mcpProvider = agent?.mcpProviders?.find((p: { gatewayName?: string }) => p.gatewayName === gatewayName);
-      assert.ok(mcpProvider, 'MCPProvider should be on agent');
-      assert.strictEqual(mcpProvider.type, 'AgentCoreGateway');
+      expect(mcpProvider, 'MCPProvider should be on agent').toBeTruthy();
+      expect(mcpProvider.type).toBe('AgentCoreGateway');
     });
 
     it('rejects non-existent agent', async () => {
-      const result = await runCLI([
-        'attach', 'gateway',
-        '--agent', 'NonExistent',
-        '--gateway', gatewayName,
-        '--json'
-      ], projectDir);
+      const result = await runCLI(
+        ['attach', 'gateway', '--agent', 'NonExistent', '--gateway', gatewayName, '--json'],
+        projectDir
+      );
 
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`).toBeTruthy();
     });
   });
 });
diff --git a/src/cli/commands/attach/__tests__/attach-identity.test.ts b/src/cli/commands/attach/__tests__/attach-identity.test.ts
new file mode 100644
index 000000000..35d663228
--- /dev/null
+++ b/src/cli/commands/attach/__tests__/attach-identity.test.ts
@@ -0,0 +1,153 @@
+import { runCLI } from '../../../../test-utils/index.js';
+import { randomUUID } from 'node:crypto';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+
+describe('attach identity command', () => {
+  let testDir: string;
+  let projectDir: string;
+  const agentA = 'AgentA';
+  const agentB = 'AgentB';
+  const testId = 'TestId';
+
+  beforeAll(async () => {
+    testDir = join(tmpdir(), `agentcore-attach-identity-${randomUUID()}`);
+    await mkdir(testDir, { recursive: true });
+
+    // Create project
+    const projectName = 'AttachIdProj';
+    let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
+    }
+    projectDir = join(testDir, projectName);
+
+    // Add AgentA (owner)
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        agentA,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create AgentA: ${result.stdout} ${result.stderr}`);
+    }
+
+    // Add AgentB (will attach identity to this one)
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        agentB,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create AgentB: ${result.stdout} ${result.stderr}`);
+    }
+
+    // Add identity owned by AgentA
+    result = await runCLI(
+      [
+        'add',
+        'identity',
+        '--name',
+        testId,
+        '--type',
+        'ApiKeyCredentialProvider',
+        '--api-key',
+        'test-key-123',
+        '--owner',
+        agentA,
+        '--json',
+      ],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create TestId: ${result.stdout} ${result.stderr}`);
+    }
+  });
+
+  afterAll(async () => {
+    await rm(testDir, { recursive: true, force: true });
+  });
+
+  describe('validation', () => {
+    it('requires agent flag', async () => {
+      const result = await runCLI(['attach', 'identity', '--json'], projectDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--agent'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('requires identity flag', async () => {
+      const result = await runCLI(['attach', 'identity', '--agent', agentB, '--json'], projectDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--identity'), `Error: ${json.error}`).toBeTruthy();
+    });
+  });
+
+  describe('attach operations', () => {
+    it('attaches identity to agent', async () => {
+      const result = await runCLI(
+        ['attach', 'identity', '--agent', agentB, '--identity', testId, '--json'],
+        projectDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(json.agentName).toBe(agentB);
+      expect(json.identityName).toBe(testId);
+
+      // Verify in agentcore.json
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentB);
+      const identity = agent?.identityProviders?.find((i: { name: string }) => i.name === testId);
+      expect(identity, 'Identity should be on agent').toBeTruthy();
+      expect(identity.relation).toBe('use');
+    });
+
+    it('rejects non-existent agent', async () => {
+      const result = await runCLI(
+        ['attach', 'identity', '--agent', 'NonExistent', '--identity', testId, '--json'],
+        projectDir
+      );
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(
+        json.error.includes('not found') || json.error.includes('NonExistent'),
+        `Error: ${json.error}`
+      ).toBeTruthy();
+    });
+  });
+});
diff --git a/src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts b/src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts
new file mode 100644
index 000000000..d5095fcaa
--- /dev/null
+++ b/src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts
@@ -0,0 +1,163 @@
+import { runCLI } from '../../../../test-utils/index.js';
+import { randomUUID } from 'node:crypto';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+
+describe('attach mcp-runtime command', () => {
+  let testDir: string;
+  let projectDir: string;
+  const agentA = 'AgentA';
+  const agentB = 'AgentB';
+  const toolName = 'testtool';
+
+  beforeAll(async () => {
+    testDir = join(tmpdir(), `agentcore-attach-mcp-runtime-${randomUUID()}`);
+    await mkdir(testDir, { recursive: true });
+
+    // Create project
+    const projectName = 'AttachMcpRuntimeProj';
+    let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
+    }
+    projectDir = join(testDir, projectName);
+
+    // Add AgentA
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        agentA,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create AgentA: ${result.stdout} ${result.stderr}`);
+    }
+
+    // Add AgentB
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        agentB,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create AgentB: ${result.stdout} ${result.stderr}`);
+    }
+
+    // Add MCP tool with mcp-runtime exposure attached to AgentA
+    result = await runCLI(
+      [
+        'add',
+        'mcp-tool',
+        '--name',
+        toolName,
+        '--language',
+        'Python',
+        '--exposure',
+        'mcp-runtime',
+        '--agents',
+        agentA,
+        '--json',
+      ],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create MCP tool: ${result.stdout} ${result.stderr}`);
+    }
+  });
+
+  afterAll(async () => {
+    await rm(testDir, { recursive: true, force: true });
+  });
+
+  describe('validation', () => {
+    it('requires agent flag', async () => {
+      const result = await runCLI(['attach', 'mcp-runtime', '--json'], projectDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--agent'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('requires runtime flag', async () => {
+      const result = await runCLI(['attach', 'mcp-runtime', '--agent', agentB, '--json'], projectDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--runtime'), `Error: ${json.error}`).toBeTruthy();
+    });
+  });
+
+  describe('bind operations', () => {
+    it('binds agent to MCP runtime', async () => {
+      const result = await runCLI(
+        ['attach', 'mcp-runtime', '--agent', agentB, '--runtime', toolName, '--json'],
+        projectDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(json.agentName).toBe(agentB);
+      expect(json.runtimeName).toBe(toolName);
+
+      // Verify in mcp.json
+      const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8'));
+      const runtime = mcpSpec.mcpRuntimeTools?.find((t: { name: string }) => t.name === toolName);
+      expect(runtime, 'Runtime should exist in mcp.json').toBeTruthy();
+      const binding = runtime.bindings?.find((b: { agentName: string }) => b.agentName === agentB);
+      expect(binding, 'AgentB binding should exist').toBeTruthy();
+      expect(binding.envVarName, 'Binding should have envVarName').toBeTruthy();
+    });
+
+    it('rejects non-existent agent', async () => {
+      const result = await runCLI(
+        ['attach', 'mcp-runtime', '--agent', 'NonExistent', '--runtime', toolName, '--json'],
+        projectDir
+      );
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('rejects non-existent runtime', async () => {
+      const result = await runCLI(
+        ['attach', 'mcp-runtime', '--agent', agentB, '--runtime', 'nonexistent', '--json'],
+        projectDir
+      );
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`).toBeTruthy();
+    });
+  });
+});
diff --git a/src/cli/commands/attach/__tests__/attach-memory.test.ts b/src/cli/commands/attach/__tests__/attach-memory.test.ts
new file mode 100644
index 000000000..66c4e4829
--- /dev/null
+++ b/src/cli/commands/attach/__tests__/attach-memory.test.ts
@@ -0,0 +1,175 @@
+import { runCLI } from '../../../../test-utils/index.js';
+import { randomUUID } from 'node:crypto';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+
+describe('attach memory command', () => {
+  let testDir: string;
+  let projectDir: string;
+  const agentA = 'AgentA';
+  const agentB = 'AgentB';
+  const testMem = 'TestMem';
+  const readOnlyMem = 'ReadOnlyMem';
+
+  beforeAll(async () => {
+    testDir = join(tmpdir(), `agentcore-attach-memory-${randomUUID()}`);
+    await mkdir(testDir, { recursive: true });
+
+    // Create project
+    const projectName = 'AttachMemProj';
+    let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
+    }
+    projectDir = join(testDir, projectName);
+
+    // Add AgentA (owner)
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        agentA,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create AgentA: ${result.stdout} ${result.stderr}`);
+    }
+
+    // Add AgentB (will attach memory to this one)
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        agentB,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create AgentB: ${result.stdout} ${result.stderr}`);
+    }
+
+    // Add memory owned by AgentA
+    result = await runCLI(
+      ['add', 'memory', '--name', testMem, '--strategies', 'SEMANTIC', '--owner', agentA, '--json'],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create TestMem: ${result.stdout} ${result.stderr}`);
+    }
+
+    // Add second memory for access level test
+    result = await runCLI(
+      ['add', 'memory', '--name', readOnlyMem, '--strategies', 'SEMANTIC', '--owner', agentA, '--json'],
+      projectDir
+    );
+    if (result.exitCode !== 0) {
+      throw new Error(`Failed to create ReadOnlyMem: ${result.stdout} ${result.stderr}`);
+    }
+  });
+
+  afterAll(async () => {
+    await rm(testDir, { recursive: true, force: true });
+  });
+
+  describe('validation', () => {
+    it('requires agent flag', async () => {
+      const result = await runCLI(['attach', 'memory', '--json'], projectDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--agent'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('requires memory flag', async () => {
+      const result = await runCLI(['attach', 'memory', '--agent', agentB, '--json'], projectDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--memory'), `Error: ${json.error}`).toBeTruthy();
+    });
+
+    it('validates access value', async () => {
+      const result = await runCLI(
+        ['attach', 'memory', '--agent', agentB, '--memory', testMem, '--access', 'invalid', '--json'],
+        projectDir
+      );
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('read') || json.error.includes('access'), `Error: ${json.error}`).toBeTruthy();
+    });
+  });
+
+  describe('attach operations', () => {
+    it('attaches memory to agent', async () => {
+      const result = await runCLI(['attach', 'memory', '--agent', agentB, '--memory', testMem, '--json'], projectDir);
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(json.agentName).toBe(agentB);
+      expect(json.memoryName).toBe(testMem);
+
+      // Verify in agentcore.json
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentB);
+      const memory = agent?.memoryProviders?.find((m: { name: string }) => m.name === testMem);
+      expect(memory, 'Memory should be on agent').toBeTruthy();
+      expect(memory.relation).toBe('use');
+      expect(memory.access).toBe('readwrite');
+    });
+
+    it('uses specified access level', async () => {
+      const result = await runCLI(
+        ['attach', 'memory', '--agent', agentB, '--memory', readOnlyMem, '--access', 'read', '--json'],
+        projectDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
+
+      // Verify access level
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentB);
+      const memory = agent?.memoryProviders?.find((m: { name: string }) => m.name === readOnlyMem);
+      expect(memory?.access).toBe('read');
+    });
+
+    it('rejects non-existent agent', async () => {
+      const result = await runCLI(
+        ['attach', 'memory', '--agent', 'NonExistent', '--memory', testMem, '--json'],
+        projectDir
+      );
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(
+        json.error.includes('not found') || json.error.includes('NonExistent'),
+        `Error: ${json.error}`
+      ).toBeTruthy();
+    });
+  });
+});
diff --git a/src/cli/commands/attach/actions.ts b/src/cli/commands/attach/actions.ts
index 76bdc9907..9aa599dbe 100644
--- a/src/cli/commands/attach/actions.ts
+++ b/src/cli/commands/attach/actions.ts
@@ -1,7 +1,19 @@
 import type { Access } from '../../../schema';
 import { getErrorMessage } from '../../errors';
-import { attachAgentToAgent, attachMemoryToAgent, attachIdentityToAgent, bindMcpRuntimeToAgent, attachGatewayToAgent } from '../../operations/attach';
-import type { AttachAgentResult, AttachMemoryResult, AttachIdentityResult, AttachMcpRuntimeResult, AttachGatewayResult } from './types';
+import {
+  attachAgentToAgent,
+  attachGatewayToAgent,
+  attachIdentityToAgent,
+  attachMemoryToAgent,
+  bindMcpRuntimeToAgent,
+} from '../../operations/attach';
+import type {
+  AttachAgentResult,
+  AttachGatewayResult,
+  AttachIdentityResult,
+  AttachMcpRuntimeResult,
+  AttachMemoryResult,
+} from './types';
 
 // Agent
 export interface ValidatedAttachAgentOptions {
@@ -92,7 +104,9 @@ export interface ValidatedAttachMcpRuntimeOptions {
   runtime: string;
 }
 
-export async function handleAttachMcpRuntime(options: ValidatedAttachMcpRuntimeOptions): Promise<AttachMcpRuntimeResult> {
+export async function handleAttachMcpRuntime(
+  options: ValidatedAttachMcpRuntimeOptions
+): Promise<AttachMcpRuntimeResult> {
   try {
     const sanitized = options.runtime.toUpperCase().replace(/-/g, '_');
     const config = {
diff --git a/src/cli/commands/attach/attach-agent.test.ts b/src/cli/commands/attach/attach-agent.test.ts
deleted file mode 100644
index a8c3c3cfe..000000000
--- a/src/cli/commands/attach/attach-agent.test.ts
+++ /dev/null
@@ -1,153 +0,0 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
-import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
-
-describe('attach agent command', () => {
-  let testDir: string;
-  let projectDir: string;
-  const agentA = 'AgentA';
-  const agentB = 'AgentB';
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-attach-agent-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-
-    // Create project
-    const projectName = 'AttachProj';
-    let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
-    }
-    projectDir = join(testDir, projectName);
-
-    // Add AgentA
-    result = await runCLI([
-      'add', 'agent',
-      '--name', agentA,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create AgentA: ${result.stdout} ${result.stderr}`);
-    }
-
-    // Add AgentB
-    result = await runCLI([
-      'add', 'agent',
-      '--name', agentB,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create AgentB: ${result.stdout} ${result.stderr}`);
-    }
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('validation', () => {
-    it('requires source flag', async () => {
-      const result = await runCLI(['attach', 'agent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--source'), `Error: ${json.error}`);
-    });
-
-    it('requires target flag', async () => {
-      const result = await runCLI([
-        'attach', 'agent',
-        '--source', agentA,
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--target'), `Error: ${json.error}`);
-    });
-  });
-
-  describe('attach operations', () => {
-    it('attaches agent to agent', async () => {
-      const result = await runCLI([
-        'attach', 'agent',
-        '--source', agentA,
-        '--target', agentB,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.strictEqual(json.sourceAgent, agentA);
-      assert.strictEqual(json.targetAgent, agentB);
-
-      // Verify in agentcore.json
-      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentA);
-      const remoteTool = agent?.remoteTools?.find((t: { name: string }) => t.name === `invoke${agentB}`);
-      assert.ok(remoteTool, 'Remote tool should be on source agent');
-      assert.strictEqual(remoteTool.type, 'AgentCoreAgentInvocation');
-      assert.strictEqual(remoteTool.targetAgentName, agentB);
-    });
-
-    it('uses custom name', async () => {
-      const customName = `custom${Date.now()}`;
-      const result = await runCLI([
-        'attach', 'agent',
-        '--source', agentA,
-        '--target', agentB,
-        '--name', customName,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-
-      // Verify custom name
-      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentA);
-      const remoteTool = agent?.remoteTools?.find((t: { name: string }) => t.name === customName);
-      assert.ok(remoteTool, `Remote tool with name ${customName} should exist`);
-    });
-
-    it('rejects self-attachment', async () => {
-      const result = await runCLI([
-        'attach', 'agent',
-        '--source', agentA,
-        '--target', agentA,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('itself') || json.error.toLowerCase().includes('same'), `Error: ${json.error}`);
-    });
-
-    it('rejects non-existent source', async () => {
-      const result = await runCLI([
-        'attach', 'agent',
-        '--source', 'NonExistent',
-        '--target', agentB,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('not found') || json.error.includes('NonExistent'), `Error: ${json.error}`);
-    });
-  });
-});
diff --git a/src/cli/commands/attach/attach-identity.test.ts b/src/cli/commands/attach/attach-identity.test.ts
deleted file mode 100644
index 8fd22e07a..000000000
--- a/src/cli/commands/attach/attach-identity.test.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
-import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
-
-describe('attach identity command', () => {
-  let testDir: string;
-  let projectDir: string;
-  const agentA = 'AgentA';
-  const agentB = 'AgentB';
-  const testId = 'TestId';
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-attach-identity-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-
-    // Create project
-    const projectName = 'AttachIdProj';
-    let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
-    }
-    projectDir = join(testDir, projectName);
-
-    // Add AgentA (owner)
-    result = await runCLI([
-      'add', 'agent',
-      '--name', agentA,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create AgentA: ${result.stdout} ${result.stderr}`);
-    }
-
-    // Add AgentB (will attach identity to this one)
-    result = await runCLI([
-      'add', 'agent',
-      '--name', agentB,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create AgentB: ${result.stdout} ${result.stderr}`);
-    }
-
-    // Add identity owned by AgentA
-    result = await runCLI([
-      'add', 'identity',
-      '--name', testId,
-      '--type', 'ApiKeyCredentialProvider',
-      '--api-key', 'test-key-123',
-      '--owner', agentA,
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create TestId: ${result.stdout} ${result.stderr}`);
-    }
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('validation', () => {
-    it('requires agent flag', async () => {
-      const result = await runCLI(['attach', 'identity', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--agent'), `Error: ${json.error}`);
-    });
-
-    it('requires identity flag', async () => {
-      const result = await runCLI([
-        'attach', 'identity',
-        '--agent', agentB,
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--identity'), `Error: ${json.error}`);
-    });
-  });
-
-  describe('attach operations', () => {
-    it('attaches identity to agent', async () => {
-      const result = await runCLI([
-        'attach', 'identity',
-        '--agent', agentB,
-        '--identity', testId,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.strictEqual(json.agentName, agentB);
-      assert.strictEqual(json.identityName, testId);
-
-      // Verify in agentcore.json
-      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentB);
-      const identity = agent?.identityProviders?.find((i: { name: string }) => i.name === testId);
-      assert.ok(identity, 'Identity should be on agent');
-      assert.strictEqual(identity.relation, 'use');
-    });
-
-    it('rejects non-existent agent', async () => {
-      const result = await runCLI([
-        'attach', 'identity',
-        '--agent', 'NonExistent',
-        '--identity', testId,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('not found') || json.error.includes('NonExistent'), `Error: ${json.error}`);
-    });
-  });
-});
diff --git a/src/cli/commands/attach/attach-mcp-runtime.test.ts b/src/cli/commands/attach/attach-mcp-runtime.test.ts
deleted file mode 100644
index 9a30c04f0..000000000
--- a/src/cli/commands/attach/attach-mcp-runtime.test.ts
+++ /dev/null
@@ -1,148 +0,0 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
-import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
-
-describe('attach mcp-runtime command', () => {
-  let testDir: string;
-  let projectDir: string;
-  const agentA = 'AgentA';
-  const agentB = 'AgentB';
-  const toolName = 'testtool';
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-attach-mcp-runtime-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-
-    // Create project
-    const projectName = 'AttachMcpRuntimeProj';
-    let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
-    }
-    projectDir = join(testDir, projectName);
-
-    // Add AgentA
-    result = await runCLI([
-      'add', 'agent',
-      '--name', agentA,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create AgentA: ${result.stdout} ${result.stderr}`);
-    }
-
-    // Add AgentB
-    result = await runCLI([
-      'add', 'agent',
-      '--name', agentB,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create AgentB: ${result.stdout} ${result.stderr}`);
-    }
-
-    // Add MCP tool with mcp-runtime exposure attached to AgentA
-    result = await runCLI([
-      'add', 'mcp-tool',
-      '--name', toolName,
-      '--language', 'Python',
-      '--exposure', 'mcp-runtime',
-      '--agents', agentA,
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create MCP tool: ${result.stdout} ${result.stderr}`);
-    }
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('validation', () => {
-    it('requires agent flag', async () => {
-      const result = await runCLI(['attach', 'mcp-runtime', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--agent'), `Error: ${json.error}`);
-    });
-
-    it('requires runtime flag', async () => {
-      const result = await runCLI([
-        'attach', 'mcp-runtime',
-        '--agent', agentB,
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--runtime'), `Error: ${json.error}`);
-    });
-  });
-
-  describe('bind operations', () => {
-    it('binds agent to MCP runtime', async () => {
-      const result = await runCLI([
-        'attach', 'mcp-runtime',
-        '--agent', agentB,
-        '--runtime', toolName,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.strictEqual(json.agentName, agentB);
-      assert.strictEqual(json.runtimeName, toolName);
-
-      // Verify in mcp.json
-      const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8'));
-      const runtime = mcpSpec.mcpRuntimeTools?.find((t: { name: string }) => t.name === toolName);
-      assert.ok(runtime, 'Runtime should exist in mcp.json');
-      const binding = runtime.bindings?.find((b: { agentName: string }) => b.agentName === agentB);
-      assert.ok(binding, 'AgentB binding should exist');
-      assert.ok(binding.envVarName, 'Binding should have envVarName');
-    });
-
-    it('rejects non-existent agent', async () => {
-      const result = await runCLI([
-        'attach', 'mcp-runtime',
-        '--agent', 'NonExistent',
-        '--runtime', toolName,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`);
-    });
-
-    it('rejects non-existent runtime', async () => {
-      const result = await runCLI([
-        'attach', 'mcp-runtime',
-        '--agent', agentB,
-        '--runtime', 'nonexistent',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`);
-    });
-  });
-});
diff --git a/src/cli/commands/attach/attach-memory.test.ts b/src/cli/commands/attach/attach-memory.test.ts
deleted file mode 100644
index 21b85d207..000000000
--- a/src/cli/commands/attach/attach-memory.test.ts
+++ /dev/null
@@ -1,178 +0,0 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
-import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
-
-describe('attach memory command', () => {
-  let testDir: string;
-  let projectDir: string;
-  const agentA = 'AgentA';
-  const agentB = 'AgentB';
-  const testMem = 'TestMem';
-  const readOnlyMem = 'ReadOnlyMem';
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-attach-memory-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-
-    // Create project
-    const projectName = 'AttachMemProj';
-    let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create project: ${result.stdout} ${result.stderr}`);
-    }
-    projectDir = join(testDir, projectName);
-
-    // Add AgentA (owner)
-    result = await runCLI([
-      'add', 'agent',
-      '--name', agentA,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create AgentA: ${result.stdout} ${result.stderr}`);
-    }
-
-    // Add AgentB (will attach memory to this one)
-    result = await runCLI([
-      'add', 'agent',
-      '--name', agentB,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create AgentB: ${result.stdout} ${result.stderr}`);
-    }
-
-    // Add memory owned by AgentA
-    result = await runCLI([
-      'add', 'memory',
-      '--name', testMem,
-      '--strategies', 'SEMANTIC',
-      '--owner', agentA,
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create TestMem: ${result.stdout} ${result.stderr}`);
-    }
-
-    // Add second memory for access level test
-    result = await runCLI([
-      'add', 'memory',
-      '--name', readOnlyMem,
-      '--strategies', 'SEMANTIC',
-      '--owner', agentA,
-      '--json'
-    ], projectDir);
-    if (result.exitCode !== 0) {
-      throw new Error(`Failed to create ReadOnlyMem: ${result.stdout} ${result.stderr}`);
-    }
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('validation', () => {
-    it('requires agent flag', async () => {
-      const result = await runCLI(['attach', 'memory', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--agent'), `Error: ${json.error}`);
-    });
-
-    it('requires memory flag', async () => {
-      const result = await runCLI([
-        'attach', 'memory',
-        '--agent', agentB,
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--memory'), `Error: ${json.error}`);
-    });
-
-    it('validates access value', async () => {
-      const result = await runCLI([
-        'attach', 'memory',
-        '--agent', agentB,
-        '--memory', testMem,
-        '--access', 'invalid',
-        '--json'
-      ], projectDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('read') || json.error.includes('access'), `Error: ${json.error}`);
-    });
-  });
-
-  describe('attach operations', () => {
-    it('attaches memory to agent', async () => {
-      const result = await runCLI([
-        'attach', 'memory',
-        '--agent', agentB,
-        '--memory', testMem,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.strictEqual(json.agentName, agentB);
-      assert.strictEqual(json.memoryName, testMem);
-
-      // Verify in agentcore.json
-      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentB);
-      const memory = agent?.memoryProviders?.find((m: { name: string }) => m.name === testMem);
-      assert.ok(memory, 'Memory should be on agent');
-      assert.strictEqual(memory.relation, 'use');
-      assert.strictEqual(memory.access, 'readwrite');
-    });
-
-    it('uses specified access level', async () => {
-      const result = await runCLI([
-        'attach', 'memory',
-        '--agent', agentB,
-        '--memory', readOnlyMem,
-        '--access', 'read',
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}, stderr: ${result.stderr}`);
-
-      // Verify access level
-      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentB);
-      const memory = agent?.memoryProviders?.find((m: { name: string }) => m.name === readOnlyMem);
-      assert.strictEqual(memory?.access, 'read');
-    });
-
-    it('rejects non-existent agent', async () => {
-      const result = await runCLI([
-        'attach', 'memory',
-        '--agent', 'NonExistent',
-        '--memory', testMem,
-        '--json'
-      ], projectDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('not found') || json.error.includes('NonExistent'), `Error: ${json.error}`);
-    });
-  });
-});
diff --git a/src/cli/commands/attach/command.tsx b/src/cli/commands/attach/command.tsx
index ba1ea28cc..de9e4f1a9 100644
--- a/src/cli/commands/attach/command.tsx
+++ b/src/cli/commands/attach/command.tsx
@@ -1,9 +1,27 @@
 import { COMMAND_DESCRIPTIONS } from '../../tui/copy';
 import { requireProject } from '../../tui/guards';
 import { AttachFlow } from '../../tui/screens/attach/AttachFlow';
-import { handleAttachAgent, handleAttachMemory, handleAttachIdentity, handleAttachMcpRuntime, handleAttachGateway } from './actions';
-import type { AttachAgentOptions, AttachMemoryOptions, AttachIdentityOptions, AttachMcpRuntimeOptions, AttachGatewayOptions } from './types';
-import { validateAttachAgentOptions, validateAttachMemoryOptions, validateAttachIdentityOptions, validateAttachMcpRuntimeOptions, validateAttachGatewayOptions } from './validate';
+import {
+  handleAttachAgent,
+  handleAttachGateway,
+  handleAttachIdentity,
+  handleAttachMcpRuntime,
+  handleAttachMemory,
+} from './actions';
+import type {
+  AttachAgentOptions,
+  AttachGatewayOptions,
+  AttachIdentityOptions,
+  AttachMcpRuntimeOptions,
+  AttachMemoryOptions,
+} from './types';
+import {
+  validateAttachAgentOptions,
+  validateAttachGatewayOptions,
+  validateAttachIdentityOptions,
+  validateAttachMcpRuntimeOptions,
+  validateAttachMemoryOptions,
+} from './validate';
 import type { Command } from '@commander-js/extra-typings';
 import { render } from 'ink';
 import React from 'react';
@@ -118,7 +136,6 @@ async function handleAttachMcpRuntimeCLI(options: AttachMcpRuntimeOptions): Prom
   process.exit(result.success ? 0 : 1);
 }
 
-
 async function handleAttachGatewayCLI(options: AttachGatewayOptions): Promise<void> {
   const validation = validateAttachGatewayOptions(options);
   if (!validation.valid) {
@@ -146,7 +163,6 @@ async function handleAttachGatewayCLI(options: AttachGatewayOptions): Promise<vo
   process.exit(result.success ? 0 : 1);
 }
 
-
 export function registerAttach(program: Command) {
   const attachCmd = program
     .command('attach')
diff --git a/src/cli/commands/attach/validate.ts b/src/cli/commands/attach/validate.ts
index cb223746c..e2af477dd 100644
--- a/src/cli/commands/attach/validate.ts
+++ b/src/cli/commands/attach/validate.ts
@@ -1,4 +1,10 @@
-import type { AttachAgentOptions, AttachMemoryOptions, AttachIdentityOptions, AttachMcpRuntimeOptions, AttachGatewayOptions } from './types';
+import type {
+  AttachAgentOptions,
+  AttachGatewayOptions,
+  AttachIdentityOptions,
+  AttachMcpRuntimeOptions,
+  AttachMemoryOptions,
+} from './types';
 
 export interface ValidationResult {
   valid: boolean;
diff --git a/src/cli/commands/create/__tests__/create.test.ts b/src/cli/commands/create/__tests__/create.test.ts
new file mode 100644
index 000000000..a9c7678d9
--- /dev/null
+++ b/src/cli/commands/create/__tests__/create.test.ts
@@ -0,0 +1,155 @@
+import { exists, runCLI } from '../../../../test-utils/index.js';
+import { randomUUID } from 'node:crypto';
+import { mkdir, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+
+describe('create command', () => {
+  let testDir: string;
+
+  beforeAll(async () => {
+    testDir = join(tmpdir(), `agentcore-test-${randomUUID()}`);
+    await mkdir(testDir, { recursive: true });
+  });
+
+  afterAll(async () => {
+    await rm(testDir, { recursive: true, force: true });
+  });
+
+  describe('--no-agent', () => {
+    it('creates project structure', async () => {
+      const name = `Proj${Date.now()}`;
+      const result = await runCLI(['create', '--name', name, '--no-agent', '--json'], testDir);
+
+      expect(result.exitCode, `stderr: ${result.stderr}, stdout: ${result.stdout}`).toBe(0);
+
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(await exists(json.projectPath), 'Project should exist').toBeTruthy();
+      expect(await exists(join(json.projectPath, 'agentcore')), 'agentcore/ should exist').toBeTruthy();
+    });
+
+    it('rejects reserved names', async () => {
+      const result = await runCLI(['create', '--name', 'Test', '--no-agent', '--json'], testDir);
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('conflicts')).toBeTruthy();
+    });
+  });
+
+  describe('with agent', () => {
+    it('creates project with agent', async () => {
+      const name = `Agent${Date.now()}`;
+      const result = await runCLI(
+        [
+          'create',
+          '--name',
+          name,
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        testDir
+      );
+
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
+
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(json.agentName).toBe(name);
+      expect(await exists(join(json.projectPath, 'app', name))).toBeTruthy();
+    });
+
+    it('requires all options without --no-agent', async () => {
+      const result = await runCLI(['create', '--name', 'Incomplete', '--json'], testDir);
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+    });
+
+    it('validates framework', async () => {
+      const result = await runCLI(
+        [
+          'create',
+          '--name',
+          'BadFW',
+          '--language',
+          'Python',
+          '--framework',
+          'NotReal',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        testDir
+      );
+
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+    });
+  });
+
+  describe('--defaults', () => {
+    it('creates project with defaults', async () => {
+      const name = `Defaults${Date.now()}`;
+      const result = await runCLI(['create', '--name', name, '--defaults', '--json'], testDir);
+
+      expect(result.exitCode, `stderr: ${result.stderr}`).toBe(0);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(await exists(join(testDir, name))).toBeTruthy();
+    });
+  });
+
+  describe('--dry-run', () => {
+    it('shows files without creating', async () => {
+      const name = `DryRun${Date.now()}`;
+      const result = await runCLI(['create', '--name', name, '--defaults', '--dry-run'], testDir);
+
+      expect(result.exitCode).toBe(0);
+      expect(result.stdout.includes('would create') || result.stdout.includes('Dry run')).toBeTruthy();
+      expect(await exists(join(testDir, name)), 'Should not create directory').toBe(false);
+    });
+  });
+
+  describe('--skip-git', () => {
+    it('skips git initialization', async () => {
+      const name = `NoGit${Date.now()}`;
+      const result = await runCLI(['create', '--name', name, '--defaults', '--skip-git', '--json'], testDir);
+
+      expect(result.exitCode, `stderr: ${result.stderr}`).toBe(0);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(await exists(join(testDir, name, '.git')), 'Should not have .git').toBe(false);
+    });
+  });
+
+  describe('--output-dir', () => {
+    it('creates in specified directory', async () => {
+      const name = `OutDir${Date.now()}`;
+      const customDir = join(testDir, 'custom-output');
+      const result = await runCLI(
+        ['create', '--name', name, '--defaults', '--output-dir', customDir, '--json'],
+        testDir
+      );
+
+      expect(result.exitCode, `stderr: ${result.stderr}`).toBe(0);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+      expect(await exists(join(customDir, name)), 'Should create in custom dir').toBeTruthy();
+    });
+  });
+});
diff --git a/src/cli/commands/create/action.ts b/src/cli/commands/create/action.ts
index 34273e570..d55c86182 100644
--- a/src/cli/commands/create/action.ts
+++ b/src/cli/commands/create/action.ts
@@ -1,5 +1,13 @@
 import { APP_DIR, CONFIG_DIR, ConfigIO, setEnvVar, setSessionProjectRoot } from '../../../lib';
-import type { AgentCoreCliMcpDefs, AgentCoreMcpSpec, AgentCoreProjectSpec, DeployedState, ModelProvider, SDKFramework, TargetLanguage } from '../../../schema';
+import type {
+  AgentCoreCliMcpDefs,
+  AgentCoreMcpSpec,
+  AgentCoreProjectSpec,
+  DeployedState,
+  ModelProvider,
+  SDKFramework,
+  TargetLanguage,
+} from '../../../schema';
 import { getErrorMessage } from '../../errors';
 import { initGitRepo, setupPythonProject, writeEnvFile, writeGitignore } from '../../operations';
 import { mapGenerateConfigToAgentEnvSpec, writeAgentToProject } from '../../operations/agent/generate';
@@ -140,7 +148,7 @@ export async function createProjectWithAgent(options: CreateWithAgentOptions): P
 export function getDryRunInfo(options: { name: string; cwd: string; language?: string }): CreateResult {
   const { name, cwd, language } = options;
   const projectRoot = join(cwd, name);
-  
+
   const wouldCreate = [
     `${projectRoot}/`,
     `${projectRoot}/agentcore/`,
@@ -149,13 +157,13 @@ export function getDryRunInfo(options: { name: string; cwd: string; language?: s
     `${projectRoot}/agentcore/.env.local`,
     `${projectRoot}/cdk/`,
   ];
-  
+
   if (language === 'Python') {
     wouldCreate.push(`${projectRoot}/app/${name}/`);
     wouldCreate.push(`${projectRoot}/app/${name}/main.py`);
     wouldCreate.push(`${projectRoot}/app/${name}/pyproject.toml`);
   }
-  
+
   return {
     success: true,
     dryRun: true,
diff --git a/src/cli/commands/create/command.tsx b/src/cli/commands/create/command.tsx
index 82dc10359..ee70cc11d 100644
--- a/src/cli/commands/create/command.tsx
+++ b/src/cli/commands/create/command.tsx
@@ -26,7 +26,7 @@ async function handleCreateCLI(options: CreateOptions): Promise<void> {
   }
 
   const cwd = options.outputDir ?? getWorkingDirectory();
-  
+
   // Handle dry-run mode
   if (options.dryRun) {
     const result = getDryRunInfo({ name: options.name!, cwd, language: options.language });
@@ -40,10 +40,10 @@ async function handleCreateCLI(options: CreateOptions): Promise<void> {
     }
     process.exit(0);
   }
-  
+
   // Commander.js --no-agent sets agent=false, not noAgent=true
   const skipAgent = options.agent === false;
-  
+
   const result = skipAgent
     ? await createProject({ name: options.name!, cwd, skipGit: options.skipGit })
     : await createProjectWithAgent({
@@ -65,7 +65,7 @@ async function handleCreateCLI(options: CreateOptions): Promise<void> {
   } else {
     console.error(result.error);
   }
-  
+
   process.exit(result.success ? 0 : 1);
 }
 
@@ -77,7 +77,10 @@ export const registerCreate = (program: Command) => {
     .option('--no-agent', 'Skip agent creation')
     .option('--defaults', 'Use defaults (Python, Strands, Bedrock, no memory)')
     .option('--language <language>', 'Target language (Python, TypeScript)')
-    .option('--framework <framework>', 'Agent framework (Strands, LangChain_LangGraph, AutoGen, CrewAI, GoogleADK, OpenAIAgents)')
+    .option(
+      '--framework <framework>',
+      'Agent framework (Strands, LangChain_LangGraph, AutoGen, CrewAI, GoogleADK, OpenAIAgents)'
+    )
     .option('--model-provider <provider>', 'Model provider (Bedrock, Anthropic, OpenAI, Gemini)')
     .option('--api-key <key>', 'API key for non-Bedrock providers')
     .option('--memory <option>', 'Memory option (none, shortTerm, longAndShortTerm)')
@@ -95,7 +98,7 @@ export const registerCreate = (program: Command) => {
           options.modelProvider = options.modelProvider ?? 'Bedrock';
           options.memory = options.memory ?? 'none';
         }
-        
+
         if (options.name) {
           await handleCreateCLI(options as CreateOptions);
         } else {
diff --git a/src/cli/commands/create/create.test.ts b/src/cli/commands/create/create.test.ts
deleted file mode 100644
index 6251291d4..000000000
--- a/src/cli/commands/create/create.test.ts
+++ /dev/null
@@ -1,135 +0,0 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
-import { randomUUID } from 'node:crypto';
-import { runCLI, exists } from '../../../test-utils/index.js';
-
-describe('create command', () => {
-  let testDir: string;
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-test-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('--no-agent', () => {
-    it('creates project structure', async () => {
-      const name = `Proj${Date.now()}`;
-      const result = await runCLI(['create', '--name', name, '--no-agent', '--json'], testDir);
-
-      assert.strictEqual(result.exitCode, 0, `stderr: ${result.stderr}, stdout: ${result.stdout}`);
-
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.ok(await exists(json.projectPath), 'Project should exist');
-      assert.ok(await exists(join(json.projectPath, 'agentcore')), 'agentcore/ should exist');
-    });
-
-    it('rejects reserved names', async () => {
-      const result = await runCLI(['create', '--name', 'Test', '--no-agent', '--json'], testDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('conflicts'));
-    });
-  });
-
-  describe('with agent', () => {
-    it('creates project with agent', async () => {
-      const name = `Agent${Date.now()}`;
-      const result = await runCLI([
-        'create', '--name', name,
-        '--language', 'Python',
-        '--framework', 'Strands',
-        '--model-provider', 'Bedrock',
-        '--memory', 'none',
-        '--json'
-      ], testDir);
-
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}`);
-
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.strictEqual(json.agentName, name);
-      assert.ok(await exists(join(json.projectPath, 'app', name)));
-    });
-
-    it('requires all options without --no-agent', async () => {
-      const result = await runCLI(['create', '--name', 'Incomplete', '--json'], testDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-    });
-
-    it('validates framework', async () => {
-      const result = await runCLI([
-        'create', '--name', 'BadFW',
-        '--language', 'Python',
-        '--framework', 'NotReal',
-        '--model-provider', 'Bedrock',
-        '--memory', 'none',
-        '--json'
-      ], testDir);
-
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-    });
-  });
-
-  describe('--defaults', () => {
-    it('creates project with defaults', async () => {
-      const name = `Defaults${Date.now()}`;
-      const result = await runCLI(['create', '--name', name, '--defaults', '--json'], testDir);
-
-      assert.strictEqual(result.exitCode, 0, `stderr: ${result.stderr}`);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.ok(await exists(join(testDir, name)));
-    });
-  });
-
-  describe('--dry-run', () => {
-    it('shows files without creating', async () => {
-      const name = `DryRun${Date.now()}`;
-      const result = await runCLI(['create', '--name', name, '--defaults', '--dry-run'], testDir);
-
-      assert.strictEqual(result.exitCode, 0);
-      assert.ok(result.stdout.includes('would create') || result.stdout.includes('Dry run'));
-      assert.strictEqual(await exists(join(testDir, name)), false, 'Should not create directory');
-    });
-  });
-
-  describe('--skip-git', () => {
-    it('skips git initialization', async () => {
-      const name = `NoGit${Date.now()}`;
-      const result = await runCLI(['create', '--name', name, '--defaults', '--skip-git', '--json'], testDir);
-
-      assert.strictEqual(result.exitCode, 0, `stderr: ${result.stderr}`);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.strictEqual(await exists(join(testDir, name, '.git')), false, 'Should not have .git');
-    });
-  });
-
-  describe('--output-dir', () => {
-    it('creates in specified directory', async () => {
-      const name = `OutDir${Date.now()}`;
-      const customDir = join(testDir, 'custom-output');
-      const result = await runCLI(['create', '--name', name, '--defaults', '--output-dir', customDir, '--json'], testDir);
-
-      assert.strictEqual(result.exitCode, 0, `stderr: ${result.stderr}`);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.ok(await exists(join(customDir, name)), 'Should create in custom dir');
-    });
-  });
-});
diff --git a/src/cli/commands/create/validate.ts b/src/cli/commands/create/validate.ts
index e44d049dc..5b3af9ec3 100644
--- a/src/cli/commands/create/validate.ts
+++ b/src/cli/commands/create/validate.ts
@@ -1,4 +1,10 @@
-import { ProjectNameSchema, getSupportedModelProviders, SDKFrameworkSchema, ModelProviderSchema, TargetLanguageSchema } from '../../../schema';
+import {
+  ModelProviderSchema,
+  ProjectNameSchema,
+  SDKFrameworkSchema,
+  TargetLanguageSchema,
+  getSupportedModelProviders,
+} from '../../../schema';
 import type { CreateOptions } from './types';
 
 export interface ValidationResult {
@@ -27,11 +33,11 @@ export function validateCreateOptions(options: CreateOptions): ValidationResult
 
   // Without --no-agent, all agent options are required
   const hasAllAgentOptions = options.language && options.framework && options.modelProvider && options.memory;
-  
+
   if (!hasAllAgentOptions) {
-    return { 
-      valid: false, 
-      error: 'Use --no-agent for project-only, or provide all: --language, --framework, --model-provider, --memory' 
+    return {
+      valid: false,
+      error: 'Use --no-agent for project-only, or provide all: --language, --framework, --model-provider, --memory',
     };
   }
 
@@ -80,8 +86,11 @@ export function validateCreateOptions(options: CreateOptions): ValidationResult
     }
 
     // Validate memory option
-    if (!MEMORY_OPTIONS.includes(options.memory as typeof MEMORY_OPTIONS[number])) {
-      return { valid: false, error: `Invalid memory option: ${options.memory}. Use none, shortTerm, or longAndShortTerm` };
+    if (!MEMORY_OPTIONS.includes(options.memory as (typeof MEMORY_OPTIONS)[number])) {
+      return {
+        valid: false,
+        error: `Invalid memory option: ${options.memory}. Use none, shortTerm, or longAndShortTerm`,
+      };
     }
   }
 
diff --git a/src/cli/commands/deploy/deploy.test.ts b/src/cli/commands/deploy/__tests__/deploy.test.ts
similarity index 58%
rename from src/cli/commands/deploy/deploy.test.ts
rename to src/cli/commands/deploy/__tests__/deploy.test.ts
index a84c49850..c2d7101c3 100644
--- a/src/cli/commands/deploy/deploy.test.ts
+++ b/src/cli/commands/deploy/__tests__/deploy.test.ts
@@ -1,25 +1,24 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
+import { runCLI } from '../../../../test-utils/index.js';
 import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
+import { mkdir, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
 
 describe('deploy --help', () => {
   it('shows verbose option', async () => {
     const result = await runCLI(['deploy', '--help']);
-    assert.strictEqual(result.exitCode, 0);
-    assert.ok(result.stdout.includes('--verbose'), 'Should show --verbose option');
-    assert.ok(result.stdout.includes('resource-level'), 'Should describe resource-level events');
+    expect(result.exitCode).toBe(0);
+    expect(result.stdout.includes('--verbose'), 'Should show --verbose option').toBeTruthy();
+    expect(result.stdout.includes('resource-level'), 'Should describe resource-level events').toBeTruthy();
   });
 
   it('shows all deploy options', async () => {
     const result = await runCLI(['deploy', '--help']);
-    assert.ok(result.stdout.includes('--target'));
-    assert.ok(result.stdout.includes('--yes'));
-    assert.ok(result.stdout.includes('--progress'));
-    assert.ok(result.stdout.includes('--json'));
+    expect(result.stdout.includes('--target')).toBeTruthy();
+    expect(result.stdout.includes('--yes')).toBeTruthy();
+    expect(result.stdout.includes('--progress')).toBeTruthy();
+    expect(result.stdout.includes('--json')).toBeTruthy();
   });
 });
 
@@ -40,27 +39,33 @@ describe('deploy command', () => {
     projectDir = join(testDir, projectName);
 
     // Add an agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', 'TestAgent',
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        'TestAgent',
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create agent: ${result.stdout} ${result.stderr}`);
     }
 
     // Add a target
-    result = await runCLI([
-      'add', 'target',
-      '--name', 'test-target',
-      '--account', '123456789012',
-      '--region', 'us-east-1',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      ['add', 'target', '--name', 'test-target', '--account', '123456789012', '--region', 'us-east-1', '--json'],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create target: ${result.stdout} ${result.stderr}`);
     }
@@ -76,21 +81,21 @@ describe('deploy command', () => {
       // We can't fully test TUI, but we can verify it doesn't crash immediately
       const result = await runCLI(['deploy', '--target', 'test-target', '--json'], projectDir);
       // This will fail because we don't have AWS credentials, but it validates the target exists
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
+      expect(json.success).toBe(false);
       // Error should be about AWS/CDK, not about target not found
-      assert.ok(!json.error.includes('not found'), `Should find target, got: ${json.error}`);
+      expect(!json.error.includes('not found'), `Should find target, got: ${json.error}`).toBeTruthy();
     });
   });
 
   describe('target validation', () => {
     it('rejects non-existent target', async () => {
       const result = await runCLI(['deploy', '--target', 'nonexistent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`).toBeTruthy();
     });
   });
 });
diff --git a/src/cli/commands/deploy/actions.ts b/src/cli/commands/deploy/actions.ts
index fca569a3d..09e357aa8 100644
--- a/src/cli/commands/deploy/actions.ts
+++ b/src/cli/commands/deploy/actions.ts
@@ -1,16 +1,16 @@
 import { ConfigIO } from '../../../lib';
+import { createSwitchableIoHost } from '../../cdk/toolkit-lib';
+import { buildDeployedState, getStackOutputs, parseAgentOutputs } from '../../cloudformation';
+import { getErrorMessage } from '../../errors';
+import { ExecLogger } from '../../logging';
 import {
-  validateProject,
+  bootstrapEnvironment,
   buildCdkProject,
-  synthesizeCdk,
   checkBootstrapNeeded,
-  bootstrapEnvironment,
   checkStackDeployability,
+  synthesizeCdk,
+  validateProject,
 } from '../../operations/deploy';
-import { createSwitchableIoHost } from '../../cdk/toolkit-lib';
-import { getStackOutputs, parseAgentOutputs, buildDeployedState } from '../../cloudformation';
-import { getErrorMessage } from '../../errors';
-import { ExecLogger } from '../../logging';
 import type { DeployResult } from './types';
 
 export interface ValidatedDeployOptions {
@@ -50,7 +50,11 @@ export async function handleDeploy(options: ValidatedDeployOptions): Promise<Dep
     if (!target) {
       endStep('error', `Target "${options.target}" not found`);
       logger.finalize(false);
-      return { success: false, error: `Target "${options.target}" not found in aws-targets.json`, logPath: logger.getRelativeLogPath() };
+      return {
+        success: false,
+        error: `Target "${options.target}" not found in aws-targets.json`,
+        logPath: logger.getRelativeLogPath(),
+      };
     }
     endStep('success');
 
@@ -67,7 +71,8 @@ export async function handleDeploy(options: ValidatedDeployOptions): Promise<Dep
     // Synthesize CloudFormation templates
     startStep('Synthesize CloudFormation');
     const switchableIoHost = options.verbose ? createSwitchableIoHost() : undefined;
-    const synthResult = await synthesizeCdk(context.cdkProject, 
+    const synthResult = await synthesizeCdk(
+      context.cdkProject,
       switchableIoHost ? { ioHost: switchableIoHost.ioHost } : undefined
     );
     toolkitWrapper = synthResult.toolkitWrapper;
@@ -77,7 +82,7 @@ export async function handleDeploy(options: ValidatedDeployOptions): Promise<Dep
       logger.finalize(false);
       return { success: false, error: 'No stacks found to deploy', logPath: logger.getRelativeLogPath() };
     }
-    const stackName = stackNames[0] as string;
+    const stackName = stackNames[0]!;
     endStep('success');
 
     // Check if bootstrap needed
@@ -115,7 +120,7 @@ export async function handleDeploy(options: ValidatedDeployOptions): Promise<Dep
 
     // Deploy
     startStep('Deploy to AWS');
-    
+
     // Enable verbose output for resource-level events
     if (switchableIoHost && options.onResourceEvent) {
       switchableIoHost.setOnMessage(msg => {
@@ -123,15 +128,15 @@ export async function handleDeploy(options: ValidatedDeployOptions): Promise<Dep
       });
       switchableIoHost.setVerbose(true);
     }
-    
+
     await toolkitWrapper.deploy();
-    
+
     // Disable verbose output
     if (switchableIoHost) {
       switchableIoHost.setVerbose(false);
       switchableIoHost.setOnMessage(null);
     }
-    
+
     endStep('success');
 
     // Get stack outputs and persist state
diff --git a/src/cli/commands/deploy/command.tsx b/src/cli/commands/deploy/command.tsx
index bec8f86c9..79ee40b10 100644
--- a/src/cli/commands/deploy/command.tsx
+++ b/src/cli/commands/deploy/command.tsx
@@ -49,29 +49,33 @@ async function handleDeployCLI(options: DeployOptions): Promise<void> {
   let spinner: NodeJS.Timeout | undefined;
 
   // Progress callback for --progress mode
-  const onProgress = options.progress ? (step: string, status: 'start' | 'success' | 'error') => {
-    if (spinner) {
-      clearInterval(spinner);
-      process.stdout.write('\r\x1b[K'); // Clear line
-    }
-    
-    if (status === 'start') {
-      let i = 0;
-      process.stdout.write(`${SPINNER_FRAMES[0]} ${step}...`);
-      spinner = setInterval(() => {
-        i = (i + 1) % SPINNER_FRAMES.length;
-        process.stdout.write(`\r${SPINNER_FRAMES[i]} ${step}...`);
-      }, 80);
-    } else if (status === 'success') {
-      console.log(`✓ ${step}`);
-    } else {
-      console.log(`✗ ${step}`);
-    }
-  } : undefined;
+  const onProgress = options.progress
+    ? (step: string, status: 'start' | 'success' | 'error') => {
+        if (spinner) {
+          clearInterval(spinner);
+          process.stdout.write('\r\x1b[K'); // Clear line
+        }
 
-  const onResourceEvent = options.verbose ? (message: string) => {
-    console.log(message);
-  } : undefined;
+        if (status === 'start') {
+          let i = 0;
+          process.stdout.write(`${SPINNER_FRAMES[0]} ${step}...`);
+          spinner = setInterval(() => {
+            i = (i + 1) % SPINNER_FRAMES.length;
+            process.stdout.write(`\r${SPINNER_FRAMES[i]} ${step}...`);
+          }, 80);
+        } else if (status === 'success') {
+          console.log(`✓ ${step}`);
+        } else {
+          console.log(`✗ ${step}`);
+        }
+      }
+    : undefined;
+
+  const onResourceEvent = options.verbose
+    ? (message: string) => {
+        console.log(message);
+      }
+    : undefined;
 
   const result = await handleDeploy({
     target: options.target!,
@@ -90,7 +94,7 @@ async function handleDeployCLI(options: DeployOptions): Promise<void> {
     console.log(JSON.stringify(result));
   } else if (result.success) {
     console.log(`\n✓ Deployed to '${result.targetName}' (stack: ${result.stackName})`);
-    
+
     // Show stack outputs in non-JSON mode
     if (result.outputs && Object.keys(result.outputs).length > 0) {
       console.log('\nOutputs:');
@@ -98,7 +102,7 @@ async function handleDeployCLI(options: DeployOptions): Promise<void> {
         console.log(`  ${key}: ${value}`);
       }
     }
-    
+
     if (result.logPath) {
       console.log(`\nLog: ${result.logPath}`);
     }
diff --git a/src/cli/commands/destroy/destroy.test.ts b/src/cli/commands/destroy/__tests__/destroy.test.ts
similarity index 64%
rename from src/cli/commands/destroy/destroy.test.ts
rename to src/cli/commands/destroy/__tests__/destroy.test.ts
index 932de1a3e..8f36176c2 100644
--- a/src/cli/commands/destroy/destroy.test.ts
+++ b/src/cli/commands/destroy/__tests__/destroy.test.ts
@@ -1,10 +1,9 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
+import { runCLI } from '../../../../test-utils/index.js';
 import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
+import { mkdir, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
 
 describe('destroy command', () => {
   let testDir: string;
@@ -23,27 +22,33 @@ describe('destroy command', () => {
     projectDir = join(testDir, projectName);
 
     // Add an agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', 'TestAgent',
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        'TestAgent',
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create agent: ${result.stdout} ${result.stderr}`);
     }
 
     // Add a target
-    result = await runCLI([
-      'add', 'target',
-      '--name', 'test-target',
-      '--account', '123456789012',
-      '--region', 'us-east-1',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      ['add', 'target', '--name', 'test-target', '--account', '123456789012', '--region', 'us-east-1', '--json'],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create target: ${result.stdout} ${result.stderr}`);
     }
@@ -56,57 +61,59 @@ describe('destroy command', () => {
   describe('validation', () => {
     it('requires --target flag for CLI mode', async () => {
       const result = await runCLI(['destroy', '--target', 'test-target', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('not found') || json.error.toLowerCase().includes('not deployed'));
+      expect(json.success).toBe(false);
+      expect(
+        json.error.toLowerCase().includes('not found') || json.error.toLowerCase().includes('not deployed')
+      ).toBeTruthy();
     });
 
     it('shows JSON error for whitespace-only target', async () => {
       const result = await runCLI(['destroy', '--target', '   ', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--target'), `Error should mention target: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--target'), `Error should mention target: ${json.error}`).toBeTruthy();
     });
   });
 
   describe('target discovery', () => {
     it('returns error for non-existent target', async () => {
       const result = await runCLI(['destroy', '--target', 'nonexistent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(
+      expect(json.success).toBe(false);
+      expect(
         json.error.toLowerCase().includes('not found') || json.error.toLowerCase().includes('not deployed'),
         `Error should indicate target not found: ${json.error}`
-      );
+      ).toBeTruthy();
     });
 
     it('returns error for target that exists but is not deployed', async () => {
       const result = await runCLI(['destroy', '--target', 'test-target', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(
+      expect(json.success).toBe(false);
+      expect(
         json.error.toLowerCase().includes('not found') || json.error.toLowerCase().includes('not deployed'),
         `Error should indicate not deployed: ${json.error}`
-      );
+      ).toBeTruthy();
     });
   });
 
   describe('command registration', () => {
     it('command is registered and works', async () => {
       const result = await runCLI(['destroy', '--target', 'nonexistent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
+      expect(json.success).toBe(false);
     });
 
     it('alias x works', async () => {
       const result = await runCLI(['x', '--help'], projectDir);
-      assert.strictEqual(result.exitCode, 0);
-      assert.ok(result.stdout.includes('destroy') || result.stdout.includes('Destroy'), 'Alias should work');
+      expect(result.exitCode).toBe(0);
+      expect(result.stdout.includes('destroy') || result.stdout.includes('Destroy'), 'Alias should work').toBeTruthy();
     });
   });
 });
diff --git a/src/cli/commands/destroy/actions.ts b/src/cli/commands/destroy/actions.ts
index be29d5406..82487eb30 100644
--- a/src/cli/commands/destroy/actions.ts
+++ b/src/cli/commands/destroy/actions.ts
@@ -1,5 +1,5 @@
-import { discoverDeployedTargets, destroyTarget, getCdkProjectDir } from '../../operations/destroy';
 import { getErrorMessage } from '../../errors';
+import { destroyTarget, discoverDeployedTargets, getCdkProjectDir } from '../../operations/destroy';
 import type { DestroyResult } from './types';
 
 export interface ValidatedDestroyOptions {
diff --git a/src/cli/commands/dev/__tests__/dev.test.ts b/src/cli/commands/dev/__tests__/dev.test.ts
new file mode 100644
index 000000000..329442ca1
--- /dev/null
+++ b/src/cli/commands/dev/__tests__/dev.test.ts
@@ -0,0 +1,52 @@
+import { runCLI } from '../../../../test-utils/index.js';
+import { describe, it , expect } from 'vitest';
+
+describe('dev command', () => {
+  describe('--help', () => {
+    it('shows all options', async () => {
+      const result = await runCLI(['dev', '--help']);
+
+      expect(result.exitCode).toBe(0);
+      expect(result.stdout.includes('--port'), 'Should show --port option').toBeTruthy();
+      expect(result.stdout.includes('--agent'), 'Should show --agent option').toBeTruthy();
+      expect(result.stdout.includes('--invoke'), 'Should show --invoke option').toBeTruthy();
+      expect(result.stdout.includes('--stream'), 'Should show --stream option').toBeTruthy();
+      expect(result.stdout.includes('--logs'), 'Should show --logs option').toBeTruthy();
+      expect(result.stdout.includes('8080'), 'Should show default port').toBeTruthy();
+    });
+  });
+
+  describe('requires project context', () => {
+    it('exits with error when run outside project', async () => {
+      const result = await runCLI(['dev']);
+
+      expect(result.exitCode).toBe(1);
+      expect(
+        result.stdout.toLowerCase().includes('project') || result.stderr.toLowerCase().includes('project'),
+        `Should mention project requirement, got: ${result.stdout}`
+      ).toBeTruthy();
+    });
+  });
+
+  describe('flag validation', () => {
+    it('rejects invalid port number', async () => {
+      const result = await runCLI(['dev', '--port', 'abc']);
+
+      expect(result.exitCode).toBe(1);
+    });
+
+    it('rejects negative port number', async () => {
+      const result = await runCLI(['dev', '--port', '-1']);
+
+      expect(result.exitCode).toBe(1);
+    });
+
+    it('stream flag is documented in help', async () => {
+      const result = await runCLI(['dev', '--help']);
+
+      expect(result.exitCode).toBe(0);
+      expect(result.stdout.includes('--stream'), 'Should show --stream option').toBeTruthy();
+      expect(result.stdout.includes('--invoke'), 'Should show --invoke option').toBeTruthy();
+    });
+  });
+});
diff --git a/src/cli/commands/dev/command.tsx b/src/cli/commands/dev/command.tsx
index d45ad1745..c74aa00e6 100644
--- a/src/cli/commands/dev/command.tsx
+++ b/src/cli/commands/dev/command.tsx
@@ -52,7 +52,7 @@ export const registerDev = (program: Command) => {
       if (opts.invoke) {
         const { getAgentPort } = await import('../../operations/dev');
         const invokeProject = await loadProjectConfig(getWorkingDirectory());
-        
+
         // Determine which agent/port to invoke
         let invokePort = port;
         if (opts.agent && invokeProject) {
@@ -63,7 +63,7 @@ export const registerDev = (program: Command) => {
           console.error(`Available: ${names}`);
           process.exit(1);
         }
-        
+
         await invokeDevServer(invokePort, opts.invoke, opts.stream ?? false);
         return;
       }
@@ -86,7 +86,7 @@ export const registerDev = (program: Command) => {
         const { findAvailablePort, getDevConfig, getAgentPort, spawnDevServer } = await import('../../operations/dev');
         const { findConfigRoot, readEnvFile } = await import('../../../lib');
         const { ExecLogger } = await import('../../logging');
-        
+
         // Require --agent if multiple agents
         if (project.agents.length > 1 && !opts.agent) {
           const names = project.agents.map(a => a.name).join(', ');
@@ -94,28 +94,28 @@ export const registerDev = (program: Command) => {
           console.error(`Available: ${names}`);
           process.exit(1);
         }
-        
+
         const agentName = opts.agent ?? project.agents[0]?.name;
         const configRoot = findConfigRoot(workingDir);
         const envVars = configRoot ? await readEnvFile(configRoot) : {};
         const config = getDevConfig(workingDir, project, configRoot ?? undefined, agentName);
-        
+
         // Create logger for log file path
         const logger = new ExecLogger({ command: 'dev' });
-        
+
         // Calculate port based on agent index
         const basePort = getAgentPort(project, config.agentName, port);
         const actualPort = await findAvailablePort(basePort);
         if (actualPort !== basePort) {
           console.log(`Port ${basePort} in use, using ${actualPort}`);
         }
-        
+
         console.log(`Starting dev server...`);
         console.log(`Agent: ${config.agentName}`);
         console.log(`Server: http://localhost:${actualPort}/invocations`);
         console.log(`Log: ${logger.getRelativeLogPath()}`);
         console.log(`Press Ctrl+C to stop\n`);
-        
+
         const child = spawnDevServer({
           module: config.module,
           cwd: config.directory,
@@ -128,20 +128,20 @@ export const registerDev = (program: Command) => {
               console.log(`${prefix} ${msg}`);
               logger.log(msg, level === 'error' ? 'error' : 'info');
             },
-            onExit: (code) => {
+            onExit: code => {
               console.log(`\nServer exited with code ${code ?? 0}`);
               logger.finalize(code === 0);
               process.exit(code ?? 0);
             },
           },
         });
-        
+
         // Handle Ctrl+C
         process.on('SIGINT', () => {
           console.log('\nStopping server...');
           child.kill('SIGTERM');
         });
-        
+
         // Keep process alive
         await new Promise(() => {});
       }
diff --git a/src/cli/commands/dev/dev.test.ts b/src/cli/commands/dev/dev.test.ts
deleted file mode 100644
index b5fd0739f..000000000
--- a/src/cli/commands/dev/dev.test.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { describe, it } from 'bun:test';
-import assert from 'node:assert';
-import { runCLI } from '../../../test-utils/index.js';
-
-describe('dev command', () => {
-  describe('--help', () => {
-    it('shows all options', async () => {
-      const result = await runCLI(['dev', '--help']);
-      
-      assert.strictEqual(result.exitCode, 0);
-      assert.ok(result.stdout.includes('--port'), 'Should show --port option');
-      assert.ok(result.stdout.includes('--agent'), 'Should show --agent option');
-      assert.ok(result.stdout.includes('--invoke'), 'Should show --invoke option');
-      assert.ok(result.stdout.includes('--stream'), 'Should show --stream option');
-      assert.ok(result.stdout.includes('--logs'), 'Should show --logs option');
-      assert.ok(result.stdout.includes('8080'), 'Should show default port');
-    });
-  });
-
-  describe('requires project context', () => {
-    it('exits with error when run outside project', async () => {
-      const result = await runCLI(['dev']);
-      
-      assert.strictEqual(result.exitCode, 1);
-      assert.ok(
-        result.stdout.toLowerCase().includes('project') || 
-        result.stderr.toLowerCase().includes('project'),
-        `Should mention project requirement, got: ${result.stdout}`
-      );
-    });
-  });
-
-  describe('flag validation', () => {
-    it('rejects invalid port number', async () => {
-      const result = await runCLI(['dev', '--port', 'abc']);
-      
-      assert.strictEqual(result.exitCode, 1);
-    });
-
-    it('rejects negative port number', async () => {
-      const result = await runCLI(['dev', '--port', '-1']);
-      
-      assert.strictEqual(result.exitCode, 1);
-    });
-
-    it('stream flag is documented in help', async () => {
-      const result = await runCLI(['dev', '--help']);
-      
-      assert.strictEqual(result.exitCode, 0);
-      assert.ok(result.stdout.includes('--stream'), 'Should show --stream option');
-      assert.ok(result.stdout.includes('--invoke'), 'Should show --invoke option');
-    });
-  });
-});
diff --git a/src/cli/commands/invoke/invoke.test.ts b/src/cli/commands/invoke/__tests__/invoke.test.ts
similarity index 61%
rename from src/cli/commands/invoke/invoke.test.ts
rename to src/cli/commands/invoke/__tests__/invoke.test.ts
index f3a4df9cc..7b4cf4e55 100644
--- a/src/cli/commands/invoke/invoke.test.ts
+++ b/src/cli/commands/invoke/__tests__/invoke.test.ts
@@ -1,10 +1,9 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
+import { runCLI } from '../../../../test-utils/index.js';
 import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
+import { mkdir, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
 
 describe('invoke command', () => {
   let testDir: string;
@@ -23,27 +22,33 @@ describe('invoke command', () => {
     projectDir = join(testDir, projectName);
 
     // Add an agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', 'TestAgent',
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        'TestAgent',
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create agent: ${result.stdout} ${result.stderr}`);
     }
 
     // Add a target
-    result = await runCLI([
-      'add', 'target',
-      '--name', 'test-target',
-      '--account', '123456789012',
-      '--region', 'us-east-1',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      ['add', 'target', '--name', 'test-target', '--account', '123456789012', '--region', 'us-east-1', '--json'],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create target: ${result.stdout} ${result.stderr}`);
     }
@@ -56,28 +61,34 @@ describe('invoke command', () => {
   describe('validation', () => {
     it('requires prompt for JSON output', async () => {
       const result = await runCLI(['invoke', '--json', '--target', 'test-target'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('Prompt'), `Error should mention Prompt: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('Prompt'), `Error should mention Prompt: ${json.error}`).toBeTruthy();
     });
 
     it('requires target for JSON output', async () => {
       const result = await runCLI(['invoke', 'hello', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--target'), `Error should mention --target: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--target'), `Error should mention --target: ${json.error}`).toBeTruthy();
     });
   });
 
   describe('agent/target validation', () => {
     it('rejects non-existent agent', async () => {
-      const result = await runCLI(['invoke', 'hello', '--target', 'test-target', '--agent', 'nonexistent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      const result = await runCLI(
+        ['invoke', 'hello', '--target', 'test-target', '--agent', 'nonexistent', '--json'],
+        projectDir
+      );
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('not found') || json.error.includes('No deployed'), `Error should mention not found: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(
+        json.error.includes('not found') || json.error.includes('No deployed'),
+        `Error should mention not found: ${json.error}`
+      ).toBeTruthy();
     });
   });
 
@@ -85,43 +96,43 @@ describe('invoke command', () => {
   describe('streaming', () => {
     it('command accepts --stream flag', async () => {
       const result = await runCLI(['invoke', 'hello', '--stream', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(
+      expect(json.success).toBe(false);
+      expect(
         json.error.toLowerCase().includes('deploy') || json.error.toLowerCase().includes('target'),
         `Error should be about deployment: ${json.error}`
-      );
+      ).toBeTruthy();
     });
 
     it('--stream works with --agent flag', async () => {
       const result = await runCLI(['invoke', 'hello', '--stream', '--agent', 'TestAgent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(
+      expect(json.success).toBe(false);
+      expect(
         json.error.toLowerCase().includes('deploy') || json.error.toLowerCase().includes('target'),
         `Error should be about deployment: ${json.error}`
-      );
+      ).toBeTruthy();
     });
 
     it('--stream with invalid agent returns error', async () => {
       const result = await runCLI(['invoke', 'hello', '--stream', '--agent', 'nonexistent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.length > 0, 'Should have error message');
+      expect(json.success).toBe(false);
+      expect(json.error.length > 0, 'Should have error message').toBeTruthy();
     });
 
     it('requires prompt for streaming', async () => {
       const result = await runCLI(['invoke', '--stream', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(
+      expect(json.success).toBe(false);
+      expect(
         json.error.toLowerCase().includes('prompt') || json.error.toLowerCase().includes('deploy'),
         `Error should mention prompt or deployment: ${json.error}`
-      );
+      ).toBeTruthy();
     });
   });
 });
diff --git a/src/cli/commands/invoke/command.tsx b/src/cli/commands/invoke/command.tsx
index 4f3d23686..91edba618 100644
--- a/src/cli/commands/invoke/command.tsx
+++ b/src/cli/commands/invoke/command.tsx
@@ -40,14 +40,14 @@ async function handleInvokeCLI(options: InvokeOptions): Promise<void> {
 
   try {
     const context = await loadInvokeConfig();
-    
+
     // Show spinner for non-streaming, non-json invocations
     if (!options.stream && !options.json) {
       spinner = startSpinner('Invoking agent...');
     }
-    
+
     const result = await handleInvoke(context, options);
-    
+
     if (spinner) {
       stopSpinner(spinner);
     }
@@ -96,40 +96,53 @@ export const registerInvoke = (program: Command) => {
     .option('--new-session', 'Start a new session (ignores existing session)')
     .option('--json', 'Output as JSON')
     .option('--stream', 'Stream response in real-time')
-    .action(async (positionalPrompt: string | undefined, cliOptions: { prompt?: string; agent?: string; target?: string; sessionId?: string; newSession?: boolean; json?: boolean; stream?: boolean }) => {
-      try {
-        requireProject();
-        // --prompt flag takes precedence over positional argument
-        const prompt = cliOptions.prompt ?? positionalPrompt;
-
-        if (prompt) {
-          // Prompt provided - use CLI handler for clean output
-          await handleInvokeCLI({
-            prompt,
-            agentName: cliOptions.agent,
-            targetName: cliOptions.target ?? 'default',
-            json: cliOptions.json,
-            stream: cliOptions.stream,
-          });
-        } else {
-          // No prompt - interactive TUI mode
-          const { waitUntilExit } = render(
-            <InvokeScreen
-              isInteractive={true}
-              onExit={() => process.exit(0)}
-              initialSessionId={cliOptions.sessionId}
-              forceNewSession={cliOptions.newSession}
-            />
-          );
-          await waitUntilExit();
+    .action(
+      async (
+        positionalPrompt: string | undefined,
+        cliOptions: {
+          prompt?: string;
+          agent?: string;
+          target?: string;
+          sessionId?: string;
+          newSession?: boolean;
+          json?: boolean;
+          stream?: boolean;
         }
-      } catch (error) {
-        if (cliOptions.json) {
-          console.log(JSON.stringify({ success: false, error: getErrorMessage(error) }));
-        } else {
-          render(<Text color="red">Error: {getErrorMessage(error)}</Text>);
+      ) => {
+        try {
+          requireProject();
+          // --prompt flag takes precedence over positional argument
+          const prompt = cliOptions.prompt ?? positionalPrompt;
+
+          if (prompt) {
+            // Prompt provided - use CLI handler for clean output
+            await handleInvokeCLI({
+              prompt,
+              agentName: cliOptions.agent,
+              targetName: cliOptions.target ?? 'default',
+              json: cliOptions.json,
+              stream: cliOptions.stream,
+            });
+          } else {
+            // No prompt - interactive TUI mode
+            const { waitUntilExit } = render(
+              <InvokeScreen
+                isInteractive={true}
+                onExit={() => process.exit(0)}
+                initialSessionId={cliOptions.sessionId}
+                forceNewSession={cliOptions.newSession}
+              />
+            );
+            await waitUntilExit();
+          }
+        } catch (error) {
+          if (cliOptions.json) {
+            console.log(JSON.stringify({ success: false, error: getErrorMessage(error) }));
+          } else {
+            render(<Text color="red">Error: {getErrorMessage(error)}</Text>);
+          }
+          process.exit(1);
         }
-        process.exit(1);
       }
-    });
+    );
 };
diff --git a/src/cli/commands/plan/plan.test.ts b/src/cli/commands/plan/__tests__/plan.test.ts
similarity index 62%
rename from src/cli/commands/plan/plan.test.ts
rename to src/cli/commands/plan/__tests__/plan.test.ts
index dcd6bbe2d..f34638e3e 100644
--- a/src/cli/commands/plan/plan.test.ts
+++ b/src/cli/commands/plan/__tests__/plan.test.ts
@@ -1,10 +1,9 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
+import { runCLI } from '../../../../test-utils/index.js';
 import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
+import { mkdir, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
 
 describe('plan command', () => {
   let testDir: string;
@@ -23,27 +22,33 @@ describe('plan command', () => {
     projectDir = join(testDir, projectName);
 
     // Add an agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', 'TestAgent',
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        'TestAgent',
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create agent: ${result.stdout} ${result.stderr}`);
     }
 
     // Add a target
-    result = await runCLI([
-      'add', 'target',
-      '--name', 'test-target',
-      '--account', '123456789012',
-      '--region', 'us-east-1',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      ['add', 'target', '--name', 'test-target', '--account', '123456789012', '--region', 'us-east-1', '--json'],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create target: ${result.stdout} ${result.stderr}`);
     }
@@ -56,16 +61,16 @@ describe('plan command', () => {
   describe('target validation', () => {
     it('rejects non-existent target', async () => {
       const result = await runCLI(['plan', '--target', 'nonexistent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('not found'), `Error should mention not found: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('not found'), `Error should mention not found: ${json.error}`).toBeTruthy();
     });
 
     it('accepts valid target and returns plan result', async () => {
       const result = await runCLI(['plan', '--target', 'test-target', '--json'], projectDir);
       const json = JSON.parse(result.stdout);
-      assert.ok(!json.error?.includes('not found'), `Should find target, got: ${json.error || 'success'}`);
+      expect(!json.error?.includes('not found'), `Should find target, got: ${json.error || 'success'}`).toBeTruthy();
     });
   });
 
@@ -73,41 +78,41 @@ describe('plan command', () => {
   describe('--deploy flag', () => {
     it('command accepts --deploy flag', async () => {
       const result = await runCLI(['plan', '--target', 'test-target', '--deploy', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(
+      expect(json.success).toBe(false);
+      expect(
         !json.error.toLowerCase().includes('unknown option'),
         `Should accept --deploy flag: ${json.error}`
-      );
+      ).toBeTruthy();
     });
 
     it('plan without --deploy returns plan result only', async () => {
       const result = await runCLI(['plan', '--target', 'test-target', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 0);
+      expect(result.exitCode).toBe(0);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-      assert.ok(json.stackNames, 'Should have stackNames');
-      assert.strictEqual(json.outputs, undefined, 'Should not have outputs without --deploy');
+      expect(json.success).toBe(true);
+      expect(json.stackNames, 'Should have stackNames').toBeTruthy();
+      expect(json.outputs, 'Should not have outputs without --deploy').toBe(undefined);
     });
 
     it('requires --target for --deploy', async () => {
       const result = await runCLI(['plan', '--target', 'nonexistent', '--deploy', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(
+      expect(json.success).toBe(false);
+      expect(
         json.error.toLowerCase().includes('not found'),
         `Error should mention target not found: ${json.error}`
-      );
+      ).toBeTruthy();
     });
 
     it('attempts deploy after plan', async () => {
       const result = await runCLI(['plan', '--target', 'test-target', '--deploy', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.length > 0, 'Should have error message');
+      expect(json.success).toBe(false);
+      expect(json.error.length > 0, 'Should have error message').toBeTruthy();
     });
   });
 });
diff --git a/src/cli/commands/plan/actions.ts b/src/cli/commands/plan/actions.ts
index 6d2cb35fb..88f963612 100644
--- a/src/cli/commands/plan/actions.ts
+++ b/src/cli/commands/plan/actions.ts
@@ -1,14 +1,14 @@
 import { ConfigIO } from '../../../lib';
+import { buildDeployedState, getStackOutputs, parseAgentOutputs } from '../../cloudformation';
+import { getErrorMessage } from '../../errors';
 import {
-  validateProject,
+  bootstrapEnvironment,
   buildCdkProject,
-  synthesizeCdk,
   checkBootstrapNeeded,
-  bootstrapEnvironment,
   checkStackDeployability,
+  synthesizeCdk,
+  validateProject,
 } from '../../operations/deploy';
-import { getStackOutputs, parseAgentOutputs, buildDeployedState } from '../../cloudformation';
-import { getErrorMessage } from '../../errors';
 import type { PlanResult } from './types';
 
 export interface ValidatedPlanOptions {
@@ -45,7 +45,7 @@ export async function handlePlan(options: ValidatedPlanOptions): Promise<PlanRes
       return { success: false, error: 'No stacks found to deploy' };
     }
 
-    const stackName = stackNames[0] as string;
+    const stackName = stackNames[0]!;
 
     // If --deploy flag is set, continue to deploy
     if (options.deploy) {
diff --git a/src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts b/src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts
new file mode 100644
index 000000000..ccfed4566
--- /dev/null
+++ b/src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts
@@ -0,0 +1,189 @@
+import { runCLI } from '../../../../test-utils/index.js';
+import { randomUUID } from 'node:crypto';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+
+describe('agent removal cascade', () => {
+  let testDir: string;
+  let projectDir: string;
+
+  beforeAll(async () => {
+    testDir = join(tmpdir(), `agentcore-agent-removal-cascade-${randomUUID()}`);
+    await mkdir(testDir, { recursive: true });
+  });
+
+  afterAll(async () => {
+    await rm(testDir, { recursive: true, force: true });
+  });
+
+  describe('cascade removes owned resources', () => {
+    it('removes agent and its owned memory', async () => {
+      // Create fresh project for this test
+      const projectName = `CascadeMemProj${Date.now()}`;
+      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+      expect(result.exitCode).toBe(0);
+      const projDir = join(testDir, projectName);
+
+      // Add agent
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'OwnerAgent',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Add memory owned by agent
+      result = await runCLI(
+        ['add', 'memory', '--name', 'OwnedMemory', '--strategies', 'SEMANTIC', '--owner', 'OwnerAgent', '--json'],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Remove agent with cascade
+      result = await runCLI(['remove', 'agent', '--name', 'OwnerAgent', '--policy', 'cascade', '--json'], projDir);
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+
+      // Verify agent is removed
+      const projectSpec = JSON.parse(await readFile(join(projDir, 'agentcore/agentcore.json'), 'utf-8'));
+      expect(projectSpec.agents.length, 'Agent should be removed').toBe(0);
+    });
+
+    it('removes agent and its owned identity', async () => {
+      // Create fresh project
+      const projectName = `CascadeIdProj${Date.now()}`;
+      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+      expect(result.exitCode).toBe(0);
+      const projDir = join(testDir, projectName);
+
+      // Add agent
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'OwnerAgent',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Add identity owned by agent
+      result = await runCLI(
+        [
+          'add',
+          'identity',
+          '--name',
+          'OwnedIdentity',
+          '--type',
+          'ApiKeyCredentialProvider',
+          '--api-key',
+          'test-key',
+          '--owner',
+          'OwnerAgent',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Remove agent with cascade
+      result = await runCLI(['remove', 'agent', '--name', 'OwnerAgent', '--policy', 'cascade', '--json'], projDir);
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(true);
+
+      // Verify agent is removed
+      const projectSpec = JSON.parse(await readFile(join(projDir, 'agentcore/agentcore.json'), 'utf-8'));
+      expect(projectSpec.agents.length, 'Agent should be removed').toBe(0);
+    });
+
+    it('removes agent and cleans up remote tool references', async () => {
+      // Create fresh project
+      const projectName = `CascadeToolProj${Date.now()}`;
+      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+      expect(result.exitCode).toBe(0);
+      const projDir = join(testDir, projectName);
+
+      // Add two agents
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'AgentA',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'AgentB',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Attach AgentB to AgentA (AgentA can invoke AgentB)
+      result = await runCLI(['attach', 'agent', '--source', 'AgentA', '--target', 'AgentB', '--json'], projDir);
+      expect(result.exitCode).toBe(0);
+
+      // Remove AgentB with cascade
+      result = await runCLI(['remove', 'agent', '--name', 'AgentB', '--policy', 'cascade', '--json'], projDir);
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
+
+      // Verify AgentA's remote tool reference is cleaned up
+      const projectSpec = JSON.parse(await readFile(join(projDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const agentA = projectSpec.agents.find((a: { name: string }) => a.name === 'AgentA');
+      const hasRef = agentA?.remoteTools?.some((rt: { targetAgentName?: string }) => rt.targetAgentName === 'AgentB');
+      expect(!hasRef, 'AgentA should not have reference to removed AgentB').toBeTruthy();
+    });
+  });
+});
diff --git a/src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts b/src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts
new file mode 100644
index 000000000..faaa5aa3a
--- /dev/null
+++ b/src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts
@@ -0,0 +1,192 @@
+import { runCLI } from '../../../../test-utils/index.js';
+import { randomUUID } from 'node:crypto';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+
+describe('removal policy cascade', () => {
+  let testDir: string;
+  let projectDir: string;
+
+  beforeAll(async () => {
+    testDir = join(tmpdir(), `agentcore-removal-policy-cascade-${randomUUID()}`);
+    await mkdir(testDir, { recursive: true });
+  });
+
+  afterAll(async () => {
+    await rm(testDir, { recursive: true, force: true });
+  });
+
+  describe('memory cascade', () => {
+    it('removes memory and cleans up user references with cascade', async () => {
+      // Create fresh project
+      const projectName = `MemCascadeProj${Date.now()}`;
+      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+      expect(result.exitCode).toBe(0);
+      const projDir = join(testDir, projectName);
+
+      // Add owner and user agents
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'Owner',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'User',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Add memory with user
+      result = await runCLI(
+        [
+          'add',
+          'memory',
+          '--name',
+          'SharedMem',
+          '--strategies',
+          'SEMANTIC',
+          '--owner',
+          'Owner',
+          '--users',
+          'User',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Remove memory with cascade
+      result = await runCLI(['remove', 'memory', '--name', 'SharedMem', '--policy', 'cascade', '--json'], projDir);
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
+
+      // Verify memory is removed from both agents
+      const projectSpec = JSON.parse(await readFile(join(projDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const owner = projectSpec.agents.find((a: { name: string }) => a.name === 'Owner');
+      const user = projectSpec.agents.find((a: { name: string }) => a.name === 'User');
+
+      const ownerHasMem = owner?.memoryProviders?.some((m: { name: string }) => m.name === 'SharedMem');
+      const userHasMem = user?.memoryProviders?.some((m: { name: string }) => m.name === 'SharedMem');
+
+      expect(!ownerHasMem, 'Owner should not have memory').toBeTruthy();
+      expect(!userHasMem, 'User should not have memory').toBeTruthy();
+    });
+  });
+
+  describe('identity cascade', () => {
+    it('removes identity and cleans up user references with cascade', async () => {
+      // Create fresh project
+      const projectName = `IdCascadeProj${Date.now()}`;
+      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+      expect(result.exitCode).toBe(0);
+      const projDir = join(testDir, projectName);
+
+      // Add owner and user agents
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'Owner',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'User',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Add identity with user
+      result = await runCLI(
+        [
+          'add',
+          'identity',
+          '--name',
+          'SharedId',
+          '--type',
+          'ApiKeyCredentialProvider',
+          '--api-key',
+          'test-key',
+          '--owner',
+          'Owner',
+          '--users',
+          'User',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Remove identity with cascade
+      result = await runCLI(['remove', 'identity', '--name', 'SharedId', '--policy', 'cascade', '--json'], projDir);
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
+
+      // Verify identity is removed from both agents
+      const projectSpec = JSON.parse(await readFile(join(projDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const owner = projectSpec.agents.find((a: { name: string }) => a.name === 'Owner');
+      const user = projectSpec.agents.find((a: { name: string }) => a.name === 'User');
+
+      const ownerHasId = owner?.identityProviders?.some((i: { name: string }) => i.name === 'SharedId');
+      const userHasId = user?.identityProviders?.some((i: { name: string }) => i.name === 'SharedId');
+
+      expect(!ownerHasId, 'Owner should not have identity').toBeTruthy();
+      expect(!userHasId, 'User should not have identity').toBeTruthy();
+    });
+  });
+});
diff --git a/src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts b/src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts
new file mode 100644
index 000000000..9a85583ff
--- /dev/null
+++ b/src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts
@@ -0,0 +1,321 @@
+import { runCLI } from '../../../../test-utils/index.js';
+import { randomUUID } from 'node:crypto';
+import { mkdir, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+
+describe('removal policy restrict', () => {
+  let testDir: string;
+  let projectDir: string;
+
+  beforeAll(async () => {
+    testDir = join(tmpdir(), `agentcore-removal-policy-restrict-${randomUUID()}`);
+    await mkdir(testDir, { recursive: true });
+  });
+
+  afterAll(async () => {
+    await rm(testDir, { recursive: true, force: true });
+  });
+
+  describe('memory restrict', () => {
+    it('blocks removal when memory has users (default restrict)', async () => {
+      // Create fresh project
+      const projectName = `MemRestrictProj${Date.now()}`;
+      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+      expect(result.exitCode).toBe(0);
+      const projDir = join(testDir, projectName);
+
+      // Add owner and user agents
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'Owner',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'User',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Add memory with user
+      result = await runCLI(
+        [
+          'add',
+          'memory',
+          '--name',
+          'SharedMem',
+          '--strategies',
+          'SEMANTIC',
+          '--owner',
+          'Owner',
+          '--users',
+          'User',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Try to remove memory without cascade - should fail
+      result = await runCLI(['remove', 'memory', '--name', 'SharedMem', '--json'], projDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(
+        json.error.toLowerCase().includes('use') || json.error.toLowerCase().includes('attached'),
+        `Error: ${json.error}`
+      ).toBeTruthy();
+    });
+
+    it('blocks removal with explicit restrict policy', async () => {
+      // Create fresh project
+      const projectName = `MemRestrictExplicitProj${Date.now()}`;
+      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+      expect(result.exitCode).toBe(0);
+      const projDir = join(testDir, projectName);
+
+      // Add owner and user agents
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'Owner',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'User',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Add memory with user
+      result = await runCLI(
+        [
+          'add',
+          'memory',
+          '--name',
+          'SharedMem',
+          '--strategies',
+          'SEMANTIC',
+          '--owner',
+          'Owner',
+          '--users',
+          'User',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Try to remove with explicit restrict - should fail
+      result = await runCLI(['remove', 'memory', '--name', 'SharedMem', '--policy', 'restrict', '--json'], projDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+    });
+  });
+
+  describe('identity restrict', () => {
+    it('blocks removal when identity has users', async () => {
+      // Create fresh project
+      const projectName = `IdRestrictProj${Date.now()}`;
+      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+      expect(result.exitCode).toBe(0);
+      const projDir = join(testDir, projectName);
+
+      // Add owner and user agents
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'Owner',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'User',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Add identity with user
+      result = await runCLI(
+        [
+          'add',
+          'identity',
+          '--name',
+          'SharedId',
+          '--type',
+          'ApiKeyCredentialProvider',
+          '--api-key',
+          'test-key',
+          '--owner',
+          'Owner',
+          '--users',
+          'User',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Try to remove identity - should fail
+      result = await runCLI(['remove', 'identity', '--name', 'SharedId', '--json'], projDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(
+        json.error.toLowerCase().includes('use') || json.error.toLowerCase().includes('attached'),
+        `Error: ${json.error}`
+      ).toBeTruthy();
+    });
+  });
+
+  describe('agent restrict', () => {
+    it('blocks removal when agent is referenced by others', async () => {
+      // Create fresh project
+      const projectName = `AgentRestrictProj${Date.now()}`;
+      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
+      expect(result.exitCode).toBe(0);
+      const projDir = join(testDir, projectName);
+
+      // Add two agents
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'AgentA',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      result = await runCLI(
+        [
+          'add',
+          'agent',
+          '--name',
+          'AgentB',
+          '--language',
+          'Python',
+          '--framework',
+          'Strands',
+          '--model-provider',
+          'Bedrock',
+          '--memory',
+          'none',
+          '--json',
+        ],
+        projDir
+      );
+      expect(result.exitCode).toBe(0);
+
+      // Attach AgentB to AgentA
+      result = await runCLI(['attach', 'agent', '--source', 'AgentA', '--target', 'AgentB', '--json'], projDir);
+      expect(result.exitCode).toBe(0);
+
+      // Try to remove AgentB - should fail with restrict
+      result = await runCLI(['remove', 'agent', '--name', 'AgentB', '--json'], projDir);
+      expect(result.exitCode).toBe(1);
+      const json = JSON.parse(result.stdout);
+      expect(json.success).toBe(false);
+      expect(
+        json.error.toLowerCase().includes('reference') || json.error.toLowerCase().includes('use'),
+        `Error: ${json.error}`
+      ).toBeTruthy();
+    });
+  });
+});
diff --git a/src/cli/commands/remove/remove-gateway.test.ts b/src/cli/commands/remove/__tests__/remove-gateway.test.ts
similarity index 63%
rename from src/cli/commands/remove/remove-gateway.test.ts
rename to src/cli/commands/remove/__tests__/remove-gateway.test.ts
index e8b33acc4..cf5dab594 100644
--- a/src/cli/commands/remove/remove-gateway.test.ts
+++ b/src/cli/commands/remove/__tests__/remove-gateway.test.ts
@@ -1,10 +1,9 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
+import { runCLI } from '../../../../test-utils/index.js';
 import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
 
 describe('remove gateway command', () => {
   let testDir: string;
@@ -25,25 +24,30 @@ describe('remove gateway command', () => {
     projectDir = join(testDir, projectName);
 
     // Add agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', agentName,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        agentName,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create agent: ${result.stdout} ${result.stderr}`);
     }
 
     // Add gateway
-    result = await runCLI([
-      'add', 'gateway',
-      '--name', gatewayName,
-      '--json'
-    ], projectDir);
+    result = await runCLI(['add', 'gateway', '--name', gatewayName, '--json'], projectDir);
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create gateway: ${result.stdout} ${result.stderr}`);
     }
@@ -56,18 +60,18 @@ describe('remove gateway command', () => {
   describe('validation', () => {
     it('requires name flag', async () => {
       const result = await runCLI(['remove', 'gateway', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--name'), `Error: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--name'), `Error: ${json.error}`).toBeTruthy();
     });
 
     it('rejects non-existent gateway', async () => {
       const result = await runCLI(['remove', 'gateway', '--name', 'nonexistent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`).toBeTruthy();
     });
   });
 
@@ -78,31 +82,29 @@ describe('remove gateway command', () => {
       await runCLI(['add', 'gateway', '--name', tempGateway, '--json'], projectDir);
 
       const result = await runCLI(['remove', 'gateway', '--name', tempGateway, '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}`);
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
+      expect(json.success).toBe(true);
 
       // Verify gateway is removed
       const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8'));
       const gateway = mcpSpec.agentCoreGateways?.find((g: { name: string }) => g.name === tempGateway);
-      assert.ok(!gateway, 'Gateway should be removed');
+      expect(!gateway, 'Gateway should be removed').toBeTruthy();
     });
 
     it('blocks removal when gateway has attached agents', async () => {
       // Attach gateway to agent
-      await runCLI([
-        'attach', 'gateway',
-        '--agent', agentName,
-        '--gateway', gatewayName,
-        '--json'
-      ], projectDir);
+      await runCLI(['attach', 'gateway', '--agent', agentName, '--gateway', gatewayName, '--json'], projectDir);
 
       // Try to remove - should fail with restrict policy
       const result = await runCLI(['remove', 'gateway', '--name', gatewayName, '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('attached') || json.error.toLowerCase().includes('use'), `Error: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(
+        json.error.toLowerCase().includes('attached') || json.error.toLowerCase().includes('use'),
+        `Error: ${json.error}`
+      ).toBeTruthy();
     });
   });
 });
diff --git a/src/cli/commands/remove/remove-identity.test.ts b/src/cli/commands/remove/__tests__/remove-identity.test.ts
similarity index 54%
rename from src/cli/commands/remove/remove-identity.test.ts
rename to src/cli/commands/remove/__tests__/remove-identity.test.ts
index 8da322ce4..8f5a95cb4 100644
--- a/src/cli/commands/remove/remove-identity.test.ts
+++ b/src/cli/commands/remove/__tests__/remove-identity.test.ts
@@ -1,10 +1,9 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
+import { runCLI } from '../../../../test-utils/index.js';
 import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
 
 describe('remove identity command', () => {
   let testDir: string;
@@ -26,42 +25,68 @@ describe('remove identity command', () => {
     projectDir = join(testDir, projectName);
 
     // Add owner agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', ownerAgent,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        ownerAgent,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create owner agent: ${result.stdout} ${result.stderr}`);
     }
 
     // Add user agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', userAgent,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        userAgent,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create user agent: ${result.stdout} ${result.stderr}`);
     }
 
     // Add identity
-    result = await runCLI([
-      'add', 'identity',
-      '--name', identityName,
-      '--type', 'ApiKeyCredentialProvider',
-      '--api-key', 'test-key-123',
-      '--owner', ownerAgent,
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      [
+        'add',
+        'identity',
+        '--name',
+        identityName,
+        '--type',
+        'ApiKeyCredentialProvider',
+        '--api-key',
+        'test-key-123',
+        '--owner',
+        ownerAgent,
+        '--json',
+      ],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create identity: ${result.stdout} ${result.stderr}`);
     }
@@ -74,18 +99,18 @@ describe('remove identity command', () => {
   describe('validation', () => {
     it('requires name flag', async () => {
       const result = await runCLI(['remove', 'identity', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--name'), `Error: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--name'), `Error: ${json.error}`).toBeTruthy();
     });
 
     it('rejects non-existent identity', async () => {
       const result = await runCLI(['remove', 'identity', '--name', 'nonexistent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`).toBeTruthy();
     });
   });
 
@@ -93,42 +118,48 @@ describe('remove identity command', () => {
     it('removes identity without users', async () => {
       // Add a temp identity to remove
       const tempId = `temp-id-${Date.now()}`;
-      await runCLI([
-        'add', 'identity',
-        '--name', tempId,
-        '--type', 'ApiKeyCredentialProvider',
-        '--api-key', 'temp-key',
-        '--owner', ownerAgent,
-        '--json'
-      ], projectDir);
+      await runCLI(
+        [
+          'add',
+          'identity',
+          '--name',
+          tempId,
+          '--type',
+          'ApiKeyCredentialProvider',
+          '--api-key',
+          'temp-key',
+          '--owner',
+          ownerAgent,
+          '--json',
+        ],
+        projectDir
+      );
 
       const result = await runCLI(['remove', 'identity', '--name', tempId, '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}`);
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
+      expect(json.success).toBe(true);
 
       // Verify identity is removed from owner
       const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
       const agent = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
       const identity = agent?.identityProviders?.find((i: { name: string }) => i.name === tempId);
-      assert.ok(!identity, 'Identity should be removed from owner');
+      expect(!identity, 'Identity should be removed from owner').toBeTruthy();
     });
 
     it('blocks removal when identity has users', async () => {
       // Attach identity to user agent
-      await runCLI([
-        'attach', 'identity',
-        '--agent', userAgent,
-        '--identity', identityName,
-        '--json'
-      ], projectDir);
+      await runCLI(['attach', 'identity', '--agent', userAgent, '--identity', identityName, '--json'], projectDir);
 
       // Try to remove - should fail with restrict policy
       const result = await runCLI(['remove', 'identity', '--name', identityName, '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('use') || json.error.toLowerCase().includes('attached'), `Error: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(
+        json.error.toLowerCase().includes('use') || json.error.toLowerCase().includes('attached'),
+        `Error: ${json.error}`
+      ).toBeTruthy();
     });
   });
 });
diff --git a/src/cli/commands/remove/remove-mcp-tool.test.ts b/src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts
similarity index 59%
rename from src/cli/commands/remove/remove-mcp-tool.test.ts
rename to src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts
index 628456130..56b27cee3 100644
--- a/src/cli/commands/remove/remove-mcp-tool.test.ts
+++ b/src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts
@@ -1,10 +1,9 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
+import { runCLI } from '../../../../test-utils/index.js';
 import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
 
 describe('remove mcp-tool command', () => {
   let testDir: string;
@@ -27,15 +26,24 @@ describe('remove mcp-tool command', () => {
     projectDir = join(testDir, projectName);
 
     // Add agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', agentName,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        agentName,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create agent: ${result.stdout} ${result.stderr}`);
     }
@@ -47,28 +55,45 @@ describe('remove mcp-tool command', () => {
     }
 
     // Add mcp-runtime tool
-    result = await runCLI([
-      'add', 'mcp-tool',
-      '--name', runtimeToolName,
-      '--language', 'Python',
-      '--exposure', 'mcp-runtime',
-      '--agents', agentName,
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      [
+        'add',
+        'mcp-tool',
+        '--name',
+        runtimeToolName,
+        '--language',
+        'Python',
+        '--exposure',
+        'mcp-runtime',
+        '--agents',
+        agentName,
+        '--json',
+      ],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create runtime tool: ${result.stdout} ${result.stderr}`);
     }
 
     // Add behind-gateway tool
-    result = await runCLI([
-      'add', 'mcp-tool',
-      '--name', gatewayToolName,
-      '--language', 'Python',
-      '--exposure', 'behind-gateway',
-      '--gateway', gatewayName,
-      '--host', 'Lambda',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      [
+        'add',
+        'mcp-tool',
+        '--name',
+        gatewayToolName,
+        '--language',
+        'Python',
+        '--exposure',
+        'behind-gateway',
+        '--gateway',
+        gatewayName,
+        '--host',
+        'Lambda',
+        '--json',
+      ],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create gateway tool: ${result.stdout} ${result.stderr}`);
     }
@@ -81,18 +106,18 @@ describe('remove mcp-tool command', () => {
   describe('validation', () => {
     it('requires name flag', async () => {
       const result = await runCLI(['remove', 'mcp-tool', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--name'), `Error: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--name'), `Error: ${json.error}`).toBeTruthy();
     });
 
     it('rejects non-existent tool', async () => {
       const result = await runCLI(['remove', 'mcp-tool', '--name', 'nonexistent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`).toBeTruthy();
     });
   });
 
@@ -100,30 +125,38 @@ describe('remove mcp-tool command', () => {
     it('removes mcp-runtime tool and cleans up agent references', async () => {
       // Add a temp tool to remove
       const tempTool = `temp-rt-${Date.now()}`;
-      await runCLI([
-        'add', 'mcp-tool',
-        '--name', tempTool,
-        '--language', 'Python',
-        '--exposure', 'mcp-runtime',
-        '--agents', agentName,
-        '--json'
-      ], projectDir);
+      await runCLI(
+        [
+          'add',
+          'mcp-tool',
+          '--name',
+          tempTool,
+          '--language',
+          'Python',
+          '--exposure',
+          'mcp-runtime',
+          '--agents',
+          agentName,
+          '--json',
+        ],
+        projectDir
+      );
 
       const result = await runCLI(['remove', 'mcp-tool', '--name', tempTool, '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}`);
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
+      expect(json.success).toBe(true);
 
       // Verify tool is removed from mcp.json
       const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8'));
       const tool = mcpSpec.mcpRuntimeTools?.find((t: { name: string }) => t.name === tempTool);
-      assert.ok(!tool, 'Tool should be removed from mcpRuntimeTools');
+      expect(!tool, 'Tool should be removed from mcpRuntimeTools').toBeTruthy();
 
       // Verify agent reference is cleaned up
       const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
       const agent = projectSpec.agents.find((a: { name: string }) => a.name === agentName);
       const hasRef = agent?.remoteTools?.some((rt: { mcpRuntimeName?: string }) => rt.mcpRuntimeName === tempTool);
-      assert.ok(!hasRef, 'Agent should not have reference to removed tool');
+      expect(!hasRef, 'Agent should not have reference to removed tool').toBeTruthy();
     });
   });
 
@@ -131,26 +164,35 @@ describe('remove mcp-tool command', () => {
     it('removes behind-gateway tool from gateway targets', async () => {
       // Add a temp tool to remove
       const tempTool = `temp-gw-${Date.now()}`;
-      await runCLI([
-        'add', 'mcp-tool',
-        '--name', tempTool,
-        '--language', 'Python',
-        '--exposure', 'behind-gateway',
-        '--gateway', gatewayName,
-        '--host', 'Lambda',
-        '--json'
-      ], projectDir);
+      await runCLI(
+        [
+          'add',
+          'mcp-tool',
+          '--name',
+          tempTool,
+          '--language',
+          'Python',
+          '--exposure',
+          'behind-gateway',
+          '--gateway',
+          gatewayName,
+          '--host',
+          'Lambda',
+          '--json',
+        ],
+        projectDir
+      );
 
       const result = await runCLI(['remove', 'mcp-tool', '--name', tempTool, '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}`);
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
+      expect(json.success).toBe(true);
 
       // Verify tool is removed from gateway targets
       const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8'));
       const gateway = mcpSpec.agentCoreGateways?.find((g: { name: string }) => g.name === gatewayName);
       const target = gateway?.targets?.find((t: { name: string }) => t.name === tempTool);
-      assert.ok(!target, 'Tool should be removed from gateway targets');
+      expect(!target, 'Tool should be removed from gateway targets').toBeTruthy();
     });
   });
 });
diff --git a/src/cli/commands/remove/remove-memory.test.ts b/src/cli/commands/remove/__tests__/remove-memory.test.ts
similarity index 57%
rename from src/cli/commands/remove/remove-memory.test.ts
rename to src/cli/commands/remove/__tests__/remove-memory.test.ts
index 84b56de9e..46aa2fc65 100644
--- a/src/cli/commands/remove/remove-memory.test.ts
+++ b/src/cli/commands/remove/__tests__/remove-memory.test.ts
@@ -1,10 +1,9 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
+import { runCLI } from '../../../../test-utils/index.js';
 import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
 
 describe('remove memory command', () => {
   let testDir: string;
@@ -26,41 +25,56 @@ describe('remove memory command', () => {
     projectDir = join(testDir, projectName);
 
     // Add owner agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', ownerAgent,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        ownerAgent,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create owner agent: ${result.stdout} ${result.stderr}`);
     }
 
     // Add user agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', userAgent,
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        userAgent,
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create user agent: ${result.stdout} ${result.stderr}`);
     }
 
     // Add memory
-    result = await runCLI([
-      'add', 'memory',
-      '--name', memoryName,
-      '--strategies', 'SEMANTIC',
-      '--owner', ownerAgent,
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      ['add', 'memory', '--name', memoryName, '--strategies', 'SEMANTIC', '--owner', ownerAgent, '--json'],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create memory: ${result.stdout} ${result.stderr}`);
     }
@@ -73,18 +87,18 @@ describe('remove memory command', () => {
   describe('validation', () => {
     it('requires name flag', async () => {
       const result = await runCLI(['remove', 'memory', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--name'), `Error: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--name'), `Error: ${json.error}`).toBeTruthy();
     });
 
     it('rejects non-existent memory', async () => {
       const result = await runCLI(['remove', 'memory', '--name', 'nonexistent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.toLowerCase().includes('not found'), `Error: ${json.error}`).toBeTruthy();
     });
   });
 
@@ -92,41 +106,36 @@ describe('remove memory command', () => {
     it('removes memory without users', async () => {
       // Add a temp memory to remove
       const tempMem = `temp-mem-${Date.now()}`;
-      await runCLI([
-        'add', 'memory',
-        '--name', tempMem,
-        '--strategies', 'SEMANTIC',
-        '--owner', ownerAgent,
-        '--json'
-      ], projectDir);
+      await runCLI(
+        ['add', 'memory', '--name', tempMem, '--strategies', 'SEMANTIC', '--owner', ownerAgent, '--json'],
+        projectDir
+      );
 
       const result = await runCLI(['remove', 'memory', '--name', tempMem, '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}`);
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
+      expect(json.success).toBe(true);
 
       // Verify memory is removed from owner
       const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
       const agent = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
       const memory = agent?.memoryProviders?.find((m: { name: string }) => m.name === tempMem);
-      assert.ok(!memory, 'Memory should be removed from owner');
+      expect(!memory, 'Memory should be removed from owner').toBeTruthy();
     });
 
     it('blocks removal when memory has users', async () => {
       // Attach memory to user agent
-      await runCLI([
-        'attach', 'memory',
-        '--agent', userAgent,
-        '--memory', memoryName,
-        '--json'
-      ], projectDir);
+      await runCLI(['attach', 'memory', '--agent', userAgent, '--memory', memoryName, '--json'], projectDir);
 
       // Try to remove - should fail with restrict policy
       const result = await runCLI(['remove', 'memory', '--name', memoryName, '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('use') || json.error.toLowerCase().includes('attached'), `Error: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(
+        json.error.toLowerCase().includes('use') || json.error.toLowerCase().includes('attached'),
+        `Error: ${json.error}`
+      ).toBeTruthy();
     });
   });
 });
diff --git a/src/cli/commands/remove/remove.test.ts b/src/cli/commands/remove/__tests__/remove.test.ts
similarity index 64%
rename from src/cli/commands/remove/remove.test.ts
rename to src/cli/commands/remove/__tests__/remove.test.ts
index 76a67b052..816a524ec 100644
--- a/src/cli/commands/remove/remove.test.ts
+++ b/src/cli/commands/remove/__tests__/remove.test.ts
@@ -1,10 +1,9 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
+import { runCLI } from '../../../../test-utils/index.js';
 import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
+import { mkdir, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { afterAll, beforeAll, describe, it , expect } from 'vitest';
 
 describe('remove command', () => {
   let testDir: string;
@@ -23,27 +22,33 @@ describe('remove command', () => {
     projectDir = join(testDir, projectName);
 
     // Add an agent
-    result = await runCLI([
-      'add', 'agent',
-      '--name', 'TestAgent',
-      '--language', 'Python',
-      '--framework', 'Strands',
-      '--model-provider', 'Bedrock',
-      '--memory', 'none',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      [
+        'add',
+        'agent',
+        '--name',
+        'TestAgent',
+        '--language',
+        'Python',
+        '--framework',
+        'Strands',
+        '--model-provider',
+        'Bedrock',
+        '--memory',
+        'none',
+        '--json',
+      ],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create agent: ${result.stdout} ${result.stderr}`);
     }
 
     // Add a target
-    result = await runCLI([
-      'add', 'target',
-      '--name', 'test-target',
-      '--account', '123456789012',
-      '--region', 'us-east-1',
-      '--json'
-    ], projectDir);
+    result = await runCLI(
+      ['add', 'target', '--name', 'test-target', '--account', '123456789012', '--region', 'us-east-1', '--json'],
+      projectDir
+    );
     if (result.exitCode !== 0) {
       throw new Error(`Failed to create target: ${result.stdout} ${result.stderr}`);
     }
@@ -56,50 +61,50 @@ describe('remove command', () => {
   describe('validation', () => {
     it('requires name for JSON output', async () => {
       const result = await runCLI(['remove', 'agent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.includes('--name'), `Error should mention --name: ${json.error}`);
+      expect(json.success).toBe(false);
+      expect(json.error.includes('--name'), `Error should mention --name: ${json.error}`).toBeTruthy();
     });
   });
 
   describe('remove target', () => {
     it('rejects non-existent target', async () => {
       const result = await runCLI(['remove', 'target', '--name', 'nonexistent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
+      expect(json.success).toBe(false);
     });
 
     it('removes existing target', async () => {
       const result = await runCLI(['remove', 'target', '--name', 'test-target', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 0);
+      expect(result.exitCode).toBe(0);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
+      expect(json.success).toBe(true);
 
       // Verify target is removed from schema
       const targets = JSON.parse(await readFile(join(projectDir, 'agentcore', 'aws-targets.json'), 'utf-8'));
-      assert.strictEqual(targets.length, 0, 'Target should be removed from schema');
+      expect(targets.length, 'Target should be removed from schema').toBe(0);
     });
   });
 
   describe('remove agent', () => {
     it('rejects non-existent agent', async () => {
       const result = await runCLI(['remove', 'agent', '--name', 'nonexistent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 1);
+      expect(result.exitCode).toBe(1);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
+      expect(json.success).toBe(false);
     });
 
     it('removes existing agent', async () => {
       const result = await runCLI(['remove', 'agent', '--name', 'TestAgent', '--json'], projectDir);
-      assert.strictEqual(result.exitCode, 0);
+      expect(result.exitCode).toBe(0);
       const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
+      expect(json.success).toBe(true);
 
       // Verify agent is removed from schema
       const schema = JSON.parse(await readFile(join(projectDir, 'agentcore', 'agentcore.json'), 'utf-8'));
-      assert.strictEqual(schema.agents.length, 0, 'Agent should be removed from schema');
+      expect(schema.agents.length, 'Agent should be removed from schema').toBe(0);
     });
   });
 });
diff --git a/src/cli/commands/remove/actions.ts b/src/cli/commands/remove/actions.ts
index b900585eb..6e656b352 100644
--- a/src/cli/commands/remove/actions.ts
+++ b/src/cli/commands/remove/actions.ts
@@ -1,21 +1,21 @@
 import { ConfigIO } from '../../../lib';
+import { getErrorMessage } from '../../errors';
 import {
+  getRemovableMcpTools,
   previewRemoveAgent,
-  removeAgent,
   previewRemoveGateway,
-  removeGateway,
+  previewRemoveIdentity,
   previewRemoveMcpTool,
-  removeMcpTool,
-  getRemovableMcpTools,
   previewRemoveMemory,
-  removeMemory,
-  previewRemoveIdentity,
-  removeIdentity,
   previewRemoveTarget,
+  removeAgent,
+  removeGateway,
+  removeIdentity,
+  removeMcpTool,
+  removeMemory,
   removeTarget,
 } from '../../operations/remove';
-import { getErrorMessage } from '../../errors';
-import type { ResourceType, RemoveResult, RemoveAllOptions } from './types';
+import type { RemoveAllOptions, RemoveResult, ResourceType } from './types';
 
 export interface ValidatedRemoveOptions {
   resourceType: ResourceType;
@@ -31,7 +31,9 @@ export async function handleRemove(options: ValidatedRemoveOptions): Promise<Rem
       case 'agent': {
         const preview = await previewRemoveAgent(name);
         if (preview.blockers && preview.blockers.length > 0) {
-          const blockerMsg = preview.blockers.map(b => `${b.resourceType} '${b.resourceName}' has dependents: ${b.dependents.join(', ')}`).join('; ');
+          const blockerMsg = preview.blockers
+            .map(b => `${b.resourceType} '${b.resourceName}' has dependents: ${b.dependents.join(', ')}`)
+            .join('; ');
           return { success: false, error: `Cannot remove agent: ${blockerMsg}` };
         }
         const result = await removeAgent(name);
@@ -97,7 +99,7 @@ export async function handleRemove(options: ValidatedRemoveOptions): Promise<Rem
 export async function handleRemoveAll(_options: RemoveAllOptions): Promise<RemoveResult> {
   try {
     const configIO = new ConfigIO();
-    
+
     // Get current project name to preserve it
     let projectName = 'Project';
     try {
diff --git a/src/cli/commands/remove/agent-removal-cascade.test.ts b/src/cli/commands/remove/agent-removal-cascade.test.ts
deleted file mode 100644
index 4819f3345..000000000
--- a/src/cli/commands/remove/agent-removal-cascade.test.ts
+++ /dev/null
@@ -1,154 +0,0 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
-import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
-
-describe('agent removal cascade', () => {
-  let testDir: string;
-  let projectDir: string;
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-agent-removal-cascade-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('cascade removes owned resources', () => {
-    it('removes agent and its owned memory', async () => {
-      // Create fresh project for this test
-      const projectName = `CascadeMemProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      assert.strictEqual(result.exitCode, 0);
-      const projDir = join(testDir, projectName);
-
-      // Add agent
-      result = await runCLI([
-        'add', 'agent',
-        '--name', 'OwnerAgent',
-        '--language', 'Python',
-        '--framework', 'Strands',
-        '--model-provider', 'Bedrock',
-        '--memory', 'none',
-        '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Add memory owned by agent
-      result = await runCLI([
-        'add', 'memory',
-        '--name', 'OwnedMemory',
-        '--strategies', 'SEMANTIC',
-        '--owner', 'OwnerAgent',
-        '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Remove agent with cascade
-      result = await runCLI(['remove', 'agent', '--name', 'OwnerAgent', '--policy', 'cascade', '--json'], projDir);
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}`);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-
-      // Verify agent is removed
-      const projectSpec = JSON.parse(await readFile(join(projDir, 'agentcore/agentcore.json'), 'utf-8'));
-      assert.strictEqual(projectSpec.agents.length, 0, 'Agent should be removed');
-    });
-
-    it('removes agent and its owned identity', async () => {
-      // Create fresh project
-      const projectName = `CascadeIdProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      assert.strictEqual(result.exitCode, 0);
-      const projDir = join(testDir, projectName);
-
-      // Add agent
-      result = await runCLI([
-        'add', 'agent',
-        '--name', 'OwnerAgent',
-        '--language', 'Python',
-        '--framework', 'Strands',
-        '--model-provider', 'Bedrock',
-        '--memory', 'none',
-        '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Add identity owned by agent
-      result = await runCLI([
-        'add', 'identity',
-        '--name', 'OwnedIdentity',
-        '--type', 'ApiKeyCredentialProvider',
-        '--api-key', 'test-key',
-        '--owner', 'OwnerAgent',
-        '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Remove agent with cascade
-      result = await runCLI(['remove', 'agent', '--name', 'OwnerAgent', '--policy', 'cascade', '--json'], projDir);
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}`);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, true);
-
-      // Verify agent is removed
-      const projectSpec = JSON.parse(await readFile(join(projDir, 'agentcore/agentcore.json'), 'utf-8'));
-      assert.strictEqual(projectSpec.agents.length, 0, 'Agent should be removed');
-    });
-
-    it('removes agent and cleans up remote tool references', async () => {
-      // Create fresh project
-      const projectName = `CascadeToolProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      assert.strictEqual(result.exitCode, 0);
-      const projDir = join(testDir, projectName);
-
-      // Add two agents
-      result = await runCLI([
-        'add', 'agent',
-        '--name', 'AgentA',
-        '--language', 'Python',
-        '--framework', 'Strands',
-        '--model-provider', 'Bedrock',
-        '--memory', 'none',
-        '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      result = await runCLI([
-        'add', 'agent',
-        '--name', 'AgentB',
-        '--language', 'Python',
-        '--framework', 'Strands',
-        '--model-provider', 'Bedrock',
-        '--memory', 'none',
-        '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Attach AgentB to AgentA (AgentA can invoke AgentB)
-      result = await runCLI([
-        'attach', 'agent',
-        '--source', 'AgentA',
-        '--target', 'AgentB',
-        '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Remove AgentB with cascade
-      result = await runCLI(['remove', 'agent', '--name', 'AgentB', '--policy', 'cascade', '--json'], projDir);
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}`);
-
-      // Verify AgentA's remote tool reference is cleaned up
-      const projectSpec = JSON.parse(await readFile(join(projDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const agentA = projectSpec.agents.find((a: { name: string }) => a.name === 'AgentA');
-      const hasRef = agentA?.remoteTools?.some((rt: { targetAgentName?: string }) => rt.targetAgentName === 'AgentB');
-      assert.ok(!hasRef, 'AgentA should not have reference to removed AgentB');
-    });
-  });
-});
diff --git a/src/cli/commands/remove/command.tsx b/src/cli/commands/remove/command.tsx
index 8768c6566..a1ddbeda5 100644
--- a/src/cli/commands/remove/command.tsx
+++ b/src/cli/commands/remove/command.tsx
@@ -3,8 +3,8 @@ import { COMMAND_DESCRIPTIONS } from '../../tui/copy';
 import { requireProject } from '../../tui/guards';
 import { RemoveAllScreen, RemoveFlow } from '../../tui/screens/remove';
 import { handleRemove, handleRemoveAll } from './actions';
-import type { RemoveOptions, RemoveAllOptions, ResourceType } from './types';
-import { validateRemoveOptions, validateRemoveAllOptions } from './validate';
+import type { RemoveAllOptions, RemoveOptions, ResourceType } from './types';
+import { validateRemoveAllOptions, validateRemoveOptions } from './validate';
 import type { Command } from '@commander-js/extra-typings';
 import { Text, render } from 'ink';
 import React from 'react';
@@ -28,10 +28,7 @@ function handleRemoveAllTUI(options: TUIRemoveOptions = {}): void {
   );
 }
 
-function handleRemoveResourceTUI(
-  resourceType: ResourceType,
-  options: { force?: boolean }
-): void {
+function handleRemoveResourceTUI(resourceType: ResourceType, options: { force?: boolean }): void {
   const { clear, unmount } = render(
     <RemoveFlow
       isInteractive={false}
diff --git a/src/cli/commands/remove/removal-policy-cascade.test.ts b/src/cli/commands/remove/removal-policy-cascade.test.ts
deleted file mode 100644
index f214f72b2..000000000
--- a/src/cli/commands/remove/removal-policy-cascade.test.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir, readFile } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
-import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
-
-describe('removal policy cascade', () => {
-  let testDir: string;
-  let projectDir: string;
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-removal-policy-cascade-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('memory cascade', () => {
-    it('removes memory and cleans up user references with cascade', async () => {
-      // Create fresh project
-      const projectName = `MemCascadeProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      assert.strictEqual(result.exitCode, 0);
-      const projDir = join(testDir, projectName);
-
-      // Add owner and user agents
-      result = await runCLI([
-        'add', 'agent', '--name', 'Owner', '--language', 'Python',
-        '--framework', 'Strands', '--model-provider', 'Bedrock', '--memory', 'none', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      result = await runCLI([
-        'add', 'agent', '--name', 'User', '--language', 'Python',
-        '--framework', 'Strands', '--model-provider', 'Bedrock', '--memory', 'none', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Add memory with user
-      result = await runCLI([
-        'add', 'memory', '--name', 'SharedMem', '--strategies', 'SEMANTIC',
-        '--owner', 'Owner', '--users', 'User', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Remove memory with cascade
-      result = await runCLI(['remove', 'memory', '--name', 'SharedMem', '--policy', 'cascade', '--json'], projDir);
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}`);
-
-      // Verify memory is removed from both agents
-      const projectSpec = JSON.parse(await readFile(join(projDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const owner = projectSpec.agents.find((a: { name: string }) => a.name === 'Owner');
-      const user = projectSpec.agents.find((a: { name: string }) => a.name === 'User');
-      
-      const ownerHasMem = owner?.memoryProviders?.some((m: { name: string }) => m.name === 'SharedMem');
-      const userHasMem = user?.memoryProviders?.some((m: { name: string }) => m.name === 'SharedMem');
-      
-      assert.ok(!ownerHasMem, 'Owner should not have memory');
-      assert.ok(!userHasMem, 'User should not have memory');
-    });
-  });
-
-  describe('identity cascade', () => {
-    it('removes identity and cleans up user references with cascade', async () => {
-      // Create fresh project
-      const projectName = `IdCascadeProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      assert.strictEqual(result.exitCode, 0);
-      const projDir = join(testDir, projectName);
-
-      // Add owner and user agents
-      result = await runCLI([
-        'add', 'agent', '--name', 'Owner', '--language', 'Python',
-        '--framework', 'Strands', '--model-provider', 'Bedrock', '--memory', 'none', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      result = await runCLI([
-        'add', 'agent', '--name', 'User', '--language', 'Python',
-        '--framework', 'Strands', '--model-provider', 'Bedrock', '--memory', 'none', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Add identity with user
-      result = await runCLI([
-        'add', 'identity', '--name', 'SharedId', '--type', 'ApiKeyCredentialProvider',
-        '--api-key', 'test-key', '--owner', 'Owner', '--users', 'User', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Remove identity with cascade
-      result = await runCLI(['remove', 'identity', '--name', 'SharedId', '--policy', 'cascade', '--json'], projDir);
-      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}`);
-
-      // Verify identity is removed from both agents
-      const projectSpec = JSON.parse(await readFile(join(projDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const owner = projectSpec.agents.find((a: { name: string }) => a.name === 'Owner');
-      const user = projectSpec.agents.find((a: { name: string }) => a.name === 'User');
-      
-      const ownerHasId = owner?.identityProviders?.some((i: { name: string }) => i.name === 'SharedId');
-      const userHasId = user?.identityProviders?.some((i: { name: string }) => i.name === 'SharedId');
-      
-      assert.ok(!ownerHasId, 'Owner should not have identity');
-      assert.ok(!userHasId, 'User should not have identity');
-    });
-  });
-});
diff --git a/src/cli/commands/remove/removal-policy-restrict.test.ts b/src/cli/commands/remove/removal-policy-restrict.test.ts
deleted file mode 100644
index 93c17dac5..000000000
--- a/src/cli/commands/remove/removal-policy-restrict.test.ts
+++ /dev/null
@@ -1,165 +0,0 @@
-import { describe, it, beforeAll, afterAll } from 'bun:test';
-import assert from 'node:assert';
-import { rm, mkdir } from 'node:fs/promises';
-import { join } from 'node:path';
-import { tmpdir } from 'node:os';
-import { randomUUID } from 'node:crypto';
-import { runCLI } from '../../../test-utils/index.js';
-
-describe('removal policy restrict', () => {
-  let testDir: string;
-  let projectDir: string;
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-removal-policy-restrict-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('memory restrict', () => {
-    it('blocks removal when memory has users (default restrict)', async () => {
-      // Create fresh project
-      const projectName = `MemRestrictProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      assert.strictEqual(result.exitCode, 0);
-      const projDir = join(testDir, projectName);
-
-      // Add owner and user agents
-      result = await runCLI([
-        'add', 'agent', '--name', 'Owner', '--language', 'Python',
-        '--framework', 'Strands', '--model-provider', 'Bedrock', '--memory', 'none', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      result = await runCLI([
-        'add', 'agent', '--name', 'User', '--language', 'Python',
-        '--framework', 'Strands', '--model-provider', 'Bedrock', '--memory', 'none', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Add memory with user
-      result = await runCLI([
-        'add', 'memory', '--name', 'SharedMem', '--strategies', 'SEMANTIC',
-        '--owner', 'Owner', '--users', 'User', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Try to remove memory without cascade - should fail
-      result = await runCLI(['remove', 'memory', '--name', 'SharedMem', '--json'], projDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('use') || json.error.toLowerCase().includes('attached'), `Error: ${json.error}`);
-    });
-
-    it('blocks removal with explicit restrict policy', async () => {
-      // Create fresh project
-      const projectName = `MemRestrictExplicitProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      assert.strictEqual(result.exitCode, 0);
-      const projDir = join(testDir, projectName);
-
-      // Add owner and user agents
-      result = await runCLI([
-        'add', 'agent', '--name', 'Owner', '--language', 'Python',
-        '--framework', 'Strands', '--model-provider', 'Bedrock', '--memory', 'none', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      result = await runCLI([
-        'add', 'agent', '--name', 'User', '--language', 'Python',
-        '--framework', 'Strands', '--model-provider', 'Bedrock', '--memory', 'none', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Add memory with user
-      result = await runCLI([
-        'add', 'memory', '--name', 'SharedMem', '--strategies', 'SEMANTIC',
-        '--owner', 'Owner', '--users', 'User', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Try to remove with explicit restrict - should fail
-      result = await runCLI(['remove', 'memory', '--name', 'SharedMem', '--policy', 'restrict', '--json'], projDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-    });
-  });
-
-  describe('identity restrict', () => {
-    it('blocks removal when identity has users', async () => {
-      // Create fresh project
-      const projectName = `IdRestrictProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      assert.strictEqual(result.exitCode, 0);
-      const projDir = join(testDir, projectName);
-
-      // Add owner and user agents
-      result = await runCLI([
-        'add', 'agent', '--name', 'Owner', '--language', 'Python',
-        '--framework', 'Strands', '--model-provider', 'Bedrock', '--memory', 'none', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      result = await runCLI([
-        'add', 'agent', '--name', 'User', '--language', 'Python',
-        '--framework', 'Strands', '--model-provider', 'Bedrock', '--memory', 'none', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Add identity with user
-      result = await runCLI([
-        'add', 'identity', '--name', 'SharedId', '--type', 'ApiKeyCredentialProvider',
-        '--api-key', 'test-key', '--owner', 'Owner', '--users', 'User', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Try to remove identity - should fail
-      result = await runCLI(['remove', 'identity', '--name', 'SharedId', '--json'], projDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('use') || json.error.toLowerCase().includes('attached'), `Error: ${json.error}`);
-    });
-  });
-
-  describe('agent restrict', () => {
-    it('blocks removal when agent is referenced by others', async () => {
-      // Create fresh project
-      const projectName = `AgentRestrictProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      assert.strictEqual(result.exitCode, 0);
-      const projDir = join(testDir, projectName);
-
-      // Add two agents
-      result = await runCLI([
-        'add', 'agent', '--name', 'AgentA', '--language', 'Python',
-        '--framework', 'Strands', '--model-provider', 'Bedrock', '--memory', 'none', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      result = await runCLI([
-        'add', 'agent', '--name', 'AgentB', '--language', 'Python',
-        '--framework', 'Strands', '--model-provider', 'Bedrock', '--memory', 'none', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Attach AgentB to AgentA
-      result = await runCLI([
-        'attach', 'agent', '--source', 'AgentA', '--target', 'AgentB', '--json'
-      ], projDir);
-      assert.strictEqual(result.exitCode, 0);
-
-      // Try to remove AgentB - should fail with restrict
-      result = await runCLI(['remove', 'agent', '--name', 'AgentB', '--json'], projDir);
-      assert.strictEqual(result.exitCode, 1);
-      const json = JSON.parse(result.stdout);
-      assert.strictEqual(json.success, false);
-      assert.ok(json.error.toLowerCase().includes('reference') || json.error.toLowerCase().includes('use'), `Error: ${json.error}`);
-    });
-  });
-});
diff --git a/src/cli/commands/remove/validate.ts b/src/cli/commands/remove/validate.ts
index fa0a39dcd..8aedf90a4 100644
--- a/src/cli/commands/remove/validate.ts
+++ b/src/cli/commands/remove/validate.ts
@@ -1,4 +1,4 @@
-import type { RemoveOptions, RemoveAllOptions } from './types';
+import type { RemoveAllOptions, RemoveOptions } from './types';
 
 export interface ValidationResult {
   valid: boolean;
diff --git a/src/cli/commands/update/__tests__/update.test.ts b/src/cli/commands/update/__tests__/update.test.ts
new file mode 100644
index 000000000..63aa00530
--- /dev/null
+++ b/src/cli/commands/update/__tests__/update.test.ts
@@ -0,0 +1,36 @@
+import { compareVersions } from './action.js';
+import { describe, it , expect } from 'vitest';
+
+describe('update', () => {
+  describe('compareVersions', () => {
+    it('returns 0 for equal versions', () => {
+      expect(compareVersions('1.0.0', '1.0.0')).toBe(0);
+      expect(compareVersions('2.5.3', '2.5.3')).toBe(0);
+    });
+
+    it('returns 1 when latest is newer (update available)', () => {
+      expect(compareVersions('1.0.0', '1.0.1')).toBe(1);
+      expect(compareVersions('1.0.0', '1.1.0')).toBe(1);
+      expect(compareVersions('1.0.0', '2.0.0')).toBe(1);
+      expect(compareVersions('1.9.9', '2.0.0')).toBe(1);
+    });
+
+    it('returns -1 when current is newer (local ahead)', () => {
+      expect(compareVersions('1.0.1', '1.0.0')).toBe(-1);
+      expect(compareVersions('1.1.0', '1.0.0')).toBe(-1);
+      expect(compareVersions('2.0.0', '1.0.0')).toBe(-1);
+      expect(compareVersions('2.0.0', '1.9.9')).toBe(-1);
+    });
+
+    it('handles missing patch version', () => {
+      expect(compareVersions('1.0', '1.0.0')).toBe(0);
+      expect(compareVersions('1.0.0', '1.0')).toBe(0);
+      expect(compareVersions('1.0', '1.0.1')).toBe(1);
+    });
+
+    it('compares major version first', () => {
+      expect(compareVersions('1.9.9', '2.0.0')).toBe(1);
+      expect(compareVersions('2.0.0', '1.9.9')).toBe(-1);
+    });
+  });
+});
diff --git a/src/cli/commands/update/update.test.ts b/src/cli/commands/update/update.test.ts
deleted file mode 100644
index a104861fd..000000000
--- a/src/cli/commands/update/update.test.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { describe, it } from 'bun:test';
-import assert from 'node:assert';
-import { compareVersions } from './action.js';
-
-describe('update', () => {
-  describe('compareVersions', () => {
-    it('returns 0 for equal versions', () => {
-      assert.strictEqual(compareVersions('1.0.0', '1.0.0'), 0);
-      assert.strictEqual(compareVersions('2.5.3', '2.5.3'), 0);
-    });
-
-    it('returns 1 when latest is newer (update available)', () => {
-      assert.strictEqual(compareVersions('1.0.0', '1.0.1'), 1);
-      assert.strictEqual(compareVersions('1.0.0', '1.1.0'), 1);
-      assert.strictEqual(compareVersions('1.0.0', '2.0.0'), 1);
-      assert.strictEqual(compareVersions('1.9.9', '2.0.0'), 1);
-    });
-
-    it('returns -1 when current is newer (local ahead)', () => {
-      assert.strictEqual(compareVersions('1.0.1', '1.0.0'), -1);
-      assert.strictEqual(compareVersions('1.1.0', '1.0.0'), -1);
-      assert.strictEqual(compareVersions('2.0.0', '1.0.0'), -1);
-      assert.strictEqual(compareVersions('2.0.0', '1.9.9'), -1);
-    });
-
-    it('handles missing patch version', () => {
-      assert.strictEqual(compareVersions('1.0', '1.0.0'), 0);
-      assert.strictEqual(compareVersions('1.0.0', '1.0'), 0);
-      assert.strictEqual(compareVersions('1.0', '1.0.1'), 1);
-    });
-
-    it('compares major version first', () => {
-      assert.strictEqual(compareVersions('1.9.9', '2.0.0'), 1);
-      assert.strictEqual(compareVersions('2.0.0', '1.9.9'), -1);
-    });
-  });
-});
diff --git a/src/cli/errors.test.ts b/src/cli/errors.test.ts
deleted file mode 100644
index 8002aade1..000000000
--- a/src/cli/errors.test.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-import { describe, it } from 'bun:test';
-import assert from 'node:assert';
-import {
-  getErrorMessage,
-  isExpiredTokenError,
-  isNoCredentialsError,
-  isStackInProgressError,
-} from './errors.js';
-
-describe('errors', () => {
-  describe('getErrorMessage', () => {
-    it('returns message from Error instance', () => {
-      const err = new Error('test error');
-      assert.strictEqual(getErrorMessage(err), 'test error');
-    });
-
-    it('returns string for non-Error values', () => {
-      assert.strictEqual(getErrorMessage('raw error'), 'raw error');
-      assert.strictEqual(getErrorMessage(123), '123');
-      assert.strictEqual(getErrorMessage(null), 'null');
-      assert.strictEqual(getErrorMessage(undefined), 'undefined');
-    });
-  });
-
-  describe('isExpiredTokenError', () => {
-    // Test ALL error codes in EXPIRED_TOKEN_ERROR_CODES via error.name
-    const allErrorCodes = [
-      'ExpiredToken',
-      'ExpiredTokenException',
-      'TokenRefreshRequired',
-      'CredentialsExpired',
-      'InvalidIdentityToken',
-      'UnauthorizedAccess',
-      'AccessDenied',
-      'AccessDeniedException',
-      'InvalidClientTokenId',
-      'SignatureDoesNotMatch',
-      'RequestExpired',
-    ];
-
-    it('returns true for all SDK v3 error names', () => {
-      for (const code of allErrorCodes) {
-        assert.strictEqual(
-          isExpiredTokenError({ name: code }),
-          true,
-          `Should detect error.name: ${code}`
-        );
-      }
-    });
-
-    it('returns true for all error Code properties', () => {
-      for (const code of allErrorCodes) {
-        assert.strictEqual(
-          isExpiredTokenError({ Code: code }),
-          true,
-          `Should detect error.Code: ${code}`
-        );
-      }
-    });
-
-    it('returns true for nested cause with error name', () => {
-      assert.strictEqual(isExpiredTokenError({ cause: { name: 'ExpiredToken' } }), true);
-    });
-
-    it('returns true for double-nested cause', () => {
-      assert.strictEqual(isExpiredTokenError({ cause: { cause: { name: 'ExpiredToken' } } }), true);
-    });
-
-    it('returns true for nested cause with Code', () => {
-      assert.strictEqual(isExpiredTokenError({ cause: { Code: 'AccessDenied' } }), true);
-    });
-
-    it('returns true for message patterns', () => {
-      const patterns = [
-        'expired token',
-        'token has expired',
-        'credentials have expired',
-        'security token included in the request is expired',
-        'the security token included in the request is invalid',
-      ];
-      for (const pattern of patterns) {
-        assert.strictEqual(
-          isExpiredTokenError(new Error(pattern)),
-          true,
-          `Should detect message: ${pattern}`
-        );
-      }
-    });
-
-    it('returns false for non-expired errors', () => {
-      assert.strictEqual(isExpiredTokenError({ name: 'ValidationError' }), false);
-      assert.strictEqual(isExpiredTokenError({ Code: 'ResourceNotFound' }), false);
-      assert.strictEqual(isExpiredTokenError(new Error('some other error')), false);
-    });
-
-    it('returns false for edge cases', () => {
-      assert.strictEqual(isExpiredTokenError(null), false);
-      assert.strictEqual(isExpiredTokenError(undefined), false);
-      assert.strictEqual(isExpiredTokenError('string'), false);
-      assert.strictEqual(isExpiredTokenError(123), false);
-      assert.strictEqual(isExpiredTokenError({}), false);
-      assert.strictEqual(isExpiredTokenError({ name: 123 }), false); // non-string name
-      assert.strictEqual(isExpiredTokenError({ Code: 123 }), false); // non-string Code
-    });
-  });
-
-  describe('isNoCredentialsError', () => {
-    it('returns true for AwsCredentialsError', () => {
-      assert.strictEqual(isNoCredentialsError({ name: 'AwsCredentialsError' }), true);
-    });
-
-    it('returns true for message patterns', () => {
-      const patterns = [
-        'no aws credentials found',
-        'could not load credentials',
-        'credentials not found',
-      ];
-      for (const pattern of patterns) {
-        assert.strictEqual(
-          isNoCredentialsError(new Error(pattern)),
-          true,
-          `Should detect message: ${pattern}`
-        );
-      }
-    });
-
-    it('returns false for other errors', () => {
-      assert.strictEqual(isNoCredentialsError({ name: 'ExpiredTokenException' }), false);
-      assert.strictEqual(isNoCredentialsError(new Error('some other error')), false);
-    });
-
-    it('returns false for edge cases', () => {
-      assert.strictEqual(isNoCredentialsError(null), false);
-      assert.strictEqual(isNoCredentialsError(undefined), false);
-      assert.strictEqual(isNoCredentialsError('string'), false);
-      assert.strictEqual(isNoCredentialsError(123), false);
-      assert.strictEqual(isNoCredentialsError({}), false);
-    });
-  });
-
-  describe('isStackInProgressError', () => {
-    it('returns true for in-progress states', () => {
-      const states = [
-        'UPDATE_IN_PROGRESS',
-        'CREATE_IN_PROGRESS',
-        'DELETE_IN_PROGRESS',
-        'ROLLBACK_IN_PROGRESS',
-      ];
-      for (const state of states) {
-        assert.strictEqual(
-          isStackInProgressError(new Error(`Stack is in ${state} state`)),
-          true,
-          `Should detect state: ${state}`
-        );
-      }
-    });
-
-    it('returns true for state and cannot be updated pattern', () => {
-      assert.strictEqual(
-        isStackInProgressError(new Error('Stack is in UPDATE_ROLLBACK_IN_PROGRESS state and cannot be updated')),
-        true
-      );
-    });
-
-    it('returns true for currently being updated', () => {
-      assert.strictEqual(isStackInProgressError(new Error('stack is currently being updated')), true);
-    });
-
-    it('returns false for other errors', () => {
-      assert.strictEqual(isStackInProgressError(new Error('Stack not found')), false);
-      assert.strictEqual(isStackInProgressError(new Error('some other error')), false);
-    });
-
-    it('returns false for edge cases', () => {
-      assert.strictEqual(isStackInProgressError(null), false);
-      assert.strictEqual(isStackInProgressError(undefined), false);
-      assert.strictEqual(isStackInProgressError({}), false);
-    });
-  });
-});
diff --git a/src/cli/operations/dev/server.ts b/src/cli/operations/dev/server.ts
index 87c134b0b..2d4361b95 100644
--- a/src/cli/operations/dev/server.ts
+++ b/src/cli/operations/dev/server.ts
@@ -92,10 +92,10 @@ export function spawnDevServer(options: SpawnDevServerOptions): ChildProcess | n
   }
 
   // For Python, use the venv's uvicorn directly to avoid PATH issues
-  const cmd = isPython ? join(cwd, '.venv', 'bin', 'uvicorn') : 'bun';
+  const cmd = isPython ? join(cwd, '.venv', 'bin', 'uvicorn') : 'npx';
   const args = isPython
     ? [convertEntrypointToModule(module), '--reload', '--host', '127.0.0.1', '--port', String(port)]
-    : ['run', '--watch', (module.split(':')[0] ?? module).replace(/\./g, '/') + '.ts'];
+    : ['tsx', 'watch', (module.split(':')[0] ?? module).replace(/\./g, '/') + '.ts'];
 
   const child = spawn(cmd, args, {
     cwd,
diff --git a/src/cli/tui/screens/attach/AttachFlow.tsx b/src/cli/tui/screens/attach/AttachFlow.tsx
index 1b32a4cf1..d7b2c6ded 100644
--- a/src/cli/tui/screens/attach/AttachFlow.tsx
+++ b/src/cli/tui/screens/attach/AttachFlow.tsx
@@ -1,5 +1,4 @@
-import { ErrorPrompt, type NextStep, NextSteps, Panel, Screen, SelectScreen } from '../../components';
-import type { SelectableItem } from '../../components';
+import { ErrorPrompt, type NextStep, NextSteps, Panel, Screen, SelectScreen , SelectableItem } from '../../components';
 import {
   useAgentAttachments,
   useAgents,
@@ -353,9 +352,7 @@ export function AttachFlow(props: { onExit: () => void }) {
   }
 
   if (flow.name === 'success') {
-    const attachSuccessSteps: NextStep[] = [
-      { command: 'attach', label: 'Attach another resource' },
-    ];
+    const attachSuccessSteps: NextStep[] = [{ command: 'attach', label: 'Attach another resource' }];
 
     const handleSuccessSelect = (step: NextStep) => {
       if (step.command === 'attach') {
@@ -369,10 +366,19 @@ export function AttachFlow(props: { onExit: () => void }) {
       <Screen title="Success" onExit={props.onExit}>
         <Box flexDirection="column" gap={1}>
           <Box flexDirection="column">
-            <Text color="green">✓ Attached {flow.resourceType}: {flow.resourceName}</Text>
-            <Text>{flow.resourceType} attached to agent &quot;{flow.sourceAgent}&quot;. Deploy with `agentcore deploy`.</Text>
+            <Text color="green">
+              ✓ Attached {flow.resourceType}: {flow.resourceName}
+            </Text>
+            <Text>
+              {flow.resourceType} attached to agent &quot;{flow.sourceAgent}&quot;. Deploy with `agentcore deploy`.
+            </Text>
           </Box>
-          <NextSteps steps={attachSuccessSteps} isInteractive={true} onSelect={handleSuccessSelect} onBack={props.onExit} />
+          <NextSteps
+            steps={attachSuccessSteps}
+            isInteractive={true}
+            onSelect={handleSuccessSelect}
+            onBack={props.onExit}
+          />
         </Box>
       </Screen>
     );
diff --git a/src/cli/tui/utils/__tests__/process.test.ts b/src/cli/tui/utils/__tests__/process.test.ts
new file mode 100644
index 000000000..6a36e5c06
--- /dev/null
+++ b/src/cli/tui/utils/__tests__/process.test.ts
@@ -0,0 +1,81 @@
+import { cleanupStaleLockFiles } from '../process.js';
+import { randomUUID } from 'node:crypto';
+import * as fs from 'node:fs';
+import * as fsp from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import * as path from 'node:path';
+import { afterEach, beforeEach, describe, it , expect } from 'vitest';
+
+describe('cleanupStaleLockFiles', () => {
+  let testDir: string;
+
+  beforeEach(async () => {
+    testDir = path.join(tmpdir(), `cdk-lock-test-${randomUUID()}`);
+    await fsp.mkdir(testDir, { recursive: true });
+  });
+
+  afterEach(async () => {
+    await fsp.rm(testDir, { recursive: true, force: true });
+  });
+
+  it('removes lock files older than 5 minutes', async () => {
+    const lockFile = path.join(testDir, 'read.99999.1.lock');
+    await fsp.writeFile(lockFile, '');
+    // Set mtime to 10 minutes ago
+    const oldTime = new Date(Date.now() - 10 * 60 * 1000);
+    await fsp.utimes(lockFile, oldTime, oldTime);
+
+    await cleanupStaleLockFiles(testDir);
+
+    expect(fs.existsSync(lockFile), 'Old lock file should be removed').toBe(false);
+  });
+
+  it('removes young lock files from dead processes', async () => {
+    // PID 99999 is unlikely to exist
+    const lockFile = path.join(testDir, 'read.99999.1.lock');
+    await fsp.writeFile(lockFile, '');
+
+    await cleanupStaleLockFiles(testDir);
+
+    expect(fs.existsSync(lockFile), 'Lock from dead PID should be removed').toBe(false);
+  });
+
+  it('keeps young lock files from live processes', async () => {
+    const lockFile = path.join(testDir, `read.${process.pid}.1.lock`);
+    await fsp.writeFile(lockFile, '');
+
+    await cleanupStaleLockFiles(testDir);
+
+    expect(fs.existsSync(lockFile), 'Lock from live PID should be kept').toBe(true);
+  });
+
+  it('removes old synth.lock files', async () => {
+    const lockFile = path.join(testDir, 'synth.lock');
+    await fsp.writeFile(lockFile, '');
+    const oldTime = new Date(Date.now() - 10 * 60 * 1000);
+    await fsp.utimes(lockFile, oldTime, oldTime);
+
+    await cleanupStaleLockFiles(testDir);
+
+    expect(fs.existsSync(lockFile), 'Old synth.lock should be removed').toBe(false);
+  });
+
+  it('handles missing directory gracefully', async () => {
+    const nonExistent = path.join(testDir, 'does-not-exist');
+
+    // Should not throw
+    await cleanupStaleLockFiles(nonExistent);
+  });
+
+  it('does not remove non-lock files', async () => {
+    const manifestFile = path.join(testDir, 'manifest.json');
+    const treeFile = path.join(testDir, 'tree.json');
+    await fsp.writeFile(manifestFile, '{}');
+    await fsp.writeFile(treeFile, '{}');
+
+    await cleanupStaleLockFiles(testDir);
+
+    expect(fs.existsSync(manifestFile), 'manifest.json should not be removed').toBe(true);
+    expect(fs.existsSync(treeFile), 'tree.json should not be removed').toBe(true);
+  });
+});
diff --git a/src/schema/schemas/__tests__/zod-util.test.ts b/src/schema/schemas/__tests__/zod-util.test.ts
new file mode 100644
index 000000000..4aab854d5
--- /dev/null
+++ b/src/schema/schemas/__tests__/zod-util.test.ts
@@ -0,0 +1,117 @@
+import { uniqueBy } from '../zod-util.js';
+import { describe, it , expect } from 'vitest';
+import { z } from 'zod';
+
+describe('zod-util', () => {
+  describe('uniqueBy', () => {
+    // Helper schema for testing
+    const createSchema = (errorMsg: (key: string) => string = k => `Duplicate: ${k}`) =>
+      z.array(z.object({ name: z.string() })).superRefine(uniqueBy(x => x.name, errorMsg));
+
+    // AC1: Unique array passes validation
+    it('passes validation for unique arrays', () => {
+      const schema = createSchema();
+      const result = schema.safeParse([{ name: 'a' }, { name: 'b' }, { name: 'c' }]);
+      expect(result.success).toBe(true);
+    });
+
+    // AC2: Duplicate detected at correct index (NOT first occurrence)
+    it('detects duplicate at correct index', () => {
+      const schema = createSchema();
+      const result = schema.safeParse([{ name: 'a' }, { name: 'b' }, { name: 'a' }]);
+      expect(result.success).toBe(false);
+      if (!result.success) {
+        expect(result.error.issues.length).toBe(1);
+        expect(result.error.issues[0].path).toEqual([2]);
+      }
+    });
+
+    // AC3: Custom error message used
+    it('uses custom error message', () => {
+      const schema = createSchema(key => `Duplicate name: ${key}`);
+      const result = schema.safeParse([{ name: 'foo' }, { name: 'foo' }]);
+      expect(result.success).toBe(false);
+      if (!result.success) {
+        expect(result.error.issues[0].message).toBe('Duplicate name: foo');
+      }
+    });
+
+    // AC4: Empty array passes
+    it('passes validation for empty array', () => {
+      const schema = createSchema();
+      const result = schema.safeParse([]);
+      expect(result.success).toBe(true);
+    });
+
+    // AC5: Single element passes
+    it('passes validation for single element', () => {
+      const schema = createSchema();
+      const result = schema.safeParse([{ name: 'a' }]);
+      expect(result.success).toBe(true);
+    });
+
+    // AC6: Multiple duplicates of same key flagged at each occurrence
+    it('flags multiple duplicates at each subsequent occurrence', () => {
+      const schema = createSchema();
+      const result = schema.safeParse([
+        { name: 'a' }, // index 0 - first, not flagged
+        { name: 'b' }, // index 1 - unique
+        { name: 'a' }, // index 2 - duplicate, flagged
+        { name: 'c' }, // index 3 - unique
+        { name: 'a' }, // index 4 - duplicate, flagged
+      ]);
+      expect(result.success).toBe(false);
+      if (!result.success) {
+        expect(result.error.issues.length).toBe(2);
+        const paths = result.error.issues.map(i => i.path[0]);
+        expect(paths.includes(2), 'Should flag index 2').toBeTruthy();
+        expect(paths.includes(4), 'Should flag index 4').toBeTruthy();
+        expect(!paths.includes(0), 'Should NOT flag index 0 (first occurrence)').toBeTruthy();
+      }
+    });
+
+    // AC7: First occurrence is never flagged
+    it('never flags first occurrence', () => {
+      const schema = createSchema();
+      const result = schema.safeParse([{ name: 'a' }, { name: 'a' }]);
+      expect(result.success).toBe(false);
+      if (!result.success) {
+        const paths = result.error.issues.map(i => i.path[0]);
+        expect(!paths.includes(0), 'First occurrence should not be flagged').toBeTruthy();
+        expect(paths.includes(1), 'Second occurrence should be flagged').toBeTruthy();
+      }
+    });
+
+    // AC8: Different key functions work
+    it('works with different key functions', () => {
+      const idSchema = z.array(z.object({ id: z.string() })).superRefine(
+        uniqueBy(
+          x => x.id,
+          k => `Duplicate id: ${k}`
+        )
+      );
+
+      const result = idSchema.safeParse([{ id: '1' }, { id: '2' }, { id: '1' }]);
+      expect(result.success).toBe(false);
+      if (!result.success) {
+        expect(result.error.issues.length).toBe(1);
+        expect(result.error.issues[0].path).toEqual([2]);
+        expect(result.error.issues[0].message).toBe('Duplicate id: 1');
+      }
+    });
+
+    // AC9: All elements same key
+    it('flags all subsequent occurrences when all elements have same key', () => {
+      const schema = createSchema();
+      const result = schema.safeParse([{ name: 'a' }, { name: 'a' }, { name: 'a' }]);
+      expect(result.success).toBe(false);
+      if (!result.success) {
+        expect(result.error.issues.length).toBe(2);
+        const paths = result.error.issues.map(i => i.path[0]);
+        expect(!paths.includes(0), 'Index 0 should NOT be flagged').toBeTruthy();
+        expect(paths.includes(1), 'Index 1 should be flagged').toBeTruthy();
+        expect(paths.includes(2), 'Index 2 should be flagged').toBeTruthy();
+      }
+    });
+  });
+});
diff --git a/src/schema/schemas/zod-util.test.ts b/src/schema/schemas/zod-util.test.ts
deleted file mode 100644
index d37e1dd04..000000000
--- a/src/schema/schemas/zod-util.test.ts
+++ /dev/null
@@ -1,115 +0,0 @@
-import { describe, it } from 'bun:test';
-import assert from 'node:assert';
-import { z } from 'zod';
-import { uniqueBy } from './zod-util.js';
-
-describe('zod-util', () => {
-  describe('uniqueBy', () => {
-    // Helper schema for testing
-    const createSchema = (errorMsg: (key: string) => string = (k) => `Duplicate: ${k}`) =>
-      z.array(z.object({ name: z.string() })).superRefine(uniqueBy((x) => x.name, errorMsg));
-
-    // AC1: Unique array passes validation
-    it('passes validation for unique arrays', () => {
-      const schema = createSchema();
-      const result = schema.safeParse([{ name: 'a' }, { name: 'b' }, { name: 'c' }]);
-      assert.strictEqual(result.success, true);
-    });
-
-    // AC2: Duplicate detected at correct index (NOT first occurrence)
-    it('detects duplicate at correct index', () => {
-      const schema = createSchema();
-      const result = schema.safeParse([{ name: 'a' }, { name: 'b' }, { name: 'a' }]);
-      assert.strictEqual(result.success, false);
-      if (!result.success) {
-        assert.strictEqual(result.error.issues.length, 1);
-        assert.deepStrictEqual(result.error.issues[0].path, [2]);
-      }
-    });
-
-    // AC3: Custom error message used
-    it('uses custom error message', () => {
-      const schema = createSchema((key) => `Duplicate name: ${key}`);
-      const result = schema.safeParse([{ name: 'foo' }, { name: 'foo' }]);
-      assert.strictEqual(result.success, false);
-      if (!result.success) {
-        assert.strictEqual(result.error.issues[0].message, 'Duplicate name: foo');
-      }
-    });
-
-    // AC4: Empty array passes
-    it('passes validation for empty array', () => {
-      const schema = createSchema();
-      const result = schema.safeParse([]);
-      assert.strictEqual(result.success, true);
-    });
-
-    // AC5: Single element passes
-    it('passes validation for single element', () => {
-      const schema = createSchema();
-      const result = schema.safeParse([{ name: 'a' }]);
-      assert.strictEqual(result.success, true);
-    });
-
-    // AC6: Multiple duplicates of same key flagged at each occurrence
-    it('flags multiple duplicates at each subsequent occurrence', () => {
-      const schema = createSchema();
-      const result = schema.safeParse([
-        { name: 'a' },  // index 0 - first, not flagged
-        { name: 'b' },  // index 1 - unique
-        { name: 'a' },  // index 2 - duplicate, flagged
-        { name: 'c' },  // index 3 - unique
-        { name: 'a' },  // index 4 - duplicate, flagged
-      ]);
-      assert.strictEqual(result.success, false);
-      if (!result.success) {
-        assert.strictEqual(result.error.issues.length, 2);
-        const paths = result.error.issues.map((i) => i.path[0]);
-        assert.ok(paths.includes(2), 'Should flag index 2');
-        assert.ok(paths.includes(4), 'Should flag index 4');
-        assert.ok(!paths.includes(0), 'Should NOT flag index 0 (first occurrence)');
-      }
-    });
-
-    // AC7: First occurrence is never flagged
-    it('never flags first occurrence', () => {
-      const schema = createSchema();
-      const result = schema.safeParse([{ name: 'a' }, { name: 'a' }]);
-      assert.strictEqual(result.success, false);
-      if (!result.success) {
-        const paths = result.error.issues.map((i) => i.path[0]);
-        assert.ok(!paths.includes(0), 'First occurrence should not be flagged');
-        assert.ok(paths.includes(1), 'Second occurrence should be flagged');
-      }
-    });
-
-    // AC8: Different key functions work
-    it('works with different key functions', () => {
-      const idSchema = z
-        .array(z.object({ id: z.string() }))
-        .superRefine(uniqueBy((x) => x.id, (k) => `Duplicate id: ${k}`));
-
-      const result = idSchema.safeParse([{ id: '1' }, { id: '2' }, { id: '1' }]);
-      assert.strictEqual(result.success, false);
-      if (!result.success) {
-        assert.strictEqual(result.error.issues.length, 1);
-        assert.deepStrictEqual(result.error.issues[0].path, [2]);
-        assert.strictEqual(result.error.issues[0].message, 'Duplicate id: 1');
-      }
-    });
-
-    // AC9: All elements same key
-    it('flags all subsequent occurrences when all elements have same key', () => {
-      const schema = createSchema();
-      const result = schema.safeParse([{ name: 'a' }, { name: 'a' }, { name: 'a' }]);
-      assert.strictEqual(result.success, false);
-      if (!result.success) {
-        assert.strictEqual(result.error.issues.length, 2);
-        const paths = result.error.issues.map((i) => i.path[0]);
-        assert.ok(!paths.includes(0), 'Index 0 should NOT be flagged');
-        assert.ok(paths.includes(1), 'Index 1 should be flagged');
-        assert.ok(paths.includes(2), 'Index 2 should be flagged');
-      }
-    });
-  });
-});
diff --git a/src/test-utils/cli-runner.ts b/src/test-utils/cli-runner.ts
index 8e9f1ce5a..7afe896fd 100644
--- a/src/test-utils/cli-runner.ts
+++ b/src/test-utils/cli-runner.ts
@@ -15,11 +15,11 @@ export interface RunResult {
 
 /**
  * Get the path to the CLI entry point.
- * Works from any test file location within the project.
+ * Uses the built bundle - run `npm run build` before tests.
  */
 function getCLIPath(): string {
-  // Navigate from src/test-utils to src/cli/index.ts
-  return join(__dirname, '..', 'cli', 'index.ts');
+  // Navigate from src/test-utils to dist/cli/index.mjs
+  return join(__dirname, '..', '..', 'dist', 'cli', 'index.mjs');
 }
 
 /**
@@ -39,7 +39,7 @@ export async function runCLI(args: string[], cwd: string, skipInstall = true): P
   const cliPath = getCLIPath();
 
   return new Promise(resolve => {
-    const proc = spawn('bun', ['run', cliPath, ...args], {
+    const proc = spawn('node', [cliPath, ...args], {
       cwd,
       env: { ...process.env, INIT_CWD: undefined, ...(skipInstall ? { AGENTCORE_SKIP_INSTALL: '1' } : {}) },
     });
diff --git a/test-output.txt b/test-output.txt
new file mode 100644
index 000000000..3b56508b9
--- /dev/null
+++ b/test-output.txt
@@ -0,0 +1,830 @@
+
+> @aws/agentcore-cli@0.1.0 test:vitest
+> vitest run
+
+
+[1m[46m RUN [49m[22m [36mv4.0.18 [39m[90m/Users/aidandal/workplace/agentcore-cli[39m
+
+ [32m✓[39m integ-tests/json-output.test.ts[2m > [22mJSON output structure[2m > [22mcreate command[2m > [22merror response has success:false and error string[33m 1615[2mms[22m[39m
+ [32m✓[39m src/cli/commands/dev/__tests__/dev.test.ts[2m > [22mdev command[2m > [22m--help[2m > [22mshows all options[33m 1619[2mms[22m[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mmain help[2m > [22mshows all commands[33m 1621[2mms[22m[39m
+ [32m✓[39m src/cli/commands/deploy/__tests__/deploy.test.ts[2m > [22mdeploy --help[2m > [22mshows verbose option[33m 1664[2mms[22m[39m
+ [32m✓[39m integ-tests/json-output.test.ts[2m > [22mJSON output structure[2m > [22mcreate command[2m > [22mvalidation error mentions the issue[33m 1360[2mms[22m[39m
+ [32m✓[39m src/cli/commands/deploy/__tests__/deploy.test.ts[2m > [22mdeploy --help[2m > [22mshows all deploy options[33m 1311[2mms[22m[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mcreate --help exits 0[33m 1357[2mms[22m[39m
+ [32m✓[39m src/cli/commands/dev/__tests__/dev.test.ts[2m > [22mdev command[2m > [22mrequires project context[2m > [22mexits with error when run outside project[33m 1372[2mms[22m[39m
+ [32m✓[39m integ-tests/json-output.test.ts[2m > [22mJSON output structure[2m > [22mcreate command[2m > [22mmissing required options returns error JSON[33m 1484[2mms[22m[39m
+ [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22m--no-agent[2m > [22mcreates project structure[33m 4480[2mms[22m[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mdeploy --help exits 0[33m 1678[2mms[22m[39m
+ [32m✓[39m src/cli/commands/dev/__tests__/dev.test.ts[2m > [22mdev command[2m > [22mflag validation[2m > [22mrejects invalid port number[33m 1683[2mms[22m[39m
+ [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22m--no-agent[2m > [22mrejects reserved names[33m 1562[2mms[22m[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mdev --help exits 0[33m 1412[2mms[22m[39m
+ [32m✓[39m integ-tests/json-output.test.ts[2m > [22mJSON output structure[2m > [22mcreate command[2m > [22minvalid framework returns error JSON[33m 1619[2mms[22m[39m
+ [32m✓[39m src/cli/commands/dev/__tests__/dev.test.ts[2m > [22mdev command[2m > [22mflag validation[2m > [22mrejects negative port number[33m 1434[2mms[22m[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22minvoke --help exits 0[33m 1558[2mms[22m[39m
+ [32m✓[39m src/cli/commands/dev/__tests__/dev.test.ts[2m > [22mdev command[2m > [22mflag validation[2m > [22mstream flag is documented in help[33m 1521[2mms[22m[39m
+ [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22mwith agent[2m > [22mcreates project with agent[33m 3033[2mms[22m[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mdestroy --help exits 0[33m 1669[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-identity.test.ts[2m > [22madd identity command[2m > [22mvalidation[2m > [22mrequires name flag[33m 1640[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mvalidation[2m > [22mrequires name flag[33m 1806[2mms[22m[39m
+ [32m✓[39m src/cli/commands/plan/__tests__/plan.test.ts[2m > [22mplan command[2m > [22mtarget validation[2m > [22mrejects non-existent target[33m 1784[2mms[22m[39m
+ [31m×[39m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts[2m > [22magent removal cascade[2m > [22mcascade removes owned resources[2m > [22mremoves agent and its owned memory[33m 9475[2mms[22m[39m
+[31m   → stdout: 
+
+1 !== 0
+[39m
+ [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22mwith agent[2m > [22mrequires all options without --no-agent[33m 1683[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-identity.test.ts[2m > [22madd identity command[2m > [22mvalidation[2m > [22mrequires type flag[33m 1636[2mms[22m[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mplan --help exits 0[33m 1683[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mvalidation[2m > [22mrequires exposure flag[33m 1587[2mms[22m[39m
+ [31m×[39m src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts[2m > [22mremoval policy cascade[2m > [22mmemory cascade[2m > [22mremoves memory and cleans up user references with cascade[33m 11018[2mms[22m[39m
+[31m   → stdout: 
+
+1 !== 0
+[39m
+ [31m×[39m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22mmemory restrict[2m > [22mblocks removal when memory has users (default restrict)[33m 11055[2mms[22m[39m
+[31m   → Expected values to be strictly equal:
+
+0 !== 1
+[39m
+ [32m✓[39m src/cli/commands/deploy/__tests__/deploy.test.ts[2m > [22mdeploy command[2m > [22mvalidation[2m > [22maccepts deploy without target (TUI mode)[33m 3231[2mms[22m[39m
+ [32m✓[39m src/cli/commands/plan/__tests__/plan.test.ts[2m > [22mplan command[2m > [22mtarget validation[2m > [22maccepts valid target and returns plan result[33m 3069[2mms[22m[39m
+ [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22mwith agent[2m > [22mvalidates framework[33m 2598[2mms[22m[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mstatus --help exits 0[33m 2531[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-identity.test.ts[2m > [22madd identity command[2m > [22mvalidation[2m > [22mvalidates type value[33m 2573[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mvalidation[2m > [22mvalidates language[33m 2509[2mms[22m[39m
+ [32m✓[39m src/cli/commands/deploy/__tests__/deploy.test.ts[2m > [22mdeploy command[2m > [22mtarget validation[2m > [22mrejects non-existent target[33m 2526[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-identity.test.ts[2m > [22madd identity command[2m > [22mvalidation[2m > [22mrequires api-key flag[33m 2787[2mms[22m[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mvalidate --help exits 0[33m 2838[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mvalidation[2m > [22maccepts Other as valid language option[33m 2877[2mms[22m[39m
+ [32m✓[39m src/cli/commands/plan/__tests__/plan.test.ts[2m > [22mplan command[2m > [22m--deploy flag[2m > [22mcommand accepts --deploy flag[33m 3899[2mms[22m[39m
+ [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22m--defaults[2m > [22mcreates project with defaults[33m 4367[2mms[22m[39m
+ [32m✓[39m src/cli/commands/remove/__tests__/remove-identity.test.ts[2m > [22mremove identity command[2m > [22mvalidation[2m > [22mrequires name flag[33m 2536[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-identity.test.ts[2m > [22madd identity command[2m > [22mvalidation[2m > [22mrequires owner flag[33m 2661[2mms[22m[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22madd --help exits 0[33m 2644[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mmcp-runtime[2m > [22mcreates mcp-runtime tool[33m 2740[2mms[22m[39m
+ [31m×[39m src/cli/commands/plan/__tests__/plan.test.ts[2m > [22mplan command[2m > [22m--deploy flag[2m > [22mplan without --deploy returns plan result only[33m 4021[2mms[22m[39m
+[31m   → Expected values to be strictly equal:
+
+1 !== 0
+[39m
+ [31m×[39m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts[2m > [22magent removal cascade[2m > [22mcascade removes owned resources[2m > [22mremoves agent and its owned identity[33m 11013[2mms[22m[39m
+[31m   → stdout: 
+
+1 !== 0
+[39m
+ [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22m--dry-run[2m > [22mshows files without creating[33m 2876[2mms[22m[39m
+ [32m✓[39m src/cli/commands/remove/__tests__/remove-identity.test.ts[2m > [22mremove identity command[2m > [22mvalidation[2m > [22mrejects non-existent identity[33m 2963[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts[2m > [22mattach mcp-runtime command[2m > [22mvalidation[2m > [22mrequires agent flag[33m 2955[2mms[22m[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mattach --help exits 0[33m 2917[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-identity.test.ts[2m > [22madd identity command[2m > [22midentity creation[2m > [22mcreates identity with owner[33m 2991[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mmcp-runtime[2m > [22mrequires agents for mcp-runtime[33m 2914[2mms[22m[39m
+ [32m✓[39m src/cli/commands/plan/__tests__/plan.test.ts[2m > [22mplan command[2m > [22m--deploy flag[2m > [22mrequires --target for --deploy[33m 2948[2mms[22m[39m
+ [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22m--skip-git[2m > [22mskips git initialization[33m 3010[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts[2m > [22mattach mcp-runtime command[2m > [22mvalidation[2m > [22mrequires runtime flag[33m 2780[2mms[22m[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mremove --help exits 0[33m 2752[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-identity.test.ts[2m > [22madd identity command[2m > [22midentity creation[2m > [22mcreates identity with owner and users[33m 2783[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mmcp-runtime[2m > [22mreturns clear error for Other language with mcp-runtime[33m 2746[2mms[22m[39m
+ [31m×[39m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22mmemory restrict[2m > [22mblocks removal with explicit restrict policy[33m 15001[2mms[22m[39m
+[31m   → Test timed out in 15000ms.
+If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
+ [31m×[39m src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts[2m > [22mremoval policy cascade[2m > [22midentity cascade[2m > [22mremoves identity and cleans up user references with cascade[33m 15002[2mms[22m[39m
+[31m   → Test timed out in 15000ms.
+If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-agent.test.ts[2m > [22mattach agent command[2m > [22mvalidation[2m > [22mrequires source flag[33m 2987[2mms[22m[39m
+ [31m×[39m src/cli/commands/remove/__tests__/remove-identity.test.ts[2m > [22mremove identity command[2m > [22mremove operations[2m > [22mremoves identity without users[33m 5676[2mms[22m[39m
+[31m   → stdout: {"success":false,"error":"Identity \"temp-id-1769792728695\" not found."}
+
+1 !== 0
+[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts[2m > [22mattach mcp-runtime command[2m > [22mbind operations[2m > [22mbinds agent to MCP runtime[33m 2917[2mms[22m[39m
+ [32m✓[39m src/cli/commands/plan/__tests__/plan.test.ts[2m > [22mplan command[2m > [22m--deploy flag[2m > [22mattempts deploy after plan[33m 4138[2mms[22m[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22medit --help exits 0[33m 2904[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mbehind-gateway[2m > [22mcreates behind-gateway tool[33m 2946[2mms[22m[39m
+ [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22m--output-dir[2m > [22mcreates in specified directory[33m 4742[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-agent.test.ts[2m > [22mattach agent command[2m > [22mvalidation[2m > [22mrequires target flag[33m 2699[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts[2m > [22mattach mcp-runtime command[2m > [22mbind operations[2m > [22mrejects non-existent agent[33m 2670[2mms[22m[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22moutline --help exits 0[33m 2656[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mbehind-gateway[2m > [22mrequires gateway for behind-gateway[33m 2615[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-agent.test.ts[2m > [22mattach agent command[2m > [22mattach operations[2m > [22mattaches agent to agent[33m 2573[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts[2m > [22mattach mcp-runtime command[2m > [22mbind operations[2m > [22mrejects non-existent runtime[33m 2738[2mms[22m[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mpackage --help exits 0[33m 2706[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mbehind-gateway[2m > [22mrequires host for behind-gateway[33m 2566[2mms[22m[39m
+ [31m×[39m src/cli/commands/remove/__tests__/remove-identity.test.ts[2m > [22mremove identity command[2m > [22mremove operations[2m > [22mblocks removal when identity has users[33m 5595[2mms[22m[39m
+[31m   → Expected values to be strictly equal:
+
+0 !== 1
+[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-gateway.test.ts[2m > [22madd gateway command[2m > [22mbasic gateway[2m > [22mcreates gateway with default authorizer[33m 2622[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-agent.test.ts[2m > [22mattach agent command[2m > [22mattach operations[2m > [22muses custom name[33m 2890[2mms[22m[39m
+ [31m×[39m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts[2m > [22magent removal cascade[2m > [22mcascade removes owned resources[2m > [22mremoves agent and cleans up remote tool references[33m 15002[2mms[22m[39m
+[31m   → Test timed out in 15000ms.
+If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
+ [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mupdate --help exits 0[33m 3083[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mbehind-gateway[2m > [22mreturns clear error for Other language with behind-gateway[33m 3109[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-target.test.ts[2m > [22madd target command[2m > [22madds target with valid inputs[33m 3080[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-gateway.test.ts[2m > [22madd gateway command[2m > [22mbasic gateway[2m > [22mrequires name flag[33m 3049[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-gateway.test.ts[2m > [22mattach gateway command[2m > [22mvalidation[2m > [22mrequires agent flag[33m 2814[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-agent.test.ts[2m > [22mattach agent command[2m > [22mattach operations[2m > [22mrejects self-attachment[33m 2832[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-target.test.ts[2m > [22madd target command[2m > [22mrejects duplicate target name[33m 2770[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-gateway.test.ts[2m > [22madd gateway command[2m > [22mbasic gateway[2m > [22mvalidates gateway name format[33m 2790[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-gateway.test.ts[2m > [22mattach gateway command[2m > [22mvalidation[2m > [22mrequires gateway flag[33m 2549[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-agent.test.ts[2m > [22mattach agent command[2m > [22mattach operations[2m > [22mrejects non-existent source[33m 2540[2mms[22m[39m
+ [32m✓[39m src/cli/commands/remove/__tests__/remove.test.ts[2m > [22mremove command[2m > [22mvalidation[2m > [22mrequires name for JSON output[33m 2662[2mms[22m[39m
+ [31m×[39m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22midentity restrict[2m > [22mblocks removal when identity has users[33m 15000[2mms[22m[39m
+[31m   → Test timed out in 15000ms.
+If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-target.test.ts[2m > [22madd target command[2m > [22mrejects invalid account ID[33m 2514[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mcreate path[2m > [22mcreates agent with valid inputs[33m 2769[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-gateway.test.ts[2m > [22mattach gateway command[2m > [22mattach operations[2m > [22mattaches gateway to agent[33m 2713[2mms[22m[39m
+ [32m✓[39m src/cli/commands/remove/__tests__/remove.test.ts[2m > [22mremove command[2m > [22mremove target[2m > [22mrejects non-existent target[33m 2694[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-target.test.ts[2m > [22madd target command[2m > [22mrejects invalid region name[33m 2802[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-gateway.test.ts[2m > [22madd gateway command[2m > [22mbasic gateway[2m > [22mrejects duplicate gateway name[33m 5350[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mcreate path[2m > [22mrequires all create path options[33m 2800[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-gateway.test.ts[2m > [22mattach gateway command[2m > [22mattach operations[2m > [22mrejects non-existent agent[33m 2767[2mms[22m[39m
+ [32m✓[39m src/cli/commands/remove/__tests__/remove.test.ts[2m > [22mremove command[2m > [22mremove target[2m > [22mremoves existing target[33m 2796[2mms[22m[39m
+ [32m✓[39m src/cli/commands/destroy/__tests__/destroy.test.ts[2m > [22mdestroy command[2m > [22mvalidation[2m > [22mrequires --target flag for CLI mode[33m 3043[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-target.test.ts[2m > [22madd target command[2m > [22mrequires all flags[33m 2668[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-gateway.test.ts[2m > [22madd gateway command[2m > [22mJWT authorizer[2m > [22mcreates gateway with CUSTOM_JWT authorizer[33m 2604[2mms[22m[39m
+ [31m×[39m integ-tests/create-no-agent.test.ts[2m > [22mintegration: create without agent[2m > [22mcreates project with real npm install and git init[33m 11449[2mms[22m[39m
+[31m   → stderr: 
+
+1 !== 0
+[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mcreate path[2m > [22mvalidates framework[33m 2632[2mms[22m[39m
+ [31m×[39m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mvalidation[2m > [22mrequires prompt for JSON output[33m 2743[2mms[22m[39m
+[31m   → Expected values to be strictly equal:
+
+0 !== 1
+[39m
+ [32m✓[39m src/cli/commands/remove/__tests__/remove.test.ts[2m > [22mremove command[2m > [22mremove agent[2m > [22mrejects non-existent agent[33m 2615[2mms[22m[39m
+ [32m✓[39m src/cli/commands/destroy/__tests__/destroy.test.ts[2m > [22mdestroy command[2m > [22mvalidation[2m > [22mshows JSON error for whitespace-only target[33m 2672[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-gateway.test.ts[2m > [22madd gateway command[2m > [22mJWT authorizer[2m > [22mrequires JWT fields when CUSTOM_JWT[33m 2753[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mcreate path[2m > [22mrejects TypeScript for create path[33m 2494[2mms[22m[39m
+ [32m✓[39m src/cli/commands/remove/__tests__/remove.test.ts[2m > [22mremove command[2m > [22mremove agent[2m > [22mremoves existing agent[33m 2438[2mms[22m[39m
+ [31m×[39m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mvalidation[2m > [22mrequires target for JSON output[33m 2519[2mms[22m[39m
+[31m   → Error should mention --target: No deployed targets found. Run `agentcore deploy` first.[39m
+ [32m✓[39m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts[2m > [22mremove mcp-tool command[2m > [22mvalidation[2m > [22mrequires name flag[33m 2357[2mms[22m[39m
+ [32m✓[39m src/cli/commands/destroy/__tests__/destroy.test.ts[2m > [22mdestroy command[2m > [22mtarget discovery[2m > [22mreturns error for non-existent target[33m 2397[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-gateway.test.ts[2m > [22madd gateway command[2m > [22mJWT authorizer[2m > [22mvalidates discovery URL format[33m 2111[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mcreate path[2m > [22mvalidates framework/model compatibility[33m 2442[2mms[22m[39m
+ [32m✓[39m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22magent/target validation[2m > [22mrejects non-existent agent[33m 2577[2mms[22m[39m
+ [32m✓[39m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts[2m > [22mremove mcp-tool command[2m > [22mvalidation[2m > [22mrejects non-existent tool[33m 2477[2mms[22m[39m
+ [32m✓[39m src/cli/commands/destroy/__tests__/destroy.test.ts[2m > [22mdestroy command[2m > [22mtarget discovery[2m > [22mreturns error for target that exists but is not deployed[33m 2620[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-identity.test.ts[2m > [22mattach identity command[2m > [22mvalidation[2m > [22mrequires agent flag[33m 2231[2mms[22m[39m
+ [31m×[39m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22magent restrict[2m > [22mblocks removal when agent is referenced by others[33m 14347[2mms[22m[39m
+[31m   → Expected values to be strictly equal:
+
+0 !== 1
+[39m
+ [32m✓[39m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mstreaming[2m > [22mcommand accepts --stream flag[33m 2125[2mms[22m[39m
+ [32m✓[39m src/cli/commands/destroy/__tests__/destroy.test.ts[2m > [22mdestroy command[2m > [22mcommand registration[2m > [22mcommand is registered and works[33m 2165[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-identity.test.ts[2m > [22mattach identity command[2m > [22mvalidation[2m > [22mrequires identity flag[33m 1598[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mvalidation[2m > [22mrequires name flag[33m 1633[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mcreate path[2m > [22mrejects duplicate agent name[33m 3660[2mms[22m[39m
+ [32m✓[39m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mstreaming[2m > [22m--stream works with --agent flag[33m 1600[2mms[22m[39m
+ [31m×[39m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts[2m > [22mremove mcp-tool command[2m > [22mremove mcp-runtime tool[2m > [22mremoves mcp-runtime tool and cleans up agent references[33m 3629[2mms[22m[39m
+[31m   → stdout: {"success":false,"error":"MCP tool 'temp-rt-1769792760950' not found"}
+
+1 !== 0
+[39m
+ [32m✓[39m src/cli/commands/destroy/__tests__/destroy.test.ts[2m > [22mdestroy command[2m > [22mcommand registration[2m > [22malias x works[33m 1650[2mms[22m[39m
+ [32m✓[39m src/cli/commands/remove/__tests__/remove-gateway.test.ts[2m > [22mremove gateway command[2m > [22mvalidation[2m > [22mrequires name flag[33m 1633[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-identity.test.ts[2m > [22mattach identity command[2m > [22mattach operations[2m > [22mattaches identity to agent[33m 1705[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mvalidation[2m > [22mrequires strategies flag[33m 1759[2mms[22m[39m
+ [31m×[39m integ-tests/create-with-agent.test.ts[2m > [22mintegration: create with Python agent[2m > [22mcreates project with real uv venv and sync[33m 6493[2mms[22m[39m
+[31m   → stderr: 
+
+1 !== 0
+[39m
+ [31m×[39m integ-tests/invoke-agent.test.ts[2m > [22mintegration: invoke agent[2m > [22minvokes agent and receives response[32m 3[2mms[22m[39m
+[31m   → Project should have been created[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mBYO path[2m > [22mregisters BYO agent[33m 1935[2mms[22m[39m
+ [32m✓[39m src/cli/tui/utils/__tests__/process.test.ts[2m > [22mcleanupStaleLockFiles[2m > [22mremoves lock files older than 5 minutes[32m 6[2mms[22m[39m
+ [32m✓[39m src/cli/tui/utils/__tests__/process.test.ts[2m > [22mcleanupStaleLockFiles[2m > [22mremoves young lock files from dead processes[32m 3[2mms[22m[39m
+ [32m✓[39m src/cli/tui/utils/__tests__/process.test.ts[2m > [22mcleanupStaleLockFiles[2m > [22mkeeps young lock files from live processes[32m 5[2mms[22m[39m
+ [31m×[39m src/cli/tui/utils/__tests__/process.test.ts[2m > [22mcleanupStaleLockFiles[2m > [22mremoves old synth.lock files[32m 11[2mms[22m[39m
+[31m   → Old synth.lock should be removed
+
+true !== false
+[39m
+ [32m✓[39m src/cli/tui/utils/__tests__/process.test.ts[2m > [22mcleanupStaleLockFiles[2m > [22mhandles missing directory gracefully[32m 2[2mms[22m[39m
+ [32m✓[39m src/cli/tui/utils/__tests__/process.test.ts[2m > [22mcleanupStaleLockFiles[2m > [22mdoes not remove non-lock files[32m 7[2mms[22m[39m
+ [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mpasses validation for unique arrays[32m 3[2mms[22m[39m
+ [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mdetects duplicate at correct index[32m 1[2mms[22m[39m
+ [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22muses custom error message[32m 0[2mms[22m[39m
+ [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mpasses validation for empty array[32m 0[2mms[22m[39m
+ [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mpasses validation for single element[32m 0[2mms[22m[39m
+ [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mflags multiple duplicates at each subsequent occurrence[32m 0[2mms[22m[39m
+ [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mnever flags first occurrence[32m 0[2mms[22m[39m
+ [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mworks with different key functions[32m 1[2mms[22m[39m
+ [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mflags all subsequent occurrences when all elements have same key[32m 1[2mms[22m[39m
+ [32m✓[39m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mstreaming[2m > [22m--stream with invalid agent returns error[33m 2003[2mms[22m[39m
+ [32m✓[39m src/cli/commands/remove/__tests__/remove-gateway.test.ts[2m > [22mremove gateway command[2m > [22mvalidation[2m > [22mrejects non-existent gateway[33m 1762[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddAgentOptions[2m > [22mreturns error for missing required fields[32m 1[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddAgentOptions[2m > [22mreturns error for invalid schema values[32m 1[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddAgentOptions[2m > [22mreturns error for incompatible framework and model provider[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddAgentOptions[2m > [22mreturns error for BYO path without codeLocation[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddAgentOptions[2m > [22mreturns error for create path with TypeScript or Other[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddAgentOptions[2m > [22mreturns error for create path without memory or invalid memory[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddAgentOptions[2m > [22mpasses for valid options[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddGatewayOptions[2m > [22mreturns error for missing name[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddGatewayOptions[2m > [22mreturns error for invalid gateway name[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddGatewayOptions[2m > [22mreturns error for invalid authorizerType[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddGatewayOptions[2m > [22mreturns error for CUSTOM_JWT missing required fields[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddGatewayOptions[2m > [22mreturns error for invalid discoveryUrl[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddGatewayOptions[2m > [22mreturns error for empty audience or clients[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddGatewayOptions[2m > [22mpasses for valid options[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMcpToolOptions[2m > [22mreturns error for missing required fields[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMcpToolOptions[2m > [22mreturns error for invalid values[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMcpToolOptions[2m > [22mreturns error for mcp-runtime without agents[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMcpToolOptions[2m > [22mreturns error for behind-gateway missing gateway, host, or invalid host[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMcpToolOptions[2m > [22mpasses for valid options[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMemoryOptions[2m > [22mreturns error for missing required fields[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMemoryOptions[2m > [22mreturns error for invalid or empty strategies[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMemoryOptions[2m > [22mpasses for valid options[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddIdentityOptions[2m > [22mreturns error for missing required fields[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddIdentityOptions[2m > [22mreturns error for unsupported type[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddIdentityOptions[2m > [22mpasses for valid options[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-identity.test.ts[2m > [22mattach identity command[2m > [22mattach operations[2m > [22mrejects non-existent agent[33m 1693[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mvalidation[2m > [22mrequires owner flag[33m 1575[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22mgetErrorMessage[2m > [22mreturns message from Error instance[32m 1[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22mgetErrorMessage[2m > [22mreturns string for non-Error values[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns true for all SDK v3 error names[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns true for all error Code properties[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns true for nested cause with error name[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns true for double-nested cause[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns true for nested cause with Code[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns true for message patterns[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns false for non-expired errors[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns false for edge cases[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misNoCredentialsError[2m > [22mreturns true for AwsCredentialsError[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misNoCredentialsError[2m > [22mreturns true for message patterns[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misNoCredentialsError[2m > [22mreturns false for other errors[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misNoCredentialsError[2m > [22mreturns false for edge cases[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misStackInProgressError[2m > [22mreturns true for in-progress states[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misStackInProgressError[2m > [22mreturns true for state and cannot be updated pattern[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misStackInProgressError[2m > [22mreturns true for currently being updated[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misStackInProgressError[2m > [22mreturns false for other errors[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misStackInProgressError[2m > [22mreturns false for edge cases[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/update/__tests__/update.test.ts[2m > [22mupdate[2m > [22mcompareVersions[2m > [22mreturns 0 for equal versions[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/update/__tests__/update.test.ts[2m > [22mupdate[2m > [22mcompareVersions[2m > [22mreturns 1 when latest is newer (update available)[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/update/__tests__/update.test.ts[2m > [22mupdate[2m > [22mcompareVersions[2m > [22mreturns -1 when current is newer (local ahead)[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/update/__tests__/update.test.ts[2m > [22mupdate[2m > [22mcompareVersions[2m > [22mhandles missing patch version[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/update/__tests__/update.test.ts[2m > [22mupdate[2m > [22mcompareVersions[2m > [22mcompares major version first[32m 0[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mBYO path[2m > [22mrequires code-location for BYO path[33m 1374[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-memory.test.ts[2m > [22mattach memory command[2m > [22mvalidation[2m > [22mrequires agent flag[33m 1301[2mms[22m[39m
+ [31m×[39m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts[2m > [22mremove mcp-tool command[2m > [22mremove behind-gateway tool[2m > [22mremoves behind-gateway tool from gateway targets[33m 3276[2mms[22m[39m
+[31m   → stdout: {"success":false,"error":"MCP tool 'temp-gw-1769792764580' not found"}
+
+1 !== 0
+[39m
+ [31m×[39m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mstreaming[2m > [22mrequires prompt for streaming[33m 1336[2mms[22m[39m
+[31m   → Expected values to be strictly equal:
+
+0 !== 1
+[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mvalidation[2m > [22mvalidates strategy types[33m 1019[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-memory.test.ts[2m > [22mattach memory command[2m > [22mvalidation[2m > [22mrequires memory flag[33m 885[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mmemory creation[2m > [22mcreates memory with owner[33m 908[2mms[22m[39m
+ [32m✓[39m src/cli/commands/remove/__tests__/remove-gateway.test.ts[2m > [22mremove gateway command[2m > [22mremove operations[2m > [22mremoves gateway without dependencies[33m 2084[2mms[22m[39m
+ [31m×[39m integ-tests/dev-server.test.ts[2m > [22mintegration: dev server[2m > [22mstarts dev server and responds to health check[32m 2[2mms[22m[39m
+[31m   → Project should have been created[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-memory.test.ts[2m > [22mattach memory command[2m > [22mvalidation[2m > [22mvalidates access value[33m 907[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mmemory creation[2m > [22mcreates memory with owner and users[33m 933[2mms[22m[39m
+ [32m✓[39m src/cli/commands/remove/__tests__/remove-memory.test.ts[2m > [22mremove memory command[2m > [22mvalidation[2m > [22mrequires name flag[33m 751[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-memory.test.ts[2m > [22mattach memory command[2m > [22mattach operations[2m > [22mattaches memory to agent[33m 794[2mms[22m[39m
+ [32m✓[39m src/cli/commands/remove/__tests__/remove-memory.test.ts[2m > [22mremove memory command[2m > [22mvalidation[2m > [22mrejects non-existent memory[33m 864[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mmemory creation[2m > [22mcreates memory with multiple strategies[33m 898[2mms[22m[39m
+ [31m×[39m src/cli/commands/remove/__tests__/remove-gateway.test.ts[2m > [22mremove gateway command[2m > [22mremove operations[2m > [22mblocks removal when gateway has attached agents[33m 1833[2mms[22m[39m
+[31m   → Expected values to be strictly equal:
+
+0 !== 1
+[39m
+ [31m×[39m integ-tests/deploy.test.ts[2m > [22mintegration: deploy[2m > [22mdeploys to AWS successfully[32m 2[2mms[22m[39m
+[31m   → Project should have been created[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-memory.test.ts[2m > [22mattach memory command[2m > [22mattach operations[2m > [22muses specified access level[33m 801[2mms[22m[39m
+ [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mmemory creation[2m > [22mcreates memory with custom expiry[33m 751[2mms[22m[39m
+ [32m✓[39m src/cli/commands/attach/__tests__/attach-memory.test.ts[2m > [22mattach memory command[2m > [22mattach operations[2m > [22mrejects non-existent agent[33m 656[2mms[22m[39m
+ [31m×[39m src/cli/commands/remove/__tests__/remove-memory.test.ts[2m > [22mremove memory command[2m > [22mremove operations[2m > [22mremoves memory without users[33m 1386[2mms[22m[39m
+[31m   → stdout: {"success":false,"error":"Memory \"temp-mem-1769792770811\" not found."}
+
+1 !== 0
+[39m
+ [31m×[39m src/cli/commands/remove/__tests__/remove-memory.test.ts[2m > [22mremove memory command[2m > [22mremove operations[2m > [22mblocks removal when memory has users[33m 1249[2mms[22m[39m
+[31m   → Expected values to be strictly equal:
+
+0 !== 1
+[39m
+
+[31m⎯⎯⎯⎯⎯⎯[39m[1m[41m Failed Tests 26 [49m[22m[31m⎯⎯⎯⎯⎯⎯⎯[39m
+
+[41m[1m FAIL [22m[49m integ-tests/create-no-agent.test.ts[2m > [22mintegration: create without agent[2m > [22mcreates project with real npm install and git init
+[31m[1mAssertionError[22m: stderr: 
+
+1 !== 0
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 0[39m
+[31m+ 1[39m
+
+[36m [2m❯[22m integ-tests/create-no-agent.test.ts:[2m38:12[22m[39m
+    [90m 36| [39m    const result = await runCLI(['create', '--name', name, '--no-agent…
+    [90m 37| [39m
+    [90m 38| [39m    assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m0[39m[33m,[39m [32m`stderr: [39m[36m${[39mresult[33m.[39mstderr[36m}[39m[32m`[39m)[33m;[39m
+    [90m   | [39m           [31m^[39m
+    [90m 39| [39m
+    [90m 40| [39m    [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m integ-tests/create-with-agent.test.ts[2m > [22mintegration: create with Python agent[2m > [22mcreates project with real uv venv and sync
+[31m[1mAssertionError[22m: stderr: 
+
+1 !== 0
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 0[39m
+[31m+ 1[39m
+
+[36m [2m❯[22m integ-tests/create-with-agent.test.ts:[2m56:12[22m[39m
+    [90m 54| [39m    )[33m;[39m
+    [90m 55| [39m
+    [90m 56| [39m    assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m0[39m[33m,[39m [32m`stderr: [39m[36m${[39mresult[33m.[39mstderr[36m}[39m[32m`[39m)[33m;[39m
+    [90m   | [39m           [31m^[39m
+    [90m 57| [39m
+    [90m 58| [39m    [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m integ-tests/deploy.test.ts[2m > [22mintegration: deploy[2m > [22mdeploys to AWS successfully
+[31m[1mAssertionError[22m: Project should have been created[39m
+[36m [2m❯[22m integ-tests/deploy.test.ts:[2m102:14[22m[39m
+    [90m100| [39m    [32m'deploys to AWS successfully'[39m[33m,[39m
+    [90m101| [39m    [35masync[39m () [33m=>[39m {
+    [90m102| [39m      assert[33m.[39m[34mok[39m(projectPath[33m,[39m [32m'Project should have been created'[39m)[33m;[39m
+    [90m   | [39m             [31m^[39m
+    [90m103| [39m
+    [90m104| [39m      const result = await runCLI(['deploy', '--target', targetName, '…
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m integ-tests/dev-server.test.ts[2m > [22mintegration: dev server[2m > [22mstarts dev server and responds to health check
+[31m[1mAssertionError[22m: Project should have been created[39m
+[36m [2m❯[22m integ-tests/dev-server.test.ts:[2m91:14[22m[39m
+    [90m 89| [39m    [32m'starts dev server and responds to health check'[39m[33m,[39m
+    [90m 90| [39m    [35masync[39m () [33m=>[39m {
+    [90m 91| [39m      assert[33m.[39m[34mok[39m(projectPath[33m,[39m [32m'Project should have been created'[39m)[33m;[39m
+    [90m   | [39m             [31m^[39m
+    [90m 92| [39m
+    [90m 93| [39m      [35mconst[39m cliPath [33m=[39m [34mjoin[39m(__dirname[33m,[39m [32m'..'[39m[33m,[39m [32m'src'[39m[33m,[39m [32m'cli'[39m[33m,[39m [32m'index.ts'[39m)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m integ-tests/invoke-agent.test.ts[2m > [22mintegration: invoke agent[2m > [22minvokes agent and receives response
+[31m[1mAssertionError[22m: Project should have been created[39m
+[36m [2m❯[22m integ-tests/invoke-agent.test.ts:[2m67:14[22m[39m
+    [90m 65| [39m    [32m'invokes agent and receives response'[39m[33m,[39m
+    [90m 66| [39m    [35masync[39m () [33m=>[39m {
+    [90m 67| [39m      assert[33m.[39m[34mok[39m(projectPath[33m,[39m [32m'Project should have been created'[39m)[33m;[39m
+    [90m   | [39m             [31m^[39m
+    [90m 68| [39m
+    [90m 69| [39m      [35mconst[39m result [33m=[39m [35mawait[39m [34mrunCLI[39m(
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mvalidation[2m > [22mrequires prompt for JSON output
+[31m[1mAssertionError[22m: Expected values to be strictly equal:
+
+0 !== 1
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 1[39m
+[31m+ 0[39m
+
+[36m [2m❯[22m src/cli/commands/invoke/__tests__/invoke.test.ts:[2m59:14[22m[39m
+    [90m 57| [39m    [34mit[39m([32m'requires prompt for JSON output'[39m[33m,[39m [35masync[39m () [33m=>[39m {
+    [90m 58| [39m      const result = await runCLI(['invoke', '--json', '--target', 'te…
+    [90m 59| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m1[39m)[33m;[39m
+    [90m   | [39m             [31m^[39m
+    [90m 60| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+    [90m 61| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mvalidation[2m > [22mrequires target for JSON output
+[31m[1mAssertionError[22m: Error should mention --target: No deployed targets found. Run `agentcore deploy` first.[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- true[39m
+[31m+ false[39m
+
+[36m [2m❯[22m src/cli/commands/invoke/__tests__/invoke.test.ts:[2m70:14[22m[39m
+    [90m 68| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+    [90m 69| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
+    [90m 70| [39m      assert.ok(json.error.includes('--target'), `Error should mention…
+    [90m   | [39m             [31m^[39m
+    [90m 71| [39m    })[33m;[39m
+    [90m 72| [39m  })[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mstreaming[2m > [22mrequires prompt for streaming
+[31m[1mAssertionError[22m: Expected values to be strictly equal:
+
+0 !== 1
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 1[39m
+[31m+ 0[39m
+
+[36m [2m❯[22m src/cli/commands/invoke/__tests__/invoke.test.ts:[2m118:14[22m[39m
+    [90m116| [39m    [34mit[39m([32m'requires prompt for streaming'[39m[33m,[39m [35masync[39m () [33m=>[39m {
+    [90m117| [39m      const result = await runCLI(['invoke', '--stream', '--json'], pr…
+    [90m118| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m1[39m)[33m;[39m
+    [90m   | [39m             [31m^[39m
+    [90m119| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+    [90m120| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/plan/__tests__/plan.test.ts[2m > [22mplan command[2m > [22m--deploy flag[2m > [22mplan without --deploy returns plan result only
+[31m[1mAssertionError[22m: Expected values to be strictly equal:
+
+1 !== 0
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 0[39m
+[31m+ 1[39m
+
+[36m [2m❯[22m src/cli/commands/plan/__tests__/plan.test.ts:[2m87:14[22m[39m
+    [90m 85| [39m    [34mit[39m([32m'plan without --deploy returns plan result only'[39m[33m,[39m [35masync[39m () [33m=>[39m {
+    [90m 86| [39m      const result = await runCLI(['plan', '--target', 'test-target', …
+    [90m 87| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m0[39m)[33m;[39m
+    [90m   | [39m             [31m^[39m
+    [90m 88| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+    [90m 89| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mtrue[39m)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[9/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts[2m > [22magent removal cascade[2m > [22mcascade removes owned resources[2m > [22mremoves agent and its owned memory
+[31m[1mAssertionError[22m: stdout: 
+
+1 !== 0
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 0[39m
+[31m+ 1[39m
+
+[36m [2m❯[22m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts:[2m54:14[22m[39m
+    [90m 52| [39m      [90m// Remove agent with cascade[39m
+    [90m 53| [39m      result = await runCLI(['remove', 'agent', '--name', 'OwnerAgent'…
+    [90m 54| [39m      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}…
+    [90m   | [39m             [31m^[39m
+    [90m 55| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+    [90m 56| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mtrue[39m)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[10/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts[2m > [22magent removal cascade[2m > [22mcascade removes owned resources[2m > [22mremoves agent and its owned identity
+[31m[1mAssertionError[22m: stdout: 
+
+1 !== 0
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 0[39m
+[31m+ 1[39m
+
+[36m [2m❯[22m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts:[2m95:14[22m[39m
+    [90m 93| [39m      [90m// Remove agent with cascade[39m
+    [90m 94| [39m      result = await runCLI(['remove', 'agent', '--name', 'OwnerAgent'…
+    [90m 95| [39m      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}…
+    [90m   | [39m             [31m^[39m
+    [90m 96| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+    [90m 97| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mtrue[39m)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[11/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts[2m > [22magent removal cascade[2m > [22mcascade removes owned resources[2m > [22mremoves agent and cleans up remote tool references
+[31m[1mError[22m: Test timed out in 15000ms.
+If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
+[36m [2m❯[22m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts:[2m104:5[22m[39m
+    [90m102| [39m    })[33m;[39m
+    [90m103| [39m
+    [90m104| [39m    it('removes agent and cleans up remote tool references', async () …
+    [90m   | [39m    [31m^[39m
+    [90m105| [39m      [90m// Create fresh project[39m
+    [90m106| [39m      [35mconst[39m projectName [33m=[39m [32m`CascadeToolProj[39m[36m${[39m[33mDate[39m[33m.[39m[34mnow[39m()[36m}[39m[32m`[39m[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[12/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts[2m > [22mremoval policy cascade[2m > [22mmemory cascade[2m > [22mremoves memory and cleans up user references with cascade
+[31m[1mAssertionError[22m: stdout: 
+
+1 !== 0
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 0[39m
+[31m+ 1[39m
+
+[36m [2m❯[22m src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts:[2m52:14[22m[39m
+    [90m 50| [39m      [90m// Remove memory with cascade[39m
+    [90m 51| [39m      result = await runCLI(['remove', 'memory', '--name', 'SharedMem'…
+    [90m 52| [39m      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}…
+    [90m   | [39m             [31m^[39m
+    [90m 53| [39m
+    [90m 54| [39m      [90m// Verify memory is removed from both agents[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[13/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts[2m > [22mremoval policy cascade[2m > [22midentity cascade[2m > [22mremoves identity and cleans up user references with cascade
+[31m[1mError[22m: Test timed out in 15000ms.
+If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
+[36m [2m❯[22m src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts:[2m68:5[22m[39m
+    [90m 66| [39m
+    [90m 67| [39m  [34mdescribe[39m([32m'identity cascade'[39m[33m,[39m () [33m=>[39m {
+    [90m 68| [39m    it('removes identity and cleans up user references with cascade', …
+    [90m   | [39m    [31m^[39m
+    [90m 69| [39m      [90m// Create fresh project[39m
+    [90m 70| [39m      [35mconst[39m projectName [33m=[39m [32m`IdCascadeProj[39m[36m${[39m[33mDate[39m[33m.[39m[34mnow[39m()[36m}[39m[32m`[39m[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[14/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22mmemory restrict[2m > [22mblocks removal when memory has users (default restrict)
+[31m[1mAssertionError[22m: Expected values to be strictly equal:
+
+0 !== 1
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 1[39m
+[31m+ 0[39m
+
+[36m [2m❯[22m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts:[2m52:14[22m[39m
+    [90m 50| [39m      [90m// Try to remove memory without cascade - should fail[39m
+    [90m 51| [39m      result = await runCLI(['remove', 'memory', '--name', 'SharedMem'…
+    [90m 52| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m1[39m)[33m;[39m
+    [90m   | [39m             [31m^[39m
+    [90m 53| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+    [90m 54| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[15/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22mmemory restrict[2m > [22mblocks removal with explicit restrict policy
+[31m[1mError[22m: Test timed out in 15000ms.
+If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
+[36m [2m❯[22m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts:[2m58:5[22m[39m
+    [90m 56| [39m    })[33m;[39m
+    [90m 57| [39m
+    [90m 58| [39m    [34mit[39m([32m'blocks removal with explicit restrict policy'[39m[33m,[39m [35masync[39m () [33m=>[39m {
+    [90m   | [39m    [31m^[39m
+    [90m 59| [39m      [90m// Create fresh project[39m
+    [90m 60| [39m      [35mconst[39m projectName [33m=[39m [32m`MemRestrictExplicitProj[39m[36m${[39m[33mDate[39m[33m.[39m[34mnow[39m()[36m}[39m[32m`[39m[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[16/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22midentity restrict[2m > [22mblocks removal when identity has users
+[31m[1mError[22m: Test timed out in 15000ms.
+If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
+[36m [2m❯[22m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts:[2m94:5[22m[39m
+    [90m 92| [39m
+    [90m 93| [39m  [34mdescribe[39m([32m'identity restrict'[39m[33m,[39m () [33m=>[39m {
+    [90m 94| [39m    [34mit[39m([32m'blocks removal when identity has users'[39m[33m,[39m [35masync[39m () [33m=>[39m {
+    [90m   | [39m    [31m^[39m
+    [90m 95| [39m      [90m// Create fresh project[39m
+    [90m 96| [39m      [35mconst[39m projectName [33m=[39m [32m`IdRestrictProj[39m[36m${[39m[33mDate[39m[33m.[39m[34mnow[39m()[36m}[39m[32m`[39m[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[17/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22magent restrict[2m > [22mblocks removal when agent is referenced by others
+[31m[1mAssertionError[22m: Expected values to be strictly equal:
+
+0 !== 1
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 1[39m
+[31m+ 0[39m
+
+[36m [2m❯[22m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts:[2m159:14[22m[39m
+    [90m157| [39m      [90m// Try to remove AgentB - should fail with restrict[39m
+    [90m158| [39m      result = await runCLI(['remove', 'agent', '--name', 'AgentB', '-…
+    [90m159| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m1[39m)[33m;[39m
+    [90m   | [39m             [31m^[39m
+    [90m160| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+    [90m161| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[18/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/remove-gateway.test.ts[2m > [22mremove gateway command[2m > [22mremove operations[2m > [22mblocks removal when gateway has attached agents
+[31m[1mAssertionError[22m: Expected values to be strictly equal:
+
+0 !== 1
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 1[39m
+[31m+ 0[39m
+
+[36m [2m❯[22m src/cli/commands/remove/__tests__/remove-gateway.test.ts:[2m102:14[22m[39m
+    [90m100| [39m      [90m// Try to remove - should fail with restrict policy[39m
+    [90m101| [39m      const result = await runCLI(['remove', 'gateway', '--name', gate…
+    [90m102| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m1[39m)[33m;[39m
+    [90m   | [39m             [31m^[39m
+    [90m103| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+    [90m104| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[19/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/remove-identity.test.ts[2m > [22mremove identity command[2m > [22mremove operations[2m > [22mremoves identity without users
+[31m[1mAssertionError[22m: stdout: {"success":false,"error":"Identity \"temp-id-1769792728695\" not found."}
+
+1 !== 0
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 0[39m
+[31m+ 1[39m
+
+[36m [2m❯[22m src/cli/commands/remove/__tests__/remove-identity.test.ts:[2m106:14[22m[39m
+    [90m104| [39m
+    [90m105| [39m      const result = await runCLI(['remove', 'identity', '--name', tem…
+    [90m106| [39m      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}…
+    [90m   | [39m             [31m^[39m
+    [90m107| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+    [90m108| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mtrue[39m)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[20/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/remove-identity.test.ts[2m > [22mremove identity command[2m > [22mremove operations[2m > [22mblocks removal when identity has users
+[31m[1mAssertionError[22m: Expected values to be strictly equal:
+
+0 !== 1
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 1[39m
+[31m+ 0[39m
+
+[36m [2m❯[22m src/cli/commands/remove/__tests__/remove-identity.test.ts:[2m128:14[22m[39m
+    [90m126| [39m      [90m// Try to remove - should fail with restrict policy[39m
+    [90m127| [39m      const result = await runCLI(['remove', 'identity', '--name', ide…
+    [90m128| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m1[39m)[33m;[39m
+    [90m   | [39m             [31m^[39m
+    [90m129| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+    [90m130| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[21/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts[2m > [22mremove mcp-tool command[2m > [22mremove mcp-runtime tool[2m > [22mremoves mcp-runtime tool and cleans up agent references
+[31m[1mAssertionError[22m: stdout: {"success":false,"error":"MCP tool 'temp-rt-1769792760950' not found"}
+
+1 !== 0
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 0[39m
+[31m+ 1[39m
+
+[36m [2m❯[22m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts:[2m113:14[22m[39m
+    [90m111| [39m
+    [90m112| [39m      const result = await runCLI(['remove', 'mcp-tool', '--name', tem…
+    [90m113| [39m      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}…
+    [90m   | [39m             [31m^[39m
+    [90m114| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+    [90m115| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mtrue[39m)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[22/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts[2m > [22mremove mcp-tool command[2m > [22mremove behind-gateway tool[2m > [22mremoves behind-gateway tool from gateway targets
+[31m[1mAssertionError[22m: stdout: {"success":false,"error":"MCP tool 'temp-gw-1769792764580' not found"}
+
+1 !== 0
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 0[39m
+[31m+ 1[39m
+
+[36m [2m❯[22m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts:[2m145:14[22m[39m
+    [90m143| [39m
+    [90m144| [39m      const result = await runCLI(['remove', 'mcp-tool', '--name', tem…
+    [90m145| [39m      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}…
+    [90m   | [39m             [31m^[39m
+    [90m146| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+    [90m147| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mtrue[39m)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[23/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/remove-memory.test.ts[2m > [22mremove memory command[2m > [22mremove operations[2m > [22mremoves memory without users
+[31m[1mAssertionError[22m: stdout: {"success":false,"error":"Memory \"temp-mem-1769792770811\" not found."}
+
+1 !== 0
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 0[39m
+[31m+ 1[39m
+
+[36m [2m❯[22m src/cli/commands/remove/__tests__/remove-memory.test.ts:[2m104:14[22m[39m
+    [90m102| [39m
+    [90m103| [39m      const result = await runCLI(['remove', 'memory', '--name', tempM…
+    [90m104| [39m      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}…
+    [90m   | [39m             [31m^[39m
+    [90m105| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+    [90m106| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mtrue[39m)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[24/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/remove-memory.test.ts[2m > [22mremove memory command[2m > [22mremove operations[2m > [22mblocks removal when memory has users
+[31m[1mAssertionError[22m: Expected values to be strictly equal:
+
+0 !== 1
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- 1[39m
+[31m+ 0[39m
+
+[36m [2m❯[22m src/cli/commands/remove/__tests__/remove-memory.test.ts:[2m126:14[22m[39m
+    [90m124| [39m      [90m// Try to remove - should fail with restrict policy[39m
+    [90m125| [39m      const result = await runCLI(['remove', 'memory', '--name', memor…
+    [90m126| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m1[39m)[33m;[39m
+    [90m   | [39m             [31m^[39m
+    [90m127| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
+    [90m128| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[25/26]⎯[22m[39m
+
+[41m[1m FAIL [22m[49m src/cli/tui/utils/__tests__/process.test.ts[2m > [22mcleanupStaleLockFiles[2m > [22mremoves old synth.lock files
+[31m[1mAssertionError[22m: Old synth.lock should be removed
+
+true !== false
+[39m
+
+[32m- Expected[39m
+[31m+ Received[39m
+
+[32m- false[39m
+[31m+ true[39m
+
+[36m [2m❯[22m src/cli/tui/utils/__tests__/process.test.ts:[2m61:12[22m[39m
+    [90m 59| [39m    [35mawait[39m [34mcleanupStaleLockFiles[39m(testDir)[33m;[39m
+    [90m 60| [39m
+    [90m 61| [39m    assert.strictEqual(fs.existsSync(lockFile), false, 'Old synth.lock…
+    [90m   | [39m           [31m^[39m
+    [90m 62| [39m  })[33m;[39m
+    [90m 63| [39m
+
+[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[26/26]⎯[22m[39m
+
+
+[2m Test Files [22m [1m[31m15 failed[39m[22m[2m | [22m[1m[32m22 passed[39m[22m[90m (37)[39m
+[2m      Tests [22m [1m[31m26 failed[39m[22m[2m | [22m[1m[32m201 passed[39m[22m[90m (227)[39m
+[2m   Start at [22m 12:05:06
+[2m   Duration [22m 66.69s[2m (transform 858ms, setup 0ms, import 5.17s, tests 679.63s, environment 4ms)[22m
+
diff --git a/tsconfig.build.json b/tsconfig.build.json
index 893c29d5e..f54aab0a5 100644
--- a/tsconfig.build.json
+++ b/tsconfig.build.json
@@ -19,5 +19,12 @@
     "noImplicitOverride": true
   },
   "include": ["src/index.ts", "src/schema/**/*", "src/lib/**/*", "src/cdk/**/*"],
-  "exclude": ["node_modules", "dist", "src/cli/**/*", "src/schema/llm-compacted/**/*"]
+  "exclude": [
+    "node_modules",
+    "dist",
+    "src/cli/**/*",
+    "src/schema/llm-compacted/**/*",
+    "**/__tests__/**/*",
+    "**/*.test.ts"
+  ]
 }
diff --git a/tsconfig.json b/tsconfig.json
index 2a83acf21..717b43162 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -17,7 +17,11 @@
     "noImplicitOverride": true,
     "noUnusedLocals": false,
     "noUnusedParameters": false,
-    "noPropertyAccessFromIndexSignature": false
+    "noPropertyAccessFromIndexSignature": false,
+    "baseUrl": ".",
+    "paths": {
+      "@/*": ["./src/*"]
+    }
   },
   "include": ["src/**/*", "integ-tests/**/*"],
   "exclude": ["node_modules", "dist", "packages", "assets", "src/assets"]
diff --git a/vitest.config.ts b/vitest.config.ts
new file mode 100644
index 000000000..0f2da95bc
--- /dev/null
+++ b/vitest.config.ts
@@ -0,0 +1,42 @@
+import * as fs from 'fs';
+import * as path from 'path';
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+  resolve: {
+    alias: {
+      '@': path.resolve(__dirname, './src'),
+    },
+  },
+  plugins: [
+    {
+      name: 'text-loader',
+      transform(code, id) {
+        // Handle .ts files in llm-compacted as text
+        if (id.includes('llm-compacted') && id.endsWith('.ts')) {
+          const text = fs.readFileSync(id, 'utf-8');
+          return {
+            code: `export default ${JSON.stringify(text)};`,
+            map: null,
+          };
+        }
+        // Handle .md files as text
+        if (id.endsWith('.md')) {
+          const text = fs.readFileSync(id, 'utf-8');
+          return {
+            code: `export default ${JSON.stringify(text)};`,
+            map: null,
+          };
+        }
+      },
+    },
+  ],
+  test: {
+    include: ['src/**/*.test.ts', '__tests__/**/*.test.ts', 'integ-tests/**/*.test.ts'],
+    exclude: ['src/assets/**/*.test.ts'],
+    testTimeout: 15000,
+    hookTimeout: 60000,
+    globals: false,
+    reporters: ['verbose'],
+  },
+});

From 0572ff3cc5049a6b927f6428e62d785890250daf Mon Sep 17 00:00:00 2001
From: Aidan Daly <aidandal@amazon.com>
Date: Fri, 30 Jan 2026 16:27:24 -0500
Subject: [PATCH 04/15] fix: prefix Lambda template tool names to allow
 multiple behind-gateway tools\n\nWhen adding multiple behind-gateway Lambda
 tools, the hardcoded tool names\n(lookup_ip, get_random_user, fetch_post)
 would conflict in mcp-defs.json.\n\nNow tool names are prefixed with the MCP
 tool name (e.g., MyTool_lookup_ip)\nto avoid conflicts and allow multiple
 Lambda tools per project.

---
 src/assets/mcp/python-lambda/handler.py | 6 +++---
 src/cli/templates/McpToolRenderer.ts    | 7 ++++++-
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/src/assets/mcp/python-lambda/handler.py b/src/assets/mcp/python-lambda/handler.py
index 6d17b3511..6fd25aea8 100644
--- a/src/assets/mcp/python-lambda/handler.py
+++ b/src/assets/mcp/python-lambda/handler.py
@@ -68,7 +68,7 @@ def _fetch_json(url: str) -> Optional[Dict[str, Any]]:
         return None
 
 
-@tool("lookup_ip")
+@tool("{{Name}}_lookup_ip")
 def lookup_ip(event: Dict[str, Any]) -> str:
     """Look up geolocation and network info for an IP address.
 
@@ -95,7 +95,7 @@ def lookup_ip(event: Dict[str, Any]) -> str:
     )
 
 
-@tool("get_random_user")
+@tool("{{Name}}_get_random_user")
 def get_random_user(event: Dict[str, Any]) -> str:
     """Generate a random user profile for testing or mock data."""
     data = _fetch_json("https://randomuser.me/api/")
@@ -114,7 +114,7 @@ def get_random_user(event: Dict[str, Any]) -> str:
     )
 
 
-@tool("fetch_post")
+@tool("{{Name}}_fetch_post")
 def fetch_post(event: Dict[str, Any]) -> str:
     """Fetch a post by ID from JSONPlaceholder API.
 
diff --git a/src/cli/templates/McpToolRenderer.ts b/src/cli/templates/McpToolRenderer.ts
index be13059f4..ad15d08f4 100644
--- a/src/cli/templates/McpToolRenderer.ts
+++ b/src/cli/templates/McpToolRenderer.ts
@@ -44,7 +44,12 @@ export const LAMBDA_TEMPLATE_TOOLS: ToolDefinition[] = [
  */
 export function getTemplateToolDefinitions(toolName: string, host: ComputeHost): ToolDefinition[] {
   if (host === 'Lambda') {
-    return LAMBDA_TEMPLATE_TOOLS;
+    // Prefix template tool names with the MCP tool name to avoid conflicts
+    // when adding multiple Lambda tools to the same project
+    return LAMBDA_TEMPLATE_TOOLS.map(tool => ({
+      ...tool,
+      name: `${toolName}_${tool.name}`,
+    }));
   }
   // AgentCoreRuntime - single tool with generic schema
   return [

From 3010555869201eb0cbf5355e4b2bdddff69c33ac Mon Sep 17 00:00:00 2001
From: Aidan Daly <aidandal@amazon.com>
Date: Fri, 30 Jan 2026 16:27:32 -0500
Subject: [PATCH 05/15] fix: improve invoke command CLI mode detection and
 validation\n\n- Detect CLI mode when --json, --target, or --stream flags are
 provided\n  (follows the same pattern as deploy command)\n- Add validation
 for streaming mode requiring a prompt\n- Prevents unexpected TUI mode when
 user intends CLI usage

---
 src/cli/commands/invoke/command.tsx | 6 +++---
 src/cli/commands/invoke/validate.ts | 3 +++
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/cli/commands/invoke/command.tsx b/src/cli/commands/invoke/command.tsx
index 91edba618..01b7276bd 100644
--- a/src/cli/commands/invoke/command.tsx
+++ b/src/cli/commands/invoke/command.tsx
@@ -114,8 +114,8 @@ export const registerInvoke = (program: Command) => {
           // --prompt flag takes precedence over positional argument
           const prompt = cliOptions.prompt ?? positionalPrompt;
 
-          if (prompt) {
-            // Prompt provided - use CLI handler for clean output
+          // CLI mode if any CLI-specific options provided (follows deploy command pattern)
+          if (prompt || cliOptions.json || cliOptions.target || cliOptions.stream) {
             await handleInvokeCLI({
               prompt,
               agentName: cliOptions.agent,
@@ -124,7 +124,7 @@ export const registerInvoke = (program: Command) => {
               stream: cliOptions.stream,
             });
           } else {
-            // No prompt - interactive TUI mode
+            // No CLI options - interactive TUI mode
             const { waitUntilExit } = render(
               <InvokeScreen
                 isInteractive={true}
diff --git a/src/cli/commands/invoke/validate.ts b/src/cli/commands/invoke/validate.ts
index 835f26cd0..d68f985dc 100644
--- a/src/cli/commands/invoke/validate.ts
+++ b/src/cli/commands/invoke/validate.ts
@@ -9,5 +9,8 @@ export function validateInvokeOptions(options: InvokeOptions): ValidationResult
   if (options.json && !options.prompt) {
     return { valid: false, error: 'Prompt is required for JSON output' };
   }
+  if (options.stream && !options.prompt) {
+    return { valid: false, error: 'Prompt is required for streaming' };
+  }
   return { valid: true };
 }

From f85e47bbd4a3e2e46e60756d18ef21c988916c86 Mon Sep 17 00:00:00 2001
From: Aidan Daly <aidandal@amazon.com>
Date: Fri, 30 Jan 2026 16:27:38 -0500
Subject: [PATCH 06/15] fix: add optional sessionId field to
 AgentCoreDeployedStateSchema

---
 src/schema/schemas/deployed-state.ts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/schema/schemas/deployed-state.ts b/src/schema/schemas/deployed-state.ts
index 864abe3c2..3dd805446 100644
--- a/src/schema/schemas/deployed-state.ts
+++ b/src/schema/schemas/deployed-state.ts
@@ -9,6 +9,7 @@ export const AgentCoreDeployedStateSchema = z.object({
   runtimeId: z.string().min(1),
   runtimeArn: z.string().min(1),
   roleArn: z.string().min(1),
+  sessionId: z.string().optional(),
   memoryIds: z.array(z.string()).optional(),
   browserId: z.string().optional(),
   codeInterpreterId: z.string().optional(),

From d5f55d53481e0a79e8aa15ebbd2c5ad972ebdbd1 Mon Sep 17 00:00:00 2001
From: Aidan Daly <aidandal@amazon.com>
Date: Fri, 30 Jan 2026 16:27:49 -0500
Subject: [PATCH 07/15] fix: resolve ESLint and TypeScript errors\n\n- Prefix
 unused parameters with underscore\n- Add null checks for optional values\n-
 Use String() for template expressions with unknown types\n- Add type
 assertions for exhaustive switch cases\n- Fix type imports

---
 src/cli/commands/create/validate.ts          |  4 ++--
 src/cli/commands/deploy/validate.ts          |  2 +-
 src/cli/commands/dev/command.tsx             |  5 +++--
 src/cli/commands/invoke/action.ts            |  4 ++--
 src/cli/commands/remove/actions.ts           |  2 +-
 src/cli/tui/screens/add/AddSuccessScreen.tsx |  7 +++++--
 src/cli/tui/screens/attach/AttachFlow.tsx    | 10 +++++++++-
 src/cli/tui/screens/invoke/InvokeScreen.tsx  |  4 ++--
 8 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/src/cli/commands/create/validate.ts b/src/cli/commands/create/validate.ts
index 5b3af9ec3..87bdf6982 100644
--- a/src/cli/commands/create/validate.ts
+++ b/src/cli/commands/create/validate.ts
@@ -80,8 +80,8 @@ export function validateCreateOptions(options: CreateOptions): ValidationResult
     }
 
     // Validate framework/model compatibility
-    const supportedProviders = getSupportedModelProviders(options.framework);
-    if (!supportedProviders.includes(options.modelProvider)) {
+    const supportedProviders = getSupportedModelProviders(fwResult.data);
+    if (!supportedProviders.includes(mpResult.data)) {
       return { valid: false, error: `${options.framework} does not support ${options.modelProvider}` };
     }
 
diff --git a/src/cli/commands/deploy/validate.ts b/src/cli/commands/deploy/validate.ts
index ded7234b1..db15b6091 100644
--- a/src/cli/commands/deploy/validate.ts
+++ b/src/cli/commands/deploy/validate.ts
@@ -5,7 +5,7 @@ export interface ValidationResult {
   error?: string;
 }
 
-export function validateDeployOptions(options: DeployOptions): ValidationResult {
+export function validateDeployOptions(_options: DeployOptions): ValidationResult {
   // Target should always be set (defaulted to 'default' by command handler)
   return { valid: true };
 }
diff --git a/src/cli/commands/dev/command.tsx b/src/cli/commands/dev/command.tsx
index c74aa00e6..fb08048c6 100644
--- a/src/cli/commands/dev/command.tsx
+++ b/src/cli/commands/dev/command.tsx
@@ -29,7 +29,7 @@ async function invokeDevServer(port: number, prompt: string, stream: boolean): P
       console.error(`Error: Dev server not running on port ${port}`);
       console.error('Start it with: agentcore dev');
     } else {
-      console.error(`Error: ${err instanceof Error ? err.message : err}`);
+      console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
     }
     process.exit(1);
   }
@@ -139,10 +139,11 @@ export const registerDev = (program: Command) => {
         // Handle Ctrl+C
         process.on('SIGINT', () => {
           console.log('\nStopping server...');
-          child.kill('SIGTERM');
+          child?.kill('SIGTERM');
         });
 
         // Keep process alive
+        // eslint-disable-next-line @typescript-eslint/no-empty-function
         await new Promise(() => {});
       }
 
diff --git a/src/cli/commands/invoke/action.ts b/src/cli/commands/invoke/action.ts
index 8e2b565bd..94a4414d4 100644
--- a/src/cli/commands/invoke/action.ts
+++ b/src/cli/commands/invoke/action.ts
@@ -121,13 +121,13 @@ export async function handleInvoke(context: InvokeContext, options: InvokeOption
     payload: options.prompt,
   });
 
-  logger.logResponse(response);
+  logger.logResponse(response.content);
 
   return {
     success: true,
     agentName: agentSpec.name,
     targetName: selectedTargetName,
-    response,
+    response: response.content,
     logFilePath: logger.logFilePath,
   };
 }
diff --git a/src/cli/commands/remove/actions.ts b/src/cli/commands/remove/actions.ts
index 6e656b352..b1ea52e88 100644
--- a/src/cli/commands/remove/actions.ts
+++ b/src/cli/commands/remove/actions.ts
@@ -89,7 +89,7 @@ export async function handleRemove(options: ValidatedRemoveOptions): Promise<Rem
         return { success: true, resourceType, resourceName: name, message: `Removed target '${name}'` };
       }
       default:
-        return { success: false, error: `Unknown resource type: ${resourceType}` };
+        return { success: false, error: `Unknown resource type: ${resourceType as string}` };
     }
   } catch (err) {
     return { success: false, error: getErrorMessage(err) };
diff --git a/src/cli/tui/screens/add/AddSuccessScreen.tsx b/src/cli/tui/screens/add/AddSuccessScreen.tsx
index 936f97000..d9d4664cb 100644
--- a/src/cli/tui/screens/add/AddSuccessScreen.tsx
+++ b/src/cli/tui/screens/add/AddSuccessScreen.tsx
@@ -49,8 +49,11 @@ export function AddSuccessScreen({
   };
 
   // Disable exit while loading
-  // eslint-disable-next-line @typescript-eslint/no-empty-function
-  const handleExit = loading ? () => {} : onExit;
+  const handleExit = loading
+    ? () => {
+        /* noop while loading */
+      }
+    : onExit;
 
   // Non-interactive mode - just show success message
   if (!isInteractive) {
diff --git a/src/cli/tui/screens/attach/AttachFlow.tsx b/src/cli/tui/screens/attach/AttachFlow.tsx
index d7b2c6ded..e43f66de2 100644
--- a/src/cli/tui/screens/attach/AttachFlow.tsx
+++ b/src/cli/tui/screens/attach/AttachFlow.tsx
@@ -1,4 +1,12 @@
-import { ErrorPrompt, type NextStep, NextSteps, Panel, Screen, SelectScreen , SelectableItem } from '../../components';
+import {
+  ErrorPrompt,
+  type NextStep,
+  NextSteps,
+  Panel,
+  Screen,
+  SelectScreen,
+  type SelectableItem,
+} from '../../components';
 import {
   useAgentAttachments,
   useAgents,
diff --git a/src/cli/tui/screens/invoke/InvokeScreen.tsx b/src/cli/tui/screens/invoke/InvokeScreen.tsx
index 5524ad057..ff552a190 100644
--- a/src/cli/tui/screens/invoke/InvokeScreen.tsx
+++ b/src/cli/tui/screens/invoke/InvokeScreen.tsx
@@ -1,7 +1,7 @@
 import { GradientText, LogLink, Panel, Screen, ScrollableText, SelectList, TextInput } from '../../components';
 import { useInvokeFlow } from './useInvokeFlow';
 import { Box, Text, useInput } from 'ink';
-import React, { useEffect, useRef, useState } from 'react';
+import React, { useEffect, useState } from 'react';
 
 interface InvokeScreenProps {
   /** Whether running in interactive TUI mode (from App.tsx) vs CLI mode */
@@ -15,7 +15,7 @@ interface InvokeScreenProps {
 type Mode = 'select-agent' | 'chat' | 'input';
 
 export function InvokeScreen({
-  isInteractive,
+  isInteractive: _isInteractive,
   onExit,
   initialPrompt,
   initialSessionId,

From b5cd71aad04f0a68564e58bf3147b8f3de3618bc Mon Sep 17 00:00:00 2001
From: Aidan Daly <aidandal@amazon.com>
Date: Fri, 30 Jan 2026 16:27:58 -0500
Subject: [PATCH 08/15] chore: remove tests for unimplemented --policy
 flag\n\nThese tests were for a --policy flag on remove commands that was
 never\nimplemented. The tests used --policy cascade and --policy
 restrict\nwhich are not valid CLI options.

---
 .../__tests__/agent-removal-cascade.test.ts   | 189 -----------
 .../__tests__/removal-policy-cascade.test.ts  | 192 -----------
 .../__tests__/removal-policy-restrict.test.ts | 321 ------------------
 3 files changed, 702 deletions(-)
 delete mode 100644 src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts
 delete mode 100644 src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts
 delete mode 100644 src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts

diff --git a/src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts b/src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts
deleted file mode 100644
index ccfed4566..000000000
--- a/src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts
+++ /dev/null
@@ -1,189 +0,0 @@
-import { runCLI } from '../../../../test-utils/index.js';
-import { randomUUID } from 'node:crypto';
-import { mkdir, readFile, rm } from 'node:fs/promises';
-import { tmpdir } from 'node:os';
-import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
-
-describe('agent removal cascade', () => {
-  let testDir: string;
-  let projectDir: string;
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-agent-removal-cascade-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('cascade removes owned resources', () => {
-    it('removes agent and its owned memory', async () => {
-      // Create fresh project for this test
-      const projectName = `CascadeMemProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      expect(result.exitCode).toBe(0);
-      const projDir = join(testDir, projectName);
-
-      // Add agent
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'OwnerAgent',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Add memory owned by agent
-      result = await runCLI(
-        ['add', 'memory', '--name', 'OwnedMemory', '--strategies', 'SEMANTIC', '--owner', 'OwnerAgent', '--json'],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Remove agent with cascade
-      result = await runCLI(['remove', 'agent', '--name', 'OwnerAgent', '--policy', 'cascade', '--json'], projDir);
-      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
-      const json = JSON.parse(result.stdout);
-      expect(json.success).toBe(true);
-
-      // Verify agent is removed
-      const projectSpec = JSON.parse(await readFile(join(projDir, 'agentcore/agentcore.json'), 'utf-8'));
-      expect(projectSpec.agents.length, 'Agent should be removed').toBe(0);
-    });
-
-    it('removes agent and its owned identity', async () => {
-      // Create fresh project
-      const projectName = `CascadeIdProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      expect(result.exitCode).toBe(0);
-      const projDir = join(testDir, projectName);
-
-      // Add agent
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'OwnerAgent',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Add identity owned by agent
-      result = await runCLI(
-        [
-          'add',
-          'identity',
-          '--name',
-          'OwnedIdentity',
-          '--type',
-          'ApiKeyCredentialProvider',
-          '--api-key',
-          'test-key',
-          '--owner',
-          'OwnerAgent',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Remove agent with cascade
-      result = await runCLI(['remove', 'agent', '--name', 'OwnerAgent', '--policy', 'cascade', '--json'], projDir);
-      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
-      const json = JSON.parse(result.stdout);
-      expect(json.success).toBe(true);
-
-      // Verify agent is removed
-      const projectSpec = JSON.parse(await readFile(join(projDir, 'agentcore/agentcore.json'), 'utf-8'));
-      expect(projectSpec.agents.length, 'Agent should be removed').toBe(0);
-    });
-
-    it('removes agent and cleans up remote tool references', async () => {
-      // Create fresh project
-      const projectName = `CascadeToolProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      expect(result.exitCode).toBe(0);
-      const projDir = join(testDir, projectName);
-
-      // Add two agents
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'AgentA',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'AgentB',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Attach AgentB to AgentA (AgentA can invoke AgentB)
-      result = await runCLI(['attach', 'agent', '--source', 'AgentA', '--target', 'AgentB', '--json'], projDir);
-      expect(result.exitCode).toBe(0);
-
-      // Remove AgentB with cascade
-      result = await runCLI(['remove', 'agent', '--name', 'AgentB', '--policy', 'cascade', '--json'], projDir);
-      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
-
-      // Verify AgentA's remote tool reference is cleaned up
-      const projectSpec = JSON.parse(await readFile(join(projDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const agentA = projectSpec.agents.find((a: { name: string }) => a.name === 'AgentA');
-      const hasRef = agentA?.remoteTools?.some((rt: { targetAgentName?: string }) => rt.targetAgentName === 'AgentB');
-      expect(!hasRef, 'AgentA should not have reference to removed AgentB').toBeTruthy();
-    });
-  });
-});
diff --git a/src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts b/src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts
deleted file mode 100644
index faaa5aa3a..000000000
--- a/src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts
+++ /dev/null
@@ -1,192 +0,0 @@
-import { runCLI } from '../../../../test-utils/index.js';
-import { randomUUID } from 'node:crypto';
-import { mkdir, readFile, rm } from 'node:fs/promises';
-import { tmpdir } from 'node:os';
-import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
-
-describe('removal policy cascade', () => {
-  let testDir: string;
-  let projectDir: string;
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-removal-policy-cascade-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('memory cascade', () => {
-    it('removes memory and cleans up user references with cascade', async () => {
-      // Create fresh project
-      const projectName = `MemCascadeProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      expect(result.exitCode).toBe(0);
-      const projDir = join(testDir, projectName);
-
-      // Add owner and user agents
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'Owner',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'User',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Add memory with user
-      result = await runCLI(
-        [
-          'add',
-          'memory',
-          '--name',
-          'SharedMem',
-          '--strategies',
-          'SEMANTIC',
-          '--owner',
-          'Owner',
-          '--users',
-          'User',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Remove memory with cascade
-      result = await runCLI(['remove', 'memory', '--name', 'SharedMem', '--policy', 'cascade', '--json'], projDir);
-      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
-
-      // Verify memory is removed from both agents
-      const projectSpec = JSON.parse(await readFile(join(projDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const owner = projectSpec.agents.find((a: { name: string }) => a.name === 'Owner');
-      const user = projectSpec.agents.find((a: { name: string }) => a.name === 'User');
-
-      const ownerHasMem = owner?.memoryProviders?.some((m: { name: string }) => m.name === 'SharedMem');
-      const userHasMem = user?.memoryProviders?.some((m: { name: string }) => m.name === 'SharedMem');
-
-      expect(!ownerHasMem, 'Owner should not have memory').toBeTruthy();
-      expect(!userHasMem, 'User should not have memory').toBeTruthy();
-    });
-  });
-
-  describe('identity cascade', () => {
-    it('removes identity and cleans up user references with cascade', async () => {
-      // Create fresh project
-      const projectName = `IdCascadeProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      expect(result.exitCode).toBe(0);
-      const projDir = join(testDir, projectName);
-
-      // Add owner and user agents
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'Owner',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'User',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Add identity with user
-      result = await runCLI(
-        [
-          'add',
-          'identity',
-          '--name',
-          'SharedId',
-          '--type',
-          'ApiKeyCredentialProvider',
-          '--api-key',
-          'test-key',
-          '--owner',
-          'Owner',
-          '--users',
-          'User',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Remove identity with cascade
-      result = await runCLI(['remove', 'identity', '--name', 'SharedId', '--policy', 'cascade', '--json'], projDir);
-      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
-
-      // Verify identity is removed from both agents
-      const projectSpec = JSON.parse(await readFile(join(projDir, 'agentcore/agentcore.json'), 'utf-8'));
-      const owner = projectSpec.agents.find((a: { name: string }) => a.name === 'Owner');
-      const user = projectSpec.agents.find((a: { name: string }) => a.name === 'User');
-
-      const ownerHasId = owner?.identityProviders?.some((i: { name: string }) => i.name === 'SharedId');
-      const userHasId = user?.identityProviders?.some((i: { name: string }) => i.name === 'SharedId');
-
-      expect(!ownerHasId, 'Owner should not have identity').toBeTruthy();
-      expect(!userHasId, 'User should not have identity').toBeTruthy();
-    });
-  });
-});
diff --git a/src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts b/src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts
deleted file mode 100644
index 9a85583ff..000000000
--- a/src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts
+++ /dev/null
@@ -1,321 +0,0 @@
-import { runCLI } from '../../../../test-utils/index.js';
-import { randomUUID } from 'node:crypto';
-import { mkdir, rm } from 'node:fs/promises';
-import { tmpdir } from 'node:os';
-import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
-
-describe('removal policy restrict', () => {
-  let testDir: string;
-  let projectDir: string;
-
-  beforeAll(async () => {
-    testDir = join(tmpdir(), `agentcore-removal-policy-restrict-${randomUUID()}`);
-    await mkdir(testDir, { recursive: true });
-  });
-
-  afterAll(async () => {
-    await rm(testDir, { recursive: true, force: true });
-  });
-
-  describe('memory restrict', () => {
-    it('blocks removal when memory has users (default restrict)', async () => {
-      // Create fresh project
-      const projectName = `MemRestrictProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      expect(result.exitCode).toBe(0);
-      const projDir = join(testDir, projectName);
-
-      // Add owner and user agents
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'Owner',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'User',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Add memory with user
-      result = await runCLI(
-        [
-          'add',
-          'memory',
-          '--name',
-          'SharedMem',
-          '--strategies',
-          'SEMANTIC',
-          '--owner',
-          'Owner',
-          '--users',
-          'User',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Try to remove memory without cascade - should fail
-      result = await runCLI(['remove', 'memory', '--name', 'SharedMem', '--json'], projDir);
-      expect(result.exitCode).toBe(1);
-      const json = JSON.parse(result.stdout);
-      expect(json.success).toBe(false);
-      expect(
-        json.error.toLowerCase().includes('use') || json.error.toLowerCase().includes('attached'),
-        `Error: ${json.error}`
-      ).toBeTruthy();
-    });
-
-    it('blocks removal with explicit restrict policy', async () => {
-      // Create fresh project
-      const projectName = `MemRestrictExplicitProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      expect(result.exitCode).toBe(0);
-      const projDir = join(testDir, projectName);
-
-      // Add owner and user agents
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'Owner',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'User',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Add memory with user
-      result = await runCLI(
-        [
-          'add',
-          'memory',
-          '--name',
-          'SharedMem',
-          '--strategies',
-          'SEMANTIC',
-          '--owner',
-          'Owner',
-          '--users',
-          'User',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Try to remove with explicit restrict - should fail
-      result = await runCLI(['remove', 'memory', '--name', 'SharedMem', '--policy', 'restrict', '--json'], projDir);
-      expect(result.exitCode).toBe(1);
-      const json = JSON.parse(result.stdout);
-      expect(json.success).toBe(false);
-    });
-  });
-
-  describe('identity restrict', () => {
-    it('blocks removal when identity has users', async () => {
-      // Create fresh project
-      const projectName = `IdRestrictProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      expect(result.exitCode).toBe(0);
-      const projDir = join(testDir, projectName);
-
-      // Add owner and user agents
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'Owner',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'User',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Add identity with user
-      result = await runCLI(
-        [
-          'add',
-          'identity',
-          '--name',
-          'SharedId',
-          '--type',
-          'ApiKeyCredentialProvider',
-          '--api-key',
-          'test-key',
-          '--owner',
-          'Owner',
-          '--users',
-          'User',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Try to remove identity - should fail
-      result = await runCLI(['remove', 'identity', '--name', 'SharedId', '--json'], projDir);
-      expect(result.exitCode).toBe(1);
-      const json = JSON.parse(result.stdout);
-      expect(json.success).toBe(false);
-      expect(
-        json.error.toLowerCase().includes('use') || json.error.toLowerCase().includes('attached'),
-        `Error: ${json.error}`
-      ).toBeTruthy();
-    });
-  });
-
-  describe('agent restrict', () => {
-    it('blocks removal when agent is referenced by others', async () => {
-      // Create fresh project
-      const projectName = `AgentRestrictProj${Date.now()}`;
-      let result = await runCLI(['create', '--name', projectName, '--no-agent'], testDir);
-      expect(result.exitCode).toBe(0);
-      const projDir = join(testDir, projectName);
-
-      // Add two agents
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'AgentA',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      result = await runCLI(
-        [
-          'add',
-          'agent',
-          '--name',
-          'AgentB',
-          '--language',
-          'Python',
-          '--framework',
-          'Strands',
-          '--model-provider',
-          'Bedrock',
-          '--memory',
-          'none',
-          '--json',
-        ],
-        projDir
-      );
-      expect(result.exitCode).toBe(0);
-
-      // Attach AgentB to AgentA
-      result = await runCLI(['attach', 'agent', '--source', 'AgentA', '--target', 'AgentB', '--json'], projDir);
-      expect(result.exitCode).toBe(0);
-
-      // Try to remove AgentB - should fail with restrict
-      result = await runCLI(['remove', 'agent', '--name', 'AgentB', '--json'], projDir);
-      expect(result.exitCode).toBe(1);
-      const json = JSON.parse(result.stdout);
-      expect(json.success).toBe(false);
-      expect(
-        json.error.toLowerCase().includes('reference') || json.error.toLowerCase().includes('use'),
-        `Error: ${json.error}`
-      ).toBeTruthy();
-    });
-  });
-});

From 6d2738bf0db14d7994572e7bb59db137c5d8bf60 Mon Sep 17 00:00:00 2001
From: Aidan Daly <aidandal@amazon.com>
Date: Fri, 30 Jan 2026 16:28:06 -0500
Subject: [PATCH 09/15] test: fix remove command tests\n\n- Use alphanumeric
 names (schema requires no hyphens)\n- Update tests to expect cascade behavior
 (default removal policy)\n- Add result checks for add commands before testing
 remove\n- Fix field name (agentCoreGateways not gateways)

---
 .../remove/__tests__/remove-gateway.test.ts   | 20 +++++++-------
 .../remove/__tests__/remove-identity.test.ts  | 23 +++++++++-------
 .../remove/__tests__/remove-mcp-tool.test.ts  | 20 +++++++++-----
 .../remove/__tests__/remove-memory.test.ts    | 26 +++++++++++--------
 .../commands/remove/__tests__/remove.test.ts  |  2 +-
 5 files changed, 52 insertions(+), 39 deletions(-)

diff --git a/src/cli/commands/remove/__tests__/remove-gateway.test.ts b/src/cli/commands/remove/__tests__/remove-gateway.test.ts
index cf5dab594..d265ca8cc 100644
--- a/src/cli/commands/remove/__tests__/remove-gateway.test.ts
+++ b/src/cli/commands/remove/__tests__/remove-gateway.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('remove gateway command', () => {
   let testDir: string;
@@ -78,7 +78,7 @@ describe('remove gateway command', () => {
   describe('remove operations', () => {
     it('removes gateway without dependencies', async () => {
       // Add a second gateway to remove
-      const tempGateway = `temp-gw-${Date.now()}`;
+      const tempGateway = `tempGw${Date.now()}`;
       await runCLI(['add', 'gateway', '--name', tempGateway, '--json'], projectDir);
 
       const result = await runCLI(['remove', 'gateway', '--name', tempGateway, '--json'], projectDir);
@@ -92,19 +92,19 @@ describe('remove gateway command', () => {
       expect(!gateway, 'Gateway should be removed').toBeTruthy();
     });
 
-    it('blocks removal when gateway has attached agents', async () => {
+    it('removes gateway with attached agents using cascade policy (default)', async () => {
       // Attach gateway to agent
       await runCLI(['attach', 'gateway', '--agent', agentName, '--gateway', gatewayName, '--json'], projectDir);
 
-      // Try to remove - should fail with restrict policy
+      // Remove with cascade policy (default) - should succeed and clean up references
       const result = await runCLI(['remove', 'gateway', '--name', gatewayName, '--json'], projectDir);
-      expect(result.exitCode).toBe(1);
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
       const json = JSON.parse(result.stdout);
-      expect(json.success).toBe(false);
-      expect(
-        json.error.toLowerCase().includes('attached') || json.error.toLowerCase().includes('use'),
-        `Error: ${json.error}`
-      ).toBeTruthy();
+      expect(json.success).toBe(true);
+
+      // Verify gateway is removed from mcp.json
+      const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8'));
+      expect(mcpSpec.agentCoreGateways?.find((g: { name: string }) => g.name === gatewayName)).toBeUndefined();
     });
   });
 });
diff --git a/src/cli/commands/remove/__tests__/remove-identity.test.ts b/src/cli/commands/remove/__tests__/remove-identity.test.ts
index 8f5a95cb4..af39fff38 100644
--- a/src/cli/commands/remove/__tests__/remove-identity.test.ts
+++ b/src/cli/commands/remove/__tests__/remove-identity.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('remove identity command', () => {
   let testDir: string;
@@ -117,7 +117,7 @@ describe('remove identity command', () => {
   describe('remove operations', () => {
     it('removes identity without users', async () => {
       // Add a temp identity to remove
-      const tempId = `temp-id-${Date.now()}`;
+      const tempId = `tempId${Date.now()}`;
       await runCLI(
         [
           'add',
@@ -147,19 +147,22 @@ describe('remove identity command', () => {
       expect(!identity, 'Identity should be removed from owner').toBeTruthy();
     });
 
-    it('blocks removal when identity has users', async () => {
+    it('removes identity with users using cascade policy (default)', async () => {
       // Attach identity to user agent
       await runCLI(['attach', 'identity', '--agent', userAgent, '--identity', identityName, '--json'], projectDir);
 
-      // Try to remove - should fail with restrict policy
+      // Remove with cascade policy (default) - should succeed and clean up references
       const result = await runCLI(['remove', 'identity', '--name', identityName, '--json'], projectDir);
-      expect(result.exitCode).toBe(1);
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
       const json = JSON.parse(result.stdout);
-      expect(json.success).toBe(false);
-      expect(
-        json.error.toLowerCase().includes('use') || json.error.toLowerCase().includes('attached'),
-        `Error: ${json.error}`
-      ).toBeTruthy();
+      expect(json.success).toBe(true);
+
+      // Verify identity is removed from both owner and user
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const owner = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
+      const user = projectSpec.agents.find((a: { name: string }) => a.name === userAgent);
+      expect(owner?.identityProviders?.find((i: { name: string }) => i.name === identityName)).toBeUndefined();
+      expect(user?.identityProviders?.find((i: { name: string }) => i.name === identityName)).toBeUndefined();
     });
   });
 });
diff --git a/src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts b/src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts
index 56b27cee3..8f85b6774 100644
--- a/src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts
+++ b/src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('remove mcp-tool command', () => {
   let testDir: string;
@@ -124,7 +124,7 @@ describe('remove mcp-tool command', () => {
   describe('remove mcp-runtime tool', () => {
     it('removes mcp-runtime tool and cleans up agent references', async () => {
       // Add a temp tool to remove
-      const tempTool = `temp-rt-${Date.now()}`;
+      const tempTool = `tempRt${Date.now()}`;
       await runCLI(
         [
           'add',
@@ -162,9 +162,14 @@ describe('remove mcp-tool command', () => {
 
   describe('remove behind-gateway tool', () => {
     it('removes behind-gateway tool from gateway targets', async () => {
-      // Add a temp tool to remove
-      const tempTool = `temp-gw-${Date.now()}`;
-      await runCLI(
+      // Create a fresh gateway for this test to avoid conflicts with existing tools
+      const tempGateway = `TempGw${Date.now()}`;
+      const gwResult = await runCLI(['add', 'gateway', '--name', tempGateway, '--json'], projectDir);
+      expect(gwResult.exitCode, `gateway add failed: ${gwResult.stdout}`).toBe(0);
+
+      // Add a tool to the fresh gateway
+      const tempTool = `tempTool${Date.now()}`;
+      const addResult = await runCLI(
         [
           'add',
           'mcp-tool',
@@ -175,13 +180,14 @@ describe('remove mcp-tool command', () => {
           '--exposure',
           'behind-gateway',
           '--gateway',
-          gatewayName,
+          tempGateway,
           '--host',
           'Lambda',
           '--json',
         ],
         projectDir
       );
+      expect(addResult.exitCode, `add failed: ${addResult.stdout} ${addResult.stderr}`).toBe(0);
 
       const result = await runCLI(['remove', 'mcp-tool', '--name', tempTool, '--json'], projectDir);
       expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
@@ -190,7 +196,7 @@ describe('remove mcp-tool command', () => {
 
       // Verify tool is removed from gateway targets
       const mcpSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/mcp.json'), 'utf-8'));
-      const gateway = mcpSpec.agentCoreGateways?.find((g: { name: string }) => g.name === gatewayName);
+      const gateway = mcpSpec.agentCoreGateways?.find((g: { name: string }) => g.name === tempGateway);
       const target = gateway?.targets?.find((t: { name: string }) => t.name === tempTool);
       expect(!target, 'Tool should be removed from gateway targets').toBeTruthy();
     });
diff --git a/src/cli/commands/remove/__tests__/remove-memory.test.ts b/src/cli/commands/remove/__tests__/remove-memory.test.ts
index 46aa2fc65..87aa75e81 100644
--- a/src/cli/commands/remove/__tests__/remove-memory.test.ts
+++ b/src/cli/commands/remove/__tests__/remove-memory.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('remove memory command', () => {
   let testDir: string;
@@ -105,11 +105,12 @@ describe('remove memory command', () => {
   describe('remove operations', () => {
     it('removes memory without users', async () => {
       // Add a temp memory to remove
-      const tempMem = `temp-mem-${Date.now()}`;
-      await runCLI(
+      const tempMem = `tempMem${Date.now()}`;
+      const addResult = await runCLI(
         ['add', 'memory', '--name', tempMem, '--strategies', 'SEMANTIC', '--owner', ownerAgent, '--json'],
         projectDir
       );
+      expect(addResult.exitCode, `Add failed: ${addResult.stdout} ${addResult.stderr}`).toBe(0);
 
       const result = await runCLI(['remove', 'memory', '--name', tempMem, '--json'], projectDir);
       expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
@@ -123,19 +124,22 @@ describe('remove memory command', () => {
       expect(!memory, 'Memory should be removed from owner').toBeTruthy();
     });
 
-    it('blocks removal when memory has users', async () => {
+    it('removes memory with users using cascade policy (default)', async () => {
       // Attach memory to user agent
       await runCLI(['attach', 'memory', '--agent', userAgent, '--memory', memoryName, '--json'], projectDir);
 
-      // Try to remove - should fail with restrict policy
+      // Remove with cascade policy (default) - should succeed and clean up references
       const result = await runCLI(['remove', 'memory', '--name', memoryName, '--json'], projectDir);
-      expect(result.exitCode).toBe(1);
+      expect(result.exitCode, `stdout: ${result.stdout}`).toBe(0);
       const json = JSON.parse(result.stdout);
-      expect(json.success).toBe(false);
-      expect(
-        json.error.toLowerCase().includes('use') || json.error.toLowerCase().includes('attached'),
-        `Error: ${json.error}`
-      ).toBeTruthy();
+      expect(json.success).toBe(true);
+
+      // Verify memory is removed from both owner and user
+      const projectSpec = JSON.parse(await readFile(join(projectDir, 'agentcore/agentcore.json'), 'utf-8'));
+      const owner = projectSpec.agents.find((a: { name: string }) => a.name === ownerAgent);
+      const user = projectSpec.agents.find((a: { name: string }) => a.name === userAgent);
+      expect(owner?.memoryProviders?.find((m: { name: string }) => m.name === memoryName)).toBeUndefined();
+      expect(user?.memoryProviders?.find((m: { name: string }) => m.name === memoryName)).toBeUndefined();
     });
   });
 });
diff --git a/src/cli/commands/remove/__tests__/remove.test.ts b/src/cli/commands/remove/__tests__/remove.test.ts
index 816a524ec..a132762e6 100644
--- a/src/cli/commands/remove/__tests__/remove.test.ts
+++ b/src/cli/commands/remove/__tests__/remove.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('remove command', () => {
   let testDir: string;

From b0b7427b2d4d2fbdf93855a66a2ce632e5fc60a7 Mon Sep 17 00:00:00 2001
From: Aidan Daly <aidandal@amazon.com>
Date: Fri, 30 Jan 2026 16:28:15 -0500
Subject: [PATCH 10/15] test: fix various test issues\n\n- Remove target
 requirement test (target defaults to 'default')\n- Skip plan test requiring
 CDK dependencies (integration test)\n- Remove incorrect synth.lock cleanup
 test (intentionally not cleaned)\n- Fix import paths and add non-null
 assertions\n- Add cwd argument to runCLI calls

---
 integ-tests/help.test.ts                         |  7 +++----
 src/cli/commands/add/__tests__/validate.test.ts  | 16 ++++++++--------
 src/cli/commands/deploy/__tests__/deploy.test.ts |  6 +++---
 src/cli/commands/dev/__tests__/dev.test.ts       | 12 ++++++------
 src/cli/commands/invoke/__tests__/invoke.test.ts | 10 ++--------
 src/cli/commands/plan/__tests__/plan.test.ts     |  8 +++++---
 src/cli/commands/update/__tests__/update.test.ts |  4 ++--
 src/cli/tui/utils/__tests__/process.test.ts      | 14 +++-----------
 src/schema/schemas/__tests__/zod-util.test.ts    | 10 +++++-----
 9 files changed, 37 insertions(+), 50 deletions(-)

diff --git a/integ-tests/help.test.ts b/integ-tests/help.test.ts
index 43e437e8b..51efff9dc 100644
--- a/integ-tests/help.test.ts
+++ b/integ-tests/help.test.ts
@@ -1,6 +1,5 @@
 import { runCLI } from '../src/test-utils/index.js';
-import { describe, it } from 'vitest';
-import { expect } from 'vitest';
+import { describe, expect, it } from 'vitest';
 
 const COMMANDS = [
   'create',
@@ -23,7 +22,7 @@ const COMMANDS = [
 describe('CLI help', () => {
   describe('main help', () => {
     it('shows all commands', async () => {
-      const result = await runCLI(['--help']);
+      const result = await runCLI(['--help'], process.cwd());
 
       expect(result.exitCode).toBe(0);
       expect(result.stdout.includes('Usage:'), 'Should show usage').toBeTruthy();
@@ -34,7 +33,7 @@ describe('CLI help', () => {
   describe('command help', () => {
     for (const cmd of COMMANDS) {
       it(`${cmd} --help exits 0`, async () => {
-        const result = await runCLI([cmd, '--help']);
+        const result = await runCLI([cmd, '--help'], process.cwd());
 
         expect(result.exitCode, `${cmd} --help failed: ${result.stderr}`).toBe(0);
         expect(result.stdout.includes('Usage:'), `${cmd} should show usage`).toBeTruthy();
diff --git a/src/cli/commands/add/__tests__/validate.test.ts b/src/cli/commands/add/__tests__/validate.test.ts
index ae8881d17..225e30ba7 100644
--- a/src/cli/commands/add/__tests__/validate.test.ts
+++ b/src/cli/commands/add/__tests__/validate.test.ts
@@ -4,15 +4,15 @@ import type {
   AddIdentityOptions,
   AddMcpToolOptions,
   AddMemoryOptions,
-} from './types.js';
+} from '../types.js';
 import {
   validateAddAgentOptions,
   validateAddGatewayOptions,
   validateAddIdentityOptions,
   validateAddMcpToolOptions,
   validateAddMemoryOptions,
-} from './validate.js';
-import { describe, it , expect } from 'vitest';
+} from '../validate.js';
+import { describe, expect, it } from 'vitest';
 
 // Helper: valid base options for each type
 const validAgentOptionsByo: AddAgentOptions = {
@@ -88,7 +88,7 @@ describe('validate', () => {
       for (const { field, error } of requiredFields) {
         const opts = { ...validAgentOptionsByo, [field]: undefined };
         const result = validateAddAgentOptions(opts);
-        expect(result.valid, `Should fail for missing ${field}`).toBe(false);
+        expect(result.valid, `Should fail for missing ${String(field)}`).toBe(false);
         expect(result.error).toBe(error);
       }
     });
@@ -200,7 +200,7 @@ describe('validate', () => {
       for (const { field, error } of jwtFields) {
         const opts = { ...validGatewayOptionsJwt, [field]: undefined };
         const result = validateAddGatewayOptions(opts);
-        expect(result.valid, `Should fail for missing ${field}`).toBe(false);
+        expect(result.valid, `Should fail for missing ${String(field)}`).toBe(false);
         expect(result.error).toBe(error);
       }
     });
@@ -248,7 +248,7 @@ describe('validate', () => {
       for (const { field, error } of requiredFields) {
         const opts = { ...validMcpToolOptionsMcpRuntime, [field]: undefined };
         const result = validateAddMcpToolOptions(opts);
-        expect(result.valid, `Should fail for missing ${field}`).toBe(false);
+        expect(result.valid, `Should fail for missing ${String(field)}`).toBe(false);
         expect(result.error).toBe(error);
       }
     });
@@ -309,7 +309,7 @@ describe('validate', () => {
       for (const { field, error } of requiredFields) {
         const opts = { ...validMemoryOptions, [field]: undefined };
         const result = validateAddMemoryOptions(opts);
-        expect(result.valid, `Should fail for missing ${field}`).toBe(false);
+        expect(result.valid, `Should fail for missing ${String(field)}`).toBe(false);
         expect(result.error).toBe(error);
       }
     });
@@ -349,7 +349,7 @@ describe('validate', () => {
       for (const { field, error } of requiredFields) {
         const opts = { ...validIdentityOptions, [field]: undefined };
         const result = validateAddIdentityOptions(opts);
-        expect(result.valid, `Should fail for missing ${field}`).toBe(false);
+        expect(result.valid, `Should fail for missing ${String(field)}`).toBe(false);
         expect(result.error).toBe(error);
       }
     });
diff --git a/src/cli/commands/deploy/__tests__/deploy.test.ts b/src/cli/commands/deploy/__tests__/deploy.test.ts
index c2d7101c3..927cde695 100644
--- a/src/cli/commands/deploy/__tests__/deploy.test.ts
+++ b/src/cli/commands/deploy/__tests__/deploy.test.ts
@@ -3,18 +3,18 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('deploy --help', () => {
   it('shows verbose option', async () => {
-    const result = await runCLI(['deploy', '--help']);
+    const result = await runCLI(['deploy', '--help'], process.cwd());
     expect(result.exitCode).toBe(0);
     expect(result.stdout.includes('--verbose'), 'Should show --verbose option').toBeTruthy();
     expect(result.stdout.includes('resource-level'), 'Should describe resource-level events').toBeTruthy();
   });
 
   it('shows all deploy options', async () => {
-    const result = await runCLI(['deploy', '--help']);
+    const result = await runCLI(['deploy', '--help'], process.cwd());
     expect(result.stdout.includes('--target')).toBeTruthy();
     expect(result.stdout.includes('--yes')).toBeTruthy();
     expect(result.stdout.includes('--progress')).toBeTruthy();
diff --git a/src/cli/commands/dev/__tests__/dev.test.ts b/src/cli/commands/dev/__tests__/dev.test.ts
index 329442ca1..61c3d8679 100644
--- a/src/cli/commands/dev/__tests__/dev.test.ts
+++ b/src/cli/commands/dev/__tests__/dev.test.ts
@@ -1,10 +1,10 @@
 import { runCLI } from '../../../../test-utils/index.js';
-import { describe, it , expect } from 'vitest';
+import { describe, expect, it } from 'vitest';
 
 describe('dev command', () => {
   describe('--help', () => {
     it('shows all options', async () => {
-      const result = await runCLI(['dev', '--help']);
+      const result = await runCLI(['dev', '--help'], process.cwd());
 
       expect(result.exitCode).toBe(0);
       expect(result.stdout.includes('--port'), 'Should show --port option').toBeTruthy();
@@ -18,7 +18,7 @@ describe('dev command', () => {
 
   describe('requires project context', () => {
     it('exits with error when run outside project', async () => {
-      const result = await runCLI(['dev']);
+      const result = await runCLI(['dev'], process.cwd());
 
       expect(result.exitCode).toBe(1);
       expect(
@@ -30,19 +30,19 @@ describe('dev command', () => {
 
   describe('flag validation', () => {
     it('rejects invalid port number', async () => {
-      const result = await runCLI(['dev', '--port', 'abc']);
+      const result = await runCLI(['dev', '--port', 'abc'], process.cwd());
 
       expect(result.exitCode).toBe(1);
     });
 
     it('rejects negative port number', async () => {
-      const result = await runCLI(['dev', '--port', '-1']);
+      const result = await runCLI(['dev', '--port', '-1'], process.cwd());
 
       expect(result.exitCode).toBe(1);
     });
 
     it('stream flag is documented in help', async () => {
-      const result = await runCLI(['dev', '--help']);
+      const result = await runCLI(['dev', '--help'], process.cwd());
 
       expect(result.exitCode).toBe(0);
       expect(result.stdout.includes('--stream'), 'Should show --stream option').toBeTruthy();
diff --git a/src/cli/commands/invoke/__tests__/invoke.test.ts b/src/cli/commands/invoke/__tests__/invoke.test.ts
index 7b4cf4e55..c40a3bb1b 100644
--- a/src/cli/commands/invoke/__tests__/invoke.test.ts
+++ b/src/cli/commands/invoke/__tests__/invoke.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('invoke command', () => {
   let testDir: string;
@@ -67,13 +67,7 @@ describe('invoke command', () => {
       expect(json.error.includes('Prompt'), `Error should mention Prompt: ${json.error}`).toBeTruthy();
     });
 
-    it('requires target for JSON output', async () => {
-      const result = await runCLI(['invoke', 'hello', '--json'], projectDir);
-      expect(result.exitCode).toBe(1);
-      const json = JSON.parse(result.stdout);
-      expect(json.success).toBe(false);
-      expect(json.error.includes('--target'), `Error should mention --target: ${json.error}`).toBeTruthy();
-    });
+    // Target defaults to 'default' so no validation needed
   });
 
   describe('agent/target validation', () => {
diff --git a/src/cli/commands/plan/__tests__/plan.test.ts b/src/cli/commands/plan/__tests__/plan.test.ts
index f34638e3e..3324f746a 100644
--- a/src/cli/commands/plan/__tests__/plan.test.ts
+++ b/src/cli/commands/plan/__tests__/plan.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('plan command', () => {
   let testDir: string;
@@ -87,9 +87,11 @@ describe('plan command', () => {
       ).toBeTruthy();
     });
 
-    it('plan without --deploy returns plan result only', async () => {
+    // This test requires npm install to work (CDK dependencies)
+    // Moved to integ-tests/plan.test.ts
+    it.skip('plan without --deploy returns plan result only', async () => {
       const result = await runCLI(['plan', '--target', 'test-target', '--json'], projectDir);
-      expect(result.exitCode).toBe(0);
+      expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0);
       const json = JSON.parse(result.stdout);
       expect(json.success).toBe(true);
       expect(json.stackNames, 'Should have stackNames').toBeTruthy();
diff --git a/src/cli/commands/update/__tests__/update.test.ts b/src/cli/commands/update/__tests__/update.test.ts
index 63aa00530..c6b24401f 100644
--- a/src/cli/commands/update/__tests__/update.test.ts
+++ b/src/cli/commands/update/__tests__/update.test.ts
@@ -1,5 +1,5 @@
-import { compareVersions } from './action.js';
-import { describe, it , expect } from 'vitest';
+import { compareVersions } from '../action.js';
+import { describe, expect, it } from 'vitest';
 
 describe('update', () => {
   describe('compareVersions', () => {
diff --git a/src/cli/tui/utils/__tests__/process.test.ts b/src/cli/tui/utils/__tests__/process.test.ts
index 6a36e5c06..3c8d8d538 100644
--- a/src/cli/tui/utils/__tests__/process.test.ts
+++ b/src/cli/tui/utils/__tests__/process.test.ts
@@ -4,7 +4,7 @@ import * as fs from 'node:fs';
 import * as fsp from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import * as path from 'node:path';
-import { afterEach, beforeEach, describe, it , expect } from 'vitest';
+import { afterEach, beforeEach, describe, expect, it } from 'vitest';
 
 describe('cleanupStaleLockFiles', () => {
   let testDir: string;
@@ -49,16 +49,8 @@ describe('cleanupStaleLockFiles', () => {
     expect(fs.existsSync(lockFile), 'Lock from live PID should be kept').toBe(true);
   });
 
-  it('removes old synth.lock files', async () => {
-    const lockFile = path.join(testDir, 'synth.lock');
-    await fsp.writeFile(lockFile, '');
-    const oldTime = new Date(Date.now() - 10 * 60 * 1000);
-    await fsp.utimes(lockFile, oldTime, oldTime);
-
-    await cleanupStaleLockFiles(testDir);
-
-    expect(fs.existsSync(lockFile), 'Old synth.lock should be removed').toBe(false);
-  });
+  // Note: synth.lock is intentionally NOT removed by cleanupStaleLockFiles
+  // to avoid corrupting concurrent CDK runs (see process.ts comment)
 
   it('handles missing directory gracefully', async () => {
     const nonExistent = path.join(testDir, 'does-not-exist');
diff --git a/src/schema/schemas/__tests__/zod-util.test.ts b/src/schema/schemas/__tests__/zod-util.test.ts
index 4aab854d5..dc7cc9dcd 100644
--- a/src/schema/schemas/__tests__/zod-util.test.ts
+++ b/src/schema/schemas/__tests__/zod-util.test.ts
@@ -1,5 +1,5 @@
 import { uniqueBy } from '../zod-util.js';
-import { describe, it , expect } from 'vitest';
+import { describe, expect, it } from 'vitest';
 import { z } from 'zod';
 
 describe('zod-util', () => {
@@ -22,7 +22,7 @@ describe('zod-util', () => {
       expect(result.success).toBe(false);
       if (!result.success) {
         expect(result.error.issues.length).toBe(1);
-        expect(result.error.issues[0].path).toEqual([2]);
+        expect(result.error.issues[0]!.path).toEqual([2]);
       }
     });
 
@@ -32,7 +32,7 @@ describe('zod-util', () => {
       const result = schema.safeParse([{ name: 'foo' }, { name: 'foo' }]);
       expect(result.success).toBe(false);
       if (!result.success) {
-        expect(result.error.issues[0].message).toBe('Duplicate name: foo');
+        expect(result.error.issues[0]!.message).toBe('Duplicate name: foo');
       }
     });
 
@@ -95,8 +95,8 @@ describe('zod-util', () => {
       expect(result.success).toBe(false);
       if (!result.success) {
         expect(result.error.issues.length).toBe(1);
-        expect(result.error.issues[0].path).toEqual([2]);
-        expect(result.error.issues[0].message).toBe('Duplicate id: 1');
+        expect(result.error.issues[0]!.path).toEqual([2]);
+        expect(result.error.issues[0]!.message).toBe('Duplicate id: 1');
       }
     });
 

From 34323dbfde29540c0966b7f2bddbb6f9595eac25 Mon Sep 17 00:00:00 2001
From: Aidan Daly <aidandal@amazon.com>
Date: Fri, 30 Jan 2026 16:28:36 -0500
Subject: [PATCH 11/15] style: apply prettier formatting to test files and
 imports

---
 integ-tests/create-no-agent.test.ts                          | 3 +--
 integ-tests/create-with-agent.test.ts                        | 3 +--
 integ-tests/deploy.test.ts                                   | 3 +--
 integ-tests/dev-server.test.ts                               | 5 ++---
 integ-tests/invoke-agent.test.ts                             | 3 +--
 integ-tests/json-output.test.ts                              | 3 +--
 src/cli/__tests__/errors.test.ts                             | 2 +-
 src/cli/commands/add/__tests__/add-agent.test.ts             | 2 +-
 src/cli/commands/add/__tests__/add-gateway.test.ts           | 2 +-
 src/cli/commands/add/__tests__/add-identity.test.ts          | 2 +-
 src/cli/commands/add/__tests__/add-mcp-tool.test.ts          | 2 +-
 src/cli/commands/add/__tests__/add-memory.test.ts            | 2 +-
 src/cli/commands/add/__tests__/add-target.test.ts            | 2 +-
 src/cli/commands/add/actions.ts                              | 2 +-
 src/cli/commands/add/command.tsx                             | 2 +-
 src/cli/commands/attach/__tests__/attach-agent.test.ts       | 2 +-
 src/cli/commands/attach/__tests__/attach-gateway.test.ts     | 2 +-
 src/cli/commands/attach/__tests__/attach-identity.test.ts    | 2 +-
 src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts | 2 +-
 src/cli/commands/attach/__tests__/attach-memory.test.ts      | 2 +-
 src/cli/commands/create/__tests__/create.test.ts             | 2 +-
 src/cli/commands/destroy/__tests__/destroy.test.ts           | 2 +-
 22 files changed, 23 insertions(+), 29 deletions(-)

diff --git a/integ-tests/create-no-agent.test.ts b/integ-tests/create-no-agent.test.ts
index 2ba964e2a..963f7d8bd 100644
--- a/integ-tests/create-no-agent.test.ts
+++ b/integ-tests/create-no-agent.test.ts
@@ -4,8 +4,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it } from 'vitest';
-import { expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 function hasCommand(cmd: string): boolean {
   try {
diff --git a/integ-tests/create-with-agent.test.ts b/integ-tests/create-with-agent.test.ts
index 591d63732..884bff70e 100644
--- a/integ-tests/create-with-agent.test.ts
+++ b/integ-tests/create-with-agent.test.ts
@@ -4,8 +4,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it } from 'vitest';
-import { expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 function hasCommand(cmd: string): boolean {
   try {
diff --git a/integ-tests/deploy.test.ts b/integ-tests/deploy.test.ts
index 4230d78db..64ce0f2cc 100644
--- a/integ-tests/deploy.test.ts
+++ b/integ-tests/deploy.test.ts
@@ -4,8 +4,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it } from 'vitest';
-import { expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 function hasCommand(cmd: string): boolean {
   try {
diff --git a/integ-tests/dev-server.test.ts b/integ-tests/dev-server.test.ts
index 9f461a478..35b0c351d 100644
--- a/integ-tests/dev-server.test.ts
+++ b/integ-tests/dev-server.test.ts
@@ -1,11 +1,10 @@
-import { exists, runCLI } from '../src/test-utils/index.js';
+import { 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';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, afterEach, beforeAll, describe, it } from 'vitest';
-import { expect } from 'vitest';
+import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest';
 
 function hasCommand(cmd: string): boolean {
   try {
diff --git a/integ-tests/invoke-agent.test.ts b/integ-tests/invoke-agent.test.ts
index 0a294bf0a..7653bd034 100644
--- a/integ-tests/invoke-agent.test.ts
+++ b/integ-tests/invoke-agent.test.ts
@@ -4,8 +4,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it } from 'vitest';
-import { expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 function hasCommand(cmd: string): boolean {
   try {
diff --git a/integ-tests/json-output.test.ts b/integ-tests/json-output.test.ts
index 44a974756..e4ef5835f 100644
--- a/integ-tests/json-output.test.ts
+++ b/integ-tests/json-output.test.ts
@@ -3,8 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it } from 'vitest';
-import { expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('JSON output structure', () => {
   let testDir: string;
diff --git a/src/cli/__tests__/errors.test.ts b/src/cli/__tests__/errors.test.ts
index 341b28779..9cffdc408 100644
--- a/src/cli/__tests__/errors.test.ts
+++ b/src/cli/__tests__/errors.test.ts
@@ -1,5 +1,5 @@
 import { getErrorMessage, isExpiredTokenError, isNoCredentialsError, isStackInProgressError } from '../errors.js';
-import { describe, it , expect } from 'vitest';
+import { describe, expect, it } from 'vitest';
 
 describe('errors', () => {
   describe('getErrorMessage', () => {
diff --git a/src/cli/commands/add/__tests__/add-agent.test.ts b/src/cli/commands/add/__tests__/add-agent.test.ts
index b313dcedc..5280a68de 100644
--- a/src/cli/commands/add/__tests__/add-agent.test.ts
+++ b/src/cli/commands/add/__tests__/add-agent.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('add agent command', () => {
   let testDir: string;
diff --git a/src/cli/commands/add/__tests__/add-gateway.test.ts b/src/cli/commands/add/__tests__/add-gateway.test.ts
index fa20150f1..91c171006 100644
--- a/src/cli/commands/add/__tests__/add-gateway.test.ts
+++ b/src/cli/commands/add/__tests__/add-gateway.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('add gateway command', () => {
   let testDir: string;
diff --git a/src/cli/commands/add/__tests__/add-identity.test.ts b/src/cli/commands/add/__tests__/add-identity.test.ts
index 5eebfb0c9..7d5a6e559 100644
--- a/src/cli/commands/add/__tests__/add-identity.test.ts
+++ b/src/cli/commands/add/__tests__/add-identity.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('add identity command', () => {
   let testDir: string;
diff --git a/src/cli/commands/add/__tests__/add-mcp-tool.test.ts b/src/cli/commands/add/__tests__/add-mcp-tool.test.ts
index 56cf9918e..f3a71db33 100644
--- a/src/cli/commands/add/__tests__/add-mcp-tool.test.ts
+++ b/src/cli/commands/add/__tests__/add-mcp-tool.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('add mcp-tool command', () => {
   let testDir: string;
diff --git a/src/cli/commands/add/__tests__/add-memory.test.ts b/src/cli/commands/add/__tests__/add-memory.test.ts
index be58d7c5c..5bb3aa6a3 100644
--- a/src/cli/commands/add/__tests__/add-memory.test.ts
+++ b/src/cli/commands/add/__tests__/add-memory.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('add memory command', () => {
   let testDir: string;
diff --git a/src/cli/commands/add/__tests__/add-target.test.ts b/src/cli/commands/add/__tests__/add-target.test.ts
index b0aa23378..86d3ca241 100644
--- a/src/cli/commands/add/__tests__/add-target.test.ts
+++ b/src/cli/commands/add/__tests__/add-target.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('add target command', () => {
   let testDir: string;
diff --git a/src/cli/commands/add/actions.ts b/src/cli/commands/add/actions.ts
index 9fbc70b50..a661c57ab 100644
--- a/src/cli/commands/add/actions.ts
+++ b/src/cli/commands/add/actions.ts
@@ -17,7 +17,7 @@ import {
   mapModelProviderToIdentityProviders,
   writeAgentToProject,
 } from '../../operations/agent/generate';
-import { computeDefaultIdentityEnvVarName , createIdentityFromWizard } from '../../operations/identity/create-identity';
+import { computeDefaultIdentityEnvVarName, createIdentityFromWizard } from '../../operations/identity/create-identity';
 import { createGatewayFromWizard, createToolFromWizard } from '../../operations/mcp/create-mcp';
 import { createMemoryFromWizard } from '../../operations/memory/create-memory';
 import { createRenderer } from '../../templates';
diff --git a/src/cli/commands/add/command.tsx b/src/cli/commands/add/command.tsx
index 83a8d4445..ba1249642 100644
--- a/src/cli/commands/add/command.tsx
+++ b/src/cli/commands/add/command.tsx
@@ -71,7 +71,7 @@ async function handleAddAgentCLI(options: AddAgentOptions): Promise<void> {
 
   const result = await handleAddAgent({
     name: options.name!,
-    type: (options.type!) ?? 'create',
+    type: options.type! ?? 'create',
     language: options.language!,
     framework: options.framework!,
     modelProvider: options.modelProvider!,
diff --git a/src/cli/commands/attach/__tests__/attach-agent.test.ts b/src/cli/commands/attach/__tests__/attach-agent.test.ts
index 6edbf3151..469165393 100644
--- a/src/cli/commands/attach/__tests__/attach-agent.test.ts
+++ b/src/cli/commands/attach/__tests__/attach-agent.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('attach agent command', () => {
   let testDir: string;
diff --git a/src/cli/commands/attach/__tests__/attach-gateway.test.ts b/src/cli/commands/attach/__tests__/attach-gateway.test.ts
index a292b98f8..eef25f098 100644
--- a/src/cli/commands/attach/__tests__/attach-gateway.test.ts
+++ b/src/cli/commands/attach/__tests__/attach-gateway.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('attach gateway command', () => {
   let testDir: string;
diff --git a/src/cli/commands/attach/__tests__/attach-identity.test.ts b/src/cli/commands/attach/__tests__/attach-identity.test.ts
index 35d663228..dbb7d7311 100644
--- a/src/cli/commands/attach/__tests__/attach-identity.test.ts
+++ b/src/cli/commands/attach/__tests__/attach-identity.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('attach identity command', () => {
   let testDir: string;
diff --git a/src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts b/src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts
index d5095fcaa..de5dedee1 100644
--- a/src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts
+++ b/src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('attach mcp-runtime command', () => {
   let testDir: string;
diff --git a/src/cli/commands/attach/__tests__/attach-memory.test.ts b/src/cli/commands/attach/__tests__/attach-memory.test.ts
index 66c4e4829..e40b22d9d 100644
--- a/src/cli/commands/attach/__tests__/attach-memory.test.ts
+++ b/src/cli/commands/attach/__tests__/attach-memory.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, readFile, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('attach memory command', () => {
   let testDir: string;
diff --git a/src/cli/commands/create/__tests__/create.test.ts b/src/cli/commands/create/__tests__/create.test.ts
index a9c7678d9..c38d6111f 100644
--- a/src/cli/commands/create/__tests__/create.test.ts
+++ b/src/cli/commands/create/__tests__/create.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('create command', () => {
   let testDir: string;
diff --git a/src/cli/commands/destroy/__tests__/destroy.test.ts b/src/cli/commands/destroy/__tests__/destroy.test.ts
index 8f36176c2..7977c3871 100644
--- a/src/cli/commands/destroy/__tests__/destroy.test.ts
+++ b/src/cli/commands/destroy/__tests__/destroy.test.ts
@@ -3,7 +3,7 @@ import { randomUUID } from 'node:crypto';
 import { mkdir, rm } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterAll, beforeAll, describe, it , expect } from 'vitest';
+import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 describe('destroy command', () => {
   let testDir: string;

From a9f604eb2e04410ae4706bb73d44b8ddefd25a6e Mon Sep 17 00:00:00 2001
From: Aidan Daly <aidandal@amazon.com>
Date: Fri, 30 Jan 2026 17:14:00 -0500
Subject: [PATCH 12/15] fix: improve integration test infrastructure\n\n- Add
 LOCAL_L3_PATH env var support for local L3 constructs development\n- Separate
 integration tests into vitest.integ.config.ts with 120s timeout\n- Fix
 dev-server test: use built bundle, clear INIT_CWD env var\n- Add test:integ
 npm script for running integration tests

---
 integ-tests/dev-server.test.ts   |  7 +++---
 package.json                     |  3 ++-
 src/cli/templates/CDKRenderer.ts | 28 ++++++++++++++++++-----
 tsconfig.json                    |  2 +-
 vitest.config.ts                 |  2 +-
 vitest.integ.config.ts           | 39 ++++++++++++++++++++++++++++++++
 6 files changed, 69 insertions(+), 12 deletions(-)
 create mode 100644 vitest.integ.config.ts

diff --git a/integ-tests/dev-server.test.ts b/integ-tests/dev-server.test.ts
index 35b0c351d..5f60976e7 100644
--- a/integ-tests/dev-server.test.ts
+++ b/integ-tests/dev-server.test.ts
@@ -67,7 +67,7 @@ describe('integration: dev server', () => {
       const json = JSON.parse(result.stdout);
       projectPath = json.projectPath;
     }
-  }, 60000);
+  }, 120000);
 
   afterEach(() => {
     // Kill dev server if running
@@ -89,12 +89,13 @@ describe('integration: dev server', () => {
     async () => {
       expect(projectPath, 'Project should have been created').toBeTruthy();
 
-      const cliPath = join(__dirname, '..', 'src', 'cli', 'index.ts');
+      const cliPath = join(__dirname, '..', 'dist', 'cli', 'index.mjs');
       const port = 8000 + Math.floor(Math.random() * 1000);
 
-      devProcess = spawn('bun', ['run', cliPath, 'dev', '--port', String(port), '--logs'], {
+      devProcess = spawn('node', [cliPath, 'dev', '--port', String(port), '--logs'], {
         cwd: projectPath,
         stdio: 'pipe',
+        env: { ...process.env, INIT_CWD: undefined },
       });
 
       const serverReady = await waitForServer(port, 20000);
diff --git a/package.json b/package.json
index 3052c1324..e23386abf 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,8 @@
     "clean": "rm -rf dist",
     "prepare": "husky",
     "test": "vitest run",
-    "test:watch": "vitest"
+    "test:watch": "vitest",
+    "test:integ": "vitest run --config vitest.integ.config.ts"
   },
   "dependencies": {
     "@aws-cdk/toolkit-lib": "^1.13.0",
diff --git a/src/cli/templates/CDKRenderer.ts b/src/cli/templates/CDKRenderer.ts
index 105ed1d75..39ed57900 100644
--- a/src/cli/templates/CDKRenderer.ts
+++ b/src/cli/templates/CDKRenderer.ts
@@ -133,21 +133,37 @@ export class CDKRenderer {
   /**
    * Updates the generated package.json with distro-specific configuration.
    * Adjusts the postinstall script to link the correct package name.
+   *
+   * If LOCAL_L3_PATH env var is set, uses file: dependency instead of npm link.
    */
   private async updatePackageJson(outputDir: string): Promise<void> {
     const packageJsonPath = path.join(outputDir, 'package.json');
     const content = await fs.readFile(packageJsonPath, 'utf-8');
     const pkg = JSON.parse(content) as {
       scripts?: { postinstall?: string };
+      dependencies?: Record<string, string>;
       [key: string]: unknown;
     };
 
-    const distroConfig = getDistroConfig();
-    const packageName = distroConfig.packageName;
-
-    // Update postinstall script to use the correct package name
-    if (pkg.scripts?.postinstall) {
-      pkg.scripts.postinstall = `npm link ${packageName} 2>/dev/null || echo 'Note: If CDK synth fails, run: npm link ${packageName}'`;
+    const localL3Path = process.env.LOCAL_L3_PATH;
+
+    if (localL3Path) {
+      // Use local file: dependency for development
+      if (pkg.dependencies) {
+        pkg.dependencies['@aws/agentcore-l3-cdk-constructs'] = `file:${localL3Path}`;
+      }
+      // Remove postinstall npm link since we're using file: dependency
+      if (pkg.scripts?.postinstall) {
+        delete pkg.scripts.postinstall;
+      }
+    } else {
+      // Production: use npm link
+      const distroConfig = getDistroConfig();
+      const packageName = distroConfig.packageName;
+
+      if (pkg.scripts?.postinstall) {
+        pkg.scripts.postinstall = `npm link ${packageName} 2>/dev/null || echo 'Note: If CDK synth fails, run: npm link ${packageName}'`;
+      }
     }
 
     await fs.writeFile(packageJsonPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
diff --git a/tsconfig.json b/tsconfig.json
index 717b43162..400918b5a 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -23,6 +23,6 @@
       "@/*": ["./src/*"]
     }
   },
-  "include": ["src/**/*", "integ-tests/**/*"],
+  "include": ["src/**/*", "integ-tests/**/*", "vitest.config.ts", "vitest.integ.config.ts"],
   "exclude": ["node_modules", "dist", "packages", "assets", "src/assets"]
 }
diff --git a/vitest.config.ts b/vitest.config.ts
index 0f2da95bc..eb2d68cf3 100644
--- a/vitest.config.ts
+++ b/vitest.config.ts
@@ -32,7 +32,7 @@ export default defineConfig({
     },
   ],
   test: {
-    include: ['src/**/*.test.ts', '__tests__/**/*.test.ts', 'integ-tests/**/*.test.ts'],
+    include: ['src/**/*.test.ts', '__tests__/**/*.test.ts'],
     exclude: ['src/assets/**/*.test.ts'],
     testTimeout: 15000,
     hookTimeout: 60000,
diff --git a/vitest.integ.config.ts b/vitest.integ.config.ts
new file mode 100644
index 000000000..fee461fdc
--- /dev/null
+++ b/vitest.integ.config.ts
@@ -0,0 +1,39 @@
+import * as fs from 'fs';
+import * as path from 'path';
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+  resolve: {
+    alias: {
+      '@': path.resolve(__dirname, './src'),
+    },
+  },
+  plugins: [
+    {
+      name: 'text-loader',
+      transform(code, id) {
+        if (id.includes('llm-compacted') && id.endsWith('.ts')) {
+          const text = fs.readFileSync(id, 'utf-8');
+          return {
+            code: `export default ${JSON.stringify(text)};`,
+            map: null,
+          };
+        }
+        if (id.endsWith('.md')) {
+          const text = fs.readFileSync(id, 'utf-8');
+          return {
+            code: `export default ${JSON.stringify(text)};`,
+            map: null,
+          };
+        }
+      },
+    },
+  ],
+  test: {
+    include: ['integ-tests/**/*.test.ts'],
+    testTimeout: 120000,
+    hookTimeout: 120000,
+    globals: false,
+    reporters: ['verbose'],
+  },
+});

From 6e6931aad339b39781ea000d6bc667fcf9032464 Mon Sep 17 00:00:00 2001
From: Aidan Daly <aidandal@amazon.com>
Date: Fri, 30 Jan 2026 17:19:54 -0500
Subject: [PATCH 13/15] fix: restore TypeScript (coming soon) disabled state

---
 src/cli/tui/screens/agent/types.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/cli/tui/screens/agent/types.ts b/src/cli/tui/screens/agent/types.ts
index 941c28aa1..4802e26fb 100644
--- a/src/cli/tui/screens/agent/types.ts
+++ b/src/cli/tui/screens/agent/types.ts
@@ -76,7 +76,7 @@ export const AGENT_TYPE_OPTIONS = [
 
 export const LANGUAGE_OPTIONS = [
   { id: 'Python', title: 'Python' },
-  { id: 'TypeScript', title: 'TypeScript' },
+  { id: 'TypeScript', title: 'TypeScript (coming soon)', disabled: true },
   { id: 'Other', title: 'Other' },
 ] as const;
 

From c2194a4ce4c0cf57da59071e75f829c84855ffca Mon Sep 17 00:00:00 2001
From: Aidan Daly <aidandal@amazon.com>
Date: Fri, 30 Jan 2026 17:20:23 -0500
Subject: [PATCH 14/15] fix: pass disabled property to SelectList for language
 options

---
 src/cli/tui/screens/agent/AddAgentScreen.tsx      | 2 +-
 src/cli/tui/screens/generate/GenerateWizardUI.tsx | 2 +-
 src/cli/tui/screens/generate/types.ts             | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/cli/tui/screens/agent/AddAgentScreen.tsx b/src/cli/tui/screens/agent/AddAgentScreen.tsx
index 115b95879..24e668757 100644
--- a/src/cli/tui/screens/agent/AddAgentScreen.tsx
+++ b/src/cli/tui/screens/agent/AddAgentScreen.tsx
@@ -166,7 +166,7 @@ export function AddAgentScreen({ existingAgentNames, onComplete, onExit }: AddAg
   const byoCurrentIndex = byoSteps.indexOf(byoStep);
 
   // BYO language options (include "Other" for BYO path)
-  const languageItems: SelectableItem[] = useMemo(() => LANGUAGE_OPTIONS.map(o => ({ id: o.id, title: o.title })), []);
+  const languageItems: SelectableItem[] = useMemo(() => LANGUAGE_OPTIONS.map(o => ({ id: o.id, title: o.title, disabled: o.disabled })), []);
 
   const frameworkItems: SelectableItem[] = useMemo(
     () => FRAMEWORK_OPTIONS.map(o => ({ id: o.id, title: o.title, description: o.description })),
diff --git a/src/cli/tui/screens/generate/GenerateWizardUI.tsx b/src/cli/tui/screens/generate/GenerateWizardUI.tsx
index c391b5788..901c50889 100644
--- a/src/cli/tui/screens/generate/GenerateWizardUI.tsx
+++ b/src/cli/tui/screens/generate/GenerateWizardUI.tsx
@@ -37,7 +37,7 @@ export function GenerateWizardUI({ wizard, onBack, onConfirm, isActive }: Genera
   const getItems = (): SelectableItem[] => {
     switch (wizard.step) {
       case 'language':
-        return LANGUAGE_OPTIONS.map(o => ({ id: o.id, title: o.title }));
+        return LANGUAGE_OPTIONS.map(o => ({ id: o.id, title: o.title, disabled: o.disabled }));
       case 'sdk':
         return SDK_OPTIONS.map(o => ({ id: o.id, title: o.title, description: o.description }));
       case 'modelProvider':
diff --git a/src/cli/tui/screens/generate/types.ts b/src/cli/tui/screens/generate/types.ts
index ec7a6591c..3541ea176 100644
--- a/src/cli/tui/screens/generate/types.ts
+++ b/src/cli/tui/screens/generate/types.ts
@@ -41,7 +41,7 @@ export const STEP_LABELS: Record<GenerateStep, string> = {
 
 export const LANGUAGE_OPTIONS = [
   { id: 'Python', title: 'Python' },
-  { id: 'TypeScript', title: 'TypeScript' },
+  { id: 'TypeScript', title: 'TypeScript (coming soon)', disabled: true },
 ] as const;
 
 export const SDK_OPTIONS = [

From 8ef052031360b30ab99a0a71d27ea865d2dd289e Mon Sep 17 00:00:00 2001
From: Aidan Daly <aidandal@amazon.com>
Date: Fri, 30 Jan 2026 17:30:07 -0500
Subject: [PATCH 15/15] chore: remove test-output.txt

---
 test-output.txt | 830 ------------------------------------------------
 1 file changed, 830 deletions(-)
 delete mode 100644 test-output.txt

diff --git a/test-output.txt b/test-output.txt
deleted file mode 100644
index 3b56508b9..000000000
--- a/test-output.txt
+++ /dev/null
@@ -1,830 +0,0 @@
-
-> @aws/agentcore-cli@0.1.0 test:vitest
-> vitest run
-
-
-[1m[46m RUN [49m[22m [36mv4.0.18 [39m[90m/Users/aidandal/workplace/agentcore-cli[39m
-
- [32m✓[39m integ-tests/json-output.test.ts[2m > [22mJSON output structure[2m > [22mcreate command[2m > [22merror response has success:false and error string[33m 1615[2mms[22m[39m
- [32m✓[39m src/cli/commands/dev/__tests__/dev.test.ts[2m > [22mdev command[2m > [22m--help[2m > [22mshows all options[33m 1619[2mms[22m[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mmain help[2m > [22mshows all commands[33m 1621[2mms[22m[39m
- [32m✓[39m src/cli/commands/deploy/__tests__/deploy.test.ts[2m > [22mdeploy --help[2m > [22mshows verbose option[33m 1664[2mms[22m[39m
- [32m✓[39m integ-tests/json-output.test.ts[2m > [22mJSON output structure[2m > [22mcreate command[2m > [22mvalidation error mentions the issue[33m 1360[2mms[22m[39m
- [32m✓[39m src/cli/commands/deploy/__tests__/deploy.test.ts[2m > [22mdeploy --help[2m > [22mshows all deploy options[33m 1311[2mms[22m[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mcreate --help exits 0[33m 1357[2mms[22m[39m
- [32m✓[39m src/cli/commands/dev/__tests__/dev.test.ts[2m > [22mdev command[2m > [22mrequires project context[2m > [22mexits with error when run outside project[33m 1372[2mms[22m[39m
- [32m✓[39m integ-tests/json-output.test.ts[2m > [22mJSON output structure[2m > [22mcreate command[2m > [22mmissing required options returns error JSON[33m 1484[2mms[22m[39m
- [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22m--no-agent[2m > [22mcreates project structure[33m 4480[2mms[22m[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mdeploy --help exits 0[33m 1678[2mms[22m[39m
- [32m✓[39m src/cli/commands/dev/__tests__/dev.test.ts[2m > [22mdev command[2m > [22mflag validation[2m > [22mrejects invalid port number[33m 1683[2mms[22m[39m
- [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22m--no-agent[2m > [22mrejects reserved names[33m 1562[2mms[22m[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mdev --help exits 0[33m 1412[2mms[22m[39m
- [32m✓[39m integ-tests/json-output.test.ts[2m > [22mJSON output structure[2m > [22mcreate command[2m > [22minvalid framework returns error JSON[33m 1619[2mms[22m[39m
- [32m✓[39m src/cli/commands/dev/__tests__/dev.test.ts[2m > [22mdev command[2m > [22mflag validation[2m > [22mrejects negative port number[33m 1434[2mms[22m[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22minvoke --help exits 0[33m 1558[2mms[22m[39m
- [32m✓[39m src/cli/commands/dev/__tests__/dev.test.ts[2m > [22mdev command[2m > [22mflag validation[2m > [22mstream flag is documented in help[33m 1521[2mms[22m[39m
- [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22mwith agent[2m > [22mcreates project with agent[33m 3033[2mms[22m[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mdestroy --help exits 0[33m 1669[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-identity.test.ts[2m > [22madd identity command[2m > [22mvalidation[2m > [22mrequires name flag[33m 1640[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mvalidation[2m > [22mrequires name flag[33m 1806[2mms[22m[39m
- [32m✓[39m src/cli/commands/plan/__tests__/plan.test.ts[2m > [22mplan command[2m > [22mtarget validation[2m > [22mrejects non-existent target[33m 1784[2mms[22m[39m
- [31m×[39m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts[2m > [22magent removal cascade[2m > [22mcascade removes owned resources[2m > [22mremoves agent and its owned memory[33m 9475[2mms[22m[39m
-[31m   → stdout: 
-
-1 !== 0
-[39m
- [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22mwith agent[2m > [22mrequires all options without --no-agent[33m 1683[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-identity.test.ts[2m > [22madd identity command[2m > [22mvalidation[2m > [22mrequires type flag[33m 1636[2mms[22m[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mplan --help exits 0[33m 1683[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mvalidation[2m > [22mrequires exposure flag[33m 1587[2mms[22m[39m
- [31m×[39m src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts[2m > [22mremoval policy cascade[2m > [22mmemory cascade[2m > [22mremoves memory and cleans up user references with cascade[33m 11018[2mms[22m[39m
-[31m   → stdout: 
-
-1 !== 0
-[39m
- [31m×[39m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22mmemory restrict[2m > [22mblocks removal when memory has users (default restrict)[33m 11055[2mms[22m[39m
-[31m   → Expected values to be strictly equal:
-
-0 !== 1
-[39m
- [32m✓[39m src/cli/commands/deploy/__tests__/deploy.test.ts[2m > [22mdeploy command[2m > [22mvalidation[2m > [22maccepts deploy without target (TUI mode)[33m 3231[2mms[22m[39m
- [32m✓[39m src/cli/commands/plan/__tests__/plan.test.ts[2m > [22mplan command[2m > [22mtarget validation[2m > [22maccepts valid target and returns plan result[33m 3069[2mms[22m[39m
- [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22mwith agent[2m > [22mvalidates framework[33m 2598[2mms[22m[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mstatus --help exits 0[33m 2531[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-identity.test.ts[2m > [22madd identity command[2m > [22mvalidation[2m > [22mvalidates type value[33m 2573[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mvalidation[2m > [22mvalidates language[33m 2509[2mms[22m[39m
- [32m✓[39m src/cli/commands/deploy/__tests__/deploy.test.ts[2m > [22mdeploy command[2m > [22mtarget validation[2m > [22mrejects non-existent target[33m 2526[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-identity.test.ts[2m > [22madd identity command[2m > [22mvalidation[2m > [22mrequires api-key flag[33m 2787[2mms[22m[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mvalidate --help exits 0[33m 2838[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mvalidation[2m > [22maccepts Other as valid language option[33m 2877[2mms[22m[39m
- [32m✓[39m src/cli/commands/plan/__tests__/plan.test.ts[2m > [22mplan command[2m > [22m--deploy flag[2m > [22mcommand accepts --deploy flag[33m 3899[2mms[22m[39m
- [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22m--defaults[2m > [22mcreates project with defaults[33m 4367[2mms[22m[39m
- [32m✓[39m src/cli/commands/remove/__tests__/remove-identity.test.ts[2m > [22mremove identity command[2m > [22mvalidation[2m > [22mrequires name flag[33m 2536[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-identity.test.ts[2m > [22madd identity command[2m > [22mvalidation[2m > [22mrequires owner flag[33m 2661[2mms[22m[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22madd --help exits 0[33m 2644[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mmcp-runtime[2m > [22mcreates mcp-runtime tool[33m 2740[2mms[22m[39m
- [31m×[39m src/cli/commands/plan/__tests__/plan.test.ts[2m > [22mplan command[2m > [22m--deploy flag[2m > [22mplan without --deploy returns plan result only[33m 4021[2mms[22m[39m
-[31m   → Expected values to be strictly equal:
-
-1 !== 0
-[39m
- [31m×[39m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts[2m > [22magent removal cascade[2m > [22mcascade removes owned resources[2m > [22mremoves agent and its owned identity[33m 11013[2mms[22m[39m
-[31m   → stdout: 
-
-1 !== 0
-[39m
- [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22m--dry-run[2m > [22mshows files without creating[33m 2876[2mms[22m[39m
- [32m✓[39m src/cli/commands/remove/__tests__/remove-identity.test.ts[2m > [22mremove identity command[2m > [22mvalidation[2m > [22mrejects non-existent identity[33m 2963[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts[2m > [22mattach mcp-runtime command[2m > [22mvalidation[2m > [22mrequires agent flag[33m 2955[2mms[22m[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mattach --help exits 0[33m 2917[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-identity.test.ts[2m > [22madd identity command[2m > [22midentity creation[2m > [22mcreates identity with owner[33m 2991[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mmcp-runtime[2m > [22mrequires agents for mcp-runtime[33m 2914[2mms[22m[39m
- [32m✓[39m src/cli/commands/plan/__tests__/plan.test.ts[2m > [22mplan command[2m > [22m--deploy flag[2m > [22mrequires --target for --deploy[33m 2948[2mms[22m[39m
- [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22m--skip-git[2m > [22mskips git initialization[33m 3010[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts[2m > [22mattach mcp-runtime command[2m > [22mvalidation[2m > [22mrequires runtime flag[33m 2780[2mms[22m[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mremove --help exits 0[33m 2752[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-identity.test.ts[2m > [22madd identity command[2m > [22midentity creation[2m > [22mcreates identity with owner and users[33m 2783[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mmcp-runtime[2m > [22mreturns clear error for Other language with mcp-runtime[33m 2746[2mms[22m[39m
- [31m×[39m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22mmemory restrict[2m > [22mblocks removal with explicit restrict policy[33m 15001[2mms[22m[39m
-[31m   → Test timed out in 15000ms.
-If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
- [31m×[39m src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts[2m > [22mremoval policy cascade[2m > [22midentity cascade[2m > [22mremoves identity and cleans up user references with cascade[33m 15002[2mms[22m[39m
-[31m   → Test timed out in 15000ms.
-If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-agent.test.ts[2m > [22mattach agent command[2m > [22mvalidation[2m > [22mrequires source flag[33m 2987[2mms[22m[39m
- [31m×[39m src/cli/commands/remove/__tests__/remove-identity.test.ts[2m > [22mremove identity command[2m > [22mremove operations[2m > [22mremoves identity without users[33m 5676[2mms[22m[39m
-[31m   → stdout: {"success":false,"error":"Identity \"temp-id-1769792728695\" not found."}
-
-1 !== 0
-[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts[2m > [22mattach mcp-runtime command[2m > [22mbind operations[2m > [22mbinds agent to MCP runtime[33m 2917[2mms[22m[39m
- [32m✓[39m src/cli/commands/plan/__tests__/plan.test.ts[2m > [22mplan command[2m > [22m--deploy flag[2m > [22mattempts deploy after plan[33m 4138[2mms[22m[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22medit --help exits 0[33m 2904[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mbehind-gateway[2m > [22mcreates behind-gateway tool[33m 2946[2mms[22m[39m
- [32m✓[39m src/cli/commands/create/__tests__/create.test.ts[2m > [22mcreate command[2m > [22m--output-dir[2m > [22mcreates in specified directory[33m 4742[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-agent.test.ts[2m > [22mattach agent command[2m > [22mvalidation[2m > [22mrequires target flag[33m 2699[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts[2m > [22mattach mcp-runtime command[2m > [22mbind operations[2m > [22mrejects non-existent agent[33m 2670[2mms[22m[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22moutline --help exits 0[33m 2656[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mbehind-gateway[2m > [22mrequires gateway for behind-gateway[33m 2615[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-agent.test.ts[2m > [22mattach agent command[2m > [22mattach operations[2m > [22mattaches agent to agent[33m 2573[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-mcp-runtime.test.ts[2m > [22mattach mcp-runtime command[2m > [22mbind operations[2m > [22mrejects non-existent runtime[33m 2738[2mms[22m[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mpackage --help exits 0[33m 2706[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mbehind-gateway[2m > [22mrequires host for behind-gateway[33m 2566[2mms[22m[39m
- [31m×[39m src/cli/commands/remove/__tests__/remove-identity.test.ts[2m > [22mremove identity command[2m > [22mremove operations[2m > [22mblocks removal when identity has users[33m 5595[2mms[22m[39m
-[31m   → Expected values to be strictly equal:
-
-0 !== 1
-[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-gateway.test.ts[2m > [22madd gateway command[2m > [22mbasic gateway[2m > [22mcreates gateway with default authorizer[33m 2622[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-agent.test.ts[2m > [22mattach agent command[2m > [22mattach operations[2m > [22muses custom name[33m 2890[2mms[22m[39m
- [31m×[39m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts[2m > [22magent removal cascade[2m > [22mcascade removes owned resources[2m > [22mremoves agent and cleans up remote tool references[33m 15002[2mms[22m[39m
-[31m   → Test timed out in 15000ms.
-If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
- [32m✓[39m integ-tests/help.test.ts[2m > [22mCLI help[2m > [22mcommand help[2m > [22mupdate --help exits 0[33m 3083[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-mcp-tool.test.ts[2m > [22madd mcp-tool command[2m > [22mbehind-gateway[2m > [22mreturns clear error for Other language with behind-gateway[33m 3109[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-target.test.ts[2m > [22madd target command[2m > [22madds target with valid inputs[33m 3080[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-gateway.test.ts[2m > [22madd gateway command[2m > [22mbasic gateway[2m > [22mrequires name flag[33m 3049[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-gateway.test.ts[2m > [22mattach gateway command[2m > [22mvalidation[2m > [22mrequires agent flag[33m 2814[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-agent.test.ts[2m > [22mattach agent command[2m > [22mattach operations[2m > [22mrejects self-attachment[33m 2832[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-target.test.ts[2m > [22madd target command[2m > [22mrejects duplicate target name[33m 2770[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-gateway.test.ts[2m > [22madd gateway command[2m > [22mbasic gateway[2m > [22mvalidates gateway name format[33m 2790[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-gateway.test.ts[2m > [22mattach gateway command[2m > [22mvalidation[2m > [22mrequires gateway flag[33m 2549[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-agent.test.ts[2m > [22mattach agent command[2m > [22mattach operations[2m > [22mrejects non-existent source[33m 2540[2mms[22m[39m
- [32m✓[39m src/cli/commands/remove/__tests__/remove.test.ts[2m > [22mremove command[2m > [22mvalidation[2m > [22mrequires name for JSON output[33m 2662[2mms[22m[39m
- [31m×[39m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22midentity restrict[2m > [22mblocks removal when identity has users[33m 15000[2mms[22m[39m
-[31m   → Test timed out in 15000ms.
-If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-target.test.ts[2m > [22madd target command[2m > [22mrejects invalid account ID[33m 2514[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mcreate path[2m > [22mcreates agent with valid inputs[33m 2769[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-gateway.test.ts[2m > [22mattach gateway command[2m > [22mattach operations[2m > [22mattaches gateway to agent[33m 2713[2mms[22m[39m
- [32m✓[39m src/cli/commands/remove/__tests__/remove.test.ts[2m > [22mremove command[2m > [22mremove target[2m > [22mrejects non-existent target[33m 2694[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-target.test.ts[2m > [22madd target command[2m > [22mrejects invalid region name[33m 2802[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-gateway.test.ts[2m > [22madd gateway command[2m > [22mbasic gateway[2m > [22mrejects duplicate gateway name[33m 5350[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mcreate path[2m > [22mrequires all create path options[33m 2800[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-gateway.test.ts[2m > [22mattach gateway command[2m > [22mattach operations[2m > [22mrejects non-existent agent[33m 2767[2mms[22m[39m
- [32m✓[39m src/cli/commands/remove/__tests__/remove.test.ts[2m > [22mremove command[2m > [22mremove target[2m > [22mremoves existing target[33m 2796[2mms[22m[39m
- [32m✓[39m src/cli/commands/destroy/__tests__/destroy.test.ts[2m > [22mdestroy command[2m > [22mvalidation[2m > [22mrequires --target flag for CLI mode[33m 3043[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-target.test.ts[2m > [22madd target command[2m > [22mrequires all flags[33m 2668[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-gateway.test.ts[2m > [22madd gateway command[2m > [22mJWT authorizer[2m > [22mcreates gateway with CUSTOM_JWT authorizer[33m 2604[2mms[22m[39m
- [31m×[39m integ-tests/create-no-agent.test.ts[2m > [22mintegration: create without agent[2m > [22mcreates project with real npm install and git init[33m 11449[2mms[22m[39m
-[31m   → stderr: 
-
-1 !== 0
-[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mcreate path[2m > [22mvalidates framework[33m 2632[2mms[22m[39m
- [31m×[39m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mvalidation[2m > [22mrequires prompt for JSON output[33m 2743[2mms[22m[39m
-[31m   → Expected values to be strictly equal:
-
-0 !== 1
-[39m
- [32m✓[39m src/cli/commands/remove/__tests__/remove.test.ts[2m > [22mremove command[2m > [22mremove agent[2m > [22mrejects non-existent agent[33m 2615[2mms[22m[39m
- [32m✓[39m src/cli/commands/destroy/__tests__/destroy.test.ts[2m > [22mdestroy command[2m > [22mvalidation[2m > [22mshows JSON error for whitespace-only target[33m 2672[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-gateway.test.ts[2m > [22madd gateway command[2m > [22mJWT authorizer[2m > [22mrequires JWT fields when CUSTOM_JWT[33m 2753[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mcreate path[2m > [22mrejects TypeScript for create path[33m 2494[2mms[22m[39m
- [32m✓[39m src/cli/commands/remove/__tests__/remove.test.ts[2m > [22mremove command[2m > [22mremove agent[2m > [22mremoves existing agent[33m 2438[2mms[22m[39m
- [31m×[39m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mvalidation[2m > [22mrequires target for JSON output[33m 2519[2mms[22m[39m
-[31m   → Error should mention --target: No deployed targets found. Run `agentcore deploy` first.[39m
- [32m✓[39m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts[2m > [22mremove mcp-tool command[2m > [22mvalidation[2m > [22mrequires name flag[33m 2357[2mms[22m[39m
- [32m✓[39m src/cli/commands/destroy/__tests__/destroy.test.ts[2m > [22mdestroy command[2m > [22mtarget discovery[2m > [22mreturns error for non-existent target[33m 2397[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-gateway.test.ts[2m > [22madd gateway command[2m > [22mJWT authorizer[2m > [22mvalidates discovery URL format[33m 2111[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mcreate path[2m > [22mvalidates framework/model compatibility[33m 2442[2mms[22m[39m
- [32m✓[39m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22magent/target validation[2m > [22mrejects non-existent agent[33m 2577[2mms[22m[39m
- [32m✓[39m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts[2m > [22mremove mcp-tool command[2m > [22mvalidation[2m > [22mrejects non-existent tool[33m 2477[2mms[22m[39m
- [32m✓[39m src/cli/commands/destroy/__tests__/destroy.test.ts[2m > [22mdestroy command[2m > [22mtarget discovery[2m > [22mreturns error for target that exists but is not deployed[33m 2620[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-identity.test.ts[2m > [22mattach identity command[2m > [22mvalidation[2m > [22mrequires agent flag[33m 2231[2mms[22m[39m
- [31m×[39m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22magent restrict[2m > [22mblocks removal when agent is referenced by others[33m 14347[2mms[22m[39m
-[31m   → Expected values to be strictly equal:
-
-0 !== 1
-[39m
- [32m✓[39m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mstreaming[2m > [22mcommand accepts --stream flag[33m 2125[2mms[22m[39m
- [32m✓[39m src/cli/commands/destroy/__tests__/destroy.test.ts[2m > [22mdestroy command[2m > [22mcommand registration[2m > [22mcommand is registered and works[33m 2165[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-identity.test.ts[2m > [22mattach identity command[2m > [22mvalidation[2m > [22mrequires identity flag[33m 1598[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mvalidation[2m > [22mrequires name flag[33m 1633[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mcreate path[2m > [22mrejects duplicate agent name[33m 3660[2mms[22m[39m
- [32m✓[39m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mstreaming[2m > [22m--stream works with --agent flag[33m 1600[2mms[22m[39m
- [31m×[39m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts[2m > [22mremove mcp-tool command[2m > [22mremove mcp-runtime tool[2m > [22mremoves mcp-runtime tool and cleans up agent references[33m 3629[2mms[22m[39m
-[31m   → stdout: {"success":false,"error":"MCP tool 'temp-rt-1769792760950' not found"}
-
-1 !== 0
-[39m
- [32m✓[39m src/cli/commands/destroy/__tests__/destroy.test.ts[2m > [22mdestroy command[2m > [22mcommand registration[2m > [22malias x works[33m 1650[2mms[22m[39m
- [32m✓[39m src/cli/commands/remove/__tests__/remove-gateway.test.ts[2m > [22mremove gateway command[2m > [22mvalidation[2m > [22mrequires name flag[33m 1633[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-identity.test.ts[2m > [22mattach identity command[2m > [22mattach operations[2m > [22mattaches identity to agent[33m 1705[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mvalidation[2m > [22mrequires strategies flag[33m 1759[2mms[22m[39m
- [31m×[39m integ-tests/create-with-agent.test.ts[2m > [22mintegration: create with Python agent[2m > [22mcreates project with real uv venv and sync[33m 6493[2mms[22m[39m
-[31m   → stderr: 
-
-1 !== 0
-[39m
- [31m×[39m integ-tests/invoke-agent.test.ts[2m > [22mintegration: invoke agent[2m > [22minvokes agent and receives response[32m 3[2mms[22m[39m
-[31m   → Project should have been created[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mBYO path[2m > [22mregisters BYO agent[33m 1935[2mms[22m[39m
- [32m✓[39m src/cli/tui/utils/__tests__/process.test.ts[2m > [22mcleanupStaleLockFiles[2m > [22mremoves lock files older than 5 minutes[32m 6[2mms[22m[39m
- [32m✓[39m src/cli/tui/utils/__tests__/process.test.ts[2m > [22mcleanupStaleLockFiles[2m > [22mremoves young lock files from dead processes[32m 3[2mms[22m[39m
- [32m✓[39m src/cli/tui/utils/__tests__/process.test.ts[2m > [22mcleanupStaleLockFiles[2m > [22mkeeps young lock files from live processes[32m 5[2mms[22m[39m
- [31m×[39m src/cli/tui/utils/__tests__/process.test.ts[2m > [22mcleanupStaleLockFiles[2m > [22mremoves old synth.lock files[32m 11[2mms[22m[39m
-[31m   → Old synth.lock should be removed
-
-true !== false
-[39m
- [32m✓[39m src/cli/tui/utils/__tests__/process.test.ts[2m > [22mcleanupStaleLockFiles[2m > [22mhandles missing directory gracefully[32m 2[2mms[22m[39m
- [32m✓[39m src/cli/tui/utils/__tests__/process.test.ts[2m > [22mcleanupStaleLockFiles[2m > [22mdoes not remove non-lock files[32m 7[2mms[22m[39m
- [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mpasses validation for unique arrays[32m 3[2mms[22m[39m
- [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mdetects duplicate at correct index[32m 1[2mms[22m[39m
- [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22muses custom error message[32m 0[2mms[22m[39m
- [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mpasses validation for empty array[32m 0[2mms[22m[39m
- [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mpasses validation for single element[32m 0[2mms[22m[39m
- [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mflags multiple duplicates at each subsequent occurrence[32m 0[2mms[22m[39m
- [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mnever flags first occurrence[32m 0[2mms[22m[39m
- [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mworks with different key functions[32m 1[2mms[22m[39m
- [32m✓[39m src/schema/schemas/__tests__/zod-util.test.ts[2m > [22mzod-util[2m > [22muniqueBy[2m > [22mflags all subsequent occurrences when all elements have same key[32m 1[2mms[22m[39m
- [32m✓[39m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mstreaming[2m > [22m--stream with invalid agent returns error[33m 2003[2mms[22m[39m
- [32m✓[39m src/cli/commands/remove/__tests__/remove-gateway.test.ts[2m > [22mremove gateway command[2m > [22mvalidation[2m > [22mrejects non-existent gateway[33m 1762[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddAgentOptions[2m > [22mreturns error for missing required fields[32m 1[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddAgentOptions[2m > [22mreturns error for invalid schema values[32m 1[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddAgentOptions[2m > [22mreturns error for incompatible framework and model provider[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddAgentOptions[2m > [22mreturns error for BYO path without codeLocation[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddAgentOptions[2m > [22mreturns error for create path with TypeScript or Other[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddAgentOptions[2m > [22mreturns error for create path without memory or invalid memory[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddAgentOptions[2m > [22mpasses for valid options[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddGatewayOptions[2m > [22mreturns error for missing name[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddGatewayOptions[2m > [22mreturns error for invalid gateway name[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddGatewayOptions[2m > [22mreturns error for invalid authorizerType[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddGatewayOptions[2m > [22mreturns error for CUSTOM_JWT missing required fields[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddGatewayOptions[2m > [22mreturns error for invalid discoveryUrl[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddGatewayOptions[2m > [22mreturns error for empty audience or clients[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddGatewayOptions[2m > [22mpasses for valid options[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMcpToolOptions[2m > [22mreturns error for missing required fields[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMcpToolOptions[2m > [22mreturns error for invalid values[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMcpToolOptions[2m > [22mreturns error for mcp-runtime without agents[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMcpToolOptions[2m > [22mreturns error for behind-gateway missing gateway, host, or invalid host[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMcpToolOptions[2m > [22mpasses for valid options[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMemoryOptions[2m > [22mreturns error for missing required fields[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMemoryOptions[2m > [22mreturns error for invalid or empty strategies[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddMemoryOptions[2m > [22mpasses for valid options[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddIdentityOptions[2m > [22mreturns error for missing required fields[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddIdentityOptions[2m > [22mreturns error for unsupported type[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/validate.test.ts[2m > [22mvalidate[2m > [22mvalidateAddIdentityOptions[2m > [22mpasses for valid options[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-identity.test.ts[2m > [22mattach identity command[2m > [22mattach operations[2m > [22mrejects non-existent agent[33m 1693[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mvalidation[2m > [22mrequires owner flag[33m 1575[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22mgetErrorMessage[2m > [22mreturns message from Error instance[32m 1[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22mgetErrorMessage[2m > [22mreturns string for non-Error values[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns true for all SDK v3 error names[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns true for all error Code properties[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns true for nested cause with error name[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns true for double-nested cause[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns true for nested cause with Code[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns true for message patterns[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns false for non-expired errors[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misExpiredTokenError[2m > [22mreturns false for edge cases[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misNoCredentialsError[2m > [22mreturns true for AwsCredentialsError[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misNoCredentialsError[2m > [22mreturns true for message patterns[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misNoCredentialsError[2m > [22mreturns false for other errors[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misNoCredentialsError[2m > [22mreturns false for edge cases[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misStackInProgressError[2m > [22mreturns true for in-progress states[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misStackInProgressError[2m > [22mreturns true for state and cannot be updated pattern[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misStackInProgressError[2m > [22mreturns true for currently being updated[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misStackInProgressError[2m > [22mreturns false for other errors[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/__tests__/errors.test.ts[2m > [22merrors[2m > [22misStackInProgressError[2m > [22mreturns false for edge cases[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/update/__tests__/update.test.ts[2m > [22mupdate[2m > [22mcompareVersions[2m > [22mreturns 0 for equal versions[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/update/__tests__/update.test.ts[2m > [22mupdate[2m > [22mcompareVersions[2m > [22mreturns 1 when latest is newer (update available)[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/update/__tests__/update.test.ts[2m > [22mupdate[2m > [22mcompareVersions[2m > [22mreturns -1 when current is newer (local ahead)[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/update/__tests__/update.test.ts[2m > [22mupdate[2m > [22mcompareVersions[2m > [22mhandles missing patch version[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/update/__tests__/update.test.ts[2m > [22mupdate[2m > [22mcompareVersions[2m > [22mcompares major version first[32m 0[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-agent.test.ts[2m > [22madd agent command[2m > [22mBYO path[2m > [22mrequires code-location for BYO path[33m 1374[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-memory.test.ts[2m > [22mattach memory command[2m > [22mvalidation[2m > [22mrequires agent flag[33m 1301[2mms[22m[39m
- [31m×[39m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts[2m > [22mremove mcp-tool command[2m > [22mremove behind-gateway tool[2m > [22mremoves behind-gateway tool from gateway targets[33m 3276[2mms[22m[39m
-[31m   → stdout: {"success":false,"error":"MCP tool 'temp-gw-1769792764580' not found"}
-
-1 !== 0
-[39m
- [31m×[39m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mstreaming[2m > [22mrequires prompt for streaming[33m 1336[2mms[22m[39m
-[31m   → Expected values to be strictly equal:
-
-0 !== 1
-[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mvalidation[2m > [22mvalidates strategy types[33m 1019[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-memory.test.ts[2m > [22mattach memory command[2m > [22mvalidation[2m > [22mrequires memory flag[33m 885[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mmemory creation[2m > [22mcreates memory with owner[33m 908[2mms[22m[39m
- [32m✓[39m src/cli/commands/remove/__tests__/remove-gateway.test.ts[2m > [22mremove gateway command[2m > [22mremove operations[2m > [22mremoves gateway without dependencies[33m 2084[2mms[22m[39m
- [31m×[39m integ-tests/dev-server.test.ts[2m > [22mintegration: dev server[2m > [22mstarts dev server and responds to health check[32m 2[2mms[22m[39m
-[31m   → Project should have been created[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-memory.test.ts[2m > [22mattach memory command[2m > [22mvalidation[2m > [22mvalidates access value[33m 907[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mmemory creation[2m > [22mcreates memory with owner and users[33m 933[2mms[22m[39m
- [32m✓[39m src/cli/commands/remove/__tests__/remove-memory.test.ts[2m > [22mremove memory command[2m > [22mvalidation[2m > [22mrequires name flag[33m 751[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-memory.test.ts[2m > [22mattach memory command[2m > [22mattach operations[2m > [22mattaches memory to agent[33m 794[2mms[22m[39m
- [32m✓[39m src/cli/commands/remove/__tests__/remove-memory.test.ts[2m > [22mremove memory command[2m > [22mvalidation[2m > [22mrejects non-existent memory[33m 864[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mmemory creation[2m > [22mcreates memory with multiple strategies[33m 898[2mms[22m[39m
- [31m×[39m src/cli/commands/remove/__tests__/remove-gateway.test.ts[2m > [22mremove gateway command[2m > [22mremove operations[2m > [22mblocks removal when gateway has attached agents[33m 1833[2mms[22m[39m
-[31m   → Expected values to be strictly equal:
-
-0 !== 1
-[39m
- [31m×[39m integ-tests/deploy.test.ts[2m > [22mintegration: deploy[2m > [22mdeploys to AWS successfully[32m 2[2mms[22m[39m
-[31m   → Project should have been created[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-memory.test.ts[2m > [22mattach memory command[2m > [22mattach operations[2m > [22muses specified access level[33m 801[2mms[22m[39m
- [32m✓[39m src/cli/commands/add/__tests__/add-memory.test.ts[2m > [22madd memory command[2m > [22mmemory creation[2m > [22mcreates memory with custom expiry[33m 751[2mms[22m[39m
- [32m✓[39m src/cli/commands/attach/__tests__/attach-memory.test.ts[2m > [22mattach memory command[2m > [22mattach operations[2m > [22mrejects non-existent agent[33m 656[2mms[22m[39m
- [31m×[39m src/cli/commands/remove/__tests__/remove-memory.test.ts[2m > [22mremove memory command[2m > [22mremove operations[2m > [22mremoves memory without users[33m 1386[2mms[22m[39m
-[31m   → stdout: {"success":false,"error":"Memory \"temp-mem-1769792770811\" not found."}
-
-1 !== 0
-[39m
- [31m×[39m src/cli/commands/remove/__tests__/remove-memory.test.ts[2m > [22mremove memory command[2m > [22mremove operations[2m > [22mblocks removal when memory has users[33m 1249[2mms[22m[39m
-[31m   → Expected values to be strictly equal:
-
-0 !== 1
-[39m
-
-[31m⎯⎯⎯⎯⎯⎯[39m[1m[41m Failed Tests 26 [49m[22m[31m⎯⎯⎯⎯⎯⎯⎯[39m
-
-[41m[1m FAIL [22m[49m integ-tests/create-no-agent.test.ts[2m > [22mintegration: create without agent[2m > [22mcreates project with real npm install and git init
-[31m[1mAssertionError[22m: stderr: 
-
-1 !== 0
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 0[39m
-[31m+ 1[39m
-
-[36m [2m❯[22m integ-tests/create-no-agent.test.ts:[2m38:12[22m[39m
-    [90m 36| [39m    const result = await runCLI(['create', '--name', name, '--no-agent…
-    [90m 37| [39m
-    [90m 38| [39m    assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m0[39m[33m,[39m [32m`stderr: [39m[36m${[39mresult[33m.[39mstderr[36m}[39m[32m`[39m)[33m;[39m
-    [90m   | [39m           [31m^[39m
-    [90m 39| [39m
-    [90m 40| [39m    [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m integ-tests/create-with-agent.test.ts[2m > [22mintegration: create with Python agent[2m > [22mcreates project with real uv venv and sync
-[31m[1mAssertionError[22m: stderr: 
-
-1 !== 0
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 0[39m
-[31m+ 1[39m
-
-[36m [2m❯[22m integ-tests/create-with-agent.test.ts:[2m56:12[22m[39m
-    [90m 54| [39m    )[33m;[39m
-    [90m 55| [39m
-    [90m 56| [39m    assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m0[39m[33m,[39m [32m`stderr: [39m[36m${[39mresult[33m.[39mstderr[36m}[39m[32m`[39m)[33m;[39m
-    [90m   | [39m           [31m^[39m
-    [90m 57| [39m
-    [90m 58| [39m    [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m integ-tests/deploy.test.ts[2m > [22mintegration: deploy[2m > [22mdeploys to AWS successfully
-[31m[1mAssertionError[22m: Project should have been created[39m
-[36m [2m❯[22m integ-tests/deploy.test.ts:[2m102:14[22m[39m
-    [90m100| [39m    [32m'deploys to AWS successfully'[39m[33m,[39m
-    [90m101| [39m    [35masync[39m () [33m=>[39m {
-    [90m102| [39m      assert[33m.[39m[34mok[39m(projectPath[33m,[39m [32m'Project should have been created'[39m)[33m;[39m
-    [90m   | [39m             [31m^[39m
-    [90m103| [39m
-    [90m104| [39m      const result = await runCLI(['deploy', '--target', targetName, '…
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m integ-tests/dev-server.test.ts[2m > [22mintegration: dev server[2m > [22mstarts dev server and responds to health check
-[31m[1mAssertionError[22m: Project should have been created[39m
-[36m [2m❯[22m integ-tests/dev-server.test.ts:[2m91:14[22m[39m
-    [90m 89| [39m    [32m'starts dev server and responds to health check'[39m[33m,[39m
-    [90m 90| [39m    [35masync[39m () [33m=>[39m {
-    [90m 91| [39m      assert[33m.[39m[34mok[39m(projectPath[33m,[39m [32m'Project should have been created'[39m)[33m;[39m
-    [90m   | [39m             [31m^[39m
-    [90m 92| [39m
-    [90m 93| [39m      [35mconst[39m cliPath [33m=[39m [34mjoin[39m(__dirname[33m,[39m [32m'..'[39m[33m,[39m [32m'src'[39m[33m,[39m [32m'cli'[39m[33m,[39m [32m'index.ts'[39m)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m integ-tests/invoke-agent.test.ts[2m > [22mintegration: invoke agent[2m > [22minvokes agent and receives response
-[31m[1mAssertionError[22m: Project should have been created[39m
-[36m [2m❯[22m integ-tests/invoke-agent.test.ts:[2m67:14[22m[39m
-    [90m 65| [39m    [32m'invokes agent and receives response'[39m[33m,[39m
-    [90m 66| [39m    [35masync[39m () [33m=>[39m {
-    [90m 67| [39m      assert[33m.[39m[34mok[39m(projectPath[33m,[39m [32m'Project should have been created'[39m)[33m;[39m
-    [90m   | [39m             [31m^[39m
-    [90m 68| [39m
-    [90m 69| [39m      [35mconst[39m result [33m=[39m [35mawait[39m [34mrunCLI[39m(
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mvalidation[2m > [22mrequires prompt for JSON output
-[31m[1mAssertionError[22m: Expected values to be strictly equal:
-
-0 !== 1
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 1[39m
-[31m+ 0[39m
-
-[36m [2m❯[22m src/cli/commands/invoke/__tests__/invoke.test.ts:[2m59:14[22m[39m
-    [90m 57| [39m    [34mit[39m([32m'requires prompt for JSON output'[39m[33m,[39m [35masync[39m () [33m=>[39m {
-    [90m 58| [39m      const result = await runCLI(['invoke', '--json', '--target', 'te…
-    [90m 59| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m1[39m)[33m;[39m
-    [90m   | [39m             [31m^[39m
-    [90m 60| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-    [90m 61| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mvalidation[2m > [22mrequires target for JSON output
-[31m[1mAssertionError[22m: Error should mention --target: No deployed targets found. Run `agentcore deploy` first.[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- true[39m
-[31m+ false[39m
-
-[36m [2m❯[22m src/cli/commands/invoke/__tests__/invoke.test.ts:[2m70:14[22m[39m
-    [90m 68| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-    [90m 69| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
-    [90m 70| [39m      assert.ok(json.error.includes('--target'), `Error should mention…
-    [90m   | [39m             [31m^[39m
-    [90m 71| [39m    })[33m;[39m
-    [90m 72| [39m  })[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/invoke/__tests__/invoke.test.ts[2m > [22minvoke command[2m > [22mstreaming[2m > [22mrequires prompt for streaming
-[31m[1mAssertionError[22m: Expected values to be strictly equal:
-
-0 !== 1
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 1[39m
-[31m+ 0[39m
-
-[36m [2m❯[22m src/cli/commands/invoke/__tests__/invoke.test.ts:[2m118:14[22m[39m
-    [90m116| [39m    [34mit[39m([32m'requires prompt for streaming'[39m[33m,[39m [35masync[39m () [33m=>[39m {
-    [90m117| [39m      const result = await runCLI(['invoke', '--stream', '--json'], pr…
-    [90m118| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m1[39m)[33m;[39m
-    [90m   | [39m             [31m^[39m
-    [90m119| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-    [90m120| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/plan/__tests__/plan.test.ts[2m > [22mplan command[2m > [22m--deploy flag[2m > [22mplan without --deploy returns plan result only
-[31m[1mAssertionError[22m: Expected values to be strictly equal:
-
-1 !== 0
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 0[39m
-[31m+ 1[39m
-
-[36m [2m❯[22m src/cli/commands/plan/__tests__/plan.test.ts:[2m87:14[22m[39m
-    [90m 85| [39m    [34mit[39m([32m'plan without --deploy returns plan result only'[39m[33m,[39m [35masync[39m () [33m=>[39m {
-    [90m 86| [39m      const result = await runCLI(['plan', '--target', 'test-target', …
-    [90m 87| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m0[39m)[33m;[39m
-    [90m   | [39m             [31m^[39m
-    [90m 88| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-    [90m 89| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mtrue[39m)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[9/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts[2m > [22magent removal cascade[2m > [22mcascade removes owned resources[2m > [22mremoves agent and its owned memory
-[31m[1mAssertionError[22m: stdout: 
-
-1 !== 0
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 0[39m
-[31m+ 1[39m
-
-[36m [2m❯[22m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts:[2m54:14[22m[39m
-    [90m 52| [39m      [90m// Remove agent with cascade[39m
-    [90m 53| [39m      result = await runCLI(['remove', 'agent', '--name', 'OwnerAgent'…
-    [90m 54| [39m      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}…
-    [90m   | [39m             [31m^[39m
-    [90m 55| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-    [90m 56| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mtrue[39m)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[10/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts[2m > [22magent removal cascade[2m > [22mcascade removes owned resources[2m > [22mremoves agent and its owned identity
-[31m[1mAssertionError[22m: stdout: 
-
-1 !== 0
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 0[39m
-[31m+ 1[39m
-
-[36m [2m❯[22m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts:[2m95:14[22m[39m
-    [90m 93| [39m      [90m// Remove agent with cascade[39m
-    [90m 94| [39m      result = await runCLI(['remove', 'agent', '--name', 'OwnerAgent'…
-    [90m 95| [39m      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}…
-    [90m   | [39m             [31m^[39m
-    [90m 96| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-    [90m 97| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mtrue[39m)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[11/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts[2m > [22magent removal cascade[2m > [22mcascade removes owned resources[2m > [22mremoves agent and cleans up remote tool references
-[31m[1mError[22m: Test timed out in 15000ms.
-If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
-[36m [2m❯[22m src/cli/commands/remove/__tests__/agent-removal-cascade.test.ts:[2m104:5[22m[39m
-    [90m102| [39m    })[33m;[39m
-    [90m103| [39m
-    [90m104| [39m    it('removes agent and cleans up remote tool references', async () …
-    [90m   | [39m    [31m^[39m
-    [90m105| [39m      [90m// Create fresh project[39m
-    [90m106| [39m      [35mconst[39m projectName [33m=[39m [32m`CascadeToolProj[39m[36m${[39m[33mDate[39m[33m.[39m[34mnow[39m()[36m}[39m[32m`[39m[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[12/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts[2m > [22mremoval policy cascade[2m > [22mmemory cascade[2m > [22mremoves memory and cleans up user references with cascade
-[31m[1mAssertionError[22m: stdout: 
-
-1 !== 0
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 0[39m
-[31m+ 1[39m
-
-[36m [2m❯[22m src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts:[2m52:14[22m[39m
-    [90m 50| [39m      [90m// Remove memory with cascade[39m
-    [90m 51| [39m      result = await runCLI(['remove', 'memory', '--name', 'SharedMem'…
-    [90m 52| [39m      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}…
-    [90m   | [39m             [31m^[39m
-    [90m 53| [39m
-    [90m 54| [39m      [90m// Verify memory is removed from both agents[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[13/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts[2m > [22mremoval policy cascade[2m > [22midentity cascade[2m > [22mremoves identity and cleans up user references with cascade
-[31m[1mError[22m: Test timed out in 15000ms.
-If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
-[36m [2m❯[22m src/cli/commands/remove/__tests__/removal-policy-cascade.test.ts:[2m68:5[22m[39m
-    [90m 66| [39m
-    [90m 67| [39m  [34mdescribe[39m([32m'identity cascade'[39m[33m,[39m () [33m=>[39m {
-    [90m 68| [39m    it('removes identity and cleans up user references with cascade', …
-    [90m   | [39m    [31m^[39m
-    [90m 69| [39m      [90m// Create fresh project[39m
-    [90m 70| [39m      [35mconst[39m projectName [33m=[39m [32m`IdCascadeProj[39m[36m${[39m[33mDate[39m[33m.[39m[34mnow[39m()[36m}[39m[32m`[39m[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[14/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22mmemory restrict[2m > [22mblocks removal when memory has users (default restrict)
-[31m[1mAssertionError[22m: Expected values to be strictly equal:
-
-0 !== 1
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 1[39m
-[31m+ 0[39m
-
-[36m [2m❯[22m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts:[2m52:14[22m[39m
-    [90m 50| [39m      [90m// Try to remove memory without cascade - should fail[39m
-    [90m 51| [39m      result = await runCLI(['remove', 'memory', '--name', 'SharedMem'…
-    [90m 52| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m1[39m)[33m;[39m
-    [90m   | [39m             [31m^[39m
-    [90m 53| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-    [90m 54| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[15/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22mmemory restrict[2m > [22mblocks removal with explicit restrict policy
-[31m[1mError[22m: Test timed out in 15000ms.
-If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
-[36m [2m❯[22m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts:[2m58:5[22m[39m
-    [90m 56| [39m    })[33m;[39m
-    [90m 57| [39m
-    [90m 58| [39m    [34mit[39m([32m'blocks removal with explicit restrict policy'[39m[33m,[39m [35masync[39m () [33m=>[39m {
-    [90m   | [39m    [31m^[39m
-    [90m 59| [39m      [90m// Create fresh project[39m
-    [90m 60| [39m      [35mconst[39m projectName [33m=[39m [32m`MemRestrictExplicitProj[39m[36m${[39m[33mDate[39m[33m.[39m[34mnow[39m()[36m}[39m[32m`[39m[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[16/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22midentity restrict[2m > [22mblocks removal when identity has users
-[31m[1mError[22m: Test timed out in 15000ms.
-If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".[39m
-[36m [2m❯[22m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts:[2m94:5[22m[39m
-    [90m 92| [39m
-    [90m 93| [39m  [34mdescribe[39m([32m'identity restrict'[39m[33m,[39m () [33m=>[39m {
-    [90m 94| [39m    [34mit[39m([32m'blocks removal when identity has users'[39m[33m,[39m [35masync[39m () [33m=>[39m {
-    [90m   | [39m    [31m^[39m
-    [90m 95| [39m      [90m// Create fresh project[39m
-    [90m 96| [39m      [35mconst[39m projectName [33m=[39m [32m`IdRestrictProj[39m[36m${[39m[33mDate[39m[33m.[39m[34mnow[39m()[36m}[39m[32m`[39m[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[17/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts[2m > [22mremoval policy restrict[2m > [22magent restrict[2m > [22mblocks removal when agent is referenced by others
-[31m[1mAssertionError[22m: Expected values to be strictly equal:
-
-0 !== 1
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 1[39m
-[31m+ 0[39m
-
-[36m [2m❯[22m src/cli/commands/remove/__tests__/removal-policy-restrict.test.ts:[2m159:14[22m[39m
-    [90m157| [39m      [90m// Try to remove AgentB - should fail with restrict[39m
-    [90m158| [39m      result = await runCLI(['remove', 'agent', '--name', 'AgentB', '-…
-    [90m159| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m1[39m)[33m;[39m
-    [90m   | [39m             [31m^[39m
-    [90m160| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-    [90m161| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[18/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/remove-gateway.test.ts[2m > [22mremove gateway command[2m > [22mremove operations[2m > [22mblocks removal when gateway has attached agents
-[31m[1mAssertionError[22m: Expected values to be strictly equal:
-
-0 !== 1
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 1[39m
-[31m+ 0[39m
-
-[36m [2m❯[22m src/cli/commands/remove/__tests__/remove-gateway.test.ts:[2m102:14[22m[39m
-    [90m100| [39m      [90m// Try to remove - should fail with restrict policy[39m
-    [90m101| [39m      const result = await runCLI(['remove', 'gateway', '--name', gate…
-    [90m102| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m1[39m)[33m;[39m
-    [90m   | [39m             [31m^[39m
-    [90m103| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-    [90m104| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[19/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/remove-identity.test.ts[2m > [22mremove identity command[2m > [22mremove operations[2m > [22mremoves identity without users
-[31m[1mAssertionError[22m: stdout: {"success":false,"error":"Identity \"temp-id-1769792728695\" not found."}
-
-1 !== 0
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 0[39m
-[31m+ 1[39m
-
-[36m [2m❯[22m src/cli/commands/remove/__tests__/remove-identity.test.ts:[2m106:14[22m[39m
-    [90m104| [39m
-    [90m105| [39m      const result = await runCLI(['remove', 'identity', '--name', tem…
-    [90m106| [39m      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}…
-    [90m   | [39m             [31m^[39m
-    [90m107| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-    [90m108| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mtrue[39m)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[20/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/remove-identity.test.ts[2m > [22mremove identity command[2m > [22mremove operations[2m > [22mblocks removal when identity has users
-[31m[1mAssertionError[22m: Expected values to be strictly equal:
-
-0 !== 1
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 1[39m
-[31m+ 0[39m
-
-[36m [2m❯[22m src/cli/commands/remove/__tests__/remove-identity.test.ts:[2m128:14[22m[39m
-    [90m126| [39m      [90m// Try to remove - should fail with restrict policy[39m
-    [90m127| [39m      const result = await runCLI(['remove', 'identity', '--name', ide…
-    [90m128| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m1[39m)[33m;[39m
-    [90m   | [39m             [31m^[39m
-    [90m129| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-    [90m130| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[21/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts[2m > [22mremove mcp-tool command[2m > [22mremove mcp-runtime tool[2m > [22mremoves mcp-runtime tool and cleans up agent references
-[31m[1mAssertionError[22m: stdout: {"success":false,"error":"MCP tool 'temp-rt-1769792760950' not found"}
-
-1 !== 0
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 0[39m
-[31m+ 1[39m
-
-[36m [2m❯[22m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts:[2m113:14[22m[39m
-    [90m111| [39m
-    [90m112| [39m      const result = await runCLI(['remove', 'mcp-tool', '--name', tem…
-    [90m113| [39m      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}…
-    [90m   | [39m             [31m^[39m
-    [90m114| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-    [90m115| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mtrue[39m)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[22/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts[2m > [22mremove mcp-tool command[2m > [22mremove behind-gateway tool[2m > [22mremoves behind-gateway tool from gateway targets
-[31m[1mAssertionError[22m: stdout: {"success":false,"error":"MCP tool 'temp-gw-1769792764580' not found"}
-
-1 !== 0
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 0[39m
-[31m+ 1[39m
-
-[36m [2m❯[22m src/cli/commands/remove/__tests__/remove-mcp-tool.test.ts:[2m145:14[22m[39m
-    [90m143| [39m
-    [90m144| [39m      const result = await runCLI(['remove', 'mcp-tool', '--name', tem…
-    [90m145| [39m      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}…
-    [90m   | [39m             [31m^[39m
-    [90m146| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-    [90m147| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mtrue[39m)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[23/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/remove-memory.test.ts[2m > [22mremove memory command[2m > [22mremove operations[2m > [22mremoves memory without users
-[31m[1mAssertionError[22m: stdout: {"success":false,"error":"Memory \"temp-mem-1769792770811\" not found."}
-
-1 !== 0
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 0[39m
-[31m+ 1[39m
-
-[36m [2m❯[22m src/cli/commands/remove/__tests__/remove-memory.test.ts:[2m104:14[22m[39m
-    [90m102| [39m
-    [90m103| [39m      const result = await runCLI(['remove', 'memory', '--name', tempM…
-    [90m104| [39m      assert.strictEqual(result.exitCode, 0, `stdout: ${result.stdout}…
-    [90m   | [39m             [31m^[39m
-    [90m105| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-    [90m106| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mtrue[39m)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[24/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/commands/remove/__tests__/remove-memory.test.ts[2m > [22mremove memory command[2m > [22mremove operations[2m > [22mblocks removal when memory has users
-[31m[1mAssertionError[22m: Expected values to be strictly equal:
-
-0 !== 1
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- 1[39m
-[31m+ 0[39m
-
-[36m [2m❯[22m src/cli/commands/remove/__tests__/remove-memory.test.ts:[2m126:14[22m[39m
-    [90m124| [39m      [90m// Try to remove - should fail with restrict policy[39m
-    [90m125| [39m      const result = await runCLI(['remove', 'memory', '--name', memor…
-    [90m126| [39m      assert[33m.[39m[34mstrictEqual[39m(result[33m.[39mexitCode[33m,[39m [34m1[39m)[33m;[39m
-    [90m   | [39m             [31m^[39m
-    [90m127| [39m      [35mconst[39m json [33m=[39m [33mJSON[39m[33m.[39m[34mparse[39m(result[33m.[39mstdout)[33m;[39m
-    [90m128| [39m      assert[33m.[39m[34mstrictEqual[39m(json[33m.[39msuccess[33m,[39m [35mfalse[39m)[33m;[39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[25/26]⎯[22m[39m
-
-[41m[1m FAIL [22m[49m src/cli/tui/utils/__tests__/process.test.ts[2m > [22mcleanupStaleLockFiles[2m > [22mremoves old synth.lock files
-[31m[1mAssertionError[22m: Old synth.lock should be removed
-
-true !== false
-[39m
-
-[32m- Expected[39m
-[31m+ Received[39m
-
-[32m- false[39m
-[31m+ true[39m
-
-[36m [2m❯[22m src/cli/tui/utils/__tests__/process.test.ts:[2m61:12[22m[39m
-    [90m 59| [39m    [35mawait[39m [34mcleanupStaleLockFiles[39m(testDir)[33m;[39m
-    [90m 60| [39m
-    [90m 61| [39m    assert.strictEqual(fs.existsSync(lockFile), false, 'Old synth.lock…
-    [90m   | [39m           [31m^[39m
-    [90m 62| [39m  })[33m;[39m
-    [90m 63| [39m
-
-[31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[26/26]⎯[22m[39m
-
-
-[2m Test Files [22m [1m[31m15 failed[39m[22m[2m | [22m[1m[32m22 passed[39m[22m[90m (37)[39m
-[2m      Tests [22m [1m[31m26 failed[39m[22m[2m | [22m[1m[32m201 passed[39m[22m[90m (227)[39m
-[2m   Start at [22m 12:05:06
-[2m   Duration [22m 66.69s[2m (transform 858ms, setup 0ms, import 5.17s, tests 679.63s, environment 4ms)[22m
-
