@aegntic/cldcde-context-tracker
Version:
A persistent context window monitor addon for Claude Code CLI that shows real-time token usage with visual indicators
149 lines (120 loc) • 4.71 kB
JavaScript
import { writeFileSync, readFileSync, existsSync, mkdirSync } from 'fs';
import { join, dirname } from 'path';
import { homedir } from 'os';
import { fileURLToPath } from 'url';
import chalk from 'chalk';
const __dirname = dirname(fileURLToPath(import.meta.url));
class ClaudeAddonInstaller {
constructor() {
this.claudeDir = join(homedir(), '.claude');
this.addonDir = join(this.claudeDir, 'addons');
this.hookFile = join(this.claudeDir, 'hooks.json');
this.monitorFile = join(this.addonDir, 'context-monitor.js');
}
// Ensure required directories exist
ensureDirectories() {
[this.claudeDir, this.addonDir].forEach(dir => {
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true });
console.log(chalk.green(`✓ Created directory: ${dir}`));
}
});
}
// Copy context monitor to Claude directory
installMonitor() {
const sourceFile = join(__dirname, '..', 'lib', 'context-monitor.js');
const monitorCode = readFileSync(sourceFile, 'utf8');
writeFileSync(this.monitorFile, monitorCode);
console.log(chalk.green('✓ Installed context monitor'));
}
// Create or update hooks configuration
setupHooks() {
let hooks = {};
// Load existing hooks if they exist
if (existsSync(this.hookFile)) {
try {
hooks = JSON.parse(readFileSync(this.hookFile, 'utf8'));
} catch (error) {
console.log(chalk.yellow('⚠ Could not read existing hooks, creating new'));
}
}
// Add context monitor hook
hooks.preCommand = hooks.preCommand || [];
hooks.postCommand = hooks.postCommand || [];
const monitorHook = {
name: 'context-monitor',
script: this.monitorFile,
enabled: true,
description: 'Display context window usage monitor'
};
// Remove existing context monitor hooks
hooks.preCommand = hooks.preCommand.filter(h => h.name !== 'context-monitor');
hooks.postCommand = hooks.postCommand.filter(h => h.name !== 'context-monitor');
// Add to preCommand
hooks.preCommand.push(monitorHook);
// Write hooks file
writeFileSync(this.hookFile, JSON.stringify(hooks, null, 2));
console.log(chalk.green('✓ Configured Claude hooks'));
}
// Create wrapper script for Claude Code
createWrapper() {
const wrapperScript = `#!/usr/bin/env node
import { spawn } from 'child_process';
import ContextMonitor from '${this.monitorFile}';
// Initialize context monitor
const monitor = new ContextMonitor();
// Intercept Claude Code execution
const args = process.argv.slice(2);
const claude = spawn('claude', args, {
stdio: ['pipe', 'inherit', 'inherit']
});
// Attach monitor to input stream
const rl = monitor.attachToInput();
// Handle Claude process
claude.on('close', (code) => {
rl.close();
process.exit(code);
});
// Forward input to Claude
process.stdin.pipe(claude.stdin);
`;
const wrapperFile = join(this.addonDir, 'claude-with-monitor.js');
writeFileSync(wrapperFile, wrapperScript);
console.log(chalk.green('✓ Created Claude wrapper script'));
return wrapperFile;
}
// Add alias to shell configuration
setupAlias(wrapperFile) {
const aliasCommand = `alias claude-monitor='node ${wrapperFile}'`;
const bashrc = join(homedir(), '.bashrc');
const zshrc = join(homedir(), '.zshrc');
console.log(chalk.cyan('\n📝 To complete installation, add this alias to your shell:'));
console.log(chalk.white(aliasCommand));
console.log(chalk.cyan('\nOr run:'));
console.log(chalk.white(`echo "${aliasCommand}" >> ~/.bashrc`));
console.log(chalk.white(`echo "${aliasCommand}" >> ~/.zshrc`));
}
// Main installation process
async install() {
console.log(chalk.bold.blue('🚀 Installing Claude Context Monitor...\n'));
try {
this.ensureDirectories();
this.installMonitor();
this.setupHooks();
const wrapperFile = this.createWrapper();
this.setupAlias(wrapperFile);
console.log(chalk.bold.green('\n✅ Installation completed successfully!'));
console.log(chalk.cyan('\n📋 Usage:'));
console.log(chalk.white(' claude-monitor # Start Claude with context monitor'));
console.log(chalk.white(' claude # Use regular Claude (monitor disabled)'));
console.log(chalk.cyan('\n💡 The monitor will appear below your input showing token usage in real-time.'));
} catch (error) {
console.error(chalk.red('❌ Installation failed:'), error.message);
process.exit(1);
}
}
}
// Run installation
const installer = new ClaudeAddonInstaller();
installer.install();