UNPKG

@every-env/cli

Version:

Multi-agent orchestrator for AI-powered development workflows

165 lines • 7.47 kB
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