cost-claude
Version:
Claude Code cost monitoring, analytics, and optimization toolkit
129 lines โข 5.88 kB
JavaScript
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