UNPKG

cost-claude

Version:

Claude Code cost monitoring, analytics, and optimization toolkit

129 lines โ€ข 5.88 kB
#!/usr/bin/env node import { homedir } from 'os'; import { writeFile, appendFile, mkdir } from 'fs/promises'; import { existsSync } from 'fs'; import { join, dirname } from 'path'; import chalk from 'chalk'; import { ClaudeFileWatcher } from './services/file-watcher.js'; async function ensureDirectory(path) { const dir = dirname(path); if (!existsSync(dir)) { await mkdir(dir, { recursive: true }); } } async function createTestMessage(type = 'assistant') { const message = { uuid: `test-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, timestamp: new Date().toISOString(), type, costUSD: type === 'assistant' ? Math.random() * 0.1 : 0, durationMs: type === 'assistant' ? Math.floor(Math.random() * 5000) + 1000 : 0, sessionId: 'test-session-001', message: type === 'assistant' ? JSON.stringify({ role: 'assistant', content: 'Test assistant response', model: 'claude-opus-4-20250514', usage: { input_tokens: Math.floor(Math.random() * 1000) + 100, output_tokens: Math.floor(Math.random() * 500) + 50, cache_read_input_tokens: Math.floor(Math.random() * 300), cache_creation_input_tokens: Math.floor(Math.random() * 100), } }) : JSON.stringify({ role: 'user', content: 'Test user message' }) }; return message; } async function testFileWatcher() { console.log(chalk.bold.blue('๐Ÿงช Claude Code Cost Watcher - Test Mode\n')); const testDir = join(homedir(), '.cost-claude', 'test'); const testFile = join(testDir, 'test-messages.jsonl'); await ensureDirectory(testFile); console.log(chalk.gray(`Test file: ${testFile}`)); const watcher = new ClaudeFileWatcher({ paths: [`${testDir}/**/*.jsonl`], ignoreInitial: false, pollInterval: 100, debounceDelay: 300, }); watcher.on('started', () => { console.log(chalk.green('โœ“ Watcher started successfully')); }); watcher.on('file-added', (path) => { console.log(chalk.cyan(`๐Ÿ“ File detected: ${path}`)); }); watcher.on('new-message', (message) => { console.log(chalk.green(`\n๐Ÿ“จ New message detected:`)); console.log(chalk.gray(` ID: ${message.uuid}`)); console.log(chalk.gray(` Type: ${message.type}`)); console.log(chalk.gray(` Cost: $${message.costUSD?.toFixed(4) || '0.0000'}`)); console.log(chalk.gray(` Duration: ${message.durationMs || 0}ms`)); }); watcher.on('error', (error) => { console.error(chalk.red('โŒ Error:'), error.message); }); watcher.on('parse-error', ({ filePath, line, error }) => { console.error(chalk.yellow('โš ๏ธ Parse error:'), { file: filePath, line: line.substring(0, 50) + '...', error: error.message }); }); await watcher.start(); console.log(chalk.bold('\n๐Ÿš€ Running test scenarios:\n')); console.log(chalk.yellow('Test 1: Creating new file with initial messages...')); const initialMessages = [ await createTestMessage('user'), await createTestMessage('assistant'), ]; const initialContent = initialMessages.map(msg => JSON.stringify(msg)).join('\n') + '\n'; await writeFile(testFile, initialContent); console.log(chalk.gray(` Wrote ${initialMessages.length} messages`)); await new Promise(resolve => setTimeout(resolve, 1000)); console.log(chalk.yellow('\nTest 2: Appending new messages...')); const newMessage = await createTestMessage('assistant'); await appendFile(testFile, JSON.stringify(newMessage) + '\n'); console.log(chalk.gray(' Appended 1 message')); await new Promise(resolve => setTimeout(resolve, 1000)); console.log(chalk.yellow('\nTest 3: Rapid message additions...')); for (let i = 0; i < 5; i++) { const msg = await createTestMessage(i % 2 === 0 ? 'user' : 'assistant'); await appendFile(testFile, JSON.stringify(msg) + '\n'); console.log(chalk.gray(` Added message ${i + 1}/5`)); await new Promise(resolve => setTimeout(resolve, 200)); } await new Promise(resolve => setTimeout(resolve, 2000)); console.log(chalk.yellow('\nTest 4: Testing error handling with invalid JSON...')); await appendFile(testFile, 'This is not valid JSON\n'); await appendFile(testFile, '{ "broken": json }\n'); await new Promise(resolve => setTimeout(resolve, 1000)); console.log(chalk.yellow('\nTest 5: Testing empty lines...')); await appendFile(testFile, '\n\n\n'); const finalMessage = await createTestMessage('assistant'); await appendFile(testFile, JSON.stringify(finalMessage) + '\n'); await new Promise(resolve => setTimeout(resolve, 1000)); const stats = watcher.getStats(); console.log(chalk.bold.blue('\n๐Ÿ“Š Watcher Statistics:')); console.log(chalk.gray(` Watched files: ${stats.watchedFiles}`)); console.log(chalk.gray(` Total bytes read: ${stats.totalBytesRead}`)); console.log(chalk.bold.yellow('\n๐Ÿ”ง Manual Test Mode:')); console.log(chalk.gray('You can now manually edit the test file to see real-time updates.')); console.log(chalk.gray(`File: ${testFile}`)); console.log(chalk.gray('Press Ctrl+C to stop the test.\n')); process.on('SIGINT', async () => { console.log(chalk.yellow('\n\nStopping test...')); await watcher.stop(); console.log(chalk.green('Test completed! ๐Ÿ‘')); process.exit(0); }); await new Promise(() => { }); } testFileWatcher().catch(error => { console.error(chalk.red('Test failed:'), error); process.exit(1); }); //# sourceMappingURL=test-watcher.js.map