UNPKG

vibetime

Version:

Track your Claude AI usage and costs. Built on ccusage. See rankings, sync data, and monitor your AI spending. Works with all Claude models.

217 lines (182 loc) 5.98 kB
#!/usr/bin/env node /** * Build script to create ccusage bundle for vibetime CLI * This handles the special case of JSR dependencies and bun runtime */ import { execSync } from 'child_process'; import { existsSync, mkdirSync, writeFileSync } from 'fs'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const projectRoot = join(__dirname, '..'); const ccusagePath = join(projectRoot, 'ccusage'); const cliPath = __dirname; const bundleDir = join(cliPath, 'src/lib/ccusage-bundle'); console.log('Building ccusage bundle for vibetime CLI...'); // Step 1: Check prerequisites if (!existsSync(ccusagePath)) { console.warn('Warning: ccusage submodule not found.'); console.warn('Falling back to npm package. Run: git submodule update --init for latest features.'); // Don't exit, let postinstall handle fallback process.exit(0); } // Check if bun is available try { execSync('bun --version', { stdio: 'ignore' }); } catch (error) { console.warn('Warning: bun is not available.'); console.warn('Falling back to npm package. Install bun from: https://bun.sh for latest features.'); // Don't exit, let postinstall handle fallback process.exit(0); } // Step 2: Create bundle directory if (!existsSync(bundleDir)) { mkdirSync(bundleDir, { recursive: true }); } // Step 3: Create a wrapper that can be bundled const wrapperContent = ` /** * Auto-generated ccusage bundle wrapper * This file provides ccusage functionality through subprocess execution */ import { spawn } from 'node:child_process'; import { join } from 'node:path'; import { existsSync } from 'node:fs'; const ccusagePath = join(process.cwd(), '../ccusage'); export async function runCcusage(args) { if (!existsSync(ccusagePath)) { throw new Error('ccusage submodule not found at: ' + ccusagePath); } return new Promise((resolve, reject) => { const bunArgs = ['run', 'start', ...args, '--json']; const child = spawn('bun', bunArgs, { cwd: ccusagePath, stdio: ['ignore', 'pipe', 'pipe'], shell: false }); let stdout = ''; let stderr = ''; child.stdout.on('data', (data) => { stdout += data.toString(); }); child.stderr.on('data', (data) => { stderr += data.toString(); }); child.on('close', (code) => { if (code !== 0) { reject(new Error(\`ccusage exited with code \${code}: \${stderr}\`)); return; } try { // Parse JSON output const lines = stdout.split('\\n'); for (const line of lines) { const trimmed = line.trim(); if (trimmed.startsWith('[') || trimmed.startsWith('{')) { const data = JSON.parse(trimmed); resolve(data); return; } } resolve(null); } catch (error) { reject(new Error('Failed to parse ccusage output: ' + error.message)); } }); child.on('error', reject); }); } // Export convenience functions export const ccusage = { daily: (options = {}) => runCcusage(['daily', ...buildArgs(options)]), monthly: (options = {}) => runCcusage(['monthly', ...buildArgs(options)]), session: (options = {}) => runCcusage(['session', ...buildArgs(options)]), blocks: (options = {}) => runCcusage(['blocks', ...buildArgs(options)]) }; function buildArgs(options) { const args = []; if (options.since) args.push('--since', options.since); if (options.until) args.push('--until', options.until); if (options.mode) args.push('--mode', options.mode); if (options.dir) args.push('--dir', options.dir); return args; } `; writeFileSync(join(bundleDir, 'index.js'), wrapperContent); // Step 4: Create TypeScript definitions const typeDefsContent = ` /** * Auto-generated TypeScript definitions for ccusage bundle */ export interface CcusageOptions { since?: string; until?: string; mode?: 'auto' | 'calculate' | 'display'; dir?: string; } export interface TokenUsage { inputTokens: number; outputTokens: number; cacheCreationTokens: number; cacheReadTokens: number; totalTokens: number; } export interface ModelBreakdown extends TokenUsage { modelName: string; cost: number; } export interface DailyUsage extends TokenUsage { date: string; cost: number; modelBreakdowns: ModelBreakdown[]; } export interface MonthlyUsage extends TokenUsage { month: string; cost: number; modelBreakdowns: ModelBreakdown[]; } export interface SessionUsage extends TokenUsage { sessionId: string; projectName: string; startTime: string; endTime: string; duration: string; cost: number; modelBreakdowns: ModelBreakdown[]; } export interface BlockUsage extends TokenUsage { startTime: string; endTime: string; cost: number; isActive?: boolean; modelBreakdowns: ModelBreakdown[]; } export declare function runCcusage(args: string[]): Promise<any>; export declare const ccusage: { daily(options?: CcusageOptions): Promise<DailyUsage[]>; monthly(options?: CcusageOptions): Promise<MonthlyUsage[]>; session(options?: CcusageOptions): Promise<SessionUsage[]>; blocks(options?: CcusageOptions): Promise<BlockUsage[]>; }; `; writeFileSync(join(bundleDir, 'index.d.ts'), typeDefsContent); // Step 5: Create package.json for the bundle const bundlePackageJson = { name: "@vibetime/ccusage-bundle", version: "1.0.0", private: true, type: "module", main: "./index.js", types: "./index.d.ts", description: "ccusage functionality bundled for vibetime CLI" }; writeFileSync( join(bundleDir, 'package.json'), JSON.stringify(bundlePackageJson, null, 2) ); console.log('✅ ccusage bundle created successfully at:', bundleDir); console.log('\nTo use the bundle:'); console.log('1. Ensure bun is installed on the target system'); console.log('2. Ensure git submodules are initialized'); console.log('3. Import from src/lib/ccusage-bundle');