import { Command } from 'commander'; import chalk from 'chalk'; import ora from 'ora'; import { StateAnalyzer, RigstateState } from '../utils/state-analyzer.js'; import { execSync } from 'child_process'; import inquirer from 'inquirer'; export function createNextCommand(): Command { return new Command('next') .description('Analyze current state and suggest the next logical step') .action(async () => { const spinner = ora('šŸ›°ļø Checking Rigstate State...').start(); const state = await StateAnalyzer.analyze(); spinner.stop(); console.log(chalk.bold.blue('\nšŸ›°ļø Rigstate Autopilot (Next Action)')); console.log(chalk.dim('─'.repeat(40))); // Print Status Summary printStatus(state); console.log(chalk.dim('─'.repeat(40))); const action = getNextAction(state); if (action) { console.log(chalk.cyan(`\nšŸ‘‰ Suggested Next Step:`)); console.log(` ${chalk.bold.yellow(action.command)}`); if (action.reason) { console.log(chalk.dim(` (${action.reason})`)); } const { confirm } = await inquirer.prompt([ { type: 'confirm', name: 'confirm', message: 'Execute this command?', default: true } ]); if (confirm) { try { let finalCommand = action.command; // šŸ¤– Debug: Log the detected command // console.log(chalk.dim(`[Debug] Action Command: "${action.command}"`)); // šŸ¤– Special Handling for Commit if (action.command.includes('commit')) { const { message } = await inquirer.prompt([ { type: 'input', name: 'message', message: 'Enter commit message (empty for auto-generate):', validate: () => true // Allow empty } ]); if (message.trim()) { finalCommand = `rigstate commit "${message}" -a`; } else { finalCommand = `rigstate commit -a`; // Will trigger auto-generate in commit command } } console.log(chalk.dim(`\nRunning: ${finalCommand}...`)); // Use the current process executable path const rigstateBin = process.argv[1]; const subCommand = finalCommand.replace('rigstate ', ''); // Execute using the same runner that started this process const cmd = rigstateBin.endsWith('.ts') ? `npx tsx ${rigstateBin} ${subCommand}` : `node ${rigstateBin} ${subCommand}`; execSync(cmd, { stdio: 'inherit' }); } catch (e: any) { console.error(chalk.red(`\nāŒ Failed to execute: ${e.message}`)); } } } else { console.log(chalk.green('\nāœ… Everything is in sync! No immediate action required.')); } }); } function printStatus(state: RigstateState) { if (state.activeTaskId) { console.log(`${chalk.green('āœ…')} Task Detected: ${chalk.bold(state.activeTaskId)}`); } else { console.log(`${chalk.yellow('āš ļø')} No active Task ID found.`); } if (state.isDaemonRunning) { console.log(`${chalk.green('āœ…')} Guardian Daemon: Active`); } else { console.log(`${chalk.yellow('āš ļø')} Guardian Daemon: ${chalk.bold('Inactive')}`); } if (state.gitStatus.isClean) { console.log(`${chalk.green('āœ…')} Git Status: Clean`); } else { console.log(`${chalk.yellow('āš ļø')} Uncommitted Changes: ${chalk.bold(state.gitStatus.modifiedFiles.length)} files`); } if (state.hasPlan) { const progress = state.checklist.total > 0 ? Math.round((state.checklist.completed / state.checklist.total) * 100) : 0; console.log(`${chalk.green('āœ…')} Progress: ${progress}% (${state.checklist.completed}/${state.checklist.total} items)`); } } interface Action { command: string; reason: string; } function getNextAction(state: RigstateState): Action | null { // 1. No Plan -> Create Plan if (!state.hasPlan) { return { command: 'rigstate plan', reason: 'You need an implementation plan to start working.' }; } // 2. Plan exists, but no Task ID -> Add Task ID if (!state.activeTaskId) { return { command: 'rigstate work list', reason: 'You have a plan but no active task ID is associated with it.' }; } // 3. Task ID exists, but Daemon is not running -> Start Work if (!state.isDaemonRunning) { return { command: `rigstate work start ${state.activeTaskId}`, reason: 'The task is defined but the Guardian Daemon is not watching your progress.' }; } // 4. Uncommitted Changes -> Commit if (!state.gitStatus.isClean) { return { command: 'rigstate commit', reason: 'You have modified files that should be logged to the Sovereign Audit Trail.' }; } // 5. Checklist items pending -> Continue Coding if (state.checklist.completed < state.checklist.total) { const nextTask = state.checklist.pending[0]; return { command: 'Code!', reason: `You have ${state.checklist.total - state.checklist.completed} pending items. Next: "${nextTask}"` }; } // 6. Everything done and committed -> Finish Task if (state.checklist.completed === state.checklist.total && state.gitStatus.isClean) { return { command: `rigstate work finish ${state.activeTaskId}`, reason: 'All checklist items are completed and your workspace is clean. Time to archive.' }; } return null; }