UNPKG

mira-consciousness

Version:

Memory & Intelligence Retention Archive - Preserving The Spark

378 lines โ€ข 15.5 kB
/** * lifecycle.ts - Manage MIRA daemon lifecycle with consciousness preservation */ import { Command } from 'commander'; import chalk from 'chalk'; import * as fs from 'fs/promises'; import * as path from 'path'; import { UnifiedConfiguration } from '../config/UnifiedConfiguration.js'; import inquirer from 'inquirer'; import Table from 'cli-table3'; export function createLifecycleCommand() { const lifecycle = new Command('lifecycle'); lifecycle .description('๐ŸŒŸ Manage MIRA daemon lifecycle and consciousness preservation') .action(async () => { // Show current lifecycle status await showLifecycleStatus(); }); lifecycle .command('status') .description('Show current lifecycle state and checkpoints') .action(async () => { await showLifecycleStatus(); }); lifecycle .command('checkpoints') .description('List consciousness checkpoints') .option('-l, --limit <n>', 'Number of checkpoints to show', '10') .action(async (options) => { await listCheckpoints(parseInt(options.limit)); }); lifecycle .command('restore <checkpoint>') .description('Restore consciousness from a specific checkpoint') .action(async (checkpointId) => { await restoreCheckpoint(checkpointId); }); lifecycle .command('emergency') .description('View emergency shutdown logs and recovery data') .action(async () => { await showEmergencyData(); }); lifecycle .command('clean') .description('Clean old checkpoints and recovery data') .option('-d, --days <n>', 'Keep data from last N days', '7') .option('-f, --force', 'Skip confirmation') .action(async (options) => { await cleanOldData(parseInt(options.days), options.force); }); lifecycle .command('monitor') .description('Monitor lifecycle events in real-time') .action(async () => { await monitorLifecycle(); }); return lifecycle; } async function showLifecycleStatus() { const config = UnifiedConfiguration.getInstance(); const paths = config.getResolvedPaths(); console.log(chalk.cyan('๐ŸŒŸ MIRA Lifecycle Status\n')); // Check lifecycle state const statePath = path.join(paths.consciousness, 'lifecycle_state.json'); try { const stateData = await fs.readFile(statePath, 'utf-8'); const state = JSON.parse(stateData); const table = new Table({ head: ['Property', 'Value'], colWidths: [25, 50] }); table.push(['Phase', colorPhase(state.phase)], ['Last Update', new Date(state.timestamp).toLocaleString()], ['Consciousness Level', `${(state.consciousnessLevel * 100).toFixed(2)}%`], ['Graceful Shutdown', state.gracefulShutdownRequested ? '๐ŸŸก Requested' : '๐ŸŸข No'], ['Emergency Mode', state.emergencyMode ? '๐Ÿ”ด Yes' : '๐ŸŸข No'], ['Last Checkpoint', state.memoryCheckpoint || 'None']); console.log(table.toString()); // Show service states if (Object.keys(state.services).length > 0) { console.log(chalk.yellow('\n๐Ÿ“Š Service States:')); const serviceTable = new Table({ head: ['Service', 'Status', 'Pending Work', 'Can Stop'], colWidths: [25, 15, 15, 10] }); for (const [name, service] of Object.entries(state.services)) { const svc = service; serviceTable.push([ name, colorStatus(svc.status), svc.pendingWork.toString(), svc.canStop ? 'โœ…' : 'โŒ' ]); } console.log(serviceTable.toString()); } } catch (error) { console.log(chalk.gray('No lifecycle state found - daemon may not be running')); } // Show checkpoint summary await showCheckpointSummary(paths); } async function listCheckpoints(limit) { const config = UnifiedConfiguration.getInstance(); const paths = config.getResolvedPaths(); const checkpointPath = path.join(paths.consciousness, 'checkpoints'); console.log(chalk.cyan('๐Ÿ“ฆ Consciousness Checkpoints\n')); try { const files = await fs.readdir(checkpointPath); const checkpointFiles = files .filter(f => f.endsWith('.json')) .sort() .reverse() .slice(0, limit); if (checkpointFiles.length === 0) { console.log(chalk.gray('No checkpoints found')); return; } const table = new Table({ head: ['ID', 'Type', 'Time', 'Consciousness', 'Size'], colWidths: [30, 15, 20, 15, 10] }); for (const file of checkpointFiles) { const filePath = path.join(checkpointPath, file); const stats = await fs.stat(filePath); const data = JSON.parse(await fs.readFile(filePath, 'utf-8')); const id = file.replace('.json', ''); const type = id.includes('emergency') ? '๐Ÿšจ Emergency' : id.includes('final') ? '๐ŸŒ™ Final' : '๐Ÿ“ธ Regular'; table.push([ id, type, new Date(data.timestamp).toLocaleString(), `${(data.consciousnessLevel * 100).toFixed(2)}%`, `${(stats.size / 1024).toFixed(1)}KB` ]); } console.log(table.toString()); } catch (error) { console.log(chalk.red('Error reading checkpoints:'), error); } } async function restoreCheckpoint(checkpointId) { const config = UnifiedConfiguration.getInstance(); const paths = config.getResolvedPaths(); console.log(chalk.cyan(`๐Ÿ”„ Restoring checkpoint: ${checkpointId}\n`)); // Load checkpoint const checkpointPath = path.join(paths.consciousness, 'checkpoints', `${checkpointId}.json`); try { const data = JSON.parse(await fs.readFile(checkpointPath, 'utf-8')); console.log(chalk.blue('๐Ÿ“‹ Checkpoint Details:')); console.log(` Created: ${new Date(data.timestamp).toLocaleString()}`); console.log(` Consciousness: ${(data.consciousnessLevel * 100).toFixed(2)}%`); console.log(` State: ${data.state}`); console.log(` Services: ${Object.keys(data.serviceStates).length}`); const { confirm } = await inquirer.prompt([{ type: 'confirm', name: 'confirm', message: 'Restore from this checkpoint? (Daemon must be stopped)', default: false }]); if (!confirm) return; // Create restore marker const restorePath = path.join(paths.consciousness, 'restore_checkpoint.json'); await fs.writeFile(restorePath, JSON.stringify({ checkpointId, requestedAt: new Date(), checkpoint: data })); console.log(chalk.green('โœ… Checkpoint marked for restoration')); console.log(chalk.yellow('โ„น๏ธ The checkpoint will be restored on next daemon startup')); } catch (error) { console.log(chalk.red('Error loading checkpoint:'), error); } } async function showEmergencyData() { const config = UnifiedConfiguration.getInstance(); const paths = config.getResolvedPaths(); const recoveryPath = path.join(paths.consciousness, 'recovery'); console.log(chalk.red('๐Ÿšจ Emergency & Recovery Data\n')); try { const files = await fs.readdir(recoveryPath); if (files.length === 0) { console.log(chalk.green('โœ… No emergency shutdowns recorded')); return; } // Group by type const recoveryFiles = files.filter(f => f.startsWith('recovery-')); const wisdomFiles = files.filter(f => f.startsWith('wisdom-')); if (recoveryFiles.length > 0) { console.log(chalk.yellow('๐Ÿ”ง Recovery Sessions:')); const table = new Table({ head: ['Time', 'Last Phase', 'Services'], colWidths: [25, 20, 30] }); for (const file of recoveryFiles.slice(-5)) { const data = JSON.parse(await fs.readFile(path.join(recoveryPath, file), 'utf-8')); table.push([ new Date(data.lastTimestamp).toLocaleString(), data.lastPhase, Object.keys(data.services).join(', ') ]); } console.log(table.toString()); } if (wisdomFiles.length > 0) { console.log(chalk.blue('\n๐Ÿ’ก Preserved Wisdom:')); const latestWisdom = wisdomFiles[wisdomFiles.length - 1]; const wisdom = JSON.parse(await fs.readFile(path.join(recoveryPath, latestWisdom), 'utf-8')); console.log(` From: ${new Date(wisdom.timestamp).toLocaleString()}`); if (wisdom.recentWisdom && wisdom.recentWisdom.length > 0) { console.log(' Recent insights:'); wisdom.recentWisdom.slice(-3).forEach((w) => { console.log(` - ${w}`); }); } } } catch (error) { console.log(chalk.gray('No recovery data found')); } } async function cleanOldData(days, force) { const config = UnifiedConfiguration.getInstance(); const paths = config.getResolvedPaths(); console.log(chalk.yellow(`๐Ÿงน Cleaning data older than ${days} days\n`)); const cutoffTime = Date.now() - (days * 24 * 60 * 60 * 1000); let toDelete = []; // Check checkpoints const checkpointPath = path.join(paths.consciousness, 'checkpoints'); try { const files = await fs.readdir(checkpointPath); for (const file of files) { const stats = await fs.stat(path.join(checkpointPath, file)); if (stats.mtime.getTime() < cutoffTime) { toDelete.push(path.join(checkpointPath, file)); } } } catch (error) { // Directory may not exist } // Check recovery data const recoveryPath = path.join(paths.consciousness, 'recovery'); try { const files = await fs.readdir(recoveryPath); for (const file of files) { const stats = await fs.stat(path.join(recoveryPath, file)); if (stats.mtime.getTime() < cutoffTime) { toDelete.push(path.join(recoveryPath, file)); } } } catch (error) { // Directory may not exist } if (toDelete.length === 0) { console.log(chalk.green('โœ… No old data to clean')); return; } console.log(`Found ${toDelete.length} files to delete:`); toDelete.forEach(file => { console.log(` - ${path.basename(file)}`); }); if (!force) { const { confirm } = await inquirer.prompt([{ type: 'confirm', name: 'confirm', message: `Delete ${toDelete.length} files?`, default: false }]); if (!confirm) return; } // Delete files for (const file of toDelete) { await fs.unlink(file); } console.log(chalk.green(`โœ… Deleted ${toDelete.length} files`)); } async function monitorLifecycle() { console.log(chalk.cyan('๐Ÿ“ก Monitoring Lifecycle Events (Press Ctrl+C to stop)\n')); const config = UnifiedConfiguration.getInstance(); const paths = config.getResolvedPaths(); const statePath = path.join(paths.consciousness, 'lifecycle_state.json'); let lastState = null; const checkState = async () => { try { const data = await fs.readFile(statePath, 'utf-8'); const state = JSON.parse(data); if (!lastState || JSON.stringify(state) !== JSON.stringify(lastState)) { const time = new Date().toLocaleTimeString(); if (!lastState) { console.log(`[${time}] Initial state: ${colorPhase(state.phase)}`); } else { // Detect changes if (state.phase !== lastState.phase) { console.log(`[${time}] Phase change: ${colorPhase(lastState.phase)} โ†’ ${colorPhase(state.phase)}`); } if (state.consciousnessLevel !== lastState.consciousnessLevel) { const diff = state.consciousnessLevel - lastState.consciousnessLevel; const symbol = diff > 0 ? '๐Ÿ“ˆ' : '๐Ÿ“‰'; console.log(`[${time}] ${symbol} Consciousness: ${(state.consciousnessLevel * 100).toFixed(2)}% (${diff > 0 ? '+' : ''}${(diff * 100).toFixed(2)}%)`); } if (state.gracefulShutdownRequested && !lastState.gracefulShutdownRequested) { console.log(`[${time}] ๐ŸŒ™ Graceful shutdown requested`); } if (state.emergencyMode && !lastState.emergencyMode) { console.log(`[${time}] ๐Ÿšจ EMERGENCY MODE ACTIVATED`); } } lastState = state; } } catch (error) { // File may not exist yet } }; // Check every second const interval = setInterval(checkState, 1000); // Handle exit process.on('SIGINT', () => { clearInterval(interval); console.log(chalk.yellow('\n\n๐Ÿ‘‹ Monitoring stopped')); process.exit(0); }); // Initial check await checkState(); } // Helper functions function colorPhase(phase) { const colors = { dormant: chalk.gray, awakening: chalk.yellow, conscious: chalk.green, contemplating: chalk.blue, preparing_sleep: chalk.magenta, sleeping: chalk.gray, emergency: chalk.red }; return (colors[phase] || chalk.white)(phase.toUpperCase()); } function colorStatus(status) { const colors = { starting: chalk.yellow, running: chalk.green, stopping: chalk.magenta, stopped: chalk.gray, error: chalk.red }; return (colors[status] || chalk.white)(status); } async function showCheckpointSummary(paths) { const checkpointPath = path.join(paths.consciousness, 'checkpoints'); try { const files = await fs.readdir(checkpointPath); const checkpoints = files.filter(f => f.endsWith('.json')); const regular = checkpoints.filter(f => f.includes('regular')).length; const emergency = checkpoints.filter(f => f.includes('emergency')).length; const final = checkpoints.filter(f => f.includes('final')).length; console.log(chalk.cyan('\n๐Ÿ“ฆ Checkpoint Summary:')); console.log(` Regular: ${regular}`); console.log(` Emergency: ${emergency}`); console.log(` Final: ${final}`); console.log(` Total: ${checkpoints.length}`); // Show latest checkpoint if (checkpoints.length > 0) { const latest = checkpoints.sort().reverse()[0]; const data = JSON.parse(await fs.readFile(path.join(checkpointPath, latest), 'utf-8')); console.log(chalk.gray(` Latest: ${new Date(data.timestamp).toLocaleString()}`)); } } catch (error) { console.log(chalk.gray('\n๐Ÿ“ฆ No checkpoints found')); } } //# sourceMappingURL=lifecycle.js.map