@every-env/cli
Version:
Multi-agent orchestrator for AI-powered development workflows
165 lines ⢠7.47 kB
JavaScript
import chalk from 'chalk';
import { logger } from './logger.js';
export class ProgressDisplay {
manager;
agents = new Map();
updateInterval;
totalAgents = 0;
completedAgents = 0;
debugMode = false;
constructor(manager, debugMode = false) {
this.manager = manager;
this.debugMode = debugMode;
this.setupEventHandlers();
}
start(totalAgents) {
this.totalAgents = totalAgents;
this.completedAgents = 0;
if (!this.debugMode) {
console.log(chalk.cyan(`\nš Running ${totalAgents} agents in parallel...\n`));
logger.setProgressActive(true);
// Start update loop
this.updateInterval = setInterval(() => this.render(), 100);
this.render();
}
else {
// In debug mode, use simpler output
console.log(chalk.cyan(`\nš Running ${totalAgents} agents in parallel (debug mode)...\n`));
}
}
stop() {
if (this.updateInterval) {
clearInterval(this.updateInterval);
this.updateInterval = undefined;
}
if (!this.debugMode) {
this.render(true); // Final render
logger.setProgressActive(false);
}
else {
// In debug mode, just show final summary
this.showDebugSummary();
}
}
setupEventHandlers() {
this.manager.on('agent:start', ({ agentId, outputPath }) => {
this.agents.set(agentId, {
id: agentId,
status: 'running',
duration: 0,
lastOutput: `Output: ${outputPath}`,
startTime: Date.now()
});
if (this.debugMode) {
console.log(chalk.blue(`ā¶ Starting agent: ${agentId}`));
console.log(chalk.gray(` Output: ${outputPath}`));
}
});
this.manager.on('agent:output', ({ agentId, type, data }) => {
const agent = this.agents.get(agentId);
if (agent && type === 'stdout') {
// Get last non-empty line
const lines = data.toString().split('\n').filter((l) => l.trim());
if (lines.length > 0) {
agent.lastOutput = lines[lines.length - 1].slice(0, 60) + (lines[lines.length - 1].length > 60 ? '...' : '');
}
}
});
this.manager.on('agent:complete', ({ agentId, duration }) => {
const agent = this.agents.get(agentId);
if (agent) {
agent.status = 'success';
agent.duration = duration;
this.completedAgents++;
if (this.debugMode) {
console.log(chalk.green(`ā Completed: ${agentId} (${this.formatDuration(agent)})`));
}
}
});
this.manager.on('agent:failed', ({ agentId, error }) => {
const agent = this.agents.get(agentId);
if (agent) {
agent.status = 'failed';
agent.lastOutput = error || 'Failed';
agent.duration = agent.startTime ? Date.now() - agent.startTime : 0;
this.completedAgents++;
if (this.debugMode) {
console.log(chalk.red(`ā Failed: ${agentId}`));
console.log(chalk.red(` Error: ${error}`));
}
}
});
}
render(final = false) {
if (this.debugMode)
return; // Don't render in debug mode
// Clear previous output
if (!final) {
process.stdout.write('\x1B[2J\x1B[H'); // Clear screen and move to top
console.log(chalk.cyan(`\nš Running ${this.totalAgents} agents in parallel...\n`));
}
// Progress bar
const progress = this.totalAgents > 0 ? Math.floor((this.completedAgents / this.totalAgents) * 100) : 0;
const barLength = 40;
const filled = Math.floor((progress / 100) * barLength);
const bar = 'ā'.repeat(filled) + 'ā'.repeat(barLength - filled);
console.log(chalk.cyan(`Progress: [${bar}] ${progress}% (${this.completedAgents}/${this.totalAgents})\n`));
// Agent table
console.log(chalk.gray('āāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāā¬āāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
console.log(chalk.gray('ā Agent ā Status ā Duration ā Last Output ā'));
console.log(chalk.gray('āāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤'));
for (const agent of this.agents.values()) {
const name = agent.id.padEnd(23).slice(0, 23);
const status = this.formatStatus(agent.status).padEnd(8);
const duration = this.formatDuration(agent).padEnd(8);
const output = agent.lastOutput.padEnd(42).slice(0, 42);
console.log(chalk.gray('ā ') +
name + chalk.gray(' ā ') +
status + chalk.gray(' ā ') +
duration + chalk.gray(' ā ') +
output + chalk.gray(' ā'));
}
console.log(chalk.gray('āāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāā“āāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
if (final) {
console.log(); // Extra line at the end
}
}
formatStatus(status) {
switch (status) {
case 'running':
return chalk.yellow('ā Running');
case 'success':
return chalk.green('ā Done');
case 'failed':
return chalk.red('ā Failed');
default:
return chalk.gray('⯠Pending');
}
}
formatDuration(agent) {
let duration = agent.duration;
if (agent.status === 'running' && agent.startTime) {
duration = Date.now() - agent.startTime;
}
if (duration === 0)
return '-';
const seconds = Math.floor(duration / 1000);
const minutes = Math.floor(seconds / 60);
if (minutes > 0) {
return `${minutes}m ${seconds % 60}s`;
}
return `${seconds}s`;
}
showDebugSummary() {
console.log(chalk.cyan('\nš Summary:\n'));
const successful = Array.from(this.agents.values()).filter(a => a.status === 'success').length;
const failed = Array.from(this.agents.values()).filter(a => a.status === 'failed').length;
console.log(` Total agents: ${this.totalAgents}`);
console.log(` ${chalk.green(`Successful:`)} ${successful}`);
if (failed > 0) {
console.log(` ${chalk.red(`Failed:`)} ${failed}`);
}
console.log();
}
}
//# sourceMappingURL=progress-display.js.map