UNPKG

claude-usage-tracker

Version:

Advanced analytics for Claude Code usage with cost optimization, conversation length analysis, and rate limit tracking

152 lines 4.69 kB
import { existsSync, readFileSync } from "node:fs"; import { join, dirname } from "node:path"; import { fileURLToPath } from "node:url"; import yaml from "js-yaml"; import { z } from "zod"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Zod schemas for validation const ModelConfigSchema = z.object({ name: z.string(), input: z.number().positive(), output: z.number().positive(), cached: z.number().positive(), }); const RateLimitSchema = z.object({ min: z.number().positive(), max: z.number().positive(), }); const PlanLimitsSchema = z.object({ price: z.number().positive(), weekly: z.object({ sonnet4: RateLimitSchema, opus4: RateLimitSchema, }), }); const ConfigSchema = z.object({ models: z.record(z.string(), ModelConfigSchema), rate_limits: z.record(z.string(), PlanLimitsSchema), token_estimates: z.object({ sonnet4: z.object({ min: z.number().positive(), max: z.number().positive(), }), opus4: z.object({ min: z.number().positive(), max: z.number().positive(), }), }), batch_api_discount: z.number().min(0).max(1), data_paths: z.array(z.string()), recommendations: z.record(z.string(), z.object({ model: z.string(), confidence: z.number().min(0).max(1), })), }); let cachedConfig = null; let testConfig = null; export function loadConfig(configPath) { // In test environment, use test config if available if (process.env.NODE_ENV === "test" && !configPath) { const testConfig = getTestConfig(); if (testConfig) { return testConfig; } } // Get config path from CLI if not explicitly provided if (!configPath && typeof process !== "undefined" && process.argv) { const configIndex = process.argv.findIndex((arg) => arg === "-c" || arg === "--config"); if (configIndex !== -1 && process.argv[configIndex + 1]) { configPath = process.argv[configIndex + 1]; } } if (cachedConfig && !configPath) { return cachedConfig; } const paths = [ configPath, process.env.CLAUDE_USAGE_CONFIG, join(process.cwd(), "config", "local.yaml"), join(process.cwd(), "config", "default.yaml"), join(__dirname, "..", "config", "default.yaml"), ].filter(Boolean); let configData = null; let usedPath = null; for (const path of paths) { if (existsSync(path)) { try { const content = readFileSync(path, "utf8"); configData = yaml.load(content); usedPath = path; break; } catch (error) { console.warn(`Failed to load config from ${path}:`, error); continue; } } } if (!configData) { throw new Error(`No valid configuration file found. Searched paths: ${paths.join(", ")}`); } try { const validatedConfig = ConfigSchema.parse(configData); cachedConfig = validatedConfig; if (process.env.NODE_ENV !== "test") { console.log(`📝 Loaded configuration from: ${usedPath}`); } return validatedConfig; } catch (error) { if (error instanceof z.ZodError) { throw new Error(`Configuration validation failed: ${error.errors .map((e) => `${e.path.join(".")}: ${e.message}`) .join(", ")}`); } throw error; } } export function clearConfigCache() { cachedConfig = null; } function getTestConfig() { return testConfig; } export function setTestConfig(config) { try { testConfig = ConfigSchema.parse(config); } catch (error) { console.warn("Invalid test config:", error); testConfig = null; } } export function clearTestConfig() { testConfig = null; } // Helper functions to access config values export function getModelPricing() { const config = loadConfig(); return config.models; } export function getRateLimits() { const config = loadConfig(); return config.rate_limits; } export function getTokenEstimates() { const config = loadConfig(); return config.token_estimates; } export function getDataPaths() { const config = loadConfig(); return config.data_paths; } export function getBatchApiDiscount() { const config = loadConfig(); return config.batch_api_discount; } export function getModelRecommendations() { const config = loadConfig(); return config.recommendations; } //# sourceMappingURL=config-loader.js.map