UNPKG

claude-monitor

Version:

Real-time terminal monitoring tool for Claude AI token usage

129 lines 5.67 kB
import chalk from 'chalk'; import { getTotalTokens } from '../types/index.js'; import { calculateLimitPercentage, formatLargeNumber, calculateSessionStatistics } from '../core/calculations.js'; import { formatTime, formatDuration } from '../utils/time.js'; export class ConsoleDisplay { clearScreen = true; constructor(options = {}) { this.clearScreen = options.clearScreen ?? true; } display(data) { if (this.clearScreen) { console.clear(); } this.displayHeader(data); console.log(); if (data.activeSession) { this.displayActiveSession(data.activeSession, data.tokenLimit, data.settings.timeFormat); } else { this.displayNoActiveSession(); } console.log(); this.displayRecentSessions(data.blocks, data.settings.timeFormat); this.displayFooter(data.lastUpdate, data.settings.timeFormat); } displayError(error) { console.error(chalk.red('❌ Error:'), error.message); } displayWarning(message) { console.warn(chalk.yellow('⚠️ Warning:'), message); } displayInfo(message) { console.info(chalk.blue('ℹ️ Info:'), message); } displayHeader(data) { const title = chalk.bold.cyan('Claude Monitor - Token Usage Tracker'); const plan = chalk.gray(`Plan: ${data.settings.planType.toUpperCase()}`); const limit = chalk.gray(`Limit: ${formatLargeNumber(data.tokenLimit)} tokens`); console.log(title); console.log(`${plan} | ${limit}`); console.log(chalk.gray('─'.repeat(60))); } displayActiveSession(session, tokenLimit, timeFormat) { const stats = calculateSessionStatistics(session); const percentage = calculateLimitPercentage(stats.totalTokens, tokenLimit); console.log(chalk.green.bold('🟢 Active Session')); console.log(); this.displayProgressBar(percentage, stats.totalTokens, tokenLimit); console.log(); console.log(chalk.white('Session Details:')); console.log(` Started: ${formatTime(session.startTime, timeFormat)}`); console.log(` Duration: ${formatDuration(stats.durationMinutes * 60)}`); console.log(` Messages: ${stats.messageCount}`); console.log(` Total Cost: $${stats.totalCost.toFixed(2)}`); console.log(); console.log(chalk.white('Token Usage:')); console.log(` Input: ${formatLargeNumber(session.tokenCounts.inputTokens)}`); console.log(` Output: ${formatLargeNumber(session.tokenCounts.outputTokens)}`); if (session.tokenCounts.cacheCreationTokens > 0) { console.log(` Cache Create: ${formatLargeNumber(session.tokenCounts.cacheCreationTokens)}`); } if (session.tokenCounts.cacheReadTokens > 0) { console.log(` Cache Read: ${formatLargeNumber(session.tokenCounts.cacheReadTokens)}`); } console.log(); if (stats.burnRate) { console.log(chalk.white('Burn Rate:')); console.log(` Tokens/min: ${stats.burnRate.tokensPerMinute}`); console.log(` Cost/hour: $${stats.burnRate.costPerHour.toFixed(2)}`); console.log(); } if (Object.keys(stats.modelBreakdown).length > 1) { console.log(chalk.white('Models Used:')); for (const [model, modelData] of Object.entries(stats.modelBreakdown)) { const data = modelData; console.log(` ${model}: ${data.percentage}% (${formatLargeNumber(data.tokens)} tokens)`); } } } displayProgressBar(percentage, used, limit) { const barWidth = 40; const filled = Math.round((percentage / 100) * barWidth); const empty = barWidth - filled; let barColor = chalk.green; if (percentage >= 90) { barColor = chalk.red; } else if (percentage >= 70) { barColor = chalk.yellow; } const bar = barColor('█'.repeat(filled)) + chalk.gray('░'.repeat(empty)); const percentText = `${percentage}%`; const usageText = `${formatLargeNumber(used)} / ${formatLargeNumber(limit)}`; console.log(` ${bar} ${percentText}`); console.log(` ${usageText} tokens used`); } displayNoActiveSession() { console.log(chalk.gray('No active session')); console.log(); console.log(chalk.gray('Waiting for Claude activity...')); } displayRecentSessions(blocks, timeFormat) { const recentBlocks = blocks .filter(b => !b.isGap && !b.isActive) .slice(-3) .reverse(); if (recentBlocks.length === 0) { return; } console.log(); console.log(chalk.gray('─'.repeat(60))); console.log(chalk.white.bold('Recent Sessions:')); console.log(); for (const block of recentBlocks) { const totalTokens = getTotalTokens(block.tokenCounts); const startTime = formatTime(block.startTime, timeFormat); const tokensText = formatLargeNumber(totalTokens); const costText = `$${block.costUsd.toFixed(2)}`; console.log(` ${startTime} - ${tokensText} tokens, ${costText}`); } } displayFooter(lastUpdate, timeFormat) { console.log(); console.log(chalk.gray('─'.repeat(60))); console.log(chalk.gray(`Last updated: ${formatTime(lastUpdate, timeFormat)}`)); console.log(chalk.gray('Press Ctrl+C to exit')); } } //# sourceMappingURL=console-display.js.map