/** * Provision command for VC-SYS CLI * Command-driven provisioning designed for Claude Code AI integration */ import { Command } from 'commander'; import chalk from 'chalk'; import { ProjectProvisioner, ProvisionOptions } from '../lib/provisioning/project-provisioner'; import { ConfigManager } from '../lib/core/config-manager'; import { Logger } from '../lib/core/logger'; import { ProvisioningError, ErrorCategory } from '../types/errors'; const logger = new Logger('ProvisionCommand'); /** * Create provision command with Claude Code integration */ export function createProvisionCommand(): Command { const provisionCommand = new Command('provision'); provisionCommand .description('Create and configure a new Supabase project') .option('--org ', 'Organization name or ID (required)') .option('--name ', 'Project name (required)') .option('--region ', 'Deployment region', 'us-east-1') .option('--template ', 'Schema template (saas-starter, chat-app, minimal)') .option('--schema ', 'Path to custom schema file') .option('--no-seeds', 'Skip adding sample data') .option('--list-orgs', 'List available organizations') .option('--list-regions', 'List available regions') .option('--list-templates', 'List available schema templates') .action(async (options) => { await handleProvision(options); }); return provisionCommand; } /** * Handle the provision command - simplified for Claude Code integration */ async function handleProvision(options: any): Promise { const configManager = new ConfigManager(); try { // Check if project is initialized try { await configManager.ensureConfigDir(); } catch (error) { outputError({ error: 'PROJECT_NOT_INITIALIZED', message: 'Project not initialized. Run: vcsys setup', suggestion: 'vcsys setup' }); process.exit(1); } // Initialize provisioner const provisioner = new ProjectProvisioner(); // Prepare provision options const provisionOptions: ProvisionOptions = { org: options.org, name: options.name, region: options.region, template: options.template, schema: options.schema, seeds: options.seeds !== false, listOrgs: options.listOrgs, listRegions: options.listRegions, listTemplates: options.listTemplates }; // Log command execution for debugging logger.info('Starting provisioning command', { hasOrg: !!options.org, hasName: !!options.name, isListCommand: !!(options.listOrgs || options.listRegions || options.listTemplates) }); // Execute provisioning (includes all list commands and actual provisioning) const result = await provisioner.provision(provisionOptions); if (result && result.success) { logger.info('Provisioning completed successfully', { projectRef: result.project?.ref, success: result.success }); process.exit(0); } else if (result === false) { // Command failed logger.error('Provisioning failed'); process.exit(1); } else { // List commands return truthy values but not ProvisioningResult process.exit(0); } } catch (error) { logger.error('Provision command failed', error); // Handle specific error types if (error instanceof ProvisioningError) { outputError({ error: error.category, message: error.message, suggestion: getErrorSuggestion(error.category) }); } else { outputError({ error: 'UNEXPECTED_ERROR', message: error instanceof Error ? error.message : 'Unknown error', suggestion: 'Please try again or check the logs for more details' }); } process.exit(1); } } /** * Output structured error data for Claude Code integration */ function outputError(errorData: { error: string; message: string; suggestion?: string }): void { console.log('--- CLAUDE CODE INTEGRATION ---'); console.log(JSON.stringify({ status: 'error', ...errorData, timestamp: new Date().toISOString() }, null, 2)); console.log('--- END INTEGRATION DATA ---'); } /** * Get error-specific suggestions */ function getErrorSuggestion(category: ErrorCategory): string { switch (category) { case ErrorCategory.AUTHENTICATION: return 'Run: vcsys auth login'; case ErrorCategory.VALIDATION: return 'Check your input parameters and try again'; case ErrorCategory.AUTHORIZATION: return 'Ensure you have access to the specified organization'; case ErrorCategory.API: return 'Check your internet connection and try again'; default: return 'Use --help for command usage information'; } } /** * Utility function to validate provision parameters */ export function validateProvisionParams(options: ProvisionOptions): { valid: boolean; errors: string[] } { const errors: string[] = []; if (!options.org || !options.name) { errors.push('Organization (--org) and project name (--name) are required'); } if (options.name && options.name.length < 3) { errors.push('Project name must be at least 3 characters long'); } if (options.name && !/^[a-zA-Z0-9-_]+$/.test(options.name)) { errors.push('Project name can only contain letters, numbers, hyphens, and underscores'); } const validRegions = ['us-east-1', 'us-west-1', 'eu-west-1', 'ap-southeast-1', 'ap-northeast-1']; if (options.region && !validRegions.includes(options.region)) { errors.push(`Invalid region. Must be one of: ${validRegions.join(', ')}`); } return { valid: errors.length === 0, errors }; } /** * Display provision command help with examples */ export function displayProvisionHelp(): void { console.log(chalk.bold('\n🎯 VC-SYS Provision Command\n')); console.log(chalk.cyan('List Commands (for Claude Code integration):')); console.log(' vcsys provision --list-orgs'); console.log(' vcsys provision --list-regions'); console.log(' vcsys provision --list-templates'); console.log(); console.log(chalk.cyan('Provisioning Commands:')); console.log(' vcsys provision --org "My Organization" --name "my-project"'); console.log(' vcsys provision --org "org-id" --name "project" --region "eu-west-1"'); console.log(); console.log(chalk.cyan('With Custom Schema:')); console.log(' vcsys provision --schema "./my-schema.sql"'); console.log(' vcsys provision --org "My Org" --name "project" --schema "./schema.sql" --no-seeds'); console.log(); console.log(chalk.yellow('Options:')); console.log(' --list-orgs List available organizations'); console.log(' --list-regions List available regions'); console.log(' --list-templates List available schema templates'); console.log(' --org Organization name or ID'); console.log(' --name Project name'); console.log(' --region Deployment region'); console.log(' --template Schema template (saas-starter, chat-app, minimal)'); console.log(' --schema Path to custom schema file'); console.log(' --no-seeds Skip adding sample data'); }