agentic-qe
Version:
Agentic Quality Engineering Fleet System - AI-driven quality management platform
407 lines ⢠16.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.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