UNPKG

agentic-qe

Version:

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

407 lines • 16.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.FleetHealthCommand = void 0; const chalk_1 = __importDefault(require("chalk")); const fs = __importStar(require("fs-extra")); class FleetHealthCommand { 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 Health Check\n')); // Collect health data const healthReport = await this.performHealthCheck(options.detailed); // Display health report this.displayHealthReport(healthReport, options.detailed); // Export report if requested if (options.exportReport) { await this.exportHealthReport(healthReport); console.log(chalk_1.default.green('\nāœ… Health report exported')); } // Auto-fix if requested if (options.fix && healthReport.issues.length > 0) { await this.autoFixIssues(healthReport.issues); } // Store health check in coordination await this.storeHealthCheck(healthReport); return healthReport; } static async performHealthCheck(detailed) { const report = { timestamp: new Date().toISOString(), status: 'healthy', components: {}, issues: [], recommendations: [], metrics: {} }; // Check configuration health report.components.configuration = await this.checkConfigurationHealth(); // Check data integrity report.components.data = await this.checkDataIntegrity(); // Check agent health report.components.agents = await this.checkAgentHealth(); // Check task execution health report.components.tasks = await this.checkTaskHealth(); // Check coordination health report.components.coordination = await this.checkCoordinationHealth(); // Check system resources report.components.resources = await this.checkSystemResources(); // Calculate overall status const componentStatuses = Object.values(report.components).map((c) => c.status); const healthyCount = componentStatuses.filter(s => s === 'healthy').length; const totalCount = componentStatuses.length; if (healthyCount === totalCount) { report.status = 'healthy'; } else if (healthyCount >= totalCount * 0.7) { report.status = 'degraded'; } else { report.status = 'unhealthy'; } // Collect issues from all components Object.values(report.components).forEach((component) => { if (component.issues) { report.issues.push(...component.issues); } }); // Generate recommendations report.recommendations = this.generateRecommendations(report.components); // Collect detailed metrics if requested if (detailed) { report.metrics = await this.collectDetailedMetrics(); } return report; } static async checkConfigurationHealth() { const health = { status: 'healthy', issues: [], checks: [] }; // Check required configuration files const requiredFiles = [ '.agentic-qe/config/fleet.json', '.agentic-qe/config/agents.json' ]; for (const file of requiredFiles) { if (await fs.pathExists(file)) { health.checks.push({ file, status: 'ok' }); } else { health.issues.push({ severity: 'critical', message: `Missing configuration: ${file}` }); health.status = 'unhealthy'; } } // Validate configuration content if (await fs.pathExists('.agentic-qe/config/fleet.json')) { const config = await fs.readJson('.agentic-qe/config/fleet.json'); if (!config.topology) { health.issues.push({ severity: 'warning', message: 'No topology specified' }); health.status = 'degraded'; } if (!config.maxAgents || config.maxAgents < 1) { health.issues.push({ severity: 'critical', message: 'Invalid maxAgents configuration' }); health.status = 'unhealthy'; } } return health; } static async checkDataIntegrity() { const health = { status: 'healthy', issues: [] }; // Check data directory if (!await fs.pathExists('.agentic-qe/data')) { health.issues.push({ severity: 'warning', message: 'Data directory missing' }); health.status = 'degraded'; return health; } // Check registry file if (await fs.pathExists('.agentic-qe/data/registry.json')) { try { const registry = await fs.readJson('.agentic-qe/data/registry.json'); // Validate registry structure if (!registry.agents || !Array.isArray(registry.agents)) { health.issues.push({ severity: 'critical', message: 'Invalid registry structure' }); health.status = 'unhealthy'; } } catch (error) { health.issues.push({ severity: 'critical', message: 'Corrupted registry file' }); health.status = 'unhealthy'; } } return health; } static async checkAgentHealth() { const health = { status: 'healthy', issues: [], agentStats: {} }; const registryPath = '.agentic-qe/data/registry.json'; if (!await fs.pathExists(registryPath)) { health.issues.push({ severity: 'warning', message: 'No agent registry found' }); health.status = 'degraded'; return health; } const registry = await fs.readJson(registryPath); const agents = registry.agents || []; health.agentStats = { total: agents.length, active: agents.filter((a) => a.status === 'active').length, idle: agents.filter((a) => a.status === 'idle').length, failed: agents.filter((a) => a.status === 'failed').length }; // Check for failed agents if (health.agentStats.failed > 0) { health.issues.push({ severity: 'warning', message: `${health.agentStats.failed} failed agents detected` }); health.status = 'degraded'; } // Check for low active agent count if (health.agentStats.active < health.agentStats.total * 0.5) { health.issues.push({ severity: 'warning', message: 'Less than 50% of agents are active' }); health.status = 'degraded'; } return health; } static async checkTaskHealth() { const health = { status: 'healthy', issues: [], taskStats: {} }; const registryPath = '.agentic-qe/data/registry.json'; if (!await fs.pathExists(registryPath)) { return health; } const registry = await fs.readJson(registryPath); const tasks = registry.tasks || []; health.taskStats = { total: tasks.length, running: tasks.filter((t) => t.status === 'running').length, completed: tasks.filter((t) => t.status === 'completed').length, failed: tasks.filter((t) => t.status === 'failed').length }; // Calculate failure rate if (health.taskStats.total > 0) { const failureRate = health.taskStats.failed / health.taskStats.total; if (failureRate > 0.3) { health.issues.push({ severity: 'critical', message: `High task failure rate: ${(failureRate * 100).toFixed(1)}%` }); health.status = 'unhealthy'; } else if (failureRate > 0.1) { health.issues.push({ severity: 'warning', message: `Elevated task failure rate: ${(failureRate * 100).toFixed(1)}%` }); health.status = 'degraded'; } } return health; } static async checkCoordinationHealth() { const health = { status: 'healthy', issues: [] }; // Check coordination scripts const scriptsDir = '.agentic-qe/scripts'; if (await fs.pathExists(scriptsDir)) { const scripts = await fs.readdir(scriptsDir); if (scripts.length === 0) { health.issues.push({ severity: 'info', message: 'No coordination scripts found' }); } } // Check if Claude Flow memory is accessible try { const { execSync } = require('child_process'); execSync('npx claude-flow@alpha hooks notify --message "Health check"', { stdio: 'ignore', timeout: 5000 }); } catch (error) { health.issues.push({ severity: 'warning', message: 'Claude Flow coordination unavailable' }); health.status = 'degraded'; } return health; } static async checkSystemResources() { const health = { status: 'healthy', issues: [], resources: {} }; // Check disk space try { const stats = await fs.stat('.agentic-qe'); health.resources.dataDir = 'ok'; } catch (error) { health.issues.push({ severity: 'critical', message: 'Cannot access data directory' }); health.status = 'unhealthy'; } return health; } static generateRecommendations(components) { const recommendations = []; Object.entries(components).forEach(([name, component]) => { if (component.status !== 'healthy') { switch (name) { case 'configuration': recommendations.push('Run `aqe fleet init` to recreate configuration files'); break; case 'data': recommendations.push('Check data directory permissions and integrity'); break; case 'agents': recommendations.push('Investigate failed agents and restart if needed'); break; case 'tasks': recommendations.push('Review task logs for failure patterns'); break; case 'coordination': recommendations.push('Verify Claude Flow installation and configuration'); break; } } }); if (recommendations.length === 0) { recommendations.push('Fleet is healthy - continue regular monitoring'); } return recommendations; } static async collectDetailedMetrics() { return { timestamp: new Date().toISOString(), uptime: process.uptime() * 1000, memoryUsage: process.memoryUsage(), nodeVersion: process.version }; } static displayHealthReport(report, detailed) { // Overall status const statusColor = this.getHealthColor(report.status); console.log(chalk_1.default.blue('šŸ“Š Overall Health:')); console.log(` Status: ${statusColor(report.status.toUpperCase())}`); // Component health console.log(chalk_1.default.blue('\nšŸ”§ Component Health:')); Object.entries(report.components).forEach(([name, component]) => { const color = this.getHealthColor(component.status); console.log(` ${name}: ${color(component.status)}`); }); // Issues if (report.issues.length > 0) { console.log(chalk_1.default.red('\n🚨 Issues Detected:')); report.issues.forEach((issue) => { const severityColor = this.getSeverityColor(issue.severity); console.log(severityColor(` [${issue.severity.toUpperCase()}] ${issue.message}`)); }); } else { console.log(chalk_1.default.green('\nāœ… No issues detected')); } // Recommendations if (report.recommendations.length > 0) { console.log(chalk_1.default.yellow('\nšŸ’” Recommendations:')); report.recommendations.forEach((rec) => { console.log(chalk_1.default.gray(` • ${rec}`)); }); } // Detailed metrics if (detailed && report.metrics) { console.log(chalk_1.default.blue('\nšŸ“ˆ Detailed Metrics:')); console.log(chalk_1.default.gray(` Uptime: ${(report.metrics.uptime / 1000).toFixed(0)}s`)); console.log(chalk_1.default.gray(` Memory RSS: ${(report.metrics.memoryUsage.rss / 1024 / 1024).toFixed(2)} MB`)); console.log(chalk_1.default.gray(` Node Version: ${report.metrics.nodeVersion}`)); } } static getHealthColor(status) { const colors = { 'healthy': chalk_1.default.green, 'degraded': chalk_1.default.yellow, 'unhealthy': chalk_1.default.red, 'unknown': chalk_1.default.gray }; return colors[status] || chalk_1.default.white; } static getSeverityColor(severity) { const colors = { 'critical': chalk_1.default.red, 'warning': chalk_1.default.yellow, 'info': chalk_1.default.blue }; return colors[severity] || chalk_1.default.gray; } static async exportHealthReport(report) { const reportsDir = '.agentic-qe/reports'; await fs.ensureDir(reportsDir); const timestamp = new Date().toISOString().replace(/:/g, '-'); const reportFile = `${reportsDir}/health-report-${timestamp}.json`; await fs.writeJson(reportFile, report, { spaces: 2 }); console.log(chalk_1.default.gray(` Report saved: ${reportFile}`)); } static async autoFixIssues(issues) { console.log(chalk_1.default.blue('\nšŸ”§ Auto-fixing detected issues...\n')); for (const issue of issues) { if (issue.severity === 'critical' && issue.message.includes('Missing configuration')) { // Attempt to recreate missing configuration console.log(chalk_1.default.yellow(` Attempting to fix: ${issue.message}`)); // In production, this would call the actual fix logic } } } static async storeHealthCheck(report) { try { const { execSync } = require('child_process'); const data = JSON.stringify({ status: report.status, timestamp: report.timestamp }); const command = `npx claude-flow@alpha memory store --key "aqe/swarm/fleet-cli-commands/health" --value '${data}'`; execSync(command, { stdio: 'ignore', timeout: 5000 }); } catch (error) { // Silently handle coordination errors } } } exports.FleetHealthCommand = FleetHealthCommand; //# sourceMappingURL=health.js.map