UNPKG

research-cli

Version:

AI-powered research assistant with web search capabilities and beautiful terminal UI

281 lines 7.4 kB
/** * Professional progress bars for research-cli using cli-progress */ import * as cliProgress from "cli-progress"; /** * Research CLI themed progress bar configuration */ export const RESEARCH_CLI_THEME = { format: "🔍 {operation} |{bar}| {percentage}% | {value}/{total} | {stage}", barCompleteChar: "█", barIncompleteChar: "░", hideCursor: true, clearOnComplete: false, barsize: 30, gracefulExit: true, fps: 10, // Use stderr to avoid interfering with actual output stream: process.stderr, etaBuffer: 100, }; /** * Compact theme for tool operations */ export const TOOL_THEME = { format: "🔧 {operation} |{bar}| {percentage}%", barCompleteChar: "▓", barIncompleteChar: "▒", hideCursor: true, clearOnComplete: true, barsize: 20, gracefulExit: true, fps: 5, stream: process.stderr, }; /** * Multi-operation theme for concurrent tasks */ export const MULTI_THEME = { format: "{operation} |{bar}| {percentage}% | {stage}", barCompleteChar: "█", barIncompleteChar: "░", hideCursor: true, clearOnComplete: false, barsize: 25, gracefulExit: true, fps: 10, stream: process.stderr, }; /** * Single progress bar wrapper with research-cli branding */ export class ResearchProgressBar { bar; isActive = false; constructor(options = {}) { // Merge theme options, filtering out incompatible types const { format: _, ...filteredTheme } = RESEARCH_CLI_THEME; const cleanedOptions = { ...filteredTheme, ...Object.fromEntries(Object.entries(options).filter(([_, value]) => value !== null)), }; this.bar = new cliProgress.SingleBar(cleanedOptions); } /** * Start the progress bar */ start(total, startValue = 0, payload = {}) { if (this.isActive) { this.stop(); } const defaultPayload = { operation: "Processing", stage: "Starting...", ...payload, }; this.bar.start(total, startValue, defaultPayload); this.isActive = true; } /** * Update progress value and/or payload */ update(value, payload) { if (!this.isActive) return; if (value !== null && value !== undefined) { this.bar.update(value, payload); } else if (payload) { this.bar.update(payload); } } /** * Increment progress by specified amount */ increment(delta = 1, payload) { if (!this.isActive) return; this.bar.increment(delta, payload); } /** * Update the operation description */ setOperation(operation) { this.update(null, { operation }); } /** * Update the current stage */ setStage(stage) { this.update(null, { stage }); } /** * Set the total value while active */ setTotal(total) { if (!this.isActive) return; this.bar.setTotal(total); } /** * Complete the progress bar with final stage */ complete(finalStage = "Complete") { if (!this.isActive) return; this.update(null, { stage: finalStage }); this.stop(); } /** * Stop the progress bar */ stop() { if (this.isActive) { this.bar.stop(); this.isActive = false; } } /** * Check if progress bar is currently active */ get active() { return this.isActive; } } /** * Multi-progress bar manager for concurrent operations */ export class ResearchMultiProgress { multibar; bars = new Map(); isActive = false; constructor(options = {}) { // Merge theme options, filtering out incompatible types const { format: _, ...filteredTheme } = MULTI_THEME; const cleanedOptions = { ...filteredTheme, ...Object.fromEntries(Object.entries(options).filter(([_, value]) => value !== null)), }; this.multibar = new cliProgress.MultiBar(cleanedOptions); } /** * Create a new progress bar */ createBar(id, total, startValue = 0, payload = {}, barOptions) { if (!this.isActive) { this.isActive = true; } // Remove existing bar with same ID this.removeBar(id); const defaultPayload = { operation: id, stage: "Starting...", ...payload, }; const bar = this.multibar.create(total, startValue, defaultPayload, barOptions); this.bars.set(id, bar); } /** * Update a specific progress bar */ updateBar(id, value, payload) { const bar = this.bars.get(id); if (!bar) return; if (value !== null && value !== undefined) { bar.update(value, payload); } else if (payload) { bar.update(payload); } } /** * Increment a specific progress bar */ incrementBar(id, delta = 1, payload) { const bar = this.bars.get(id); if (!bar) return; bar.increment(delta, payload); } /** * Complete a specific progress bar */ completeBar(id, finalStage = "Complete") { this.updateBar(id, null, { stage: finalStage }); this.removeBar(id); } /** * Remove a specific progress bar */ removeBar(id) { const bar = this.bars.get(id); if (bar) { this.multibar.remove(bar); this.bars.delete(id); } } /** * Log a message above the progress bars */ log(message) { if (this.isActive) { this.multibar.log(`${message}\n`); } else { // Fallback to stderr if multibar not active process.stderr.write(`${message}\n`); } } /** * Stop all progress bars */ stop() { if (this.isActive) { this.multibar.stop(); this.bars.clear(); this.isActive = false; } } /** * Get list of active bar IDs */ getActiveBars() { return Array.from(this.bars.keys()); } /** * Check if multibar is currently active */ get active() { return this.isActive; } } /** * Utility function to create a themed progress bar */ export function createProgressBar(theme = "research", options = {}) { let baseTheme; switch (theme) { case "tool": baseTheme = TOOL_THEME; break; default: baseTheme = RESEARCH_CLI_THEME; break; } // Filter out format property from baseTheme to avoid type conflicts const { format: _, ...filteredTheme } = baseTheme; // Clean options to remove null values and ensure compatibility with cli-progress const cleanedOptions = Object.fromEntries(Object.entries(options).filter(([_, value]) => value !== null && value !== undefined)); return new ResearchProgressBar({ ...filteredTheme, ...cleanedOptions, }); } /** * Utility function to create a multi-progress manager */ export function createMultiProgress(options = {}) { return new ResearchMultiProgress(options); } //# sourceMappingURL=progress.js.map