agentic-qe
Version:
Agentic Quality Engineering Fleet System - AI-driven quality management platform
297 lines • 13.9 kB
JavaScript
;
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