import * as fs from "fs"; import * as path from "path"; const REPO_ROOT = process.env.REPO_ROOT || path.resolve(process.cwd(), ".."); const USAGE_LOG = path.join(REPO_ROOT, "apps/palacemonitor", "usage.jsonl"); export interface UsageEntry { channel: string; model?: string; domain?: string; duration_ms: number; total_cost_usd: number; input_tokens: number; output_tokens: number; cache_read_input_tokens: number; cache_creation_input_tokens: number; num_turns: number; } export function logUsage(entry: UsageEntry): void { const now = new Date(); const date = now.toLocaleDateString("en-CA", { timeZone: "America/Los_Angeles" }); const time = now.toLocaleTimeString("en-US", { timeZone: "America/Los_Angeles", hour12: false, hour: "2-digit", minute: "2-digit", }); const row: Record = { date, time, channel: entry.channel, model: entry.model || "opus", duration_min: Math.round(entry.duration_ms / 60000), duration_ms: entry.duration_ms, tokens_in: entry.input_tokens + entry.cache_read_input_tokens + entry.cache_creation_input_tokens, tokens_out: entry.output_tokens, cost_usd: entry.total_cost_usd, num_turns: entry.num_turns, }; if (entry.domain) row.domain = entry.domain; try { fs.appendFileSync(USAGE_LOG, JSON.stringify(row) + "\n"); } catch (err) { console.error("[usage] failed to log:", err); } } export function extractUsageFromResult(msg: any): Omit { return { duration_ms: msg.duration_ms || 0, total_cost_usd: msg.total_cost_usd || 0, input_tokens: msg.usage?.input_tokens || 0, output_tokens: msg.usage?.output_tokens || 0, cache_read_input_tokens: msg.usage?.cache_read_input_tokens || 0, cache_creation_input_tokens: msg.usage?.cache_creation_input_tokens || 0, num_turns: msg.num_turns || 0, }; }