khodkar-cli
Version:
A TypeScript CLI application that extracts business rules and logic from codebases for customer support knowledge bases
194 lines • 6.83 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProgressTracker = void 0;
const ora_1 = __importDefault(require("ora"));
const chalk_1 = __importDefault(require("chalk"));
class ProgressTracker {
options;
spinner;
startTime;
verbose;
showETA;
updateInterval;
constructor(options = {}) {
this.options = options;
this.verbose = options.verbose || false;
this.showETA = options.showETA || true;
this.updateInterval = options.updateInterval || 1000;
this.startTime = Date.now();
this.spinner = (0, ora_1.default)({
text: 'Initializing...',
spinner: 'dots',
color: 'blue'
});
}
start(message) {
if (message) {
this.spinner.text = message;
}
if (!this.verbose) {
this.spinner.start();
}
else {
console.log(chalk_1.default.blue(`🚀 ${this.spinner.text}`));
}
}
update(progress) {
const percentage = Math.round((progress.filesProcessed / progress.totalFiles) * 100);
const eta = this.calculateETA(progress);
let message = `${progress.currentPhase}: ${progress.currentFile} (${progress.filesProcessed}/${progress.totalFiles} - ${percentage}%)`;
if (this.showETA && eta) {
message += ` - ETA: ${this.formatDuration(eta)}`;
}
if (this.verbose) {
this.spinner.stop();
console.log(chalk_1.default.gray(` ${message}`));
if (!this.isComplete(progress)) {
this.spinner.start();
}
}
else {
this.spinner.text = message;
}
}
updatePhase(phase, message) {
const phaseMessages = {
scanning: '🔍 Scanning files...',
analyzing: '🤖 Analyzing with LLM...',
formatting: '📝 Formatting output...',
complete: '✅ Complete!'
};
const displayMessage = message || phaseMessages[phase];
if (this.verbose) {
this.spinner.stop();
console.log(chalk_1.default.blue(displayMessage));
if (phase !== 'complete') {
this.spinner.start();
}
}
else {
this.spinner.text = displayMessage;
}
}
succeed(message) {
if (this.verbose) {
this.spinner.stop();
console.log(chalk_1.default.green(`✅ ${message || 'Complete!'}`));
}
else {
this.spinner.succeed(message);
}
}
fail(message) {
if (this.verbose) {
this.spinner.stop();
console.error(chalk_1.default.red(`❌ ${message || 'Failed!'}`));
}
else {
this.spinner.fail(message);
}
}
warn(message) {
if (this.verbose) {
this.spinner.stop();
console.warn(chalk_1.default.yellow(`⚠ ${message}`));
this.spinner.start();
}
else {
// For non-verbose mode, just update the spinner text briefly
const originalText = this.spinner.text;
this.spinner.text = chalk_1.default.yellow(`⚠ ${message}`);
setTimeout(() => {
this.spinner.text = originalText;
}, 2000);
}
}
info(message) {
if (this.verbose) {
this.spinner.stop();
console.log(chalk_1.default.blue(`ℹ ${message}`));
this.spinner.start();
}
}
stop() {
this.spinner.stop();
}
calculateETA(progress) {
if (progress.filesProcessed === 0) {
return null;
}
const elapsed = Date.now() - this.startTime;
const rate = progress.filesProcessed / elapsed; // files per ms
const remaining = progress.totalFiles - progress.filesProcessed;
return remaining / rate;
}
formatDuration(ms) {
const seconds = Math.floor(ms / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
if (hours > 0) {
return `${hours}h ${minutes % 60}m`;
}
else if (minutes > 0) {
return `${minutes}m ${seconds % 60}s`;
}
else {
return `${seconds}s`;
}
}
isComplete(progress) {
return progress.currentPhase === 'complete' ||
progress.filesProcessed >= progress.totalFiles;
}
// Static utility methods
static createFileProgressBar(current, total, width = 40) {
const percentage = current / total;
const filled = Math.round(width * percentage);
const empty = width - filled;
const bar = '█'.repeat(filled) + '░'.repeat(empty);
const percent = Math.round(percentage * 100);
return `[${bar}] ${percent}% (${current}/${total})`;
}
static formatFileSize(bytes) {
const units = ['B', 'KB', 'MB', 'GB'];
let size = bytes;
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(1)} ${units[unitIndex]}`;
}
static formatProcessingRate(filesProcessed, timeElapsed) {
const rate = filesProcessed / (timeElapsed / 1000); // files per second
if (rate < 1) {
return `${(rate * 60).toFixed(1)} files/min`;
}
else {
return `${rate.toFixed(1)} files/sec`;
}
}
// Method to create a summary of the analysis
createSummary(totalFiles, rulesExtracted, errors) {
const elapsed = Date.now() - this.startTime;
const rate = ProgressTracker.formatProcessingRate(totalFiles, elapsed);
console.log('\n' + chalk_1.default.bold('Analysis Summary:'));
console.log(` ${chalk_1.default.green('✓')} Files processed: ${totalFiles}`);
console.log(` ${chalk_1.default.green('✓')} Rules extracted: ${rulesExtracted}`);
console.log(` ${chalk_1.default.blue('ℹ')} Processing rate: ${rate}`);
console.log(` ${chalk_1.default.blue('ℹ')} Total time: ${this.formatDuration(elapsed)}`);
if (errors.length > 0) {
console.log(` ${chalk_1.default.yellow('⚠')} Errors encountered: ${errors.length}`);
if (this.verbose) {
errors.forEach(error => {
console.log(` ${chalk_1.default.gray('•')} ${error}`);
});
}
}
}
}
exports.ProgressTracker = ProgressTracker;
//# sourceMappingURL=progress-tracker.js.map