UNPKG

claude-flow-novice

Version:

Claude Flow Novice - Advanced orchestration platform for multi-agent AI workflows with CFN Loop architecture Includes Local RuVector Accelerator and all CFN skills for complete functionality.

244 lines (235 loc) 8.09 kB
#!/usr/bin/env node /** * Agent Spawning CLI Entry Point * * Provides command-line interface for spawning agents. * Fully backward compatible with bash version. * * Usage: * spawn-agent-cli <agent-type> --task-id <id> [--iteration N] [--mode mode] * spawn-agent-cli --help * spawn-agent-cli --version */ import { AgentSpawner } from './agent-spawner'; import { readFileSync } from 'fs'; import { resolve, dirname } from 'path'; import { fileURLToPath } from 'url'; // ESM-compatible __dirname const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); /** * Parse command-line arguments */ function parseArgs(args) { const parsed = { background: true }; for(let i = 0; i < args.length; i++){ const arg = args[i]; if (arg === '--help') { parsed.help = true; } else if (arg === '--version') { parsed.version = true; } else if (arg === '--json') { parsed.json = true; } else if (arg === '--foreground') { parsed.background = false; } else if (arg === '--background') { parsed.background = true; } else if (arg === '--task-id' || arg === '-t') { parsed.taskId = args[++i]; } else if (arg === '--iteration' || arg === '-i') { parsed.iteration = parseInt(args[++i], 10); } else if (arg === '--mode' || arg === '-m') { parsed.mode = args[++i]; } else if (arg === '--provider' || arg === '-p') { parsed.provider = args[++i]; } else if (arg === '--model') { parsed.model = args[++i]; } else if (arg === '--prompt') { parsed.prompt = args[++i]; } else if (!arg.startsWith('-')) { if (!parsed.agentType) { parsed.agentType = arg; } } } return parsed; } /** * Print help message */ function printHelp() { console.log(` Agent Spawning CLI USAGE: spawn-agent-cli <agent-type> [OPTIONS] ARGUMENTS: <agent-type> Type of agent to spawn (e.g., backend-dev, tester) OPTIONS: -t, --task-id <id> Task ID for coordination (required for CLI mode) -i, --iteration <n> Iteration number (default: 1) -m, --mode <mode> Mode: mvp, standard, enterprise (default: standard) -p, --provider <p> Provider: zai, anthropic, etc. (default: auto-detect) --model <model> Explicit model name (default: auto-detect) --prompt <text> Task prompt/description to pass to agent --foreground Run in foreground (default: background) --background Run in background (default) --json Output result as JSON -h, --help Show this help message -v, --version Show version information EXAMPLES: # Basic agent spawn spawn-agent-cli backend-dev --task-id task-123 # With explicit iteration spawn-agent-cli tester --task-id task-123 --iteration 2 # With custom provider spawn-agent-cli reviewer --task-id task-123 --provider anthropic # JSON output for integration spawn-agent-cli coder --task-id task-123 --json ENVIRONMENT VARIABLES: TASK_ID Task ID (can be set instead of --task-id) PROJECT_ROOT Project root directory (default: cwd) AGENT_ID Custom agent ID (default: generated) `); } /** * Print version information */ function printVersion() { try { const packageJson = JSON.parse(readFileSync(resolve(__dirname, '../../package.json'), 'utf-8')); console.log(`spawn-agent-cli v${packageJson.version}`); } catch { console.log('spawn-agent-cli v1.0.0'); } } /** * Phase 1: Mode Prefix Function for CLI/Trigger.dev Collision Mitigation * * Generates task ID with mode prefix to prevent Redis key collisions between * CLI mode and Trigger.dev Docker mode. Both modes share identical Redis coordination * patterns and must use isolated namespaces. * * @param rawTaskId - Original task ID without prefix * @param mode - Execution mode: 'cli' for CLI mode, 'trigger' for Trigger.dev * @returns Prefixed task ID in format "MODE:rawTaskId" * * Example: * generateTaskId('task-123', 'cli') => 'cli:task-123' * generateTaskId('task-123', 'trigger') => 'trigger:task-123' * * Redis Key Isolation (After): * CLI: cfn:task:cli:task-123:status * Trigger: cfn:task:trigger:task-123:status */ function generateTaskId(rawTaskId, mode) { // Don't add prefix if task ID already has a namespace prefix if (/^[a-z]+:/.test(rawTaskId)) { return rawTaskId; } return `${mode}:${rawTaskId}`; } /** * Validate CLI arguments */ function validateArgs(args) { const errors = []; if (!args.agentType) { errors.push('Agent type is required'); } const taskId = args.taskId || process.env.TASK_ID; if (!taskId) { errors.push('Task ID is required (--task-id or TASK_ID env var)'); } // Allow optional namespace prefix (e.g., "cli:", "task:") for coordination routing if (taskId && !/^([a-z]+:)?[a-zA-Z0-9_.-]{1,64}$/.test(taskId)) { errors.push('Invalid task ID format'); } if (args.iteration && (args.iteration < 1 || !Number.isInteger(args.iteration))) { errors.push('Iteration must be a positive integer'); } if (args.mode && ![ 'mvp', 'standard', 'enterprise' ].includes(args.mode)) { errors.push('Mode must be mvp, standard, or enterprise'); } return { valid: errors.length === 0, errors }; } /** * Format output based on options */ function formatOutput(result, json = false) { if (json) { return JSON.stringify(result, null, 2); } if (typeof result === 'object' && result !== null) { const obj = result; if (obj.status === 'failed') { return `ERROR: ${obj.error || 'Failed to spawn agent'}`; } return `Agent spawned: ${obj.agentId} (PID: ${obj.pid})`; } return String(result); } /** * Main CLI function */ async function main() { const args = parseArgs(process.argv.slice(2)); // Handle flags if (args.help) { printHelp(); process.exit(0); } if (args.version) { printVersion(); process.exit(0); } // Validate arguments const taskId = args.taskId || process.env.TASK_ID; const validation = validateArgs({ ...args, taskId }); if (!validation.valid) { console.error('Argument validation failed:'); validation.errors.forEach((err)=>console.error(` - ${err}`)); console.error('Use --help for usage information'); process.exit(1); } // Create spawner const projectRoot = process.env.PROJECT_ROOT || process.cwd(); const spawner = new AgentSpawner(projectRoot); // Build config with CLI mode prefix for Redis key isolation (Phase 1) const prefixedTaskId = generateTaskId(taskId, 'cli'); const config = { agentType: args.agentType, taskId: prefixedTaskId, iteration: args.iteration || 1, mode: args.mode || 'standard', provider: args.provider, model: args.model, prompt: args.prompt, background: args.background !== false, env: { TASK_ID: prefixedTaskId } }; try { // Spawn agent const result = await spawner.spawnAgent(config); // Output result console.log(formatOutput(result, args.json)); // Exit with appropriate code process.exit(result.status === 'spawned' ? 0 : 1); } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); console.error(`ERROR: ${errorMsg}`); process.exit(2); } } // Run main function main().catch((error)=>{ console.error('Unexpected error:', error); process.exit(2); }); export { parseArgs, validateArgs, formatOutput, generateTaskId }; //# sourceMappingURL=spawn-agent-cli.js.map