@sethdouglasford/claude-flow
Version:
Claude Code Flow - Advanced AI-powered development workflows with SPARC methodology
206 lines • 7.65 kB
JavaScript
/**
* Beautiful Terminal Display for Claude Token Monitor
* Real-time visual interface with progress bars and live stats
*/
import { createProgressBar, createTimeProgressBar } from "./claude-token-monitor.js";
export class TokenMonitorDisplay {
monitor;
isDisplaying = false;
displayProcess;
constructor(monitor) {
this.monitor = monitor;
this.setupEventListeners();
}
setupEventListeners() {
this.monitor.on('stats', (stats) => {
if (this.isDisplaying) {
this.renderDisplay(stats);
}
});
this.monitor.on('error', (error) => {
this.renderError(error);
});
}
clearScreen() {
// Move cursor to top without clearing (preserves scrollback)
process.stdout.write('\x1b[H');
}
hideCursor() {
process.stdout.write('\x1b[?25l');
}
showCursor() {
process.stdout.write('\x1b[?25h');
}
printHeader() {
const cyan = '\x1b[96m';
const blue = '\x1b[94m';
const reset = '\x1b[0m';
const sparkles = `${cyan}✦ ✧ ✦ ✧ ${reset}`;
console.log(`${sparkles}${cyan}CLAUDE TOKEN MONITOR${reset} ${sparkles}`);
console.log(`${blue}${'='.repeat(60)}${reset}`);
console.log();
}
getVelocityIndicator(burnRate) {
if (burnRate < 50)
return '🐌'; // Slow
if (burnRate < 150)
return '➡️'; // Normal
if (burnRate < 300)
return '🚀'; // Fast
return '⚡'; // Very fast
}
renderDisplay(stats) {
this.clearScreen();
// Color codes
const cyan = '\x1b[96m';
const green = '\x1b[92m';
const blue = '\x1b[94m';
const red = '\x1b[91m';
const yellow = '\x1b[93m';
const white = '\x1b[97m';
const gray = '\x1b[90m';
const reset = '\x1b[0m';
// Header
this.printHeader();
// Token Usage Progress Bar
const tokenProgressBar = createProgressBar(stats.usagePercentage);
console.log(`📊 ${white}Token Usage:${reset} ${tokenProgressBar}`);
console.log();
// Time to Reset Progress Bar
const timeSinceReset = Math.max(0, 300 - stats.timeToReset); // Assume 5-hour cycles
const timeProgressBar = createTimeProgressBar(timeSinceReset, 300);
console.log(`⏳ ${white}Time to Reset:${reset} ${timeProgressBar}`);
console.log();
// Detailed Stats
console.log(`🎯 ${white}Tokens:${reset} ${white}${stats.tokensUsed.toLocaleString()}${reset} / ${gray}~${(stats.tokensUsed + stats.tokensLeft).toLocaleString()}${reset} (${cyan}${stats.tokensLeft.toLocaleString()} left${reset})`);
const velocityIcon = this.getVelocityIndicator(stats.burnRate);
console.log(`🔥 ${white}Burn Rate:${reset} ${velocityIcon} ${yellow}${stats.burnRate.toFixed(1)}${reset} ${gray}tokens/min${reset}`);
console.log();
// Predictions
const predictedEndStr = stats.predictedEndTime.toLocaleTimeString('en-US', {
hour12: false,
hour: '2-digit',
minute: '2-digit'
});
const resetTimeStr = stats.resetTime.toLocaleTimeString('en-US', {
hour12: false,
hour: '2-digit',
minute: '2-digit'
});
console.log(`🏁 ${white}Predicted End:${reset} ${predictedEndStr}`);
console.log(`🔄 ${white}Token Reset:${reset} ${resetTimeStr}`);
console.log();
// Warnings and Notifications
if (stats.usagePercentage > 90) {
console.log(`🚨 ${red}WARNING: Token usage above 90%!${reset}`);
console.log();
}
if (stats.predictedEndTime < stats.resetTime) {
console.log(`⚠️ ${red}Tokens will run out BEFORE reset!${reset}`);
console.log();
}
if (stats.burnRate > 200) {
console.log(`⚡ ${yellow}High burn rate detected - consider optimizing usage${reset}`);
console.log();
}
// Status Line
const currentTimeStr = new Date().toLocaleTimeString('en-US', { hour12: false });
console.log(`⏰ ${gray}${currentTimeStr}${reset} 📝 ${cyan}Monitoring active...${reset} | ${gray}Ctrl+C to exit${reset} 🟨`);
// Clear any remaining lines below
process.stdout.write('\x1b[J');
}
renderError(error) {
const red = '\x1b[91m';
const yellow = '\x1b[93m';
const reset = '\x1b[0m';
console.log(`${red}❌ Monitor Error:${reset} ${error.message}`);
if (error.message.includes('ccusage')) {
console.log(`${yellow}💡 Make sure 'ccusage' is installed and available in PATH${reset}`);
console.log(`${yellow} Install: pip install claude-cli${reset}`);
}
}
async start() {
if (this.isDisplaying)
return;
this.isDisplaying = true;
this.hideCursor();
// Clear screen initially
console.clear();
// Handle graceful shutdown
const handleExit = () => {
this.stop();
this.showCursor();
console.log('\n\n💙 Claude Token Monitor stopped.');
console.clear();
process.exit(0);
};
process.on('SIGINT', handleExit);
process.on('SIGTERM', handleExit);
// Start the monitor if not already running
if (!this.monitor.isMonitoring()) {
await this.monitor.start();
}
// Show initial display
const stats = this.monitor.getLastStats();
if (stats) {
this.renderDisplay(stats);
}
else {
console.log('🔄 Starting token monitor...');
}
}
stop() {
this.isDisplaying = false;
this.showCursor();
if (this.displayProcess) {
clearTimeout(this.displayProcess);
this.displayProcess = undefined;
}
}
}
export class TokenMonitorWidget {
monitor;
lastStats;
hasError = false;
constructor(monitor) {
this.monitor = monitor;
this.monitor.on('stats', (stats) => {
this.lastStats = stats;
this.hasError = false;
});
this.monitor.on('error', () => {
this.hasError = true;
});
}
getCompactDisplay() {
if (this.hasError || !this.lastStats) {
return '📊 Claude Token Monitor: Initializing...';
}
const { tokensUsed, tokensLeft, usagePercentage, burnRate } = this.lastStats;
const velocityIcon = this.getVelocityIndicator(burnRate);
return `📊 ${tokensUsed.toLocaleString()}/${(tokensUsed + tokensLeft).toLocaleString()} (${usagePercentage.toFixed(1)}%) ${velocityIcon} ${burnRate.toFixed(1)}/min`;
}
getStatusLine() {
if (this.hasError || !this.lastStats) {
return '🔄 Searching for active Claude sessions...';
}
const { predictedEndTime, resetTime, usagePercentage } = this.lastStats;
if (usagePercentage > 90) {
return `🚨 High usage: ${usagePercentage.toFixed(1)}%`;
}
if (predictedEndTime < resetTime) {
return `⚠️ Will run out before reset`;
}
return `✅ Normal usage`;
}
getVelocityIndicator(burnRate) {
if (burnRate < 50)
return '🐌';
if (burnRate < 150)
return '➡️';
if (burnRate < 300)
return '🚀';
return '⚡';
}
}
//# sourceMappingURL=token-display.js.map