UNPKG

devflow-ai

Version:

Enterprise-grade AI agent orchestration with swarm management UI dashboard

163 lines (131 loc) 4.3 kB
/** * Progress Reporter - Provides visual feedback during migration */ import * as chalk from 'chalk'; import type { MigrationProgress } from './types.js'; export class ProgressReporter { private progress: MigrationProgress; private startTime: Date; private spinner: string[] = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; private spinnerIndex: number = 0; private intervalId: NodeJS.Timeout | null = null; constructor() { this.progress = { total: 0, completed: 0, current: '', phase: 'analyzing', errors: 0, warnings: 0, }; this.startTime = new Date(); } start(phase: MigrationProgress['phase'], message: string): void { this.progress.phase = phase; this.progress.current = message; this.startTime = new Date(); console.log(chalk.bold(`\n🚀 Starting ${phase}...`)); this.startSpinner(); } update( phase: MigrationProgress['phase'], message: string, completed?: number, total?: number, ): void { this.progress.phase = phase; this.progress.current = message; if (completed !== undefined) { this.progress.completed = completed; } if (total !== undefined) { this.progress.total = total; } this.updateDisplay(); } complete(message: string): void { this.stopSpinner(); const duration = new Date().getTime() - this.startTime.getTime(); const seconds = (duration / 1000).toFixed(2); console.log(chalk.green(`\n✅ ${message}`)); console.log(chalk.gray(` Completed in ${seconds}s`)); if (this.progress.warnings > 0) { console.log(chalk.yellow(` ${this.progress.warnings} warnings`)); } if (this.progress.errors > 0) { console.log(chalk.red(` ${this.progress.errors} errors`)); } } error(message: string): void { this.stopSpinner(); console.log(chalk.red(`\n❌ ${message}`)); this.progress.errors++; } warning(message: string): void { console.log(chalk.yellow(`⚠️ ${message}`)); this.progress.warnings++; } info(message: string): void { console.log(chalk.blue(`ℹ️ ${message}`)); } private startSpinner(): void { this.intervalId = setInterval(() => { this.spinnerIndex = (this.spinnerIndex + 1) % this.spinner.length; this.updateDisplay(); }, 100); } private stopSpinner(): void { if (this.intervalId) { clearInterval(this.intervalId); this.intervalId = null; } // Clear the spinner line process.stdout.write('\r\x1b[K'); } private updateDisplay(): void { const spinner = this.spinner[this.spinnerIndex]; const phase = this.getPhaseDisplay(); const progress = this.getProgressDisplay(); const message = `${spinner} ${phase} ${progress} ${this.progress.current}`; // Clear line and write new message process.stdout.write('\r\x1b[K' + message); } private getPhaseDisplay(): string { const phases = { analyzing: chalk.blue('📊 Analyzing'), 'backing-up': chalk.yellow('💾 Backing up'), migrating: chalk.green('🔄 Migrating'), validating: chalk.cyan('✅ Validating'), complete: chalk.green('✅ Complete'), }; return phases[this.progress.phase] || chalk.gray('⏳ Processing'); } private getProgressDisplay(): string { if (this.progress.total > 0) { const percentage = Math.round((this.progress.completed / this.progress.total) * 100); const progressBar = this.createProgressBar(percentage); return `${progressBar} ${this.progress.completed}/${this.progress.total} (${percentage}%)`; } return ''; } private createProgressBar(percentage: number, width: number = 20): 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); } setTotal(total: number): void { this.progress.total = total; } increment(message?: string): void { this.progress.completed++; if (message) { this.progress.current = message; } this.updateDisplay(); } getProgress(): MigrationProgress { return { ...this.progress }; } }