/** * Module deploy command * * Deploys module to infrastructure (Terraform + Ansible) */ import { getDb } from '../../db/client'; import { formatPreflightResult, runPreflight } from '../../services/deploy-preflight'; import { deployModule } from '../../services/module-deploy'; import { getArg, hasFlag, validateRequiredArgs } from '../parser'; import type { CommandResult } from '../types'; /** * Handle module deploy command * * Usage: * celilo module deploy [--debug] [--preflight] [--verbose] [--keep] * * Note: there is no `--no-interactive` flag. The deploy interview * runs through the bus event system; automation answers via a * responder (Claude subagent, `celilo events respond`, autoresponder * daemon, etc.). When stdin is a TTY the deploy registers a built-in * terminal-responder. See INTERACTIVE_DEPLOYS_VIA_BUS.md. * * @param args - Command arguments * @param flags - Command flags * @returns Command result */ export async function handleModuleDeploy( args: string[], flags: Record, ): Promise { // Validate arguments const error = validateRequiredArgs(args, 1); if (error) { return { success: false, error: `${error}\n\nUsage:\n celilo module deploy [--preflight]`, }; } const moduleId = getArg(args, 0); if (!moduleId) { return { success: false, error: 'Module ID is required', }; } const db = getDb(); // --preflight: fast validation only, no actual deployment if (hasFlag(flags, 'preflight')) { const preflight = await runPreflight(moduleId, db); const message = formatPreflightResult(preflight); return preflight.success ? { success: true, message } : { success: false, error: message }; } const debug = hasFlag(flags, 'debug'); const verbose = hasFlag(flags, 'verbose'); const stopAfterInterview = hasFlag(flags, 'stop-after-interview'); const keepGeneratedProject = hasFlag(flags, 'keep'); const result = await deployModule(moduleId, db, { debug, verbose, stopAfterInterview, keepGeneratedProject, }); if (!result.success) { return { success: false, error: result.error || 'Deployment failed', details: result.phases, }; } // Success message is emitted by deployModule via the active ProgressDisplay, // so we return an empty message — index.ts exits without writing anything // more, rather than printing a duplicate line in a different style. return { success: true, message: '', data: result.phases, }; }