UNPKG

agentic-qe

Version:

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

745 lines (730 loc) • 35.3 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.FleetCommand = void 0; const chalk_1 = __importDefault(require("chalk")); const ora_1 = __importDefault(require("ora")); const fs = __importStar(require("fs-extra")); class FleetCommand { static async execute(action, options) { console.log(chalk_1.default.blue.bold('\n🚁 Fleet Management Operations\n')); try { // Validate inputs await this.validateInputs(action, options); const spinner = (0, ora_1.default)('Initializing fleet operation...').start(); // Execute the requested action switch (action) { case 'status': await this.showFleetStatus(options, spinner); break; case 'scale': await this.scaleFleet(options, spinner); break; case 'deploy': await this.deployFleet(options, spinner); break; case 'destroy': await this.destroyFleet(options, spinner); break; case 'health': await this.healthCheck(options, spinner); break; default: await this.showFleetStatus(options, spinner); } } catch (error) { console.error(chalk_1.default.red('āŒ Fleet operation failed:'), error.message); if (options.verbose) { console.error(chalk_1.default.gray(error.stack)); } process.exit(1); } } static async validateInputs(action, options) { const validActions = ['status', 'scale', 'deploy', 'destroy', 'health']; if (!validActions.includes(action)) { throw new Error(`Invalid action '${action}'. Must be one of: ${validActions.join(', ')}`); } if (action === 'scale' && !options.agents) { throw new Error('Agent count required for scaling operation'); } if (action === 'scale' && options.agents) { const agentCount = parseInt(options.agents); if (agentCount < 1 || agentCount > 50) { throw new Error('Agent count must be between 1 and 50'); } } // Check if fleet configuration exists if (!await fs.pathExists('.agentic-qe/config/fleet.json')) { throw new Error('Fleet not initialized. Run: agentic-qe init'); } } static async showFleetStatus(options, spinner) { spinner.text = 'Loading fleet configuration...'; // Load fleet configuration const fleetConfig = await fs.readJson('.agentic-qe/config/fleet.json'); const agentConfig = await fs.readJson('.agentic-qe/config/agents.json'); spinner.text = 'Analyzing fleet status...'; // Load fleet registry const registryPath = '.agentic-qe/data/registry.json'; let fleetRegistry = { fleet: { agents: [], status: 'unknown' } }; if (await fs.pathExists(registryPath)) { fleetRegistry = await fs.readJson(registryPath); } // Get execution history const executionHistory = await this.getExecutionHistory(); // Analyze agent performance const agentPerformance = await this.analyzeAgentPerformance(); spinner.succeed(chalk_1.default.green('Fleet status loaded successfully!')); // Display comprehensive status this.displayFleetStatus(fleetConfig, agentConfig, fleetRegistry, executionHistory, agentPerformance, options); // Store status check in coordination await this.storeStatusCheck(); } static async scaleFleet(options, spinner) { const targetAgents = parseInt(options.agents); spinner.text = `Scaling fleet to ${targetAgents} agents...`; // Load current configuration const fleetConfig = await fs.readJson('.agentic-qe/config/fleet.json'); const agentConfig = await fs.readJson('.agentic-qe/config/agents.json'); // Calculate scaling changes const currentAgents = fleetConfig.maxAgents; const scalingOperation = targetAgents > currentAgents ? 'scale-up' : 'scale-down'; spinner.text = `Performing ${scalingOperation} operation...`; // Update configuration fleetConfig.maxAgents = targetAgents; fleetConfig.lastModified = new Date().toISOString(); // Update agent distribution const agentTypes = agentConfig.fleet.agents; const agentsPerType = Math.ceil(targetAgents / agentTypes.length); agentTypes.forEach((agent) => { agent.count = Math.min(agentsPerType, targetAgents); }); agentConfig.fleet.maxAgents = targetAgents; spinner.text = 'Updating configuration files...'; // Save updated configurations await fs.writeJson('.agentic-qe/config/fleet.json', fleetConfig, { spaces: 2 }); await fs.writeJson('.agentic-qe/config/agents.json', agentConfig, { spaces: 2 }); // Generate scaling script await this.generateScalingScript(scalingOperation, currentAgents, targetAgents, options); spinner.succeed(chalk_1.default.green(`Fleet scaled from ${currentAgents} to ${targetAgents} agents!`)); // Display scaling summary this.displayScalingSummary(currentAgents, targetAgents, scalingOperation); // Store scaling operation in coordination await this.storeScalingOperation(currentAgents, targetAgents); } static async deployFleet(options, spinner) { spinner.text = `Deploying fleet to ${options.env} environment...`; // Load configurations const fleetConfig = await fs.readJson('.agentic-qe/config/fleet.json'); const envConfig = await this.loadEnvironmentConfig(options.env); spinner.text = 'Preparing deployment manifests...'; // Generate deployment configuration const deploymentConfig = await this.generateDeploymentConfig(fleetConfig, envConfig, options); spinner.text = 'Creating deployment artifacts...'; // Create deployment directory const deploymentDir = `.agentic-qe/deployments/${options.env}-${Date.now()}`; await fs.ensureDir(deploymentDir); // Write deployment artifacts await fs.writeJson(`${deploymentDir}/deployment.json`, deploymentConfig, { spaces: 2 }); // Generate deployment scripts await this.generateDeploymentScripts(deploymentDir, deploymentConfig, options); spinner.text = 'Validating deployment configuration...'; // Validate deployment const validation = await this.validateDeployment(deploymentConfig); if (!validation.valid) { throw new Error(`Deployment validation failed: ${validation.errors.join(', ')}`); } spinner.succeed(chalk_1.default.green(`Fleet deployment prepared for ${options.env} environment!`)); // Display deployment summary this.displayDeploymentSummary(deploymentConfig, validation, options); // Store deployment operation await this.storeDeploymentOperation(deploymentConfig); } static async destroyFleet(options, spinner) { spinner.text = 'Initiating fleet destruction...'; // Load current configuration const fleetConfig = await fs.readJson('.agentic-qe/config/fleet.json'); spinner.text = 'Stopping all agents gracefully...'; // Generate destruction script const destructionScript = `#!/bin/bash # Fleet Destruction Script echo "Stopping Agentic QE Fleet..." # Stop coordination npx claude-flow@alpha hooks notify --message "Fleet destruction initiated" # Archive current state mkdir -p .agentic-qe/archive/$(date +%Y%m%d-%H%M%S) cp -r .agentic-qe/data/* .agentic-qe/archive/$(date +%Y%m%d-%H%M%S)/ cp -r .agentic-qe/reports/* .agentic-qe/archive/$(date +%Y%m%d-%H%M%S)/ # Clear runtime data rm -rf .agentic-qe/data/registry.json rm -rf .agentic-qe/executions/* echo "Fleet destroyed successfully" npx claude-flow@alpha hooks notify --message "Fleet destruction completed" `; await fs.writeFile('.agentic-qe/scripts/destroy-fleet.sh', destructionScript); await fs.chmod('.agentic-qe/scripts/destroy-fleet.sh', '755'); spinner.text = 'Archiving fleet data...'; // Create archive const archiveDir = `.agentic-qe/archive/${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}`; await fs.ensureDir(archiveDir); // Archive important data const dataToArchive = [ '.agentic-qe/config', '.agentic-qe/data', '.agentic-qe/reports' ]; for (const dataPath of dataToArchive) { if (await fs.pathExists(dataPath)) { await fs.copy(dataPath, `${archiveDir}/${dataPath.split('/').pop()}`); } } spinner.text = 'Cleaning up fleet resources...'; // Update fleet status const destructionRecord = { fleet: { id: fleetConfig.fleet?.id || 'unknown', status: 'destroyed', destroyedAt: new Date().toISOString(), reason: 'user_requested', agentCount: fleetConfig.maxAgents } }; await fs.writeJson('.agentic-qe/data/destruction.json', destructionRecord, { spaces: 2 }); spinner.succeed(chalk_1.default.green('Fleet destroyed successfully!')); // Display destruction summary this.displayDestructionSummary(fleetConfig, archiveDir); // Store destruction operation await this.storeDestructionOperation(destructionRecord); } static async healthCheck(options, spinner) { spinner.text = 'Running comprehensive health check...'; const healthReport = { timestamp: new Date().toISOString(), overall: 'unknown', components: {}, issues: [], recommendations: [] }; // Check configuration files spinner.text = 'Checking configuration integrity...'; healthReport.components.configuration = await this.checkConfigurationHealth(); // Check data integrity spinner.text = 'Checking data integrity...'; healthReport.components.data = await this.checkDataHealth(); // Check recent executions spinner.text = 'Checking execution history...'; healthReport.components.executions = await this.checkExecutionHealth(); // Check coordination status spinner.text = 'Checking coordination status...'; healthReport.components.coordination = await this.checkCoordinationHealth(); // Calculate overall health const componentStatuses = Object.values(healthReport.components).map((c) => c.status); const healthyCount = componentStatuses.filter((status) => status === 'healthy').length; const totalCount = componentStatuses.length; if (healthyCount === totalCount) { healthReport.overall = 'healthy'; } else if (healthyCount >= totalCount * 0.7) { healthReport.overall = 'degraded'; } else { healthReport.overall = 'critical'; } // Generate recommendations healthReport.recommendations = this.generateHealthRecommendations(healthReport.components); spinner.succeed(chalk_1.default.green('Health check completed!')); // Display health report this.displayHealthReport(healthReport, options); // Store health check results await this.storeHealthCheck(healthReport); } static async getExecutionHistory() { const reportsDir = '.agentic-qe/reports'; if (!await fs.pathExists(reportsDir)) { return []; } const reportFiles = await fs.readdir(reportsDir); const executionFiles = reportFiles .filter(file => file.startsWith('execution-') && file.endsWith('.json')) .sort() .reverse() .slice(0, 10); // Last 10 executions const history = []; for (const file of executionFiles) { try { const execution = await fs.readJson(`${reportsDir}/${file}`); history.push(execution); } catch (error) { // Skip corrupted files } } return history; } static async analyzeAgentPerformance() { const executionHistory = await this.getExecutionHistory(); const performance = { totalExecutions: executionHistory.length, averageSuccess: 0, averageDuration: 0, agentUtilization: {}, trends: 'stable' }; if (executionHistory.length === 0) { return performance; } // Calculate averages const totalTests = executionHistory.reduce((sum, exec) => sum + (exec.summary?.total || 0), 0); const passedTests = executionHistory.reduce((sum, exec) => sum + (exec.summary?.passed || 0), 0); const totalDuration = executionHistory.reduce((sum, exec) => sum + (exec.summary?.duration || 0), 0); performance.averageSuccess = totalTests > 0 ? (passedTests / totalTests) * 100 : 0; performance.averageDuration = totalDuration / executionHistory.length; // Analyze agent utilization executionHistory.forEach(exec => { Object.entries(exec.agents || {}).forEach(([agent, data]) => { if (!performance.agentUtilization[agent]) { performance.agentUtilization[agent] = { usage: 0, tasks: 0, avgDuration: 0 }; } performance.agentUtilization[agent].usage++; performance.agentUtilization[agent].tasks += data.tasks || 0; performance.agentUtilization[agent].avgDuration += data.duration || 0; }); }); // Normalize agent utilization Object.values(performance.agentUtilization).forEach((agent) => { agent.avgDuration = agent.avgDuration / agent.usage; }); return performance; } static displayFleetStatus(fleetConfig, agentConfig, registry, history, performance, options) { console.log(chalk_1.default.yellow('\n🚁 Fleet Status Dashboard\n')); // Basic fleet information console.log(chalk_1.default.blue('šŸ“‹ Fleet Configuration:')); console.log(chalk_1.default.gray(` Topology: ${fleetConfig.topology}`)); console.log(chalk_1.default.gray(` Max Agents: ${fleetConfig.maxAgents}`)); console.log(chalk_1.default.gray(` Testing Focus: ${fleetConfig.testingFocus?.join(', ') || 'Not specified'}`)); console.log(chalk_1.default.gray(` Environments: ${fleetConfig.environments?.join(', ') || 'Not specified'}`)); // Agent configuration console.log(chalk_1.default.blue('\nšŸ¤– Agent Configuration:')); const agents = agentConfig.fleet?.agents || []; agents.forEach((agent) => { console.log(chalk_1.default.gray(` ${agent.type}: ${agent.count} instances`)); }); // Fleet status console.log(chalk_1.default.blue('\nšŸ“Š Fleet Metrics:')); console.log(chalk_1.default.gray(` Registry Status: ${registry.fleet?.status || 'Unknown'}`)); console.log(chalk_1.default.gray(` Total Executions: ${performance.totalExecutions}`)); console.log(chalk_1.default.gray(` Average Success Rate: ${performance.averageSuccess.toFixed(1)}%`)); console.log(chalk_1.default.gray(` Average Execution Time: ${(performance.averageDuration / 1000).toFixed(2)}s`)); // Recent activity if (history.length > 0) { console.log(chalk_1.default.blue('\nšŸ“ˆ Recent Activity:')); const latest = history[0]; console.log(chalk_1.default.gray(` Latest Execution: ${new Date(latest.timestamp).toLocaleString()}`)); console.log(chalk_1.default.gray(` Tests: ${latest.summary?.passed || 0}/${latest.summary?.total || 0} passed`)); console.log(chalk_1.default.gray(` Duration: ${((latest.summary?.duration || 0) / 1000).toFixed(2)}s`)); } // Agent utilization (if verbose) if (options.verbose && Object.keys(performance.agentUtilization).length > 0) { console.log(chalk_1.default.blue('\nšŸ”§ Agent Utilization:')); Object.entries(performance.agentUtilization).forEach(([agent, data]) => { console.log(chalk_1.default.gray(` ${agent}: ${data.usage} uses, ${data.tasks} tasks, ${(data.avgDuration / 1000).toFixed(2)}s avg`)); }); } // Health indicators const healthStatus = this.calculateFleetHealth(fleetConfig, history, performance); console.log(chalk_1.default.blue('\nšŸ’š Health Status:')); console.log(chalk_1.default.gray(` Overall: ${this.getHealthColor(healthStatus.overall)}${healthStatus.overall}`)); if (healthStatus.warnings.length > 0) { console.log(chalk_1.default.yellow('\nāš ļø Warnings:')); healthStatus.warnings.forEach((warning) => { console.log(chalk_1.default.yellow(` • ${warning}`)); }); } // Next actions console.log(chalk_1.default.yellow('\nšŸ’” Recommended Actions:')); if (performance.totalExecutions === 0) { console.log(chalk_1.default.gray(' 1. Run initial tests: agentic-qe run tests')); } else { console.log(chalk_1.default.gray(' 1. Monitor fleet performance regularly')); if (performance.averageSuccess < 90) { console.log(chalk_1.default.gray(' 2. Investigate failing tests')); } } console.log(chalk_1.default.gray(' 3. Scale fleet if needed: agentic-qe fleet scale --agents <count>')); } static calculateFleetHealth(fleetConfig, history, performance) { const health = { overall: 'healthy', warnings: [] }; // Check configuration issues if (!fleetConfig.testingFocus || fleetConfig.testingFocus.length === 0) { health.warnings.push('No testing focus areas configured'); } // Check execution history if (history.length === 0) { health.warnings.push('No test execution history found'); health.overall = 'unknown'; } else { // Check success rate if (performance.averageSuccess < 80) { health.warnings.push(`Low success rate: ${performance.averageSuccess.toFixed(1)}%`); health.overall = 'degraded'; } // Check recent activity const latestExecution = new Date(history[0].timestamp); const daysSinceLastExecution = (Date.now() - latestExecution.getTime()) / (1000 * 60 * 60 * 24); if (daysSinceLastExecution > 7) { health.warnings.push('No recent test executions (>7 days)'); health.overall = 'stale'; } } // Critical issues if (health.warnings.length > 3) { health.overall = 'critical'; } return health; } static getHealthColor(status) { const colors = { 'healthy': chalk_1.default.green, 'degraded': chalk_1.default.yellow, 'critical': chalk_1.default.red, 'unknown': chalk_1.default.gray, 'stale': chalk_1.default.yellow }; return (colors[status] || chalk_1.default.white); } static displayScalingSummary(current, target, operation) { console.log(chalk_1.default.yellow('\nšŸ“Š Scaling Summary:')); console.log(chalk_1.default.gray(` Operation: ${operation}`)); console.log(chalk_1.default.gray(` Previous Agent Count: ${current}`)); console.log(chalk_1.default.gray(` New Agent Count: ${target}`)); console.log(chalk_1.default.gray(` Change: ${target > current ? '+' : ''}${target - current} agents`)); console.log(chalk_1.default.yellow('\nšŸ’” Next Steps:')); console.log(chalk_1.default.gray(' 1. Verify agent allocation with: agentic-qe fleet status --verbose')); console.log(chalk_1.default.gray(' 2. Run tests to validate scaled fleet: agentic-qe run tests')); } static displayDeploymentSummary(config, validation, options) { console.log(chalk_1.default.yellow('\nšŸ“¦ Deployment Summary:')); console.log(chalk_1.default.gray(` Environment: ${options.env}`)); console.log(chalk_1.default.gray(` Agents: ${config.agentCount}`)); console.log(chalk_1.default.gray(` Components: ${config.components?.length || 0}`)); console.log(chalk_1.default.gray(` Validation: ${validation.valid ? 'Passed' : 'Failed'}`)); if (validation.warnings?.length > 0) { console.log(chalk_1.default.yellow('\nāš ļø Deployment Warnings:')); validation.warnings.forEach((warning) => { console.log(chalk_1.default.yellow(` • ${warning}`)); }); } console.log(chalk_1.default.yellow('\nšŸ’” Next Steps:')); console.log(chalk_1.default.gray(' 1. Review deployment artifacts in .agentic-qe/deployments/')); console.log(chalk_1.default.gray(' 2. Execute deployment script to apply changes')); console.log(chalk_1.default.gray(' 3. Monitor deployment status after execution')); } static displayDestructionSummary(fleetConfig, archiveDir) { console.log(chalk_1.default.yellow('\nšŸ’„ Fleet Destruction Summary:')); console.log(chalk_1.default.gray(` Fleet ID: ${fleetConfig.fleet?.id || 'Unknown'}`)); console.log(chalk_1.default.gray(` Agents Destroyed: ${fleetConfig.maxAgents}`)); console.log(chalk_1.default.gray(` Data Archived: ${archiveDir}`)); console.log(chalk_1.default.gray(` Destruction Time: ${new Date().toLocaleString()}`)); console.log(chalk_1.default.yellow('\nšŸ’” Important Notes:')); console.log(chalk_1.default.gray(' • All fleet data has been archived for recovery')); console.log(chalk_1.default.gray(' • Run agentic-qe init to create a new fleet')); console.log(chalk_1.default.gray(' • Historical data remains accessible in archive')); } static displayHealthReport(healthReport, options) { console.log(chalk_1.default.yellow('\nšŸ„ Fleet Health Report\n')); // Overall status const overallColor = this.getHealthColor(healthReport.overall); console.log(chalk_1.default.blue('šŸ“Š Overall Health:')); console.log(` Status: ${overallColor(healthReport.overall.toUpperCase())}`); // Component health console.log(chalk_1.default.blue('\nšŸ”§ Component Health:')); Object.entries(healthReport.components).forEach(([component, data]) => { const statusColor = this.getHealthColor(data.status); console.log(` ${component}: ${statusColor(data.status)} ${data.message ? `- ${data.message}` : ''}`); }); // Issues if (healthReport.issues.length > 0) { console.log(chalk_1.default.red('\n🚨 Issues Found:')); healthReport.issues.forEach((issue) => { console.log(chalk_1.default.red(` • ${issue.severity.toUpperCase()}: ${issue.description}`)); }); } // Recommendations if (healthReport.recommendations.length > 0) { console.log(chalk_1.default.yellow('\nšŸ’” Recommendations:')); healthReport.recommendations.forEach((rec) => { console.log(chalk_1.default.gray(` • ${rec}`)); }); } console.log(chalk_1.default.yellow('\nšŸ“ Health Report Saved:')); console.log(chalk_1.default.gray(' Location: .agentic-qe/reports/health-check-[timestamp].json')); } // Helper methods for deployment and health checks static async loadEnvironmentConfig(env) { const envConfigPath = `.agentic-qe/config/environments.json`; if (await fs.pathExists(envConfigPath)) { const envConfigs = await fs.readJson(envConfigPath); return envConfigs[env] || {}; } return {}; } static async generateDeploymentConfig(fleetConfig, envConfig, options) { return { version: '1.0', environment: options.env, fleet: fleetConfig, environment_config: envConfig, agentCount: fleetConfig.maxAgents, components: [ 'fleet-manager', 'agent-registry', 'coordination-service', 'monitoring-dashboard' ], resources: { memory: `${fleetConfig.maxAgents * 100}MB`, cpu: `${fleetConfig.maxAgents * 0.5}`, storage: '1GB' }, metadata: { generatedAt: new Date().toISOString(), topology: fleetConfig.topology } }; } static async generateDeploymentScripts(deploymentDir, config, options) { const deployScript = `#!/bin/bash # Deployment script for ${options.env} environment echo "Deploying Agentic QE Fleet to ${options.env}..." # Pre-deployment hooks npx claude-flow@alpha hooks pre-task --description "Fleet deployment to ${options.env}" # Deploy components echo "Deploying ${config.agentCount} agents..." # Post-deployment validation echo "Validating deployment..." # Store deployment status npx claude-flow@alpha memory store --key "agentic-qe/deployment/status" --value "deployed" npx claude-flow@alpha hooks notify --message "Fleet deployed to ${options.env}" echo "Deployment completed successfully!" `; await fs.writeFile(`${deploymentDir}/deploy.sh`, deployScript); await fs.chmod(`${deploymentDir}/deploy.sh`, '755'); } static async validateDeployment(config) { const validation = { valid: true, errors: [], warnings: [] }; // Validate agent count if (config.agentCount < 1) { validation.errors.push('Agent count must be at least 1'); validation.valid = false; } // Validate resources if (!config.resources) { validation.warnings.push('No resource limits specified'); } // Validate environment if (!config.environment) { validation.errors.push('Environment not specified'); validation.valid = false; } return validation; } static async generateScalingScript(operation, current, target, options) { const script = `#!/bin/bash # Fleet scaling script: ${operation} echo "Scaling fleet from ${current} to ${target} agents..." # Pre-scaling coordination npx claude-flow@alpha hooks pre-task --description "Fleet scaling: ${operation}" # Update agent configurations echo "Updating agent configurations..." # Restart services if needed if [ "${operation}" = "scale-up" ]; then echo "Starting additional agents..." else echo "Stopping excess agents..." fi # Post-scaling validation echo "Validating scaled fleet..." # Store scaling results npx claude-flow@alpha memory store --key "agentic-qe/scaling/latest" --value '{"from":${current},"to":${target},"operation":"${operation}"}' npx claude-flow@alpha hooks notify --message "Fleet scaled: ${operation} from ${current} to ${target} agents" echo "Scaling completed successfully!" `; await fs.writeFile('.agentic-qe/scripts/scale-fleet.sh', script); await fs.chmod('.agentic-qe/scripts/scale-fleet.sh', '755'); } static async checkConfigurationHealth() { const health = { status: 'healthy', issues: [] }; const requiredFiles = [ '.agentic-qe/config/fleet.json', '.agentic-qe/config/agents.json' ]; for (const file of requiredFiles) { if (!await fs.pathExists(file)) { health.issues.push(`Missing configuration file: ${file}`); health.status = 'critical'; } } return health; } static async checkDataHealth() { const health = { status: 'healthy', issues: [] }; // Check if data directory exists if (!await fs.pathExists('.agentic-qe/data')) { health.issues.push('Data directory missing'); health.status = 'degraded'; } return health; } static async checkExecutionHealth() { const health = { status: 'healthy', issues: [] }; const executionHistory = await this.getExecutionHistory(); if (executionHistory.length === 0) { health.issues.push('No execution history found'); health.status = 'unknown'; } else { const latestExecution = executionHistory[0]; const failureRate = latestExecution.summary?.failed / latestExecution.summary?.total; if (failureRate > 0.2) { health.issues.push(`High failure rate: ${(failureRate * 100).toFixed(1)}%`); health.status = 'degraded'; } } return health; } static async checkCoordinationHealth() { const health = { status: 'healthy', issues: [] }; // Check if coordination scripts exist const coordinationScripts = [ '.agentic-qe/scripts/pre-execution.sh', '.agentic-qe/scripts/post-execution.sh' ]; let scriptsFound = 0; for (const script of coordinationScripts) { if (await fs.pathExists(script)) { scriptsFound++; } } if (scriptsFound === 0) { health.issues.push('No coordination scripts found'); health.status = 'degraded'; } return health; } static generateHealthRecommendations(components) { const recommendations = []; Object.entries(components).forEach(([component, data]) => { if (data.status !== 'healthy') { switch (component) { case 'configuration': recommendations.push('Run agentic-qe init to recreate missing configuration files'); break; case 'data': recommendations.push('Ensure data directory exists and has proper permissions'); break; case 'executions': recommendations.push('Run agentic-qe run tests to generate execution history'); break; case 'coordination': recommendations.push('Check Claude Flow integration and coordination scripts'); break; } } }); if (recommendations.length === 0) { recommendations.push('Fleet is healthy - continue regular monitoring'); } return recommendations; } // Coordination storage methods static async storeStatusCheck() { const script = `npx claude-flow@alpha hooks notify --message "Fleet status check completed"`; await this.executeCoordinationScript(script); } static async storeScalingOperation(current, target) { const script = `npx claude-flow@alpha memory store --key "agentic-qe/fleet/scaling" --value '{"from":${current},"to":${target},"timestamp":"${new Date().toISOString()}"}'`; await this.executeCoordinationScript(script); } static async storeDeploymentOperation(config) { const script = `npx claude-flow@alpha memory store --key "agentic-qe/fleet/deployment" --value '${JSON.stringify(config)}'`; await this.executeCoordinationScript(script); } static async storeDestructionOperation(record) { const script = `npx claude-flow@alpha memory store --key "agentic-qe/fleet/destruction" --value '${JSON.stringify(record)}'`; await this.executeCoordinationScript(script); } static async storeHealthCheck(healthReport) { // Save health report to file const reportsDir = '.agentic-qe/reports'; await fs.ensureDir(reportsDir); const timestamp = new Date().toISOString().replace(/:/g, '-'); const reportFile = `${reportsDir}/health-check-${timestamp}.json`; await fs.writeJson(reportFile, healthReport, { spaces: 2 }); // Store in coordination const script = `npx claude-flow@alpha memory store --key "agentic-qe/fleet/health" --value '{"status":"${healthReport.overall}","timestamp":"${healthReport.timestamp}"}'`; await this.executeCoordinationScript(script); } static async executeCoordinationScript(script) { try { const { execSecure } = require('../../../security/secure-command-executor'); // Validate the script contains only safe coordination commands const allowedCommands = ['npx claude-flow@alpha memory store', 'npx claude-flow@alpha hooks']; const isAllowedScript = allowedCommands.some(cmd => script.startsWith(cmd)); if (!isAllowedScript) { console.warn(chalk_1.default.yellow(`āš ļø Script not allowed: ${script}`)); return; } execSecure(script, (error) => { if (error) { console.warn(chalk_1.default.yellow(`āš ļø Coordination warning: ${error.message}`)); } }); } catch (error) { // Silently handle coordination errors } } } exports.FleetCommand = FleetCommand; //# sourceMappingURL=fleet.js.map