UNPKG

agentic-qe

Version:

Agentic Quality Engineering Fleet System - AI-driven quality management platform

297 lines 13.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FleetShutdownCommand = void 0; const chalk_1 = __importDefault(require("chalk")); const fs = __importStar(require("fs-extra")); class FleetShutdownCommand { static async execute(options) { // Check if fleet is initialized if (!await fs.pathExists('.agentic-qe/config/fleet.json')) { throw new Error('Fleet not initialized. Run: aqe fleet init'); } console.log(chalk_1.default.blue.bold('\n⏹️ Fleet Shutdown\n')); const fleetConfig = await fs.readJson('.agentic-qe/config/fleet.json'); // Confirm shutdown if (!options.force && !options.graceful) { console.log(chalk_1.default.yellow('⚠️ This will shut down the entire fleet. Use --graceful for safe shutdown.')); } // Archive data if requested if (options.archive) { await this.archiveFleetData(fleetConfig); } // Update status to shutting down await this.updateFleetStatus('shutting_down'); // Graceful shutdown if (options.graceful) { await this.gracefulShutdown(); } else if (options.force) { await this.forceShutdown(); } else { await this.standardShutdown(); } // Preserve state if requested if (options.preserve) { await this.preserveState(fleetConfig); } else { // Clean up runtime data await this.cleanupRuntimeData(); } // Update final status await this.updateFleetStatus('shutdown'); // Generate shutdown report await this.generateShutdownReport(fleetConfig, options); console.log(chalk_1.default.green('\n✅ Fleet shut down successfully')); // Store shutdown in coordination await this.storeShutdownOperation(options); } static async archiveFleetData(fleetConfig) { console.log(chalk_1.default.blue('📦 Archiving fleet data...')); const archiveDir = `.agentic-qe/archive/shutdown-${Date.now()}`; await fs.ensureDir(archiveDir); // Archive directories const dirsToArchive = [ '.agentic-qe/config', '.agentic-qe/data', '.agentic-qe/reports', '.agentic-qe/logs' ]; for (const dir of dirsToArchive) { if (await fs.pathExists(dir)) { const dirName = dir.split('/').pop(); await fs.copy(dir, `${archiveDir}/${dirName}`, { overwrite: true }); } } // Create archive manifest const manifest = { fleetId: fleetConfig.id, topology: fleetConfig.topology, maxAgents: fleetConfig.maxAgents, archivedAt: new Date().toISOString(), reason: 'shutdown' }; await fs.writeJson(`${archiveDir}/manifest.json`, manifest, { spaces: 2 }); console.log(chalk_1.default.gray(` Archive saved: ${archiveDir}`)); } static async updateFleetStatus(status) { const fleetConfig = await fs.readJson('.agentic-qe/config/fleet.json'); fleetConfig.status = status; fleetConfig.lastStatusUpdate = new Date().toISOString(); if (status === 'shutdown') { fleetConfig.shutdownAt = new Date().toISOString(); } await fs.writeJson('.agentic-qe/config/fleet.json', fleetConfig, { spaces: 2 }); // Update registry if (await fs.pathExists('.agentic-qe/data/registry.json')) { const registry = await fs.readJson('.agentic-qe/data/registry.json'); registry.fleet = registry.fleet || {}; registry.fleet.status = status; await fs.writeJson('.agentic-qe/data/registry.json', registry, { spaces: 2 }); } } static async gracefulShutdown() { console.log(chalk_1.default.blue('🛑 Graceful shutdown initiated...')); // Load registry if (await fs.pathExists('.agentic-qe/data/registry.json')) { const registry = await fs.readJson('.agentic-qe/data/registry.json'); // Wait for running tasks const runningTasks = registry.tasks?.filter((t) => t.status === 'running') || []; if (runningTasks.length > 0) { console.log(chalk_1.default.yellow(` Waiting for ${runningTasks.length} tasks to complete...`)); // Simulate waiting for tasks await new Promise(resolve => setTimeout(resolve, 3000)); // Mark remaining tasks as cancelled registry.tasks?.forEach((task) => { if (task.status === 'running') { task.status = 'cancelled'; task.cancelledAt = new Date().toISOString(); task.reason = 'fleet_shutdown'; } }); } // Stop all agents gracefully registry.agents?.forEach((agent) => { agent.status = 'stopped'; agent.stoppedAt = new Date().toISOString(); agent.shutdownReason = 'graceful'; }); await fs.writeJson('.agentic-qe/data/registry.json', registry, { spaces: 2 }); } console.log(chalk_1.default.gray(' All agents stopped gracefully')); } static async forceShutdown() { console.log(chalk_1.default.yellow('⚠️ Force shutdown initiated...')); // Load registry if (await fs.pathExists('.agentic-qe/data/registry.json')) { const registry = await fs.readJson('.agentic-qe/data/registry.json'); // Immediately stop all agents registry.agents?.forEach((agent) => { agent.status = 'stopped'; agent.stoppedAt = new Date().toISOString(); agent.shutdownReason = 'force'; }); // Cancel all tasks registry.tasks?.forEach((task) => { if (task.status !== 'completed' && task.status !== 'failed') { task.status = 'cancelled'; task.cancelledAt = new Date().toISOString(); task.reason = 'force_shutdown'; } }); await fs.writeJson('.agentic-qe/data/registry.json', registry, { spaces: 2 }); } console.log(chalk_1.default.gray(' All agents force stopped')); } static async standardShutdown() { console.log(chalk_1.default.blue('🛑 Standard shutdown initiated...')); // Load registry if (await fs.pathExists('.agentic-qe/data/registry.json')) { const registry = await fs.readJson('.agentic-qe/data/registry.json'); // Give tasks brief time to complete const runningTasks = registry.tasks?.filter((t) => t.status === 'running') || []; if (runningTasks.length > 0) { console.log(chalk_1.default.yellow(` Allowing ${runningTasks.length} tasks brief time to complete...`)); await new Promise(resolve => setTimeout(resolve, 5000)); } // Stop agents registry.agents?.forEach((agent) => { agent.status = 'stopped'; agent.stoppedAt = new Date().toISOString(); agent.shutdownReason = 'standard'; }); await fs.writeJson('.agentic-qe/data/registry.json', registry, { spaces: 2 }); } console.log(chalk_1.default.gray(' All agents stopped')); } static async preserveState(fleetConfig) { console.log(chalk_1.default.blue('💾 Preserving fleet state...')); const stateDir = '.agentic-qe/state'; await fs.ensureDir(stateDir); // Save state snapshot const state = { fleetConfig, preservedAt: new Date().toISOString(), canRestore: true }; // Copy critical files to state directory const filesToPreserve = [ '.agentic-qe/config/fleet.json', '.agentic-qe/config/agents.json', '.agentic-qe/data/registry.json' ]; for (const file of filesToPreserve) { if (await fs.pathExists(file)) { const fileName = file.split('/').pop(); await fs.copy(file, `${stateDir}/${fileName}`, { overwrite: true }); } } await fs.writeJson(`${stateDir}/state.json`, state, { spaces: 2 }); console.log(chalk_1.default.gray(' State preserved - can be restored with: aqe fleet restart --restore')); } static async cleanupRuntimeData() { console.log(chalk_1.default.blue('🧹 Cleaning up runtime data...')); // Clear temporary and cache directories const cleanupDirs = [ '.agentic-qe/tmp', '.agentic-qe/cache', '.agentic-qe/locks' ]; for (const dir of cleanupDirs) { if (await fs.pathExists(dir)) { await fs.remove(dir); } } // Clear active execution data if (await fs.pathExists('.agentic-qe/data/registry.json')) { const registry = await fs.readJson('.agentic-qe/data/registry.json'); // Keep only historical data registry.agents = []; registry.tasks = registry.tasks?.filter((t) => t.status === 'completed' || t.status === 'failed') || []; await fs.writeJson('.agentic-qe/data/registry.json', registry, { spaces: 2 }); } console.log(chalk_1.default.gray(' Runtime data cleaned')); } static async generateShutdownReport(fleetConfig, options) { const reportsDir = '.agentic-qe/reports'; await fs.ensureDir(reportsDir); // Load registry for stats let registry = { agents: [], tasks: [] }; if (await fs.pathExists('.agentic-qe/data/registry.json')) { registry = await fs.readJson('.agentic-qe/data/registry.json'); } const report = { fleetId: fleetConfig.id, topology: fleetConfig.topology, maxAgents: fleetConfig.maxAgents, shutdownMode: options.force ? 'force' : options.graceful ? 'graceful' : 'standard', shutdownAt: new Date().toISOString(), archived: options.archive || false, statePreserved: options.preserve || false, statistics: { totalAgents: registry.agents.length, stoppedAgents: registry.agents.filter((a) => a.status === 'stopped').length, totalTasks: registry.tasks.length, completedTasks: registry.tasks.filter((t) => t.status === 'completed').length, cancelledTasks: registry.tasks.filter((t) => t.status === 'cancelled').length } }; const timestamp = new Date().toISOString().replace(/:/g, '-'); const reportFile = `${reportsDir}/shutdown-${timestamp}.json`; await fs.writeJson(reportFile, report, { spaces: 2 }); console.log(chalk_1.default.blue('\n📊 Shutdown Summary:')); console.log(chalk_1.default.gray(` Fleet ID: ${report.fleetId}`)); console.log(chalk_1.default.gray(` Mode: ${report.shutdownMode}`)); console.log(chalk_1.default.gray(` Agents Stopped: ${report.statistics.stoppedAgents}/${report.statistics.totalAgents}`)); console.log(chalk_1.default.gray(` Tasks Completed: ${report.statistics.completedTasks}/${report.statistics.totalTasks}`)); if (report.statistics.cancelledTasks > 0) { console.log(chalk_1.default.yellow(` Tasks Cancelled: ${report.statistics.cancelledTasks}`)); } console.log(chalk_1.default.gray(` Report: ${reportFile}`)); } static async storeShutdownOperation(options) { try { const { execSync } = require('child_process'); const data = JSON.stringify({ mode: options.force ? 'force' : options.graceful ? 'graceful' : 'standard', archived: options.archive || false, preserved: options.preserve || false, timestamp: new Date().toISOString() }); const command = `npx claude-flow@alpha memory store --key "aqe/swarm/fleet-cli-commands/shutdown" --value '${data}'`; execSync(command, { stdio: 'ignore', timeout: 5000 }); } catch (error) { // Silently handle coordination errors } } } exports.FleetShutdownCommand = FleetShutdownCommand; //# sourceMappingURL=shutdown.js.map