/** * logger.js — persistent JSONL log to ~/.logs/token-monitor/YYYY-MM-DD.jsonl */ import { appendFileSync, mkdirSync, existsSync, readFileSync } from 'fs'; import { homedir } from 'os'; import { join } from 'path'; export function logRun(data) { const dir = join(homedir(), '.logs', 'token-monitor'); mkdirSync(dir, { recursive: true }); const file = join(dir, `${new Date().toISOString().slice(0, 10)}.jsonl`); appendFileSync(file, JSON.stringify({ ts: new Date().toISOString(), ...data }) + '\n'); } export function getLogPath() { const today = new Date().toISOString().slice(0, 10); return join(homedir(), '.logs', 'token-monitor', `${today}.jsonl`); } /** * Returns the last logged run if it was within maxAgeMinutes, otherwise null. * Skips test/empty entries (entries where providers has no typed providers). */ export function getCachedRun(maxAgeMinutes = 20) { const dir = join(homedir(), '.logs', 'token-monitor'); const today = new Date().toISOString().slice(0, 10); const file = join(dir, `${today}.jsonl`); if (!existsSync(file)) return null; const lines = readFileSync(file, 'utf-8').trim().split('\n').filter(Boolean); for (let i = lines.length - 1; i >= 0; i--) { try { const entry = JSON.parse(lines[i]); const providers = entry.providers || {}; // Skip test/empty entries — real entries have at least one provider with a type const hasRealData = Object.values(providers).some(p => p && p.type); if (!hasRealData) continue; const ageMinutes = (Date.now() - new Date(entry.ts).getTime()) / 60000; if (ageMinutes <= maxAgeMinutes) return entry; return null; // last real entry is too old } catch { continue; } } return null; }