@chanl/cli 2.0.4 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/__tests__/agents.test.js +574 -0
  2. package/dist/__tests__/agents.test.js.map +1 -0
  3. package/dist/__tests__/auth.test.d.ts +2 -0
  4. package/dist/__tests__/auth.test.js +87 -0
  5. package/dist/__tests__/auth.test.js.map +1 -0
  6. package/dist/__tests__/calls.test.d.ts +2 -0
  7. package/dist/__tests__/calls.test.js +115 -0
  8. package/dist/__tests__/calls.test.js.map +1 -0
  9. package/dist/__tests__/chat.test.d.ts +2 -0
  10. package/dist/__tests__/chat.test.js +357 -0
  11. package/dist/__tests__/chat.test.js.map +1 -0
  12. package/dist/__tests__/cli-base.test.d.ts +2 -0
  13. package/dist/__tests__/cli-base.test.js +87 -0
  14. package/dist/__tests__/cli-base.test.js.map +1 -0
  15. package/dist/__tests__/cli-missing.test.d.ts +2 -0
  16. package/dist/__tests__/cli-missing.test.js +546 -0
  17. package/dist/__tests__/cli-missing.test.js.map +1 -0
  18. package/dist/__tests__/cli-p0-scenarios.test.d.ts +2 -0
  19. package/dist/__tests__/cli-p0-scenarios.test.js +123 -0
  20. package/dist/__tests__/cli-p0-scenarios.test.js.map +1 -0
  21. package/dist/__tests__/helpers.d.ts +234 -0
  22. package/dist/__tests__/helpers.js +314 -0
  23. package/dist/__tests__/helpers.js.map +1 -0
  24. package/dist/__tests__/mcp.test.d.ts +2 -0
  25. package/dist/__tests__/mcp.test.js +470 -0
  26. package/dist/__tests__/mcp.test.js.map +1 -0
  27. package/dist/__tests__/prompts.test.d.ts +2 -0
  28. package/dist/__tests__/prompts.test.js +227 -0
  29. package/dist/__tests__/prompts.test.js.map +1 -0
  30. package/dist/__tests__/scenarios.test.d.ts +2 -0
  31. package/dist/__tests__/scenarios.test.js +270 -0
  32. package/dist/__tests__/scenarios.test.js.map +1 -0
  33. package/dist/__tests__/tools.test.d.ts +2 -0
  34. package/dist/__tests__/tools.test.js +331 -0
  35. package/dist/__tests__/tools.test.js.map +1 -0
  36. package/dist/__tests__/toolsets.test.d.ts +2 -0
  37. package/dist/__tests__/toolsets.test.js +196 -0
  38. package/dist/__tests__/toolsets.test.js.map +1 -0
  39. package/dist/__tests__/workspaces.test.d.ts +2 -0
  40. package/dist/__tests__/workspaces.test.js +155 -0
  41. package/dist/__tests__/workspaces.test.js.map +1 -0
  42. package/dist/cli.js +8 -0
  43. package/dist/cli.js.map +1 -1
  44. package/dist/commands/agents.js +194 -6
  45. package/dist/commands/agents.js.map +1 -1
  46. package/dist/commands/chat.js +2 -2
  47. package/dist/commands/chat.js.map +1 -1
  48. package/dist/commands/config.js +24 -2
  49. package/dist/commands/config.js.map +1 -1
  50. package/dist/commands/customers.d.ts +8 -0
  51. package/dist/commands/customers.js +289 -0
  52. package/dist/commands/customers.js.map +1 -0
  53. package/dist/commands/index.d.ts +3 -0
  54. package/dist/commands/index.js +7 -0
  55. package/dist/commands/index.js.map +1 -1
  56. package/dist/commands/memory.js +134 -1
  57. package/dist/commands/memory.js.map +1 -1
  58. package/dist/commands/messaging.d.ts +12 -0
  59. package/dist/commands/messaging.js +208 -0
  60. package/dist/commands/messaging.js.map +1 -0
  61. package/dist/commands/prompts.js +148 -1
  62. package/dist/commands/prompts.js.map +1 -1
  63. package/dist/commands/scenarios.js +121 -0
  64. package/dist/commands/scenarios.js.map +1 -1
  65. package/dist/commands/scorecards.js +3 -3
  66. package/dist/commands/scorecards.js.map +1 -1
  67. package/dist/commands/whatsapp.d.ts +8 -0
  68. package/dist/commands/whatsapp.js +332 -0
  69. package/dist/commands/whatsapp.js.map +1 -0
  70. package/dist/utils/config-store.d.ts +8 -0
  71. package/dist/utils/config-store.js +18 -1
  72. package/dist/utils/config-store.js.map +1 -1
  73. package/dist/utils/sdk-factory.js +15 -3
  74. package/dist/utils/sdk-factory.js.map +1 -1
  75. package/package.json +4 -4
  76. package/dist/__tests__/cli.test.js +0 -2308
  77. package/dist/__tests__/cli.test.js.map +0 -1
  78. /package/dist/__tests__/{cli.test.d.ts → agents.test.d.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/agents.ts"],"sourcesContent":["import { Command } from 'commander';\nimport ora from 'ora';\nimport chalk from 'chalk';\nimport { readFileSync } from 'fs';\nimport type { Agent, CreateAgentData, SyncAgentsResult } from '@chanl/sdk';\nimport { createSdk } from '../utils/sdk-factory.js';\nimport {\n printError,\n printSuccess,\n printInfo,\n printBlank,\n printSimpleTable,\n printLabel,\n isJsonOutput,\n printJson,\n formatDate,\n} from '../utils/output.js';\n\n/**\n * Create the agents command group\n */\nexport function createAgentsCommand(): Command {\n const agents = new Command('agents')\n .description('Manage AI agents (VAPI, ElevenLabs, custom)')\n .addHelpText(\n 'after',\n `\nWhat are Agents?\n Agents are AI-powered voice assistants from various platforms (VAPI, ElevenLabs)\n or custom implementations. They can be tested with scenarios and analyzed with\n scorecards.\n\nQuick Start:\n $ chanl agents list # List all agents\n $ chanl agents get <id> # View agent details\n $ chanl agents sync vapi # Sync from VAPI\n $ chanl agents create --template vapi # Generate VAPI template\n $ chanl agents stats # View statistics\n\nWorkflow:\n 1. Sync agents from your platform (vapi, elevenlabs)\n 2. Or create custom agents with 'create -f agent.json'\n 3. Test agents with 'chanl scenarios run <id> --agent <agentId>'\n 4. Analyze results with 'chanl calls analysis <id>'`\n );\n\n // agents list\n agents\n .command('list')\n .description('List all agents')\n .option('-p, --platform <platform>', 'Filter by platform (vapi, elevenlabs, custom)')\n .option('-s, --status <status>', 'Filter by status (active, inactive)')\n .option('-l, --limit <number>', 'Number of items per page', '20')\n .option('--page <number>', 'Page number', '1')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents list # List all agents\n $ chanl agents list --platform vapi # Filter by platform\n $ chanl agents list --status active # Only active agents\n $ chanl agents list --json # Output as JSON`\n )\n .action(handleAgentsList);\n\n // agents get <id>\n agents\n .command('get <id>')\n .description('Get agent details')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents get abc123 # Get agent details\n $ chanl agents get abc123 --json # Output as JSON`\n )\n .action(handleAgentsGet);\n\n // agents create\n agents\n .command('create')\n .description('Create a new agent')\n .option('-f, --file <path>', 'Path to JSON file with agent data')\n .option('--template [platform]', 'Output a template JSON (vapi, elevenlabs, custom)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents create --template vapi > agent.json # VAPI template\n $ chanl agents create --template custom > agent.json # Custom template\n $ chanl agents create -f agent.json # Create from file\n\nTemplates include platform-specific configurations and examples.`\n )\n .action(handleAgentsCreate);\n\n // agents update <id>\n agents\n .command('update <id>')\n .description('Update an existing agent')\n .option('-f, --file <path>', 'Path to JSON file with update data')\n .option('--sync-to-vapi', 'Sync changes back to VAPI platform')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents update abc123 -f updates.json\n $ chanl agents update abc123 -f updates.json --sync-to-vapi`\n )\n .action(handleAgentsUpdate);\n\n // agents delete <id>\n agents\n .command('delete <id>')\n .description('Delete an agent')\n .option('-y, --yes', 'Skip confirmation prompt')\n .option('--delete-from-integration', 'Also delete from platform (VAPI, etc.)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents delete abc123\n $ chanl agents delete abc123 --delete-from-integration`\n )\n .action(handleAgentsDelete);\n\n // agents sync <platform>\n agents\n .command('sync <platform>')\n .description('Sync agents from a platform (vapi, bland, twilio)')\n .option('-f, --force', 'Force update existing agents')\n .option('--clean', 'Delete all existing agents for this platform before sync')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents sync vapi # Sync from VAPI\n $ chanl agents sync vapi --force # Force update all\n $ chanl agents sync vapi --clean # Clean sync (delete first)`\n )\n .action(handleAgentsSync);\n\n // agents sync-all\n agents\n .command('sync-all')\n .description('Sync agents from all configured platforms')\n .option('-f, --force', 'Force update existing agents')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents sync-all # Sync from all platforms\n $ chanl agents sync-all --force # Force update all`\n )\n .action(handleAgentsSyncAll);\n\n // agents import\n agents\n .command('import')\n .description('Import a specific agent from a third-party platform')\n .requiredOption('--from <platform>', 'Source platform (vapi, retell, bland)')\n .requiredOption('--agent-id <id>', 'External agent ID on the source platform')\n .option('-n, --name <name>', 'Override the agent name')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents import --from vapi --agent-id asst_abc123\n $ chanl agents import --from retell --agent-id ret_xyz --name \"My Agent\"\n $ chanl agents import --from vapi --agent-id asst_abc --json`\n )\n .action(handleAgentsImport);\n\n // agents publish\n agents\n .command('publish <agent-id>')\n .description('Publish an agent to a third-party platform')\n .requiredOption('--to <platform>', 'Target platform (vapi, retell, bland)')\n .option('--target <ext-id>', 'External agent ID to update (omit to create new)')\n .option('--with-mcp', 'Include MCP URL for tool access')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents publish agent_123 --to vapi\n $ chanl agents publish agent_123 --to vapi --with-mcp\n $ chanl agents publish agent_123 --to vapi --target ext_456\n $ chanl agents publish agent_123 --to vapi --json`\n )\n .action(handleAgentsPublish);\n\n // agents push-mcp\n agents\n .command('push-mcp <agent-id>')\n .description('Push MCP URL to a third-party agent for tool access')\n .requiredOption('--to <platform>', 'Target platform (vapi, retell, bland)')\n .option('--target <ext-id>', 'External agent ID (omit to use default)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents push-mcp agent_123 --to vapi\n $ chanl agents push-mcp agent_123 --to vapi --target ext_456\n $ chanl agents push-mcp agent_123 --to vapi --json`\n )\n .action(handleAgentsPushMcp);\n\n // agents stats\n agents\n .command('stats')\n .description('View agent statistics')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents stats # View statistics\n $ chanl agents stats --json # Output as JSON`\n )\n .action(handleAgentsStats);\n\n return agents;\n}\n\n/**\n * Format agent status with color\n */\nfunction formatStatus(status?: string): string {\n switch (status) {\n case 'active':\n return chalk.green('active');\n case 'inactive':\n return chalk.gray('inactive');\n case 'error':\n return chalk.red('error');\n case 'training':\n return chalk.cyan('training');\n case 'maintenance':\n return chalk.yellow('maintenance');\n default:\n return chalk.gray(status || 'unknown');\n }\n}\n\n/**\n * Format platform with color\n */\nfunction formatPlatform(platform?: string): string {\n switch (platform) {\n case 'vapi':\n return chalk.blue('vapi');\n case 'elevenlabs':\n return chalk.magenta('elevenlabs');\n case 'custom':\n return chalk.cyan('custom');\n default:\n return chalk.gray(platform || 'unknown');\n }\n}\n\n/**\n * Get agent template for a platform\n */\nfunction getAgentTemplate(platform: string = 'custom'): CreateAgentData {\n const baseTemplate: CreateAgentData = {\n platform: 'custom',\n name: 'My Custom Agent',\n type: 'Voice Assistant',\n status: 'inactive',\n useCase: 'support',\n description: 'A custom AI agent for customer support',\n configuration: {\n prompt: 'You are a helpful customer support agent. Be friendly and professional.',\n model: 'gpt-4o',\n },\n autoAnalysisEnabled: true,\n simulationMode: 'text',\n };\n\n if (platform === 'vapi') {\n return {\n ...baseTemplate,\n platform: 'vapi',\n platformAgentId: 'YOUR_VAPI_ASSISTANT_ID',\n name: 'VAPI Support Agent',\n description: 'VAPI-powered customer support agent',\n phoneNumbers: ['+1234567890'],\n testPhoneNumber: '+1234567890',\n configuration: {\n prompt: 'You are a helpful customer support agent.',\n model: 'gpt-4o',\n voice: 'YOUR_VOICE_ID',\n transcriber: 'deepgram',\n vapi: {\n firstMessage: 'Hello! How can I help you today?',\n webhookUrl: 'https://your-domain.com/webhooks/vapi',\n },\n },\n defaultSimulationChannel: 'websocket',\n simulationMode: 'websocket',\n };\n }\n\n if (platform === 'elevenlabs') {\n return {\n ...baseTemplate,\n platform: 'elevenlabs',\n platformAgentId: 'YOUR_ELEVENLABS_AGENT_ID',\n name: 'ElevenLabs Voice Agent',\n type: 'Text-to-Speech',\n description: 'ElevenLabs-powered voice agent',\n configuration: {\n prompt: 'You are a helpful assistant.',\n voice: 'YOUR_ELEVENLABS_VOICE_ID',\n elevenlabs: {},\n },\n };\n }\n\n return baseTemplate;\n}\n\n/**\n * Handle agents list command\n */\nasync function handleAgentsList(options: {\n platform?: string;\n status?: string;\n limit: string;\n page: string;\n}): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Fetching agents...').start();\n\n try {\n const response = await sdk.agents.list({\n provider: options.platform,\n status: options.status,\n limit: parseInt(options.limit, 10),\n page: parseInt(options.page, 10),\n });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to fetch agents', response.message);\n process.exitCode = 1;\n return;\n }\n\n const { agents, pagination } = response.data;\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n if (agents.length === 0) {\n printInfo('No agents found');\n printInfo(\"Use 'chanl agents sync vapi' to import from VAPI\");\n printInfo(\"Or 'chanl agents create --template' to create a custom agent\");\n return;\n }\n\n printBlank();\n printSimpleTable(\n ['ID', 'Name', 'Platform', 'Status', 'Created'],\n agents.map((a: Agent) => [\n a.id.slice(-12),\n a.name.slice(0, 25),\n formatPlatform(a.provider),\n formatStatus(a.status),\n formatDate(a.createdAt),\n ])\n );\n\n printBlank();\n if (pagination) {\n printInfo(`Total: ${pagination.total} agents (Page ${pagination.page} of ${pagination.totalPages})`);\n }\n } catch (error) {\n spinner.fail('Failed to fetch agents');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents get command\n */\nasync function handleAgentsGet(id: string): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Fetching agent...').start();\n\n try {\n const response = await sdk.agents.get(id);\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to fetch agent', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const agent = response.data;\n printBlank();\n console.log(chalk.bold('Agent Details:'));\n console.log(` ID: ${agent.id}`);\n console.log(` Name: ${agent.name}`);\n console.log(` Platform: ${formatPlatform(agent.provider)}`);\n console.log(` Status: ${formatStatus(agent.status)}`);\n if (agent.providerId) console.log(` Platform ID: ${agent.providerId}`);\n if (agent.description) console.log(` Description: ${agent.description}`);\n console.log(` Created: ${formatDate(agent.createdAt)}`);\n console.log(` Updated: ${formatDate(agent.updatedAt)}`);\n printBlank();\n } catch (error) {\n spinner.fail('Failed to fetch agent');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents create command\n */\nasync function handleAgentsCreate(options: {\n file?: string;\n template?: string | boolean;\n}): Promise<void> {\n // Handle template output\n if (options.template !== undefined) {\n const platform = typeof options.template === 'string' ? options.template : 'custom';\n const template = getAgentTemplate(platform);\n console.log(JSON.stringify(template, null, 2));\n return;\n }\n\n // Require file for actual creation\n if (!options.file) {\n printError('Missing required option', \"Use '-f <file>' to specify agent data or '--template [platform]' to get a template\");\n process.exitCode = 1;\n return;\n }\n\n const sdk = createSdk();\n if (!sdk) return;\n\n // Read and parse the file\n let agentData: CreateAgentData;\n try {\n const content = readFileSync(options.file, 'utf-8');\n agentData = JSON.parse(content);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Failed to read file', message);\n process.exitCode = 1;\n return;\n }\n\n const spinner = ora('Creating agent...').start();\n\n try {\n const response = await sdk.agents.create(agentData);\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to create agent', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const agent = response.data;\n printSuccess(`Agent created: ${agent.name}`);\n printLabel('ID', agent.id);\n printLabel('Platform', agent.provider || 'custom');\n } catch (error) {\n spinner.fail('Failed to create agent');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents update command\n */\nasync function handleAgentsUpdate(\n id: string,\n options: { file?: string; syncToVapi?: boolean }\n): Promise<void> {\n if (!options.file) {\n printError('Missing required option', \"Use '-f <file>' to specify update data\");\n process.exitCode = 1;\n return;\n }\n\n const sdk = createSdk();\n if (!sdk) return;\n\n // Read and parse the file\n let updateData: Partial<CreateAgentData> & { syncToVapi?: boolean };\n try {\n const content = readFileSync(options.file, 'utf-8');\n updateData = JSON.parse(content);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Failed to read file', message);\n process.exitCode = 1;\n return;\n }\n\n // Add syncToVapi flag if specified\n if (options.syncToVapi) {\n updateData.syncToVapi = true;\n }\n\n const spinner = ora('Updating agent...').start();\n\n try {\n const response = await sdk.agents.update(id, updateData);\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to update agent', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const agent = response.data;\n printSuccess(`Agent updated: ${agent.name}`);\n if (options.syncToVapi) {\n printInfo('Changes synced to VAPI');\n }\n } catch (error) {\n spinner.fail('Failed to update agent');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents delete command\n */\nasync function handleAgentsDelete(\n id: string,\n options: { yes?: boolean; deleteFromIntegration?: boolean }\n): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n if (!options.yes) {\n printInfo(`About to delete agent: ${id}`);\n if (options.deleteFromIntegration) {\n printInfo('This will also delete the agent from the integration platform');\n }\n printInfo(\"Use '--yes' flag to skip this confirmation\");\n }\n\n const spinner = ora('Deleting agent...').start();\n\n try {\n const response = await sdk.agents.delete(id, {\n deleteFromIntegration: options.deleteFromIntegration,\n });\n\n spinner.stop();\n\n if (!response.success) {\n printError('Failed to delete agent', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson({ success: true, deleted: id });\n return;\n }\n\n printSuccess(`Agent deleted: ${id}`);\n } catch (error) {\n spinner.fail('Failed to delete agent');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents sync command\n */\nasync function handleAgentsSync(\n platform: string,\n options: { force?: boolean; clean?: boolean }\n): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const validPlatforms = ['vapi', 'bland', 'twilio'];\n if (!validPlatforms.includes(platform)) {\n printError('Invalid platform', `Valid platforms: ${validPlatforms.join(', ')}`);\n process.exitCode = 1;\n return;\n }\n\n const spinner = ora(`Syncing agents from ${platform}...`).start();\n\n try {\n const response = await sdk.agents.sync(platform as 'vapi' | 'bland' | 'twilio', {\n forceUpdate: options.force,\n cleanBeforeSync: options.clean,\n });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to sync agents', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const result = response.data as SyncAgentsResult;\n printBlank();\n console.log(chalk.bold('Sync Results:'));\n console.log(` Processed: ${result.processed}`);\n console.log(` Created: ${chalk.green(result.created.toString())}`);\n console.log(` Updated: ${chalk.cyan(result.updated.toString())}`);\n if (result.errors > 0) {\n console.log(` Errors: ${chalk.red(result.errors.toString())}`);\n }\n\n if (result.details && result.details.length > 0) {\n console.log(chalk.bold('\\nDetails:'));\n for (const detail of result.details.slice(0, 10)) {\n const statusColor =\n detail.status === 'created'\n ? chalk.green\n : detail.status === 'updated'\n ? chalk.cyan\n : detail.status === 'error'\n ? chalk.red\n : chalk.gray;\n console.log(` ${detail.name.slice(0, 30)}: ${statusColor(detail.status)}`);\n }\n if (result.details.length > 10) {\n printInfo(`... and ${result.details.length - 10} more`);\n }\n }\n\n printBlank();\n } catch (error) {\n spinner.fail('Failed to sync agents');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents sync-all command\n */\nasync function handleAgentsSyncAll(options: { force?: boolean }): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Syncing agents from all platforms...').start();\n\n try {\n const response = await sdk.agents.syncAll({\n forceUpdate: options.force,\n });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to sync agents', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const result = response.data as SyncAgentsResult;\n printSuccess(result.message || 'Sync completed');\n console.log(` Processed: ${result.processed}`);\n console.log(` Created: ${chalk.green(result.created.toString())}`);\n console.log(` Updated: ${chalk.cyan(result.updated.toString())}`);\n if (result.errors > 0) {\n console.log(` Errors: ${chalk.red(result.errors.toString())}`);\n }\n printBlank();\n } catch (error) {\n spinner.fail('Failed to sync agents');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents stats command\n */\nasync function handleAgentsImport(options: {\n from: string;\n agentId: string;\n name?: string;\n}): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora(`Importing agent from ${options.from}...`).start();\n\n try {\n const response = await sdk.agents.importFromPlatform({\n platform: options.from,\n externalAgentId: options.agentId,\n ...(options.name ? { name: options.name } : {}),\n });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Import failed', response.message || 'Could not import agent');\n process.exitCode = 1;\n return;\n }\n\n const agent = response.data;\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n printBlank();\n printSuccess(`Agent imported from ${options.from}`);\n printBlank();\n printLabel('Name', agent.name);\n printLabel('Chanl ID', agent.id);\n printLabel('Platform', (agent as any).platform || options.from);\n printLabel('External ID', (agent as any).platformAgentId || options.agentId);\n printLabel('Status', agent.status || 'active');\n if (agent.deployments?.length) {\n const dep = agent.deployments[0]!;\n printLabel('Deployment', `${dep.orchestrator} → ${dep.externalId} (${dep.status})`);\n }\n printBlank();\n } catch (error) {\n spinner.fail('Import failed');\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', errorMessage);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents publish command\n */\nasync function handleAgentsPublish(\n agentId: string,\n options: {\n to: string;\n target?: string;\n withMcp?: boolean;\n },\n): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora(`Publishing agent to ${options.to}...`).start();\n\n try {\n const response = await sdk.agents.publish(agentId, {\n platform: options.to,\n ...(options.target ? { targetExternalId: options.target } : {}),\n ...(options.withMcp ? { includeMcp: true } : {}),\n });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Publish failed', response.message || 'Could not publish agent');\n process.exitCode = 1;\n return;\n }\n\n const result = response.data;\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n printBlank();\n printSuccess(`Agent ${result.action} on ${result.platform}`);\n printBlank();\n printLabel('Action', result.action);\n printLabel('Platform', result.platform);\n printLabel('External ID', result.externalId);\n printLabel('Status', result.status);\n if (result.mcpUrl) {\n printLabel('MCP URL', result.mcpUrl);\n }\n printBlank();\n } catch (error) {\n spinner.fail('Publish failed');\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', errorMessage);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents push-mcp command\n */\nasync function handleAgentsPushMcp(\n agentId: string,\n options: {\n to: string;\n target?: string;\n },\n): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora(`Pushing MCP URL to ${options.to}...`).start();\n\n try {\n const response = await sdk.agents.pushMcp(agentId, {\n platform: options.to,\n ...(options.target ? { targetExternalId: options.target } : {}),\n });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Push MCP failed', response.message || 'Could not push MCP URL');\n process.exitCode = 1;\n return;\n }\n\n const result = response.data;\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n printBlank();\n printSuccess(`MCP URL pushed to ${result.platform}`);\n printBlank();\n printLabel('MCP URL', result.mcpUrl);\n printLabel('Platform', result.platform);\n printLabel('External ID', result.externalId);\n printLabel('Status', result.status);\n printBlank();\n } catch (error) {\n spinner.fail('Push MCP failed');\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', errorMessage);\n process.exitCode = 1;\n }\n}\n\nasync function handleAgentsStats(): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Fetching statistics...').start();\n\n try {\n const response = await sdk.agents.getStats();\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to fetch statistics', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const stats = response.data;\n printBlank();\n console.log(chalk.bold('Agent Statistics:'));\n console.log(chalk.dim('─'.repeat(40)));\n console.log(` Total Agents: ${stats.totalAgents}`);\n console.log(` Average Score: ${stats.avgScore !== null ? `${stats.avgScore.toFixed(1)}%` : '-'}`);\n console.log(` Tool Failures: ${stats.toolFailures}`);\n console.log(` Top Provider: ${stats.topProvider || '-'}`);\n\n if (stats.byPlatform && Object.keys(stats.byPlatform).length > 0) {\n console.log(chalk.bold('\\n By Platform:'));\n for (const [platform, count] of Object.entries(stats.byPlatform)) {\n console.log(` ${formatPlatform(platform)}: ${count}`);\n }\n }\n\n if (stats.byStatus && Object.keys(stats.byStatus).length > 0) {\n console.log(chalk.bold('\\n By Status:'));\n for (const [status, count] of Object.entries(stats.byStatus)) {\n console.log(` ${formatStatus(status)}: ${count}`);\n }\n }\n\n printBlank();\n } catch (error) {\n spinner.fail('Failed to fetch statistics');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/commands/agents.ts"],"sourcesContent":["import { Command } from 'commander';\nimport ora from 'ora';\nimport chalk from 'chalk';\nimport { readFileSync } from 'fs';\nimport type { Agent, AgentTemplateSummary, CreateAgentData, SyncAgentsResult } from '@chanl/sdk';\nimport { createSdk } from '../utils/sdk-factory.js';\nimport {\n printError,\n printSuccess,\n printInfo,\n printBlank,\n printSimpleTable,\n printLabel,\n isJsonOutput,\n printJson,\n formatDate,\n} from '../utils/output.js';\n\n/**\n * Create the agents command group\n */\nexport function createAgentsCommand(): Command {\n const agents = new Command('agents')\n .description('Manage AI agents (VAPI, ElevenLabs, custom)')\n .addHelpText(\n 'after',\n `\nWhat are Agents?\n Agents are AI-powered voice assistants from various platforms (VAPI, ElevenLabs)\n or custom implementations. They can be tested with scenarios and analyzed with\n scorecards.\n\nQuick Start:\n $ chanl agents list # List all agents\n $ chanl agents get <id> # View agent details\n $ chanl agents sync vapi # Sync from VAPI\n $ chanl agents templates # List provisionable templates\n $ chanl agents create --from-template lead-qualifier --name \"Lead Gen Bot\"\n $ chanl agents create --template vapi # Generate local VAPI scaffold\n $ chanl agents stats # View statistics\n\nWorkflow:\n 1. Sync agents from your platform (vapi, elevenlabs)\n 2. Or create custom agents with 'create -f agent.json'\n 3. Test agents with 'chanl scenarios run <id> --agent <agentId>'\n 4. Analyze results with 'chanl calls analysis <id>'`\n );\n\n // agents list\n agents\n .command('list')\n .description('List all agents')\n .option('-p, --platform <platform>', 'Filter by platform (vapi, elevenlabs, custom)')\n .option('-s, --status <status>', 'Filter by status (active, inactive)')\n .option('-l, --limit <number>', 'Number of items per page', '20')\n .option('--page <number>', 'Page number', '1')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents list # List all agents\n $ chanl agents list --platform vapi # Filter by platform\n $ chanl agents list --status active # Only active agents\n $ chanl agents list --json # Output as JSON`\n )\n .action(handleAgentsList);\n\n // agents get <id>\n agents\n .command('get <id>')\n .description('Get agent details')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents get abc123 # Get agent details\n $ chanl agents get abc123 --json # Output as JSON`\n )\n .action(handleAgentsGet);\n\n // agents templates\n agents\n .command('templates')\n .description('List registry templates you can provision an agent from')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents templates # List registry templates\n $ chanl agents templates --json # Output as JSON\n\nProvision one with:\n $ chanl agents create --from-template lead-qualifier --name \"My Agent\"`\n )\n .action(handleAgentsTemplates);\n\n // agents create\n agents\n .command('create')\n .description('Create a new agent')\n .option('-f, --file <path>', 'Path to JSON file with agent data')\n .option('--template [platform]', 'Output a local scaffold JSON (vapi, elevenlabs, custom) — no server call')\n .option('--from-template <templateId>', \"Provision from a registry template (see 'chanl agents templates')\")\n .option('-n, --name <name>', 'Agent name (used with --from-template)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents create --from-template lead-qualifier --name \"Lead Gen Bot\"\n # Provision from registry template\n $ chanl agents create --template vapi > agent.json # VAPI scaffold JSON (local, no server call)\n $ chanl agents create --template custom > agent.json # Custom scaffold JSON\n $ chanl agents create -f agent.json # Create from file\n\n'--from-template' creates a real, configured agent via the platform's template\nregistry (run 'chanl agents templates' to see what's available). '--template'\njust prints a local JSON scaffold to fill in yourself.`\n )\n .action(handleAgentsCreate);\n\n // agents update <id>\n agents\n .command('update <id>')\n .description('Update an existing agent')\n .option('-f, --file <path>', 'Path to JSON file with update data')\n .option('--sync-to-vapi', 'Sync changes back to VAPI platform')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents update abc123 -f updates.json\n $ chanl agents update abc123 -f updates.json --sync-to-vapi`\n )\n .action(handleAgentsUpdate);\n\n // agents delete <id>\n agents\n .command('delete <id>')\n .description('Delete an agent')\n .option('-y, --yes', 'Skip confirmation prompt')\n .option('--delete-from-integration', 'Also delete from platform (VAPI, etc.)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents delete abc123\n $ chanl agents delete abc123 --delete-from-integration`\n )\n .action(handleAgentsDelete);\n\n // agents sync <platform>\n agents\n .command('sync <platform>')\n .description('Sync agents from a platform (vapi, bland, twilio)')\n .option('-f, --force', 'Force update existing agents')\n .option('--clean', 'Delete all existing agents for this platform before sync')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents sync vapi # Sync from VAPI\n $ chanl agents sync vapi --force # Force update all\n $ chanl agents sync vapi --clean # Clean sync (delete first)`\n )\n .action(handleAgentsSync);\n\n // agents sync-all\n agents\n .command('sync-all')\n .description('Sync agents from all configured platforms')\n .option('-f, --force', 'Force update existing agents')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents sync-all # Sync from all platforms\n $ chanl agents sync-all --force # Force update all`\n )\n .action(handleAgentsSyncAll);\n\n // agents import\n agents\n .command('import')\n .description('Import a specific agent from a third-party platform')\n .requiredOption('--from <platform>', 'Source platform (vapi, retell, bland)')\n .requiredOption('--agent-id <id>', 'External agent ID on the source platform')\n .option('-n, --name <name>', 'Override the agent name')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents import --from vapi --agent-id asst_abc123\n $ chanl agents import --from retell --agent-id ret_xyz --name \"My Agent\"\n $ chanl agents import --from vapi --agent-id asst_abc --json`\n )\n .action(handleAgentsImport);\n\n // agents publish\n agents\n .command('publish <agent-id>')\n .description('Publish an agent to a third-party platform')\n .requiredOption('--to <platform>', 'Target platform (vapi, retell, bland)')\n .option('--target <ext-id>', 'External agent ID to update (omit to create new)')\n .option('--with-mcp', 'Include MCP URL for tool access')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents publish agent_123 --to vapi\n $ chanl agents publish agent_123 --to vapi --with-mcp\n $ chanl agents publish agent_123 --to vapi --target ext_456\n $ chanl agents publish agent_123 --to vapi --json`\n )\n .action(handleAgentsPublish);\n\n // agents push-mcp\n agents\n .command('push-mcp <agent-id>')\n .description('Push MCP URL to a third-party agent for tool access')\n .requiredOption('--to <platform>', 'Target platform (vapi, retell, bland)')\n .option('--target <ext-id>', 'External agent ID (omit to use default)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents push-mcp agent_123 --to vapi\n $ chanl agents push-mcp agent_123 --to vapi --target ext_456\n $ chanl agents push-mcp agent_123 --to vapi --json`\n )\n .action(handleAgentsPushMcp);\n\n // agents clone\n agents\n .command('clone <id>')\n .description('Clone an agent with optional overrides')\n .option('-n, --name <name>', 'New agent name')\n .option('--model <provider/model>', 'Override model (e.g., anthropic/claude-sonnet-4-5-20250929)')\n .option('--type <type>', 'Override type (voice, text, hybrid)')\n .option('--platform <platform>', 'Override platform')\n .option('--prompt <text>', 'Override system prompt')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents clone agent_abc -n \"Copy of Bot\"\n $ chanl agents clone agent_abc --model openai/gpt-4o-mini --type text\n $ chanl agents clone agent_abc --json`\n )\n .action(handleAgentsClone);\n\n // agents report\n agents\n .command('report <agentId>')\n .description('View scenario test report for an agent')\n .option('--from <date>', 'Report start date (ISO)')\n .option('--to <date>', 'Report end date (ISO)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents report agent_abc\n $ chanl agents report agent_abc --json`\n )\n .action(handleAgentsReport);\n\n // agents stats\n agents\n .command('stats')\n .description('View agent statistics')\n .addHelpText(\n 'after',\n `\nExamples:\n $ chanl agents stats # View statistics\n $ chanl agents stats --json # Output as JSON`\n )\n .action(handleAgentsStats);\n\n return agents;\n}\n\n/**\n * Format agent status with color\n */\nfunction formatStatus(status?: string): string {\n switch (status) {\n case 'active':\n return chalk.green('active');\n case 'inactive':\n return chalk.gray('inactive');\n case 'error':\n return chalk.red('error');\n case 'training':\n return chalk.cyan('training');\n case 'maintenance':\n return chalk.yellow('maintenance');\n default:\n return chalk.gray(status || 'unknown');\n }\n}\n\n/**\n * Format platform with color\n */\nfunction formatPlatform(platform?: string): string {\n switch (platform) {\n case 'vapi':\n return chalk.blue('vapi');\n case 'elevenlabs':\n return chalk.magenta('elevenlabs');\n case 'custom':\n return chalk.cyan('custom');\n default:\n return chalk.gray(platform || 'unknown');\n }\n}\n\n/**\n * Get agent template for a platform\n */\nfunction getAgentTemplate(platform: string = 'custom'): CreateAgentData {\n const baseTemplate: CreateAgentData = {\n platform: 'custom',\n name: 'My Custom Agent',\n type: 'Voice Assistant',\n status: 'inactive',\n useCase: 'support',\n description: 'A custom AI agent for customer support',\n configuration: {\n prompt: 'You are a helpful customer support agent. Be friendly and professional.',\n model: 'gpt-4o',\n },\n autoAnalysisEnabled: true,\n simulationMode: 'text',\n };\n\n if (platform === 'vapi') {\n return {\n ...baseTemplate,\n platform: 'vapi',\n platformAgentId: 'YOUR_VAPI_ASSISTANT_ID',\n name: 'VAPI Support Agent',\n description: 'VAPI-powered customer support agent',\n phoneNumbers: ['+1234567890'],\n testPhoneNumber: '+1234567890',\n configuration: {\n prompt: 'You are a helpful customer support agent.',\n model: 'gpt-4o',\n voice: 'YOUR_VOICE_ID',\n transcriber: 'deepgram',\n vapi: {\n firstMessage: 'Hello! How can I help you today?',\n webhookUrl: 'https://your-domain.com/webhooks/vapi',\n },\n },\n defaultSimulationChannel: 'websocket',\n simulationMode: 'websocket',\n };\n }\n\n if (platform === 'elevenlabs') {\n return {\n ...baseTemplate,\n platform: 'elevenlabs',\n platformAgentId: 'YOUR_ELEVENLABS_AGENT_ID',\n name: 'ElevenLabs Voice Agent',\n type: 'Text-to-Speech',\n description: 'ElevenLabs-powered voice agent',\n configuration: {\n prompt: 'You are a helpful assistant.',\n voice: 'YOUR_ELEVENLABS_VOICE_ID',\n elevenlabs: {},\n },\n };\n }\n\n return baseTemplate;\n}\n\n/**\n * Handle agents list command\n */\nasync function handleAgentsList(options: {\n platform?: string;\n status?: string;\n limit: string;\n page: string;\n}): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Fetching agents...').start();\n\n try {\n const response = await sdk.agents.list({\n provider: options.platform,\n status: options.status,\n limit: parseInt(options.limit, 10),\n page: parseInt(options.page, 10),\n });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to fetch agents', response.message);\n process.exitCode = 1;\n return;\n }\n\n const { agents, pagination } = response.data;\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n if (agents.length === 0) {\n printInfo('No agents found');\n printInfo(\"Use 'chanl agents sync vapi' to import from VAPI\");\n printInfo(\"Or 'chanl agents create --template' to create a custom agent\");\n return;\n }\n\n printBlank();\n printSimpleTable(\n ['ID', 'Name', 'Platform', 'Status', 'Created'],\n agents.map((a: Agent) => [\n a.id.slice(-12),\n a.name.slice(0, 25),\n formatPlatform(a.provider),\n formatStatus(a.status),\n formatDate(a.createdAt),\n ])\n );\n\n printBlank();\n if (pagination) {\n printInfo(`Total: ${pagination.total} agents (Page ${pagination.page} of ${pagination.totalPages})`);\n }\n } catch (error) {\n spinner.fail('Failed to fetch agents');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents get command\n */\nasync function handleAgentsGet(id: string): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Fetching agent...').start();\n\n try {\n const response = await sdk.agents.get(id);\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to fetch agent', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const agent = response.data;\n printBlank();\n console.log(chalk.bold('Agent Details:'));\n console.log(` ID: ${agent.id}`);\n console.log(` Name: ${agent.name}`);\n console.log(` Platform: ${formatPlatform(agent.provider)}`);\n console.log(` Status: ${formatStatus(agent.status)}`);\n if (agent.providerId) console.log(` Platform ID: ${agent.providerId}`);\n if (agent.description) console.log(` Description: ${agent.description}`);\n console.log(` Created: ${formatDate(agent.createdAt)}`);\n console.log(` Updated: ${formatDate(agent.updatedAt)}`);\n printBlank();\n } catch (error) {\n spinner.fail('Failed to fetch agent');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents templates command\n */\nasync function handleAgentsTemplates(): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Fetching templates...').start();\n\n try {\n const response = await sdk.agents.listTemplates();\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to fetch templates', response.message);\n process.exitCode = 1;\n return;\n }\n\n const { templates } = response.data;\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n if (templates.length === 0) {\n printInfo('No templates available');\n return;\n }\n\n printBlank();\n printSimpleTable(\n ['ID', 'Name', 'Version', 'Description'],\n templates.map((t: AgentTemplateSummary) => [t.id, t.name, t.version.toString(), t.description])\n );\n printBlank();\n printInfo('Provision one with: chanl agents create --from-template <id> --name \"My Agent\"');\n } catch (error) {\n spinner.fail('Failed to fetch templates');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle provisioning an agent from a registry template\n * (the --from-template path of `agents create`)\n */\nasync function handleAgentsCreateFromTemplate(templateId: string, name?: string): Promise<void> {\n if (!name) {\n printError('Missing required option', \"Use '-n, --name <name>' together with --from-template\");\n process.exitCode = 1;\n return;\n }\n\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora(`Provisioning agent from template '${templateId}'...`).start();\n\n try {\n const response = await sdk.agents.createFromTemplate(templateId, { name });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to create agent from template', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const agent = response.data;\n printSuccess(`Agent created from template: ${agent.name}`);\n printLabel('ID', agent.id);\n printLabel('Template', templateId);\n } catch (error) {\n spinner.fail('Failed to create agent from template');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents create command\n */\nasync function handleAgentsCreate(options: {\n file?: string;\n template?: string | boolean;\n fromTemplate?: string;\n name?: string;\n}): Promise<void> {\n // Handle local scaffold output (no server call)\n if (options.template !== undefined) {\n const platform = typeof options.template === 'string' ? options.template : 'custom';\n const template = getAgentTemplate(platform);\n console.log(JSON.stringify(template, null, 2));\n return;\n }\n\n // Handle real provisioning from the platform's template registry\n if (options.fromTemplate) {\n await handleAgentsCreateFromTemplate(options.fromTemplate, options.name);\n return;\n }\n\n // Require file for actual creation\n if (!options.file) {\n printError(\n 'Missing required option',\n \"Use '-f <file>' for agent data, '--from-template <id>' to provision from a registry template, or '--template [platform]' for a local scaffold\"\n );\n process.exitCode = 1;\n return;\n }\n\n const sdk = createSdk();\n if (!sdk) return;\n\n // Read and parse the file\n let agentData: CreateAgentData;\n try {\n const content = readFileSync(options.file, 'utf-8');\n agentData = JSON.parse(content);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Failed to read file', message);\n process.exitCode = 1;\n return;\n }\n\n const spinner = ora('Creating agent...').start();\n\n try {\n const response = await sdk.agents.create(agentData);\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to create agent', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const agent = response.data;\n printSuccess(`Agent created: ${agent.name}`);\n printLabel('ID', agent.id);\n printLabel('Platform', agent.provider || 'custom');\n } catch (error) {\n spinner.fail('Failed to create agent');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents update command\n */\nasync function handleAgentsUpdate(\n id: string,\n options: { file?: string; syncToVapi?: boolean }\n): Promise<void> {\n if (!options.file) {\n printError('Missing required option', \"Use '-f <file>' to specify update data\");\n process.exitCode = 1;\n return;\n }\n\n const sdk = createSdk();\n if (!sdk) return;\n\n // Read and parse the file\n let updateData: Partial<CreateAgentData> & { syncToVapi?: boolean };\n try {\n const content = readFileSync(options.file, 'utf-8');\n updateData = JSON.parse(content);\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Failed to read file', message);\n process.exitCode = 1;\n return;\n }\n\n // Add syncToVapi flag if specified\n if (options.syncToVapi) {\n updateData.syncToVapi = true;\n }\n\n const spinner = ora('Updating agent...').start();\n\n try {\n const response = await sdk.agents.update(id, updateData);\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to update agent', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const agent = response.data;\n printSuccess(`Agent updated: ${agent.name}`);\n if (options.syncToVapi) {\n printInfo('Changes synced to VAPI');\n }\n } catch (error) {\n spinner.fail('Failed to update agent');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents delete command\n */\nasync function handleAgentsDelete(\n id: string,\n options: { yes?: boolean; deleteFromIntegration?: boolean }\n): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n if (!options.yes) {\n printInfo(`About to delete agent: ${id}`);\n if (options.deleteFromIntegration) {\n printInfo('This will also delete the agent from the integration platform');\n }\n printInfo(\"Use '--yes' flag to skip this confirmation\");\n }\n\n const spinner = ora('Deleting agent...').start();\n\n try {\n const response = await sdk.agents.delete(id, {\n deleteFromIntegration: options.deleteFromIntegration,\n });\n\n spinner.stop();\n\n if (!response.success) {\n printError('Failed to delete agent', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson({ success: true, deleted: id });\n return;\n }\n\n printSuccess(`Agent deleted: ${id}`);\n } catch (error) {\n spinner.fail('Failed to delete agent');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents sync command\n */\nasync function handleAgentsSync(\n platform: string,\n options: { force?: boolean; clean?: boolean }\n): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const validPlatforms = ['vapi', 'bland', 'twilio'];\n if (!validPlatforms.includes(platform)) {\n printError('Invalid platform', `Valid platforms: ${validPlatforms.join(', ')}`);\n process.exitCode = 1;\n return;\n }\n\n const spinner = ora(`Syncing agents from ${platform}...`).start();\n\n try {\n const response = await sdk.agents.sync(platform as 'vapi' | 'bland' | 'twilio', {\n forceUpdate: options.force,\n cleanBeforeSync: options.clean,\n });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to sync agents', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const result = response.data as SyncAgentsResult;\n printBlank();\n console.log(chalk.bold('Sync Results:'));\n console.log(` Processed: ${result.processed}`);\n console.log(` Created: ${chalk.green(result.created.toString())}`);\n console.log(` Updated: ${chalk.cyan(result.updated.toString())}`);\n if (result.errors > 0) {\n console.log(` Errors: ${chalk.red(result.errors.toString())}`);\n }\n\n if (result.details && result.details.length > 0) {\n console.log(chalk.bold('\\nDetails:'));\n for (const detail of result.details.slice(0, 10)) {\n const statusColor =\n detail.status === 'created'\n ? chalk.green\n : detail.status === 'updated'\n ? chalk.cyan\n : detail.status === 'error'\n ? chalk.red\n : chalk.gray;\n console.log(` ${detail.name.slice(0, 30)}: ${statusColor(detail.status)}`);\n }\n if (result.details.length > 10) {\n printInfo(`... and ${result.details.length - 10} more`);\n }\n }\n\n printBlank();\n } catch (error) {\n spinner.fail('Failed to sync agents');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents sync-all command\n */\nasync function handleAgentsSyncAll(options: { force?: boolean }): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Syncing agents from all platforms...').start();\n\n try {\n const response = await sdk.agents.syncAll({\n forceUpdate: options.force,\n });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to sync agents', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const result = response.data as SyncAgentsResult;\n printSuccess(result.message || 'Sync completed');\n console.log(` Processed: ${result.processed}`);\n console.log(` Created: ${chalk.green(result.created.toString())}`);\n console.log(` Updated: ${chalk.cyan(result.updated.toString())}`);\n if (result.errors > 0) {\n console.log(` Errors: ${chalk.red(result.errors.toString())}`);\n }\n printBlank();\n } catch (error) {\n spinner.fail('Failed to sync agents');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents stats command\n */\nasync function handleAgentsImport(options: {\n from: string;\n agentId: string;\n name?: string;\n}): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora(`Importing agent from ${options.from}...`).start();\n\n try {\n const response = await sdk.agents.importFromPlatform({\n platform: options.from,\n externalAgentId: options.agentId,\n ...(options.name ? { name: options.name } : {}),\n });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Import failed', response.message || 'Could not import agent');\n process.exitCode = 1;\n return;\n }\n\n const agent = response.data;\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n printBlank();\n printSuccess(`Agent imported from ${options.from}`);\n printBlank();\n printLabel('Name', agent.name);\n printLabel('Chanl ID', agent.id);\n printLabel('Platform', (agent as any).platform || options.from);\n printLabel('External ID', (agent as any).platformAgentId || options.agentId);\n printLabel('Status', agent.status || 'active');\n if (agent.deployments?.length) {\n const dep = agent.deployments[0]!;\n printLabel('Deployment', `${dep.orchestrator} → ${dep.externalId} (${dep.status})`);\n }\n printBlank();\n } catch (error) {\n spinner.fail('Import failed');\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', errorMessage);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents publish command\n */\nasync function handleAgentsPublish(\n agentId: string,\n options: {\n to: string;\n target?: string;\n withMcp?: boolean;\n },\n): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora(`Publishing agent to ${options.to}...`).start();\n\n try {\n const response = await sdk.agents.publish(agentId, {\n platform: options.to,\n ...(options.target ? { targetExternalId: options.target } : {}),\n ...(options.withMcp ? { includeMcp: true } : {}),\n });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Publish failed', response.message || 'Could not publish agent');\n process.exitCode = 1;\n return;\n }\n\n const result = response.data;\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n printBlank();\n printSuccess(`Agent ${result.action} on ${result.platform}`);\n printBlank();\n printLabel('Action', result.action);\n printLabel('Platform', result.platform);\n printLabel('External ID', result.externalId);\n printLabel('Status', result.status);\n if (result.mcpUrl) {\n printLabel('MCP URL', result.mcpUrl);\n }\n printBlank();\n } catch (error) {\n spinner.fail('Publish failed');\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', errorMessage);\n process.exitCode = 1;\n }\n}\n\n/**\n * Handle agents push-mcp command\n */\nasync function handleAgentsPushMcp(\n agentId: string,\n options: {\n to: string;\n target?: string;\n },\n): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora(`Pushing MCP URL to ${options.to}...`).start();\n\n try {\n const response = await sdk.agents.pushMcp(agentId, {\n platform: options.to,\n ...(options.target ? { targetExternalId: options.target } : {}),\n });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Push MCP failed', response.message || 'Could not push MCP URL');\n process.exitCode = 1;\n return;\n }\n\n const result = response.data;\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n printBlank();\n printSuccess(`MCP URL pushed to ${result.platform}`);\n printBlank();\n printLabel('MCP URL', result.mcpUrl);\n printLabel('Platform', result.platform);\n printLabel('External ID', result.externalId);\n printLabel('Status', result.status);\n printBlank();\n } catch (error) {\n spinner.fail('Push MCP failed');\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', errorMessage);\n process.exitCode = 1;\n }\n}\n\nasync function handleAgentsStats(): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Fetching statistics...').start();\n\n try {\n const response = await sdk.agents.getStats();\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to fetch statistics', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const stats = response.data;\n printBlank();\n console.log(chalk.bold('Agent Statistics:'));\n console.log(chalk.dim('─'.repeat(40)));\n console.log(` Total Agents: ${stats.totalAgents}`);\n console.log(` Average Score: ${stats.avgScore !== null ? `${stats.avgScore.toFixed(1)}%` : '-'}`);\n console.log(` Tool Failures: ${stats.toolFailures}`);\n console.log(` Top Provider: ${stats.topProvider || '-'}`);\n\n if (stats.byPlatform && Object.keys(stats.byPlatform).length > 0) {\n console.log(chalk.bold('\\n By Platform:'));\n for (const [platform, count] of Object.entries(stats.byPlatform)) {\n console.log(` ${formatPlatform(platform)}: ${count}`);\n }\n }\n\n if (stats.byStatus && Object.keys(stats.byStatus).length > 0) {\n console.log(chalk.bold('\\n By Status:'));\n for (const [status, count] of Object.entries(stats.byStatus)) {\n console.log(` ${formatStatus(status)}: ${count}`);\n }\n }\n\n printBlank();\n } catch (error) {\n spinner.fail('Failed to fetch statistics');\n const message = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', message);\n process.exitCode = 1;\n }\n}\n\nasync function handleAgentsClone(\n id: string,\n options: {\n name?: string;\n model?: string;\n type?: string;\n platform?: string;\n prompt?: string;\n },\n): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Cloning agent...').start();\n\n try {\n const response = await sdk.agents.clone(id, {\n name: options.name,\n model: options.model,\n type: options.type,\n platform: options.platform as CreateAgentData['platform'] | undefined,\n prompt: options.prompt,\n });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Clone failed', response.message);\n process.exitCode = 1;\n return;\n }\n\n const cloned = response.data;\n\n if (isJsonOutput()) {\n printJson(cloned);\n return;\n }\n\n printBlank();\n console.log(chalk.green(`Cloned agent: ${cloned.id}`));\n printLabel('Name', cloned.name);\n if (cloned.type) printLabel('Type', cloned.type);\n if (cloned.platform) printLabel('Platform', cloned.platform);\n const model = (cloned.configuration as { model?: { provider?: string; model?: string } })?.model;\n if (model?.provider && model?.model) {\n printLabel('Model', `${model.provider} / ${model.model}`);\n }\n printLabel('Cloned from', id);\n printBlank();\n } catch (error) {\n spinner.fail('Clone failed');\n printError('Error', error instanceof Error ? error.message : 'Unknown error');\n process.exitCode = 1;\n }\n}\n\nasync function handleAgentsReport(\n agentId: string,\n options: { from?: string; to?: string },\n): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n const spinner = ora('Fetching agent test report...').start();\n\n try {\n const response = await sdk.scenarios.getAgentTestReport(agentId, {\n from: options.from,\n to: options.to,\n });\n\n spinner.stop();\n\n if (!response.success || !response.data) {\n printError('Failed to fetch report', response.message);\n process.exitCode = 1;\n return;\n }\n\n if (isJsonOutput()) {\n printJson(response.data);\n return;\n }\n\n const report = response.data;\n printBlank();\n console.log(chalk.bold(`Test Report: ${agentId}`));\n console.log(` Total runs: ${report.totalRuns} Passed: ${report.passed} Failed: ${report.failed}`);\n console.log(` Avg score: ${report.avgScore}% Success rate: ${report.successRate}%`);\n\n if (report.scenarios?.length) {\n printBlank();\n printSimpleTable(\n ['Scenario', 'Runs', 'Avg Score', 'Last Passed'],\n report.scenarios.map((s) => [\n s.scenarioName,\n s.runs.toString(),\n `${s.avgScore}%`,\n s.lastPassed ? chalk.green('yes') : chalk.red('no'),\n ]),\n );\n }\n printBlank();\n } catch (error) {\n spinner.fail('Failed to fetch report');\n printError('Error', error instanceof Error ? error.message : 'Unknown error');\n process.exitCode = 1;\n }\n}\n"],"mappings":"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","names":[]}
@@ -17,8 +17,8 @@ function createChatCommand() {
17
17
  `
18
18
  What is Chat?
19
19
  Chat lets you test an AI agent via text in your terminal. It creates a session
20
- through interactions-service which manages the full lifecycle including
21
- transcription, billing, and evaluation.
20
+ on the Chanl platform, which manages the full lifecycle including
21
+ transcription, billing, and post-chat evaluation.
22
22
 
23
23
  Modes:
24
24
  Interactive (default): Opens a prompt loop \u2014 type messages, see agent responses.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/chat.ts"],"sourcesContent":["import { Command } from 'commander';\nimport ora from 'ora';\nimport chalk from 'chalk';\nimport { createInterface } from 'node:readline';\nimport type { ChanlSDK, ToolCall } from '@chanl/sdk';\nimport { createSdk } from '../utils/sdk-factory.js';\nimport {\n printError,\n printSuccess,\n printInfo,\n printBlank,\n isJsonOutput,\n printJson,\n} from '../utils/output.js';\n\n/**\n * Create the chat command\n */\nexport function createChatCommand(): Command {\n const chat = new Command('chat')\n .description('Start an interactive chat session with an agent')\n .argument('<agent-id>', 'ID of the agent to chat with')\n .option('-m, --message <text>', 'Send a single message and exit')\n .option('-s, --stream', 'Enable streaming responses (real-time text)')\n .option('-w, --workspace <id>', 'Workspace ID override')\n .addHelpText(\n 'after',\n `\nWhat is Chat?\n Chat lets you test an AI agent via text in your terminal. It creates a session\n through interactions-service which manages the full lifecycle including\n transcription, billing, and evaluation.\n\nModes:\n Interactive (default): Opens a prompt loop — type messages, see agent responses.\n Type 'exit', 'quit', or press Ctrl+C to end.\n\n Single message: Send one message with --message, print response, exit.\n\nStreaming:\n Use --stream for real-time text output. Text appears as the agent generates it.\n Note: streaming responses do not include tool call metadata.\n\nExamples:\n $ chanl chat abc123 # Interactive chat\n $ chanl chat abc123 --stream # Interactive with streaming\n $ chanl chat abc123 --message \"Hello\" # Single message mode\n $ chanl chat abc123 --message \"Hi\" --stream # Single message, streamed\n $ chanl chat abc123 --message \"Hi\" --json # Single message, JSON output\n $ chanl chat abc123 --workspace ws_456 # Override workspace`\n )\n .action(handleChat);\n\n return chat;\n}\n\n/**\n * Handle the chat command\n */\nasync function handleChat(\n agentId: string,\n options: { message?: string; stream?: boolean; workspace?: string },\n): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n if (options.message) {\n await handleSingleMessage(sdk, agentId, options.message, options.stream);\n } else {\n await handleInteractiveChat(sdk, agentId, options.stream);\n }\n}\n\n/**\n * Single message mode: create session, send message, print response, end session\n * Uses SDK LiveChat for session management\n */\nasync function handleSingleMessage(\n sdk: ChanlSDK,\n agentId: string,\n message: string,\n stream?: boolean,\n): Promise<void> {\n const spinner = ora('Connecting to agent...').start();\n\n try {\n const chat = await sdk.chat.session(agentId);\n spinner.text = 'Sending message...';\n\n try {\n if (stream && !isJsonOutput()) {\n // Streaming mode: show text as it arrives\n spinner.stop();\n printBlank();\n console.log(chalk.dim('You >'), message);\n process.stdout.write(chalk.cyan('Agent > '));\n\n const reply = await chat.send(message, {\n stream: true,\n onChunk: (delta) => process.stdout.write(delta),\n });\n\n // Newline after streamed text\n console.log();\n if (reply.latencyMs) {\n printBlank();\n printInfo(`Response time: ${reply.latencyMs}ms`);\n }\n printBlank();\n } else {\n // Non-streaming or JSON mode\n const reply = await chat.send(message);\n spinner.stop();\n\n if (isJsonOutput()) {\n printJson({\n sessionId: chat.sessionId,\n agentId,\n message,\n response: reply.message,\n toolCalls: reply.toolCalls,\n latencyMs: reply.latencyMs,\n });\n } else {\n printBlank();\n console.log(chalk.dim('You >'), message);\n if (reply.toolCalls?.length) {\n console.log(chalk.dim(' Tools:'));\n printToolCalls(reply.toolCalls);\n }\n console.log(chalk.cyan('Agent >'), reply.message);\n if (reply.latencyMs) {\n printBlank();\n printInfo(`Response time: ${reply.latencyMs}ms`);\n }\n printBlank();\n }\n }\n } finally {\n await chat.end();\n }\n } catch (error) {\n spinner.fail('Chat failed');\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', errorMessage);\n process.exitCode = 1;\n }\n}\n\n/**\n * Interactive mode: readline prompt loop with agent\n * Uses SDK LiveChat for session management\n */\nasync function handleInteractiveChat(\n sdk: ChanlSDK,\n agentId: string,\n stream?: boolean,\n): Promise<void> {\n const spinner = ora('Connecting to agent...').start();\n\n try {\n const chat = await sdk.chat.session(agentId);\n const agentName = chat.agentName || 'Agent';\n spinner.succeed(`Connected to ${agentName}${stream ? ' (streaming)' : ''}`);\n printInfo(\"Type 'exit' or 'quit' to end the session. Ctrl+C also works.\");\n printBlank();\n\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const prompt = (): void => {\n rl.question(chalk.bold('You > '), async (input) => {\n const trimmed = input.trim();\n\n if (!trimmed) {\n prompt();\n return;\n }\n\n if (trimmed.toLowerCase() === 'exit' || trimmed.toLowerCase() === 'quit') {\n await endSessionCleanly(chat);\n rl.close();\n return;\n }\n\n try {\n if (stream) {\n // Streaming: show text character-by-character\n process.stdout.write(chalk.cyan('Agent > '));\n const reply = await chat.send(trimmed, {\n stream: true,\n onChunk: (delta) => process.stdout.write(delta),\n });\n console.log(); // newline after stream\n if (reply.latencyMs) {\n printInfo(`${reply.latencyMs}ms`);\n }\n } else {\n const reply = await chat.send(trimmed);\n if (reply.toolCalls?.length) {\n console.log(chalk.dim(' Tools:'));\n printToolCalls(reply.toolCalls);\n }\n console.log(chalk.cyan('Agent >'), reply.message);\n }\n printBlank();\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n printError('Send failed', errorMessage);\n printBlank();\n }\n\n prompt();\n });\n };\n\n // Handle Ctrl+C gracefully\n const handleSigint = async (): Promise<void> => {\n printBlank();\n await endSessionCleanly(chat);\n rl.close();\n process.exit(0);\n };\n\n rl.on('SIGINT', () => {\n void handleSigint();\n });\n\n rl.on('close', () => {\n // Readline closed (e.g., piped input ended)\n });\n\n prompt();\n } catch (error) {\n spinner.fail('Failed to connect');\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', errorMessage);\n process.exitCode = 1;\n }\n}\n\n/**\n * Display tool calls in a readable format\n */\nfunction printToolCalls(toolCalls: ToolCall[]): void {\n for (const tc of toolCalls) {\n const statusIcon =\n tc.status === 'success'\n ? chalk.green('✓')\n : tc.status === 'error'\n ? chalk.red('✗')\n : tc.status === 'timeout'\n ? chalk.yellow('⏱')\n : chalk.dim('…');\n const duration = tc.durationMs ? chalk.dim(` (${tc.durationMs}ms)`) : '';\n const params = Object.keys(tc.parameters).length\n ? chalk.dim(` ${JSON.stringify(tc.parameters)}`)\n : '';\n\n console.log(` ${statusIcon} ${chalk.yellow(tc.name)}${params}${duration}`);\n\n if (tc.status === 'error' && tc.error) {\n console.log(` ${chalk.red(tc.error.message)}`);\n }\n }\n}\n\n/**\n * End a chat session with user feedback\n */\nasync function endSessionCleanly(\n chat: { end: () => Promise<void> },\n): Promise<void> {\n try {\n await chat.end();\n printSuccess('Session ended');\n } catch {\n printInfo('Session closed');\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/commands/chat.ts"],"sourcesContent":["import { Command } from 'commander';\nimport ora from 'ora';\nimport chalk from 'chalk';\nimport { createInterface } from 'node:readline';\nimport type { ChanlSDK, ToolCall } from '@chanl/sdk';\nimport { createSdk } from '../utils/sdk-factory.js';\nimport {\n printError,\n printSuccess,\n printInfo,\n printBlank,\n isJsonOutput,\n printJson,\n} from '../utils/output.js';\n\n/**\n * Create the chat command\n */\nexport function createChatCommand(): Command {\n const chat = new Command('chat')\n .description('Start an interactive chat session with an agent')\n .argument('<agent-id>', 'ID of the agent to chat with')\n .option('-m, --message <text>', 'Send a single message and exit')\n .option('-s, --stream', 'Enable streaming responses (real-time text)')\n .option('-w, --workspace <id>', 'Workspace ID override')\n .addHelpText(\n 'after',\n `\nWhat is Chat?\n Chat lets you test an AI agent via text in your terminal. It creates a session\n on the Chanl platform, which manages the full lifecycle including\n transcription, billing, and post-chat evaluation.\n\nModes:\n Interactive (default): Opens a prompt loop — type messages, see agent responses.\n Type 'exit', 'quit', or press Ctrl+C to end.\n\n Single message: Send one message with --message, print response, exit.\n\nStreaming:\n Use --stream for real-time text output. Text appears as the agent generates it.\n Note: streaming responses do not include tool call metadata.\n\nExamples:\n $ chanl chat abc123 # Interactive chat\n $ chanl chat abc123 --stream # Interactive with streaming\n $ chanl chat abc123 --message \"Hello\" # Single message mode\n $ chanl chat abc123 --message \"Hi\" --stream # Single message, streamed\n $ chanl chat abc123 --message \"Hi\" --json # Single message, JSON output\n $ chanl chat abc123 --workspace ws_456 # Override workspace`\n )\n .action(handleChat);\n\n return chat;\n}\n\n/**\n * Handle the chat command\n */\nasync function handleChat(\n agentId: string,\n options: { message?: string; stream?: boolean; workspace?: string },\n): Promise<void> {\n const sdk = createSdk();\n if (!sdk) return;\n\n if (options.message) {\n await handleSingleMessage(sdk, agentId, options.message, options.stream);\n } else {\n await handleInteractiveChat(sdk, agentId, options.stream);\n }\n}\n\n/**\n * Single message mode: create session, send message, print response, end session\n * Uses SDK LiveChat for session management\n */\nasync function handleSingleMessage(\n sdk: ChanlSDK,\n agentId: string,\n message: string,\n stream?: boolean,\n): Promise<void> {\n const spinner = ora('Connecting to agent...').start();\n\n try {\n const chat = await sdk.chat.session(agentId);\n spinner.text = 'Sending message...';\n\n try {\n if (stream && !isJsonOutput()) {\n // Streaming mode: show text as it arrives\n spinner.stop();\n printBlank();\n console.log(chalk.dim('You >'), message);\n process.stdout.write(chalk.cyan('Agent > '));\n\n const reply = await chat.send(message, {\n stream: true,\n onChunk: (delta) => process.stdout.write(delta),\n });\n\n // Newline after streamed text\n console.log();\n if (reply.latencyMs) {\n printBlank();\n printInfo(`Response time: ${reply.latencyMs}ms`);\n }\n printBlank();\n } else {\n // Non-streaming or JSON mode\n const reply = await chat.send(message);\n spinner.stop();\n\n if (isJsonOutput()) {\n printJson({\n sessionId: chat.sessionId,\n agentId,\n message,\n response: reply.message,\n toolCalls: reply.toolCalls,\n latencyMs: reply.latencyMs,\n });\n } else {\n printBlank();\n console.log(chalk.dim('You >'), message);\n if (reply.toolCalls?.length) {\n console.log(chalk.dim(' Tools:'));\n printToolCalls(reply.toolCalls);\n }\n console.log(chalk.cyan('Agent >'), reply.message);\n if (reply.latencyMs) {\n printBlank();\n printInfo(`Response time: ${reply.latencyMs}ms`);\n }\n printBlank();\n }\n }\n } finally {\n await chat.end();\n }\n } catch (error) {\n spinner.fail('Chat failed');\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', errorMessage);\n process.exitCode = 1;\n }\n}\n\n/**\n * Interactive mode: readline prompt loop with agent\n * Uses SDK LiveChat for session management\n */\nasync function handleInteractiveChat(\n sdk: ChanlSDK,\n agentId: string,\n stream?: boolean,\n): Promise<void> {\n const spinner = ora('Connecting to agent...').start();\n\n try {\n const chat = await sdk.chat.session(agentId);\n const agentName = chat.agentName || 'Agent';\n spinner.succeed(`Connected to ${agentName}${stream ? ' (streaming)' : ''}`);\n printInfo(\"Type 'exit' or 'quit' to end the session. Ctrl+C also works.\");\n printBlank();\n\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const prompt = (): void => {\n rl.question(chalk.bold('You > '), async (input) => {\n const trimmed = input.trim();\n\n if (!trimmed) {\n prompt();\n return;\n }\n\n if (trimmed.toLowerCase() === 'exit' || trimmed.toLowerCase() === 'quit') {\n await endSessionCleanly(chat);\n rl.close();\n return;\n }\n\n try {\n if (stream) {\n // Streaming: show text character-by-character\n process.stdout.write(chalk.cyan('Agent > '));\n const reply = await chat.send(trimmed, {\n stream: true,\n onChunk: (delta) => process.stdout.write(delta),\n });\n console.log(); // newline after stream\n if (reply.latencyMs) {\n printInfo(`${reply.latencyMs}ms`);\n }\n } else {\n const reply = await chat.send(trimmed);\n if (reply.toolCalls?.length) {\n console.log(chalk.dim(' Tools:'));\n printToolCalls(reply.toolCalls);\n }\n console.log(chalk.cyan('Agent >'), reply.message);\n }\n printBlank();\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n printError('Send failed', errorMessage);\n printBlank();\n }\n\n prompt();\n });\n };\n\n // Handle Ctrl+C gracefully\n const handleSigint = async (): Promise<void> => {\n printBlank();\n await endSessionCleanly(chat);\n rl.close();\n process.exit(0);\n };\n\n rl.on('SIGINT', () => {\n void handleSigint();\n });\n\n rl.on('close', () => {\n // Readline closed (e.g., piped input ended)\n });\n\n prompt();\n } catch (error) {\n spinner.fail('Failed to connect');\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n printError('Error', errorMessage);\n process.exitCode = 1;\n }\n}\n\n/**\n * Display tool calls in a readable format\n */\nfunction printToolCalls(toolCalls: ToolCall[]): void {\n for (const tc of toolCalls) {\n const statusIcon =\n tc.status === 'success'\n ? chalk.green('✓')\n : tc.status === 'error'\n ? chalk.red('✗')\n : tc.status === 'timeout'\n ? chalk.yellow('⏱')\n : chalk.dim('…');\n const duration = tc.durationMs ? chalk.dim(` (${tc.durationMs}ms)`) : '';\n const params = Object.keys(tc.parameters).length\n ? chalk.dim(` ${JSON.stringify(tc.parameters)}`)\n : '';\n\n console.log(` ${statusIcon} ${chalk.yellow(tc.name)}${params}${duration}`);\n\n if (tc.status === 'error' && tc.error) {\n console.log(` ${chalk.red(tc.error.message)}`);\n }\n }\n}\n\n/**\n * End a chat session with user feedback\n */\nasync function endSessionCleanly(\n chat: { end: () => Promise<void> },\n): Promise<void> {\n try {\n await chat.end();\n printSuccess('Session ended');\n } catch {\n printInfo('Session closed');\n }\n}\n"],"mappings":"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","names":[]}
@@ -14,6 +14,9 @@ import {
14
14
  const VALID_KEYS = [
15
15
  "apiKey",
16
16
  "baseUrl",
17
+ "server",
18
+ "deployment",
19
+ "apiPrefix",
17
20
  "workspaceId",
18
21
  "defaultFormat"
19
22
  ];
@@ -25,6 +28,9 @@ const KEY_DESCRIPTIONS = {
25
28
  jwtToken: "JWT access token (from browser login)",
26
29
  refreshToken: "JWT refresh token (from browser login)",
27
30
  baseUrl: "Base URL for the Chanl API",
31
+ server: "Alias for baseUrl (e.g. http://localhost:18005)",
32
+ deployment: "local | cloud \u2014 local rewrites /api/v1 paths for OSS scenario servers",
33
+ apiPrefix: "Override API prefix; empty string for flat /scenarios routes",
28
34
  workspaceId: "Default workspace ID",
29
35
  appUrl: "App URL for browser-based flows",
30
36
  defaultFormat: "Default output format (table or json)"
@@ -143,16 +149,24 @@ function handleConfigSet(key, value) {
143
149
  }
144
150
  }
145
151
  configStore.set(typedKey, value);
152
+ const clearedServer = typedKey === "baseUrl" && configStore.has("server");
153
+ if (clearedServer) {
154
+ configStore.delete("server");
155
+ }
146
156
  if (isJsonOutput()) {
147
157
  printJson({
148
158
  success: true,
149
159
  key,
150
- value: key === "apiKey" ? maskString(value) : value
160
+ value: key === "apiKey" ? maskString(value) : value,
161
+ ...clearedServer && { clearedServer: true }
151
162
  });
152
163
  return;
153
164
  }
154
165
  const displayValue = key === "apiKey" ? maskString(value) : value;
155
166
  printSuccess(`Set ${key} = ${displayValue}`);
167
+ if (clearedServer) {
168
+ printLabel("Note", "cleared 'server' (alias for baseUrl) so this change takes effect");
169
+ }
156
170
  }
157
171
  function handleConfigDelete(key) {
158
172
  if (!isValidKey(key)) {
@@ -215,15 +229,23 @@ function handleConfigUse(environment) {
215
229
  return;
216
230
  }
217
231
  configStore.set("baseUrl", url);
232
+ const clearedServer = configStore.has("server");
233
+ if (clearedServer) {
234
+ configStore.delete("server");
235
+ }
218
236
  if (isJsonOutput()) {
219
237
  printJson({
220
238
  success: true,
221
239
  environment: env,
222
- baseUrl: url
240
+ baseUrl: url,
241
+ ...clearedServer && { clearedServer: true }
223
242
  });
224
243
  return;
225
244
  }
226
245
  printSuccess(`Switched to ${env}: ${url}`);
246
+ if (clearedServer) {
247
+ printLabel("Note", "cleared 'server' (alias for baseUrl) so this change takes effect");
248
+ }
227
249
  }
228
250
  export {
229
251
  createConfigCommand
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/config.ts"],"sourcesContent":["import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { configStore, type ChanlCliConfig } from '../utils/config-store.js';\nimport {\n printSuccess,\n printError,\n printLabel,\n printBlank,\n printTable,\n isJsonOutput,\n printJson,\n maskString,\n} from '../utils/output.js';\n\n/**\n * Valid configuration keys\n */\nconst VALID_KEYS: (keyof ChanlCliConfig)[] = [\n 'apiKey',\n 'baseUrl',\n 'workspaceId',\n 'defaultFormat',\n];\n\n/**\n * Environment presets for quick switching\n * Only production is exposed publicly. Use `chanl config set baseUrl <url>` for custom endpoints.\n */\nconst ENVIRONMENT_PRESETS: Record<string, string> = {\n production: 'https://platform.chanl.ai',\n};\n\n/**\n * Configuration key descriptions\n */\nconst KEY_DESCRIPTIONS: Record<keyof ChanlCliConfig, string> = {\n apiKey: 'Chanl API key for authentication',\n jwtToken: 'JWT access token (from browser login)',\n refreshToken: 'JWT refresh token (from browser login)',\n baseUrl: 'Base URL for the Chanl API',\n workspaceId: 'Default workspace ID',\n appUrl: 'App URL for browser-based flows',\n defaultFormat: 'Default output format (table or json)',\n};\n\n/**\n * Create the config command group\n */\nexport function createConfigCommand(): Command {\n const config = new Command('config').description('Manage CLI configuration');\n\n // `chanl config list` subcommand\n config\n .command('list')\n .description('List all configuration values')\n .action(handleConfigList);\n\n // `chanl config get <key>` subcommand\n config\n .command('get <key>')\n .description('Get a configuration value')\n .action(handleConfigGet);\n\n // `chanl config set <key> <value>` subcommand\n config\n .command('set <key> <value>')\n .description('Set a configuration value')\n .action(handleConfigSet);\n\n // `chanl config delete <key>` subcommand\n config\n .command('delete <key>')\n .alias('unset')\n .description('Delete a configuration value')\n .action(handleConfigDelete);\n\n // `chanl config path` subcommand\n config\n .command('path')\n .description('Show path to configuration file')\n .action(handleConfigPath);\n\n // `chanl config use <environment>` subcommand\n config\n .command('use <environment>')\n .description('Reset to production API (or set a custom base URL with `config set baseUrl`)')\n .action(handleConfigUse);\n\n return config;\n}\n\n/**\n * Handle config list command\n */\nfunction handleConfigList(): void {\n const allConfig = configStore.getAll();\n\n if (isJsonOutput()) {\n // Mask sensitive values in JSON output\n const safeConfig = {\n ...allConfig,\n apiKey: allConfig.apiKey ? maskString(allConfig.apiKey) : undefined,\n };\n printJson(safeConfig);\n return;\n }\n\n printBlank();\n\n const rows = VALID_KEYS.map((key) => {\n let value = allConfig[key];\n const source = getConfigSource(key);\n\n // Mask API key\n if (key === 'apiKey' && typeof value === 'string') {\n value = maskString(value);\n }\n\n return {\n key,\n value: value ?? chalk.dim('(not set)'),\n source,\n description: KEY_DESCRIPTIONS[key],\n };\n });\n\n printTable(\n [\n { header: 'Key', key: 'key', width: 15 },\n { header: 'Value', key: 'value', width: 30 },\n { header: 'Source', key: 'source', width: 10 },\n ],\n rows\n );\n\n printBlank();\n printLabel('Config file', configStore.getPath());\n printBlank();\n}\n\n/**\n * Handle config get command\n */\nfunction handleConfigGet(key: string): void {\n if (!isValidKey(key)) {\n printError(`Unknown configuration key: ${key}`);\n printBlank();\n printLabel('Valid keys', VALID_KEYS.join(', '));\n process.exitCode = 1;\n return;\n }\n\n const typedKey = key as keyof ChanlCliConfig;\n let value: string | undefined;\n\n // Get value with env var fallback\n switch (typedKey) {\n case 'apiKey':\n value = configStore.getApiKey();\n break;\n case 'baseUrl':\n value = configStore.getBaseUrl();\n break;\n case 'workspaceId':\n value = configStore.getWorkspaceId();\n break;\n default:\n value = configStore.get(typedKey) as string | undefined;\n }\n\n if (isJsonOutput()) {\n printJson({\n key,\n value: key === 'apiKey' && value ? maskString(value) : value,\n source: getConfigSource(typedKey),\n });\n return;\n }\n\n if (value === undefined) {\n console.log(chalk.dim('(not set)'));\n return;\n }\n\n // Mask API key even in regular output\n if (key === 'apiKey') {\n console.log(maskString(value));\n } else {\n console.log(value);\n }\n}\n\n/**\n * Handle config set command\n */\nfunction handleConfigSet(key: string, value: string): void {\n if (!isValidKey(key)) {\n printError(`Unknown configuration key: ${key}`);\n printBlank();\n printLabel('Valid keys', VALID_KEYS.join(', '));\n process.exitCode = 1;\n return;\n }\n\n const typedKey = key as keyof ChanlCliConfig;\n\n // Validate specific keys\n if (typedKey === 'defaultFormat') {\n if (value !== 'table' && value !== 'json') {\n printError(`Invalid format: ${value}`);\n printLabel('Valid values', 'table, json');\n process.exitCode = 1;\n return;\n }\n }\n\n if (typedKey === 'baseUrl') {\n try {\n new URL(value);\n } catch {\n printError(`Invalid URL: ${value}`);\n process.exitCode = 1;\n return;\n }\n }\n\n // Set the value\n configStore.set(typedKey, value as never);\n\n if (isJsonOutput()) {\n printJson({\n success: true,\n key,\n value: key === 'apiKey' ? maskString(value) : value,\n });\n return;\n }\n\n const displayValue = key === 'apiKey' ? maskString(value) : value;\n printSuccess(`Set ${key} = ${displayValue}`);\n}\n\n/**\n * Handle config delete command\n */\nfunction handleConfigDelete(key: string): void {\n if (!isValidKey(key)) {\n printError(`Unknown configuration key: ${key}`);\n printBlank();\n printLabel('Valid keys', VALID_KEYS.join(', '));\n process.exitCode = 1;\n return;\n }\n\n const typedKey = key as keyof ChanlCliConfig;\n\n // Check if key exists\n if (!configStore.has(typedKey)) {\n if (isJsonOutput()) {\n printJson({ success: true, key, message: 'Key was not set' });\n } else {\n printSuccess(`${key} was not set`);\n }\n return;\n }\n\n configStore.delete(typedKey);\n\n if (isJsonOutput()) {\n printJson({ success: true, key, message: 'Deleted' });\n return;\n }\n\n printSuccess(`Deleted ${key}`);\n}\n\n/**\n * Handle config path command\n */\nfunction handleConfigPath(): void {\n const path = configStore.getPath();\n\n if (isJsonOutput()) {\n printJson({ path });\n return;\n }\n\n console.log(path);\n}\n\n/**\n * Check if a key is a valid configuration key\n */\nfunction isValidKey(key: string): key is keyof ChanlCliConfig {\n return VALID_KEYS.includes(key as keyof ChanlCliConfig);\n}\n\n/**\n * Get the source of a configuration value\n */\nfunction getConfigSource(key: keyof ChanlCliConfig): string {\n const envVarMap: Partial<Record<keyof ChanlCliConfig, string>> = {\n apiKey: 'CHANL_API_KEY',\n baseUrl: 'CHANL_BASE_URL',\n workspaceId: 'CHANL_WORKSPACE_ID',\n };\n\n const envVar = envVarMap[key];\n if (envVar && process.env[envVar]) {\n return chalk.cyan('env');\n }\n\n if (configStore.has(key)) {\n return chalk.green('config');\n }\n\n return chalk.dim('default');\n}\n\n/**\n * Handle config use command - switch to a preset environment\n */\nfunction handleConfigUse(environment: string): void {\n const env = environment.toLowerCase();\n const url = ENVIRONMENT_PRESETS[env];\n\n if (!url) {\n printError(`Unknown environment: ${environment}`);\n printBlank();\n printLabel('Available environments', Object.keys(ENVIRONMENT_PRESETS).join(', '));\n process.exitCode = 1;\n return;\n }\n\n configStore.set('baseUrl', url);\n\n if (isJsonOutput()) {\n printJson({\n success: true,\n environment: env,\n baseUrl: url,\n });\n return;\n }\n\n printSuccess(`Switched to ${env}: ${url}`);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/commands/config.ts"],"sourcesContent":["import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { configStore, type ChanlCliConfig } from '../utils/config-store.js';\nimport {\n printSuccess,\n printError,\n printLabel,\n printBlank,\n printTable,\n isJsonOutput,\n printJson,\n maskString,\n} from '../utils/output.js';\n\n/**\n * Valid configuration keys\n */\nconst VALID_KEYS: (keyof ChanlCliConfig)[] = [\n 'apiKey',\n 'baseUrl',\n 'server',\n 'deployment',\n 'apiPrefix',\n 'workspaceId',\n 'defaultFormat',\n];\n\n/**\n * Environment presets for quick switching\n * Only production is exposed publicly. Use `chanl config set baseUrl <url>` for custom endpoints.\n */\nconst ENVIRONMENT_PRESETS: Record<string, string> = {\n production: 'https://platform.chanl.ai',\n};\n\n/**\n * Configuration key descriptions\n */\nconst KEY_DESCRIPTIONS: Record<keyof ChanlCliConfig, string> = {\n apiKey: 'Chanl API key for authentication',\n jwtToken: 'JWT access token (from browser login)',\n refreshToken: 'JWT refresh token (from browser login)',\n baseUrl: 'Base URL for the Chanl API',\n server: 'Alias for baseUrl (e.g. http://localhost:18005)',\n deployment: 'local | cloud — local rewrites /api/v1 paths for OSS scenario servers',\n apiPrefix: 'Override API prefix; empty string for flat /scenarios routes',\n workspaceId: 'Default workspace ID',\n appUrl: 'App URL for browser-based flows',\n defaultFormat: 'Default output format (table or json)',\n};\n\n/**\n * Create the config command group\n */\nexport function createConfigCommand(): Command {\n const config = new Command('config').description('Manage CLI configuration');\n\n // `chanl config list` subcommand\n config\n .command('list')\n .description('List all configuration values')\n .action(handleConfigList);\n\n // `chanl config get <key>` subcommand\n config\n .command('get <key>')\n .description('Get a configuration value')\n .action(handleConfigGet);\n\n // `chanl config set <key> <value>` subcommand\n config\n .command('set <key> <value>')\n .description('Set a configuration value')\n .action(handleConfigSet);\n\n // `chanl config delete <key>` subcommand\n config\n .command('delete <key>')\n .alias('unset')\n .description('Delete a configuration value')\n .action(handleConfigDelete);\n\n // `chanl config path` subcommand\n config\n .command('path')\n .description('Show path to configuration file')\n .action(handleConfigPath);\n\n // `chanl config use <environment>` subcommand\n config\n .command('use <environment>')\n .description('Reset to production API (or set a custom base URL with `config set baseUrl`)')\n .action(handleConfigUse);\n\n return config;\n}\n\n/**\n * Handle config list command\n */\nfunction handleConfigList(): void {\n const allConfig = configStore.getAll();\n\n if (isJsonOutput()) {\n // Mask sensitive values in JSON output\n const safeConfig = {\n ...allConfig,\n apiKey: allConfig.apiKey ? maskString(allConfig.apiKey) : undefined,\n };\n printJson(safeConfig);\n return;\n }\n\n printBlank();\n\n const rows = VALID_KEYS.map((key) => {\n let value = allConfig[key];\n const source = getConfigSource(key);\n\n // Mask API key\n if (key === 'apiKey' && typeof value === 'string') {\n value = maskString(value);\n }\n\n return {\n key,\n value: value ?? chalk.dim('(not set)'),\n source,\n description: KEY_DESCRIPTIONS[key],\n };\n });\n\n printTable(\n [\n { header: 'Key', key: 'key', width: 15 },\n { header: 'Value', key: 'value', width: 30 },\n { header: 'Source', key: 'source', width: 10 },\n ],\n rows\n );\n\n printBlank();\n printLabel('Config file', configStore.getPath());\n printBlank();\n}\n\n/**\n * Handle config get command\n */\nfunction handleConfigGet(key: string): void {\n if (!isValidKey(key)) {\n printError(`Unknown configuration key: ${key}`);\n printBlank();\n printLabel('Valid keys', VALID_KEYS.join(', '));\n process.exitCode = 1;\n return;\n }\n\n const typedKey = key as keyof ChanlCliConfig;\n let value: string | undefined;\n\n // Get value with env var fallback\n switch (typedKey) {\n case 'apiKey':\n value = configStore.getApiKey();\n break;\n case 'baseUrl':\n value = configStore.getBaseUrl();\n break;\n case 'workspaceId':\n value = configStore.getWorkspaceId();\n break;\n default:\n value = configStore.get(typedKey) as string | undefined;\n }\n\n if (isJsonOutput()) {\n printJson({\n key,\n value: key === 'apiKey' && value ? maskString(value) : value,\n source: getConfigSource(typedKey),\n });\n return;\n }\n\n if (value === undefined) {\n console.log(chalk.dim('(not set)'));\n return;\n }\n\n // Mask API key even in regular output\n if (key === 'apiKey') {\n console.log(maskString(value));\n } else {\n console.log(value);\n }\n}\n\n/**\n * Handle config set command\n */\nfunction handleConfigSet(key: string, value: string): void {\n if (!isValidKey(key)) {\n printError(`Unknown configuration key: ${key}`);\n printBlank();\n printLabel('Valid keys', VALID_KEYS.join(', '));\n process.exitCode = 1;\n return;\n }\n\n const typedKey = key as keyof ChanlCliConfig;\n\n // Validate specific keys\n if (typedKey === 'defaultFormat') {\n if (value !== 'table' && value !== 'json') {\n printError(`Invalid format: ${value}`);\n printLabel('Valid values', 'table, json');\n process.exitCode = 1;\n return;\n }\n }\n\n if (typedKey === 'baseUrl') {\n try {\n new URL(value);\n } catch {\n printError(`Invalid URL: ${value}`);\n process.exitCode = 1;\n return;\n }\n }\n\n // Set the value\n configStore.set(typedKey, value as never);\n\n // `server` is an alias for `baseUrl` that takes priority in getBaseUrl().\n // Setting baseUrl while a stale `server` is still around would silently\n // have no effect, so clear it here to keep the two in sync.\n const clearedServer = typedKey === 'baseUrl' && configStore.has('server');\n if (clearedServer) {\n configStore.delete('server');\n }\n\n if (isJsonOutput()) {\n printJson({\n success: true,\n key,\n value: key === 'apiKey' ? maskString(value) : value,\n ...(clearedServer && { clearedServer: true }),\n });\n return;\n }\n\n const displayValue = key === 'apiKey' ? maskString(value) : value;\n printSuccess(`Set ${key} = ${displayValue}`);\n if (clearedServer) {\n printLabel('Note', \"cleared 'server' (alias for baseUrl) so this change takes effect\");\n }\n}\n\n/**\n * Handle config delete command\n */\nfunction handleConfigDelete(key: string): void {\n if (!isValidKey(key)) {\n printError(`Unknown configuration key: ${key}`);\n printBlank();\n printLabel('Valid keys', VALID_KEYS.join(', '));\n process.exitCode = 1;\n return;\n }\n\n const typedKey = key as keyof ChanlCliConfig;\n\n // Check if key exists\n if (!configStore.has(typedKey)) {\n if (isJsonOutput()) {\n printJson({ success: true, key, message: 'Key was not set' });\n } else {\n printSuccess(`${key} was not set`);\n }\n return;\n }\n\n configStore.delete(typedKey);\n\n if (isJsonOutput()) {\n printJson({ success: true, key, message: 'Deleted' });\n return;\n }\n\n printSuccess(`Deleted ${key}`);\n}\n\n/**\n * Handle config path command\n */\nfunction handleConfigPath(): void {\n const path = configStore.getPath();\n\n if (isJsonOutput()) {\n printJson({ path });\n return;\n }\n\n console.log(path);\n}\n\n/**\n * Check if a key is a valid configuration key\n */\nfunction isValidKey(key: string): key is keyof ChanlCliConfig {\n return VALID_KEYS.includes(key as keyof ChanlCliConfig);\n}\n\n/**\n * Get the source of a configuration value\n */\nfunction getConfigSource(key: keyof ChanlCliConfig): string {\n const envVarMap: Partial<Record<keyof ChanlCliConfig, string>> = {\n apiKey: 'CHANL_API_KEY',\n baseUrl: 'CHANL_BASE_URL',\n workspaceId: 'CHANL_WORKSPACE_ID',\n };\n\n const envVar = envVarMap[key];\n if (envVar && process.env[envVar]) {\n return chalk.cyan('env');\n }\n\n if (configStore.has(key)) {\n return chalk.green('config');\n }\n\n return chalk.dim('default');\n}\n\n/**\n * Handle config use command - switch to a preset environment\n */\nfunction handleConfigUse(environment: string): void {\n const env = environment.toLowerCase();\n const url = ENVIRONMENT_PRESETS[env];\n\n if (!url) {\n printError(`Unknown environment: ${environment}`);\n printBlank();\n printLabel('Available environments', Object.keys(ENVIRONMENT_PRESETS).join(', '));\n process.exitCode = 1;\n return;\n }\n\n configStore.set('baseUrl', url);\n\n // Same reasoning as `config set baseUrl`: `server` overrides baseUrl in\n // getBaseUrl(), so leaving a stale `server` in place would make this\n // command a no-op from the caller's perspective.\n const clearedServer = configStore.has('server');\n if (clearedServer) {\n configStore.delete('server');\n }\n\n if (isJsonOutput()) {\n printJson({\n success: true,\n environment: env,\n baseUrl: url,\n ...(clearedServer && { clearedServer: true }),\n });\n return;\n }\n\n printSuccess(`Switched to ${env}: ${url}`);\n if (clearedServer) {\n printLabel('Note', \"cleared 'server' (alias for baseUrl) so this change takes effect\");\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,8 @@
1
+ import { Command } from 'commander';
2
+
3
+ /**
4
+ * Create the customers command group
5
+ */
6
+ declare function createCustomersCommand(): Command;
7
+
8
+ export { createCustomersCommand };