import { Command } from 'commander'; import ora from 'ora'; import { IndemnClient } from '../sdk/client.js'; import { AgentsSDK } from '../sdk/agents.js'; import { exportAgentCard } from '../report/export.js'; import { formatTable, printJson, printError, printSuccess, confirm } from './utils/output.js'; function formatChannels(channels: unknown[]): string { if (!channels || channels.length === 0) return 'WEB'; return channels.map((c) => typeof c === 'string' ? c : (c as Record).name || (c as Record).type || String(c) ).join(', '); } export function registerAgentCommands(program: Command): void { const agents = program.command('agents').description('Manage AI agents'); agents .command('list') .description('List all agents') .option('--json', 'Output as JSON') .option('--limit ', 'Limit number of results') .option('--page ', 'Page number (use with --limit)') .action(async (options) => { try { const client = new IndemnClient(); const sdk = new AgentsSDK(client); const spinner = ora('Fetching agents...').start(); let agentList = await sdk.listAgents(); spinner.stop(); if (options.page && options.limit) { const page = parseInt(options.page, 10); const limit = parseInt(options.limit, 10); agentList = agentList.slice((page - 1) * limit, page * limit); } else if (options.limit) { agentList = agentList.slice(0, parseInt(options.limit, 10)); } if (options.json) { printJson(agentList); return; } if (agentList.length === 0) { console.log('No agents found.'); return; } const rows = agentList.map((a) => [ a._id, a.name || '', formatChannels(a.channels || []), a.updatedAt ? new Date(a.updatedAt).toLocaleDateString() : '', ]); console.log(formatTable(['ID', 'Name', 'Channels', 'Updated'], rows)); } catch (err) { printError(err); process.exit(1); } }); agents .command('get') .argument('', 'Agent ID') .description('Get agent details') .option('--json', 'Output as JSON') .action(async (id: string, options) => { try { const client = new IndemnClient(); const sdk = new AgentsSDK(client); const spinner = ora('Fetching agent...').start(); const agent = await sdk.getAgent(id); spinner.stop(); if (options.json) { printJson(agent); return; } console.log(`ID: ${agent._id}`); console.log(`Name: ${agent.name}`); console.log(`Description: ${agent.description || '(none)'}`); console.log(`Channels: ${formatChannels(agent.channels || [])}`); console.log(`Webhook URL: ${agent.webhook_url || '(none)'}`); console.log(`Webhook: ${agent.webhook_enabled ? 'enabled' : 'disabled'}`); console.log(`Project: ${agent.id_project || '(none)'}`); console.log(`Created: ${agent.createdAt || ''}`); console.log(`Updated: ${agent.updatedAt || ''}`); } catch (err) { printError(err); process.exit(1); } }); agents .command('create') .description('Create a new agent') .requiredOption('--name ', 'Agent name') .option('--channels ', 'Comma-separated channels', 'WEB') .action(async (options) => { try { const client = new IndemnClient(); const sdk = new AgentsSDK(client); const spinner = ora('Creating agent...').start(); const channels = options.channels.split(',').map((c: string) => c.trim()); const agent = await sdk.createAgent({ name: options.name, channels }); spinner.stop(); printSuccess(`Agent created: ${agent._id}`); console.log(` Name: ${agent.name}`); console.log(` Channels: ${formatChannels(agent.channels || [])}`); } catch (err) { printError(err); process.exit(1); } }); agents .command('update') .argument('', 'Agent ID') .description('Update an agent') .option('--name ', 'New agent name') .option('--description ', 'Agent description') .option('--webhook-url ', 'Webhook URL') .action(async (id: string, options) => { try { const input: Record = {}; if (options.name) input.name = options.name; if (options.description) input.description = options.description; if (options.webhookUrl) input.webhook_url = options.webhookUrl; if (Object.keys(input).length === 0) { printError('No update options provided. Use --name, --description, or --webhook-url.'); process.exit(1); } const client = new IndemnClient(); const sdk = new AgentsSDK(client); const spinner = ora('Updating agent...').start(); const agent = await sdk.updateAgent(id, input); spinner.stop(); printSuccess(`Agent ${agent._id} updated.`); } catch (err) { printError(err); process.exit(1); } }); agents .command('delete') .argument('', 'Agent ID') .description('Delete an agent') .action(async (id: string) => { try { const confirmed = await confirm(`Delete agent ${id}? This cannot be undone.`); if (!confirmed) { console.log('Cancelled.'); return; } const client = new IndemnClient(); const sdk = new AgentsSDK(client); const spinner = ora('Deleting agent...').start(); await sdk.deleteAgent(id); spinner.stop(); printSuccess(`Agent ${id} deleted.`); } catch (err) { printError(err); process.exit(1); } }); agents .command('card') .argument('', 'Agent ID') .description('Generate branded agent card PDF') .option('--output ', 'Output file path') .action(async (id: string, options) => { try { const client = new IndemnClient(); const spinner = ora('Fetching agent data...').start(); spinner.text = 'Generating PDF...'; const result = await exportAgentCard(id, options.output, client); spinner.stop(); printSuccess(`Agent card saved to ${result.file_path}`); } catch (err) { printError(err); process.exit(1); } }); agents .command('clone') .argument('', 'Agent ID to clone') .description('Clone an agent') .action(async (id: string) => { try { const client = new IndemnClient(); const sdk = new AgentsSDK(client); const spinner = ora('Cloning agent...').start(); const result = await sdk.cloneAgent(id); spinner.stop(); // Clone returns { new_agent_id, new_agent_name } or an Agent object const raw = result as unknown as Record; const cloneId = raw.new_agent_id || result._id; const cloneName = raw.new_agent_name || result.name; printSuccess(`Agent cloned: ${cloneId}`); console.log(` Name: ${cloneName}`); console.log(` Source: ${id}`); } catch (err) { printError(err); process.exit(1); } }); }