@oliverpople/agency-x
Version:
🚀 **Transform feature requests into production-ready code in seconds**
124 lines (98 loc) • 3.45 kB
text/typescript
import chalk from 'chalk';
interface ProgressState {
total: number;
completed: number;
failed: number;
running: number;
startTime: number;
}
export class ProgressTracker {
private state: ProgressState;
private updateInterval?: NodeJS.Timer;
private lastUpdate: number = 0;
constructor(total: number) {
this.state = {
total,
completed: 0,
failed: 0,
running: 0,
startTime: Date.now(),
};
}
start() {
this.updateInterval = setInterval(() => {
this.render();
}, 500);
}
stop() {
if (this.updateInterval) {
clearInterval(this.updateInterval);
this.updateInterval = undefined;
}
}
update(status: { completed: number; failed: number; running: number }) {
this.state.completed = status.completed;
this.state.failed = status.failed;
this.state.running = status.running;
this.lastUpdate = Date.now();
}
private getProgressBar(percentage: number, width: number = 30): string {
const filled = Math.round((percentage / 100) * width);
const empty = width - filled;
const filledBar = '█'.repeat(filled);
const emptyBar = '░'.repeat(empty);
return chalk.green(filledBar) + chalk.gray(emptyBar);
}
private formatTime(ms: number): string {
const seconds = Math.floor(ms / 1000);
const minutes = Math.floor(seconds / 60);
if (minutes > 0) {
return `${minutes}m ${seconds % 60}s`;
}
return `${seconds}s`;
}
private estimateTimeRemaining(): string {
const elapsed = Date.now() - this.state.startTime;
const progress = this.state.completed / this.state.total;
if (progress === 0) return 'calculating...';
const estimated = elapsed / progress;
const remaining = estimated - elapsed;
return remaining > 0 ? this.formatTime(remaining) : '0s';
}
private render() {
const { completed, failed, running, total } = this.state;
const pending = total - completed - failed - running;
const completionPercentage = ((completed + failed) / total) * 100;
// Clear the line and render progress
process.stdout.write('\r\x1b[K');
const progressBar = this.getProgressBar(completionPercentage);
const elapsed = this.formatTime(Date.now() - this.state.startTime);
const estimated = this.estimateTimeRemaining();
const statusLine = [
`${progressBar} ${completionPercentage.toFixed(1)}%`,
chalk.green(`✅ ${completed}`),
running > 0 ? chalk.yellow(`🔄 ${running}`) : '',
failed > 0 ? chalk.red(`❌ ${failed}`) : '',
pending > 0 ? chalk.gray(`⏳ ${pending}`) : '',
`⏱️ ${elapsed}`,
completionPercentage < 100 ? `(~${estimated} left)` : '',
].filter(Boolean).join(' ');
process.stdout.write(statusLine);
}
complete() {
this.stop();
const elapsed = this.formatTime(Date.now() - this.state.startTime);
process.stdout.write('\r\x1b[K');
if (this.state.failed > 0) {
console.log(`🎯 Orchestration completed with ${this.state.failed} failures in ${elapsed}`);
} else {
console.log(`🎉 Orchestration completed successfully in ${elapsed}`);
}
}
error(message: string) {
this.stop();
const elapsed = this.formatTime(Date.now() - this.state.startTime);
process.stdout.write('\r\x1b[K');
console.log(`💥 Orchestration failed after ${elapsed}: ${message}`);
}
}