agentic-qe
Version:
Agentic Quality Engineering Fleet System - AI-driven quality management platform
256 lines ⢠10.5 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.FleetLogsCommand = void 0;
const chalk_1 = __importDefault(require("chalk"));
const fs = __importStar(require("fs-extra"));
class FleetLogsCommand {
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 Logs\n'));
// Ensure logs directory exists
const logsDir = '.agentic-qe/logs';
await fs.ensureDir(logsDir);
// Get log files
const logFiles = await this.getLogFiles(logsDir);
if (logFiles.length === 0) {
console.log(chalk_1.default.yellow('No log files found'));
return '';
}
// Read and filter logs
const logs = await this.readLogs(logFiles, options);
// Display logs
this.displayLogs(logs, options);
// Follow mode
if (options.follow) {
await this.followLogs(logFiles, options);
}
// Store log access in coordination
await this.storeLogAccess();
return logs;
}
static async getLogFiles(logsDir) {
const files = await fs.readdir(logsDir);
return files
.filter(f => f.endsWith('.log'))
.map(f => `${logsDir}/${f}`)
.sort()
.reverse(); // Most recent first
}
static async readLogs(logFiles, options) {
let allLogs = '';
// Read logs from all files
for (const logFile of logFiles) {
if (await fs.pathExists(logFile)) {
const content = await fs.readFile(logFile, 'utf-8');
allLogs += content;
}
}
// Split into lines
let lines = allLogs.split('\n').filter(line => line.trim().length > 0);
// Filter by level
if (options.level) {
const levelUpper = options.level.toUpperCase();
lines = lines.filter(line => line.includes(`[${levelUpper}]`));
}
// Filter by agent
if (options.agent) {
lines = lines.filter(line => line.includes(options.agent));
}
// Filter by timestamp
if (options.since) {
const sinceDate = new Date(options.since);
lines = lines.filter(line => {
const timestamp = this.extractTimestamp(line);
return timestamp && new Date(timestamp) >= sinceDate;
});
}
// Limit lines
const lineLimit = options.lines || 100;
lines = lines.slice(-lineLimit);
return lines.join('\n');
}
static displayLogs(logs, options) {
if (!logs) {
console.log(chalk_1.default.yellow('No logs match the specified filters'));
return;
}
const lines = logs.split('\n');
lines.forEach(line => {
// Colorize log levels
if (line.includes('[ERROR]')) {
console.log(chalk_1.default.red(line));
}
else if (line.includes('[WARN]')) {
console.log(chalk_1.default.yellow(line));
}
else if (line.includes('[INFO]')) {
console.log(chalk_1.default.blue(line));
}
else if (line.includes('[DEBUG]')) {
console.log(chalk_1.default.gray(line));
}
else {
console.log(line);
}
});
console.log(chalk_1.default.gray(`\n(Showing ${lines.length} lines)`));
}
static async followLogs(logFiles, options) {
console.log(chalk_1.default.blue('\nš” Following logs... (Press Ctrl+C to stop)\n'));
this.isFollowing = true;
let lastPosition = 0;
// Get initial file sizes
const fileSizes = {};
for (const file of logFiles) {
const stats = await fs.stat(file);
fileSizes[file] = stats.size;
}
this.followInterval = setInterval(async () => {
if (!this.isFollowing) {
this.stopFollowing();
return;
}
// Check each log file for new content
for (const file of logFiles) {
try {
const stats = await fs.stat(file);
const currentSize = stats.size;
const lastSize = fileSizes[file] || 0;
if (currentSize > lastSize) {
// Read new content
const stream = fs.createReadStream(file, {
start: lastSize,
end: currentSize
});
let newContent = '';
for await (const chunk of stream) {
newContent += chunk.toString();
}
// Display new lines
const newLines = newContent.split('\n').filter(l => l.trim().length > 0);
newLines.forEach(line => {
// Apply filters
if (options.level && !line.includes(`[${options.level.toUpperCase()}]`)) {
return;
}
if (options.agent && !line.includes(options.agent)) {
return;
}
// Colorize and display
if (line.includes('[ERROR]')) {
console.log(chalk_1.default.red(line));
}
else if (line.includes('[WARN]')) {
console.log(chalk_1.default.yellow(line));
}
else if (line.includes('[INFO]')) {
console.log(chalk_1.default.blue(line));
}
else if (line.includes('[DEBUG]')) {
console.log(chalk_1.default.gray(line));
}
else {
console.log(line);
}
});
fileSizes[file] = currentSize;
}
}
catch (error) {
// File might have been rotated or removed
}
}
}, 1000); // Check every second
// Handle graceful shutdown
process.on('SIGINT', () => {
this.stopFollowing();
console.log(chalk_1.default.yellow('\n\nš Log following stopped'));
process.exit(0);
});
// Keep process alive
await new Promise(() => { });
}
static stopFollowing() {
this.isFollowing = false;
if (this.followInterval) {
clearInterval(this.followInterval);
this.followInterval = null;
}
}
static extractTimestamp(line) {
// Try to extract ISO timestamp
const isoMatch = line.match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/);
if (isoMatch) {
return isoMatch[0];
}
// Try to extract other timestamp formats
const dateMatch = line.match(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/);
if (dateMatch) {
return dateMatch[0];
}
return null;
}
static async storeLogAccess() {
try {
const { execSync } = require('child_process');
const data = JSON.stringify({
accessedAt: new Date().toISOString()
});
const command = `npx claude-flow@alpha memory store --key "aqe/swarm/fleet-cli-commands/logs" --value '${data}'`;
execSync(command, { stdio: 'ignore', timeout: 5000 });
}
catch (error) {
// Silently handle coordination errors
}
}
// Helper method to generate sample logs for testing
static async generateSampleLogs() {
const logsDir = '.agentic-qe/logs';
await fs.ensureDir(logsDir);
const timestamp = new Date().toISOString();
const logFile = `${logsDir}/fleet-${new Date().toISOString().split('T')[0]}.log`;
const sampleLogs = [
`${timestamp} [INFO] Fleet initialized with topology: hierarchical`,
`${timestamp} [INFO] Agent qe-test-generator spawned`,
`${timestamp} [INFO] Agent qe-test-executor spawned`,
`${timestamp} [WARN] Agent qe-coverage-analyzer: High memory usage detected`,
`${timestamp} [ERROR] Task execution failed: timeout after 30s`,
`${timestamp} [INFO] Task completed successfully in 1250ms`,
`${timestamp} [DEBUG] Coordination message sent to agent qe-quality-gate`
].join('\n') + '\n';
await fs.appendFile(logFile, sampleLogs);
}
}
exports.FleetLogsCommand = FleetLogsCommand;
FleetLogsCommand.isFollowing = false;
FleetLogsCommand.followInterval = null;
//# sourceMappingURL=logs.js.map