claude-monitor
Version:
Real-time terminal monitoring tool for Claude AI token usage
129 lines • 5.67 kB
JavaScript
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