#!/usr/bin/env bun
// @bun
var __defProp = Object.defineProperty;
var __returnValue = (v) => v;
function __exportSetter(name, newValue) {
  this[name] = __returnValue.bind(null, newValue);
}
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, {
      get: all[name],
      enumerable: true,
      configurable: true,
      set: __exportSetter.bind(all, name)
    });
};
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
var __require = import.meta.require;

// packages/core/dist/constants.js
var DEFAULT_DAYS = 90, DEFAULT_CONCURRENCY = 3, MAX_JSONL_RECORD_BYTES, SCHEMA_VERSION = 1;
var init_constants = __esm(() => {
  MAX_JSONL_RECORD_BYTES = 10 * 1024 * 1024;
});

// packages/core/dist/date-utils.js
function dateToUtcMs(dateString) {
  return new Date(dateString + "T00:00:00Z").getTime();
}
function formatDateStringUtc(date) {
  return date.toISOString().slice(0, 10);
}
function compareDateStrings(a, b) {
  return dateToUtcMs(a) - dateToUtcMs(b);
}
var ONE_DAY_MS = 86400000;

// packages/core/dist/aggregation/streaks.js
function calculateStreaks(daily) {
  if (daily.length === 0) {
    return { current: 0, longest: 0 };
  }
  const sorted = [...daily].sort((a, b) => dateToUtcMs(a.date) - dateToUtcMs(b.date));
  let longest = 1;
  let currentRun = 1;
  for (let i = 1;i < sorted.length; i++) {
    const prev = dateToUtcMs(sorted[i - 1].date);
    const curr = dateToUtcMs(sorted[i].date);
    const diff = curr - prev;
    if (diff === ONE_DAY_MS) {
      currentRun++;
    } else {
      currentRun = 1;
    }
    if (currentRun > longest) {
      longest = currentRun;
    }
  }
  let current = 1;
  for (let i = sorted.length - 1;i > 0; i--) {
    const curr = dateToUtcMs(sorted[i].date);
    const prev = dateToUtcMs(sorted[i - 1].date);
    if (curr - prev === ONE_DAY_MS) {
      current++;
    } else {
      break;
    }
  }
  return { current, longest };
}
var init_streaks = () => {};

// packages/core/dist/aggregation/rolling-window.js
function rollingWindow(daily, days, referenceDate) {
  if (daily.length === 0 || days <= 0) {
    return { tokens: 0, cost: 0 };
  }
  const refTime = dateToUtcMs(referenceDate);
  const windowStart = refTime - (days - 1) * ONE_DAY_MS;
  let tokens = 0;
  let cost = 0;
  for (const entry of daily) {
    const entryTime = dateToUtcMs(entry.date);
    if (entryTime >= windowStart && entryTime <= refTime) {
      tokens += entry.totalTokens;
      cost += entry.cost;
    }
  }
  return { tokens, cost };
}
var init_rolling_window = () => {};

// packages/core/dist/aggregation/peaks.js
function findPeakDay(daily) {
  if (daily.length === 0) {
    return null;
  }
  let peak = null;
  for (const entry of daily) {
    if (peak === null || entry.totalTokens > peak.tokens || entry.totalTokens === peak.tokens && entry.date > peak.date) {
      peak = { date: entry.date, tokens: entry.totalTokens };
    }
  }
  return peak;
}

// packages/core/dist/aggregation/day-of-week.js
function dayOfWeekBreakdown(daily) {
  const buckets = DAY_LABELS.map((label, i) => ({
    day: i,
    label,
    tokens: 0,
    cost: 0,
    count: 0
  }));
  for (const entry of daily) {
    const dayIndex = new Date(dateToUtcMs(entry.date)).getUTCDay();
    const bucket = buckets[dayIndex];
    bucket.tokens += entry.totalTokens;
    bucket.cost += entry.cost;
    bucket.count += 1;
  }
  return buckets;
}
var DAY_LABELS;
var init_day_of_week = __esm(() => {
  DAY_LABELS = [
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday"
  ];
});

// packages/core/dist/aggregation/cache-rate.js
function cacheHitRate(daily) {
  let totalCacheRead = 0;
  let totalInput = 0;
  for (const entry of daily) {
    totalCacheRead += entry.cacheReadTokens;
    totalInput += entry.inputTokens;
  }
  const denominator = totalInput + totalCacheRead;
  if (denominator === 0) {
    return 0;
  }
  return totalCacheRead / denominator;
}

// packages/core/dist/aggregation/averages.js
function calculateAverages(daily, totalDays) {
  if (totalDays <= 0 || daily.length === 0) {
    return { tokens: 0, cost: 0 };
  }
  let totalTokens = 0;
  let totalCost = 0;
  for (const entry of daily) {
    totalTokens += entry.totalTokens;
    totalCost += entry.cost;
  }
  return {
    tokens: totalTokens / totalDays,
    cost: totalCost / totalDays
  };
}

// packages/core/dist/aggregation/top-models.js
function topModels(daily, limit = DEFAULT_LIMIT) {
  const modelMap = new Map;
  for (const entry of daily) {
    for (const m of entry.models) {
      const existing = modelMap.get(m.model);
      if (existing) {
        existing.tokens += m.totalTokens;
        existing.cost += m.cost;
      } else {
        modelMap.set(m.model, { tokens: m.totalTokens, cost: m.cost });
      }
    }
  }
  let grandTotal = 0;
  for (const v of modelMap.values()) {
    grandTotal += v.tokens;
  }
  const entries = [];
  for (const [model, { tokens, cost }] of modelMap) {
    entries.push({
      model,
      tokens,
      cost,
      percentage: grandTotal > 0 ? tokens / grandTotal * 100 : 0
    });
  }
  entries.sort((a, b) => b.tokens - a.tokens);
  return entries.slice(0, limit);
}
var DEFAULT_LIMIT = 10;

// packages/core/dist/aggregation/aggregate.js
function aggregate(daily, referenceDate) {
  const streaks = calculateStreaks(daily);
  const rolling30 = rollingWindow(daily, 30, referenceDate);
  const rolling7 = rollingWindow(daily, 7, referenceDate);
  const peak = findPeakDay(daily);
  const dow = dayOfWeekBreakdown(daily);
  const cache = cacheHitRate(daily);
  const models = topModels(daily);
  let totalTokens = 0;
  let totalInputTokens = 0;
  let totalOutputTokens = 0;
  let totalCost = 0;
  for (const entry of daily) {
    totalTokens += entry.totalTokens;
    totalInputTokens += entry.inputTokens;
    totalOutputTokens += entry.outputTokens;
    totalCost += entry.cost;
  }
  const rolling30dTopModel = computeRolling30dTopModel(daily, referenceDate);
  const activeDays = daily.length;
  const totalDays = computeTotalDays(daily);
  const averages = calculateAverages(daily, totalDays);
  return {
    currentStreak: streaks.current,
    longestStreak: streaks.longest,
    rolling30dTokens: rolling30.tokens,
    rolling30dCost: rolling30.cost,
    rolling7dTokens: rolling7.tokens,
    rolling7dCost: rolling7.cost,
    peakDay: peak,
    averageDailyTokens: averages.tokens,
    averageDailyCost: averages.cost,
    cacheHitRate: cache,
    totalTokens,
    totalInputTokens,
    totalOutputTokens,
    totalCost,
    totalDays,
    activeDays,
    dayOfWeek: dow,
    topModels: models,
    rolling30dTopModel
  };
}
function computeRolling30dTopModel(daily, referenceDate) {
  const refTime = dateToUtcMs(referenceDate);
  const windowStart = refTime - (ROLLING_WINDOW_DAYS - 1) * ONE_DAY_MS;
  const modelTokensMap = new Map;
  for (const entry of daily) {
    const entryTime = dateToUtcMs(entry.date);
    if (entryTime >= windowStart && entryTime <= refTime) {
      for (const m of entry.models) {
        modelTokensMap.set(m.model, (modelTokensMap.get(m.model) ?? 0) + m.totalTokens);
      }
    }
  }
  let topModel = null;
  let maxTokens = 0;
  for (const [model, tokens] of modelTokensMap) {
    if (tokens > maxTokens) {
      maxTokens = tokens;
      topModel = model;
    }
  }
  return topModel;
}
function computeTotalDays(daily) {
  if (daily.length === 0)
    return 0;
  const sorted = [...daily].sort((a, b) => dateToUtcMs(a.date) - dateToUtcMs(b.date));
  const first = dateToUtcMs(sorted[0].date);
  const last = dateToUtcMs(sorted[sorted.length - 1].date);
  return Math.round((last - first) / ONE_DAY_MS) + 1;
}
var ROLLING_WINDOW_DAYS = 30;
var init_aggregate = __esm(() => {
  init_streaks();
  init_rolling_window();
  init_day_of_week();
});

// packages/core/dist/aggregation/merge.js
function mergeModelArrays(existing, incoming) {
  const map = new Map;
  for (const m of existing) {
    map.set(m.model, { ...m });
  }
  for (const m of incoming) {
    const prev = map.get(m.model);
    if (prev) {
      prev.inputTokens += m.inputTokens;
      prev.outputTokens += m.outputTokens;
      prev.cacheReadTokens += m.cacheReadTokens;
      prev.cacheWriteTokens += m.cacheWriteTokens;
      prev.totalTokens += m.totalTokens;
      prev.cost += m.cost;
    } else {
      map.set(m.model, { ...m });
    }
  }
  return [...map.values()];
}
function mergeProviderData(providers) {
  const dateMap = new Map;
  for (const provider of providers) {
    for (const entry of provider.daily) {
      const existing = dateMap.get(entry.date);
      if (existing) {
        existing.inputTokens += entry.inputTokens;
        existing.outputTokens += entry.outputTokens;
        existing.cacheReadTokens += entry.cacheReadTokens;
        existing.cacheWriteTokens += entry.cacheWriteTokens;
        existing.totalTokens += entry.totalTokens;
        existing.cost += entry.cost;
        existing.models = mergeModelArrays(existing.models, entry.models);
      } else {
        dateMap.set(entry.date, {
          date: entry.date,
          inputTokens: entry.inputTokens,
          outputTokens: entry.outputTokens,
          cacheReadTokens: entry.cacheReadTokens,
          cacheWriteTokens: entry.cacheWriteTokens,
          totalTokens: entry.totalTokens,
          cost: entry.cost,
          models: [...entry.models]
        });
      }
    }
  }
  return [...dateMap.values()].sort((a, b) => compareDateStrings(a.date, b.date));
}
var init_merge = () => {};

// packages/core/dist/aggregation/compare.js
function filterByRange(daily, range) {
  return daily.filter((d) => d.date >= range.since && d.date <= range.until);
}
function computeDeltas(statsA, statsB) {
  return {
    tokens: statsB.totalTokens - statsA.totalTokens,
    cost: statsB.totalCost - statsA.totalCost,
    streak: statsB.currentStreak - statsA.currentStreak,
    activeDays: statsB.activeDays - statsA.activeDays,
    averageDailyTokens: statsB.averageDailyTokens - statsA.averageDailyTokens,
    cacheHitRate: statsB.cacheHitRate - statsA.cacheHitRate
  };
}
function buildCompareOutput(periodA, periodB) {
  return {
    schemaVersion: SCHEMA_VERSION,
    generated: new Date().toISOString(),
    periodA,
    periodB,
    deltas: computeDeltas(periodA.stats, periodB.stats)
  };
}
function parseCompareRange(rangeStr) {
  const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
  const parts = rangeStr.split("..");
  if (parts.length !== 2)
    return null;
  const [since, until] = parts;
  if (!DATE_PATTERN.test(since) || !DATE_PATTERN.test(until))
    return null;
  if (since > until)
    return null;
  return { since, until };
}
function computePreviousPeriod(current) {
  const sinceMs = dateToUtcMs(current.since);
  const untilMs = dateToUtcMs(current.until);
  const periodDays = Math.round((untilMs - sinceMs) / ONE_DAY_MS);
  const prevUntil = new Date(sinceMs - ONE_DAY_MS);
  const prevSince = new Date(prevUntil.getTime() - periodDays * ONE_DAY_MS);
  return {
    since: formatDateStringUtc(prevSince),
    until: formatDateStringUtc(prevUntil)
  };
}
function compareRanges(daily, rangeA, rangeB) {
  const dailyA = filterByRange(daily, rangeA);
  const dailyB = filterByRange(daily, rangeB);
  const statsA = aggregate(dailyA, rangeA.until);
  const statsB = aggregate(dailyB, rangeB.until);
  const deltas = computeDeltas(statsA, statsB);
  return {
    schemaVersion: SCHEMA_VERSION,
    generated: new Date().toISOString(),
    periodA: { range: rangeA, stats: statsA },
    periodB: { range: rangeB, stats: statsB },
    deltas
  };
}
var init_compare = __esm(() => {
  init_constants();
  init_aggregate();
});

// packages/core/dist/aggregation/analytics.js
import { dirname, basename, relative } from "path";
function isAbsoluteProjectPath(value) {
  return value.startsWith("/") || /^[A-Za-z]:[\\/]/.test(value);
}
function normalizePathLike(value) {
  return value.replace(/\\/g, "/");
}
function inferRepoRoot(projectId) {
  if (!projectId || !projectId.trim()) {
    return null;
  }
  const normalized = normalizePathLike(projectId.trim());
  if (!isAbsoluteProjectPath(normalized)) {
    return normalized;
  }
  const parts = normalized.split("/").filter(Boolean);
  if (parts.length === 0) {
    return normalized;
  }
  if (normalized.startsWith("/Users/") && parts.length >= 3) {
    return `/${parts.slice(0, 3).join("/")}`;
  }
  if (normalized.startsWith("/home/") && parts.length >= 3) {
    return `/${parts.slice(0, 3).join("/")}`;
  }
  if (/^[A-Za-z]:\//.test(normalized) && parts.length >= 2) {
    return `${parts[0]}/${parts[1]}`;
  }
  return dirname(normalized);
}
function inferDirectoryLabel(projectId, repoRoot) {
  if (!projectId || !projectId.trim()) {
    return null;
  }
  const normalized = normalizePathLike(projectId.trim());
  if (!repoRoot || !isAbsoluteProjectPath(normalized)) {
    return basename(normalized) || normalized;
  }
  const rel = normalizePathLike(relative(repoRoot, normalized));
  if (!rel || rel === "" || rel === ".") {
    return ".";
  }
  const [first] = rel.split("/").filter(Boolean);
  return first ?? ".";
}
function topModelEntries(modelTokens, totalTokens, limit) {
  return [...modelTokens.entries()].map(([model, value]) => ({
    model,
    tokens: value.tokens,
    cost: value.cost,
    percentage: totalTokens > 0 ? value.tokens / totalTokens : 0
  })).sort((a, b) => b.tokens - a.tokens).slice(0, limit);
}
function topNames(tokensByName, limit) {
  return [...tokensByName.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, limit).map(([name]) => name);
}
function humanizeTaskStyle(taskStyle) {
  return taskStyle.replace(/-/g, " ");
}
function parseIsoTime(value) {
  const parsed = Date.parse(value);
  return Number.isFinite(parsed) ? parsed : null;
}
function inferAttributionTaskStyle(session) {
  const durationMs = session.durationMs ?? 0;
  if (durationMs > 0 && durationMs <= 10 * 60 * 1000 && session.eventCount <= 2 && session.totalTokens < 6000) {
    return "quick-hit";
  }
  if (durationMs >= 45 * 60 * 1000 || session.eventCount >= 5 || session.totalTokens >= 20000) {
    return "deep-work";
  }
  if (durationMs >= 15 * 60 * 1000 || session.eventCount >= 3 || session.totalTokens >= 6000) {
    return "iterative";
  }
  return "mixed";
}
function resolveAttributionScope(session) {
  const hasStablePath = (session.projectId ? isAbsoluteProjectPath(normalizePathLike(session.projectId)) : false) || (session.repoRoot ? isAbsoluteProjectPath(normalizePathLike(session.repoRoot)) : false);
  if (hasStablePath && session.repoRoot && session.directory) {
    const labelBase = session.directory === "." ? basename(session.repoRoot) : session.directory;
    return {
      key: `repo:${session.repoRoot}::dir:${session.directory}`,
      labelBase,
      repoRoot: session.repoRoot,
      directory: session.directory
    };
  }
  if (session.projectId) {
    return {
      key: `project:${session.provider}:${session.projectId}`,
      labelBase: session.directory ?? session.projectId,
      repoRoot: hasStablePath ? session.repoRoot : null,
      directory: hasStablePath ? session.directory : null
    };
  }
  return {
    key: `session:${session.provider}:${session.sessionId}`,
    labelBase: session.directory ?? session.label,
    repoRoot: session.repoRoot,
    directory: session.directory
  };
}
function buildAttributionWindows(sessions) {
  if (sessions.length === 0) {
    return [];
  }
  const ordered = sessions.slice().sort((a, b) => {
    const aTime = parseIsoTime(a.start);
    const bTime = parseIsoTime(b.start);
    if (aTime === null && bTime === null) {
      return a.start.localeCompare(b.start);
    }
    if (aTime === null) {
      return 1;
    }
    if (bTime === null) {
      return -1;
    }
    return aTime - bTime;
  });
  const windows = [];
  for (const session of ordered) {
    const startMs = parseIsoTime(session.start);
    const endMs = parseIsoTime(session.end) ?? startMs;
    const lastWindow = windows.at(-1);
    if (lastWindow && startMs !== null && endMs !== null && parseIsoTime(lastWindow.end) !== null && startMs <= (parseIsoTime(lastWindow.end) ?? startMs) + ATTRIBUTION_WINDOW_GAP_MS) {
      if ((parseIsoTime(lastWindow.end) ?? endMs) < endMs) {
        lastWindow.end = session.end;
      }
      lastWindow.sessionCount += 1;
      continue;
    }
    windows.push({
      start: session.start,
      end: session.end,
      sessionCount: 1
    });
  }
  return windows;
}
function buildSessionRollups(events, topModelLimit = 3) {
  const sessions = new Map;
  for (const event of events) {
    const sessionId = event.sessionId?.trim() || `${event.provider}:${event.timestamp}`;
    const projectId = event.projectId?.trim() || null;
    const repoRoot = event.repoRoot ?? inferRepoRoot(projectId);
    const directory = event.directory ?? inferDirectoryLabel(projectId, repoRoot);
    const label = projectId ?? sessionId;
    let session = sessions.get(sessionId);
    if (!session) {
      session = {
        sessionId,
        label,
        provider: event.provider,
        projectId,
        repoRoot,
        directory,
        start: event.timestamp,
        end: event.timestamp,
        durationMs: null,
        eventCount: 0,
        inputTokens: 0,
        outputTokens: 0,
        cacheReadTokens: 0,
        cacheWriteTokens: 0,
        totalTokens: 0,
        cost: 0,
        modelTokens: new Map,
        activeDates: new Set
      };
      sessions.set(sessionId, session);
    } else {
      if (!session.projectId && projectId) {
        session.projectId = projectId;
        session.label = projectId;
      }
      if (!session.repoRoot && repoRoot) {
        session.repoRoot = repoRoot;
      }
      if (!session.directory && directory) {
        session.directory = directory;
      }
    }
    session.start = session.start < event.timestamp ? session.start : event.timestamp;
    session.end = session.end > event.timestamp ? session.end : event.timestamp;
    session.eventCount += 1;
    session.inputTokens += event.inputTokens;
    session.outputTokens += event.outputTokens;
    session.cacheReadTokens += event.cacheReadTokens;
    session.cacheWriteTokens += event.cacheWriteTokens;
    session.totalTokens += event.totalTokens;
    session.cost += event.cost;
    session.activeDates.add(event.date);
    const existingModel = session.modelTokens.get(event.model) ?? { tokens: 0, cost: 0 };
    existingModel.tokens += event.totalTokens;
    existingModel.cost += event.cost;
    session.modelTokens.set(event.model, existingModel);
    if (typeof event.durationMs === "number" && Number.isFinite(event.durationMs) && event.durationMs > 0) {
      session.durationMs = (session.durationMs ?? 0) + event.durationMs;
    }
  }
  return [...sessions.values()].map((session) => {
    let durationMs = session.durationMs;
    if (durationMs === null) {
      const startMs = Date.parse(session.start);
      const endMs = Date.parse(session.end);
      if (Number.isFinite(startMs) && Number.isFinite(endMs) && endMs > startMs) {
        durationMs = endMs - startMs;
      }
    }
    return {
      sessionId: session.sessionId,
      label: session.label,
      provider: session.provider,
      projectId: session.projectId,
      repoRoot: session.repoRoot,
      directory: session.directory,
      start: session.start,
      end: session.end,
      durationMs,
      eventCount: session.eventCount,
      inputTokens: session.inputTokens,
      outputTokens: session.outputTokens,
      cacheReadTokens: session.cacheReadTokens,
      cacheWriteTokens: session.cacheWriteTokens,
      totalTokens: session.totalTokens,
      cost: session.cost,
      topModels: topModelEntries(session.modelTokens, session.totalTokens, topModelLimit)
    };
  }).sort((a, b) => b.totalTokens - a.totalTokens);
}
function buildProjectRollups(events, topModelLimit = 5, topSessionLimit = 3) {
  const sessions = buildSessionRollups(events, topModelLimit);
  const byProject = new Map;
  for (const event of events) {
    const projectId = event.projectId?.trim();
    if (!projectId) {
      continue;
    }
    const repoRoot = event.repoRoot ?? inferRepoRoot(projectId);
    const directory = event.directory ?? inferDirectoryLabel(projectId, repoRoot);
    let project = byProject.get(projectId);
    if (!project) {
      project = {
        projectId,
        repoRoot,
        directory,
        sessionCount: 0,
        activeDates: new Set,
        inputTokens: 0,
        outputTokens: 0,
        cacheReadTokens: 0,
        cacheWriteTokens: 0,
        totalTokens: 0,
        cost: 0,
        modelTokens: new Map,
        topSessions: []
      };
      byProject.set(projectId, project);
    }
    project.activeDates.add(event.date);
    project.inputTokens += event.inputTokens;
    project.outputTokens += event.outputTokens;
    project.cacheReadTokens += event.cacheReadTokens;
    project.cacheWriteTokens += event.cacheWriteTokens;
    project.totalTokens += event.totalTokens;
    project.cost += event.cost;
    const existingModel = project.modelTokens.get(event.model) ?? { tokens: 0, cost: 0 };
    existingModel.tokens += event.totalTokens;
    existingModel.cost += event.cost;
    project.modelTokens.set(event.model, existingModel);
  }
  for (const session of sessions) {
    if (!session.projectId) {
      continue;
    }
    const project = byProject.get(session.projectId);
    if (!project) {
      continue;
    }
    project.sessionCount += 1;
    project.topSessions.push(session);
  }
  return [...byProject.values()].map((project) => {
    const streakDaily = [...project.activeDates].sort().map((date) => ({
      date,
      inputTokens: 0,
      outputTokens: 0,
      cacheReadTokens: 0,
      cacheWriteTokens: 0,
      totalTokens: 0,
      cost: 0,
      models: []
    }));
    const streak = calculateStreaks(streakDaily).longest;
    return {
      projectId: project.projectId,
      repoRoot: project.repoRoot,
      directory: project.directory,
      sessionCount: project.sessionCount,
      activeDays: project.activeDates.size,
      streak,
      inputTokens: project.inputTokens,
      outputTokens: project.outputTokens,
      cacheReadTokens: project.cacheReadTokens,
      cacheWriteTokens: project.cacheWriteTokens,
      totalTokens: project.totalTokens,
      cost: project.cost,
      topModels: topModelEntries(project.modelTokens, project.totalTokens, topModelLimit),
      topSessions: project.topSessions.sort((a, b) => b.totalTokens - a.totalTokens).slice(0, topSessionLimit).map((session) => ({
        label: session.label,
        tokens: session.totalTokens,
        cost: session.cost,
        count: session.eventCount,
        durationMs: session.durationMs
      }))
    };
  }).sort((a, b) => b.totalTokens - a.totalTokens);
}
function buildAttributionClusters(events, modelLimit = 5, providerLimit = 4) {
  const sessions = buildSessionRollups(events, modelLimit);
  const clusters = new Map;
  const clusterBySessionId = new Map;
  for (const session of sessions) {
    const taskStyle = inferAttributionTaskStyle(session);
    const scope = resolveAttributionScope(session);
    const clusterId = `${scope.key}::style:${taskStyle}`;
    clusterBySessionId.set(session.sessionId, clusterId);
    let cluster = clusters.get(clusterId);
    if (!cluster) {
      cluster = {
        clusterId,
        label: `${scope.labelBase} \xB7 ${humanizeTaskStyle(taskStyle)}`,
        taskStyle,
        repoRoot: scope.repoRoot,
        directory: scope.directory,
        tokens: 0,
        cost: 0,
        sessions: [],
        activeDates: new Set,
        providerTokens: new Map,
        modelTokens: new Map
      };
      clusters.set(clusterId, cluster);
    }
    cluster.sessions.push(session);
  }
  for (const event of events) {
    const sessionId = event.sessionId?.trim() || `${event.provider}:${event.timestamp}`;
    const clusterId = clusterBySessionId.get(sessionId);
    if (!clusterId) {
      continue;
    }
    const cluster = clusters.get(clusterId);
    if (!cluster) {
      continue;
    }
    cluster.tokens += event.totalTokens;
    cluster.cost += event.cost;
    cluster.activeDates.add(event.date);
    cluster.providerTokens.set(event.provider, (cluster.providerTokens.get(event.provider) ?? 0) + event.totalTokens);
    cluster.modelTokens.set(event.model, (cluster.modelTokens.get(event.model) ?? 0) + event.totalTokens);
  }
  return [...clusters.values()].map((cluster) => ({
    clusterId: cluster.clusterId,
    label: cluster.label,
    taskStyle: cluster.taskStyle,
    repoRoot: cluster.repoRoot,
    directory: cluster.directory,
    sessionCount: cluster.sessions.length,
    activeDays: cluster.activeDates.size,
    tokens: cluster.tokens,
    cost: cluster.cost,
    providers: topNames(cluster.providerTokens, providerLimit),
    models: topNames(cluster.modelTokens, modelLimit),
    timeWindows: buildAttributionWindows(cluster.sessions)
  })).sort((a, b) => b.tokens - a.tokens || b.sessionCount - a.sessionCount);
}
function normalizeScores(values) {
  if (values.length === 0) {
    return [];
  }
  const min = Math.min(...values);
  const max = Math.max(...values);
  if (max === min) {
    return values.map(() => 1);
  }
  return values.map((value) => (value - min) / (max - min));
}
var ATTRIBUTION_WINDOW_GAP_MS;
var init_analytics = __esm(() => {
  init_streaks();
  ATTRIBUTION_WINDOW_GAP_MS = 6 * 60 * 60 * 1000;
});

// packages/core/dist/aggregation/more.js
function daysInMonth(dateString) {
  const [year, month] = dateString.split("-").map(Number);
  if (!year || !month) {
    return 30;
  }
  return new Date(Date.UTC(year, month, 0)).getUTCDate();
}
function buildInputOutput(providers) {
  let inputTokens = 0;
  let outputTokens = 0;
  for (const provider of providers) {
    for (const day of provider.daily) {
      inputTokens += day.inputTokens;
      outputTokens += day.outputTokens;
    }
  }
  const nonCacheTokens = inputTokens + outputTokens;
  return {
    inputPerOutput: outputTokens > 0 ? inputTokens / outputTokens : null,
    outputPerInput: inputTokens > 0 ? outputTokens / inputTokens : null,
    outputShare: nonCacheTokens > 0 ? outputTokens / nonCacheTokens : 0
  };
}
function buildMonthlyBurn(providers, range) {
  const monthPrefix = range.until.slice(0, 7);
  const monthStart = `${monthPrefix}-01`;
  const observedSince = range.since > monthStart ? range.since : monthStart;
  const observedDays = Math.max(1, Math.round((Date.parse(`${range.until}T00:00:00Z`) - Date.parse(`${observedSince}T00:00:00Z`)) / 86400000) + 1);
  let observedTokens = 0;
  let observedCost = 0;
  for (const provider of providers) {
    for (const day of provider.daily) {
      if (day.date >= observedSince && day.date <= range.until) {
        observedTokens += day.totalTokens;
        observedCost += day.cost;
      }
    }
  }
  const calendarDays = daysInMonth(range.until);
  const tokensPerDay = observedTokens / observedDays;
  const costPerDay = observedCost / observedDays;
  return {
    projectedTokens: tokensPerDay * calendarDays,
    projectedCost: costPerDay * calendarDays,
    observedDays,
    calendarDays
  };
}
function buildCacheEconomics(providers) {
  let readTokens = 0;
  let writeTokens = 0;
  let inputTokens = 0;
  for (const provider of providers) {
    for (const day of provider.daily) {
      readTokens += day.cacheReadTokens;
      writeTokens += day.cacheWriteTokens;
      inputTokens += day.inputTokens;
    }
  }
  const readCoverage = readTokens + inputTokens > 0 ? readTokens / (readTokens + inputTokens) : 0;
  return {
    readTokens,
    writeTokens,
    readCoverage,
    reuseRatio: writeTokens > 0 ? readTokens / writeTokens : null
  };
}
function createCacheRoiAccumulator() {
  return {
    readTokens: 0,
    writeTokens: 0,
    readSavings: 0,
    writeCost: 0
  };
}
function addCacheRoiUsage(accumulator, readTokens, writeTokens, pricing) {
  if (!pricing || !readTokens && !writeTokens) {
    return;
  }
  accumulator.readTokens += readTokens;
  accumulator.writeTokens += writeTokens;
  accumulator.readSavings += readTokens / TOKENS_PER_MILLION * (pricing.input - pricing.cacheRead);
  accumulator.writeCost += writeTokens / TOKENS_PER_MILLION * pricing.cacheWrite;
}
function finalizeCacheRoi(accumulator) {
  return {
    readTokens: accumulator.readTokens,
    writeTokens: accumulator.writeTokens,
    readSavings: accumulator.readSavings,
    writeCost: accumulator.writeCost,
    netSavings: accumulator.readSavings - accumulator.writeCost,
    reuseRatio: accumulator.writeTokens > 0 ? accumulator.readTokens / accumulator.writeTokens : null,
    paybackRatio: accumulator.writeCost > 0 ? accumulator.readSavings / accumulator.writeCost : null
  };
}
function sortCacheRoiBreakdowns(breakdowns) {
  return breakdowns.sort((left, right) => {
    if (right.netSavings !== left.netSavings) {
      return right.netSavings - left.netSavings;
    }
    if (right.readSavings !== left.readSavings) {
      return right.readSavings - left.readSavings;
    }
    if (right.readTokens !== left.readTokens) {
      return right.readTokens - left.readTokens;
    }
    return left.label.localeCompare(right.label);
  });
}
function buildCacheRoi(providers, events) {
  const summary = createCacheRoiAccumulator();
  const byProvider = new Map;
  const byModel = new Map;
  const byProject = new Map;
  for (const provider of providers) {
    const providerAccumulator = byProvider.get(provider.displayName) ?? createCacheRoiAccumulator();
    byProvider.set(provider.displayName, providerAccumulator);
    for (const day of provider.daily) {
      for (const model of day.models) {
        addCacheRoiUsage(summary, model.cacheReadTokens, model.cacheWriteTokens, model.pricing);
        addCacheRoiUsage(providerAccumulator, model.cacheReadTokens, model.cacheWriteTokens, model.pricing);
        const modelAccumulator = byModel.get(model.model) ?? createCacheRoiAccumulator();
        byModel.set(model.model, modelAccumulator);
        addCacheRoiUsage(modelAccumulator, model.cacheReadTokens, model.cacheWriteTokens, model.pricing);
      }
    }
  }
  for (const event of events) {
    const projectLabel = event.projectId?.trim() || event.repoRoot?.trim() || event.directory?.trim();
    if (!projectLabel) {
      continue;
    }
    const projectAccumulator = byProject.get(projectLabel) ?? createCacheRoiAccumulator();
    byProject.set(projectLabel, projectAccumulator);
    addCacheRoiUsage(projectAccumulator, event.cacheReadTokens, event.cacheWriteTokens, event.pricing);
  }
  const summaryMetrics = finalizeCacheRoi(summary);
  if (summaryMetrics.readTokens === 0 && summaryMetrics.writeTokens === 0) {
    return null;
  }
  return {
    method: "cache-pricing-v1",
    summary: summaryMetrics,
    byProvider: sortCacheRoiBreakdowns([...byProvider.entries()].map(([label, accumulator]) => ({ label, ...finalizeCacheRoi(accumulator) })).filter((entry) => entry.readTokens > 0 || entry.writeTokens > 0)),
    byModel: sortCacheRoiBreakdowns([...byModel.entries()].map(([label, accumulator]) => ({ label, ...finalizeCacheRoi(accumulator) })).filter((entry) => entry.readTokens > 0 || entry.writeTokens > 0)),
    byProject: sortCacheRoiBreakdowns([...byProject.entries()].map(([label, accumulator]) => ({ label, ...finalizeCacheRoi(accumulator) })).filter((entry) => entry.readTokens > 0 || entry.writeTokens > 0))
  };
}
function collectEvents(providers) {
  return providers.flatMap((provider) => provider.events ?? []);
}
function buildHourOfDay(events) {
  const buckets = Array.from({ length: 24 }, (_, hour) => ({
    hour,
    tokens: 0,
    cost: 0,
    count: 0
  }));
  for (const event of events) {
    const date = new Date(event.timestamp);
    if (Number.isNaN(date.getTime())) {
      continue;
    }
    const bucket = buckets[date.getHours()];
    if (!bucket) {
      continue;
    }
    bucket.tokens += event.totalTokens;
    bucket.cost += event.cost;
    bucket.count += 1;
  }
  return buckets;
}
function buildSessionMetrics(sessionDrilldown, projectDrilldown) {
  const totalSessions = sessionDrilldown.length;
  let totalTokens = 0;
  let totalCost = 0;
  let totalMessages = 0;
  let durationTotal = 0;
  let durationCount = 0;
  let longestSession = null;
  let longestSessionDuration = -1;
  for (const session of sessionDrilldown) {
    totalTokens += session.totalTokens;
    totalCost += session.cost;
    totalMessages += session.eventCount;
    if (typeof session.durationMs === "number" && session.durationMs > 0) {
      durationTotal += session.durationMs;
      durationCount += 1;
    }
    if ((session.durationMs ?? 0) > longestSessionDuration || (session.durationMs ?? 0) === longestSessionDuration && (!longestSession || session.totalTokens > longestSession.tokens)) {
      longestSessionDuration = session.durationMs ?? 0;
      longestSession = {
        label: session.label,
        tokens: session.totalTokens,
        cost: session.cost,
        count: session.eventCount,
        durationMs: session.durationMs
      };
    }
  }
  const projectBreakdown = projectDrilldown.map((project) => ({ name: project.projectId, tokens: project.totalTokens })).slice(0, 10);
  const topProject = projectBreakdown[0] ?? null;
  return {
    totalSessions,
    averageTokens: totalSessions > 0 ? totalTokens / totalSessions : 0,
    averageCost: totalSessions > 0 ? totalCost / totalSessions : 0,
    averageMessages: totalSessions > 0 ? totalMessages / totalSessions : 0,
    averageDurationMs: durationCount > 0 ? durationTotal / durationCount : null,
    longestSession,
    projectCount: projectDrilldown.length,
    topProject,
    projectBreakdown
  };
}
function buildModelEfficiency(events) {
  const byModel = new Map;
  for (const event of events) {
    let model = byModel.get(event.model);
    if (!model) {
      model = {
        model: event.model,
        eventCount: 0,
        totalTokens: 0,
        inputTokens: 0,
        outputTokens: 0,
        cacheReadTokens: 0,
        cacheWriteTokens: 0,
        cost: 0
      };
      byModel.set(event.model, model);
    }
    model.eventCount += 1;
    model.totalTokens += event.totalTokens;
    model.inputTokens += event.inputTokens;
    model.outputTokens += event.outputTokens;
    model.cacheReadTokens += event.cacheReadTokens;
    model.cacheWriteTokens += event.cacheWriteTokens;
    model.cost += event.cost;
  }
  const eligible = [...byModel.values()];
  const rankingsBase = [];
  const ineligibleModels = [];
  for (const model of eligible) {
    const reasons = [];
    if (model.eventCount < MIN_MODEL_EFFICIENCY_EVENTS) {
      reasons.push(`needs at least ${MIN_MODEL_EFFICIENCY_EVENTS} events`);
    }
    if (model.totalTokens < MIN_MODEL_EFFICIENCY_TOTAL_TOKENS) {
      reasons.push(`needs at least ${MIN_MODEL_EFFICIENCY_TOTAL_TOKENS} total tokens`);
    }
    if (model.inputTokens <= 0) {
      reasons.push("needs input tokens");
    }
    if (model.outputTokens <= 0) {
      reasons.push("needs output tokens");
    }
    if (model.cost <= 0) {
      reasons.push("needs positive cost");
    }
    if (reasons.length > 0) {
      ineligibleModels.push({
        model: model.model,
        eventCount: model.eventCount,
        totalTokens: model.totalTokens,
        reason: reasons.join("; ")
      });
      continue;
    }
    rankingsBase.push({
      model: model.model,
      eventCount: model.eventCount,
      totalTokens: model.totalTokens,
      inputTokens: model.inputTokens,
      outputTokens: model.outputTokens,
      cacheReadTokens: model.cacheReadTokens,
      cacheWriteTokens: model.cacheWriteTokens,
      cost: model.cost,
      outputInputRatio: model.outputTokens / model.inputTokens,
      outputPerDollar: model.outputTokens / model.cost,
      cacheCoverage: model.inputTokens + model.cacheReadTokens > 0 ? model.cacheReadTokens / (model.inputTokens + model.cacheReadTokens) : 0,
      costPer1MTotal: model.totalTokens > 0 ? model.cost / model.totalTokens * 1e6 : 0
    });
  }
  const outputPerDollarScores = normalizeScores(rankingsBase.map((entry) => entry.outputPerDollar));
  const outputInputScores = normalizeScores(rankingsBase.map((entry) => entry.outputInputRatio));
  const cacheCoverageScores = normalizeScores(rankingsBase.map((entry) => entry.cacheCoverage));
  const rankings = rankingsBase.map((entry, index) => {
    const scoreBreakdown = {
      outputPerDollar: outputPerDollarScores[index] ?? 0,
      outputInputRatio: outputInputScores[index] ?? 0,
      cacheCoverage: cacheCoverageScores[index] ?? 0
    };
    const score = (scoreBreakdown.outputPerDollar + scoreBreakdown.outputInputRatio + scoreBreakdown.cacheCoverage) / 3;
    return {
      ...entry,
      score,
      scoreBreakdown
    };
  }).sort((a, b) => {
    if (b.score !== a.score) {
      return b.score - a.score;
    }
    if (b.outputPerDollar !== a.outputPerDollar) {
      return b.outputPerDollar - a.outputPerDollar;
    }
    return b.totalTokens - a.totalTokens;
  });
  ineligibleModels.sort((a, b) => {
    if (b.totalTokens !== a.totalTokens) {
      return b.totalTokens - a.totalTokens;
    }
    return b.eventCount - a.eventCount;
  });
  return {
    method: MODEL_EFFICIENCY_METHOD,
    rankings,
    ineligibleModels
  };
}
function computeModelMixShift(currentProviders, previousProviders, limit = 5) {
  const currentModelTokens = new Map;
  const previousModelTokens = new Map;
  let currentTotal = 0;
  let previousTotal = 0;
  for (const provider of currentProviders) {
    for (const day of provider.daily) {
      for (const model of day.models) {
        currentModelTokens.set(model.model, (currentModelTokens.get(model.model) ?? 0) + model.totalTokens);
        currentTotal += model.totalTokens;
      }
    }
  }
  for (const provider of previousProviders) {
    for (const day of provider.daily) {
      for (const model of day.models) {
        previousModelTokens.set(model.model, (previousModelTokens.get(model.model) ?? 0) + model.totalTokens);
        previousTotal += model.totalTokens;
      }
    }
  }
  const models = new Set([
    ...currentModelTokens.keys(),
    ...previousModelTokens.keys()
  ]);
  return [...models].map((model) => {
    const currentTokens = currentModelTokens.get(model) ?? 0;
    const previousTokens = previousModelTokens.get(model) ?? 0;
    const currentShare = currentTotal > 0 ? currentTokens / currentTotal : 0;
    const previousShare = previousTotal > 0 ? previousTokens / previousTotal : 0;
    return {
      model,
      currentShare,
      previousShare,
      deltaShare: currentShare - previousShare,
      currentTokens,
      previousTokens
    };
  }).sort((a, b) => Math.abs(b.deltaShare) - Math.abs(a.deltaShare)).slice(0, limit);
}
function buildMoreStats(providers, range, compare = null) {
  const events = collectEvents(providers);
  const sessionDrilldown = buildSessionRollups(events);
  const projectDrilldown = buildProjectRollups(events);
  const attribution = buildAttributionClusters(events);
  return {
    inputOutput: buildInputOutput(providers),
    monthlyBurn: buildMonthlyBurn(providers, range),
    cacheEconomics: buildCacheEconomics(providers),
    cacheRoi: buildCacheRoi(providers, events),
    hourOfDay: buildHourOfDay(events),
    sessionMetrics: buildSessionMetrics(sessionDrilldown, projectDrilldown),
    sessionDrilldown,
    projectDrilldown,
    modelEfficiency: buildModelEfficiency(events),
    attribution,
    compare: compare ? {
      previousRange: compare.previousRange,
      previousStats: compare.previousStats,
      deltas: compare.deltas,
      modelMixShift: computeModelMixShift(providers, compare.previousProviders)
    } : null
  };
}
var MIN_MODEL_EFFICIENCY_EVENTS = 2, MIN_MODEL_EFFICIENCY_TOTAL_TOKENS = 1000, MODEL_EFFICIENCY_METHOD, TOKENS_PER_MILLION = 1e6;
var init_more = __esm(() => {
  init_analytics();
  MODEL_EFFICIENCY_METHOD = `Eligible models need at least ${MIN_MODEL_EFFICIENCY_EVENTS} events, ` + `${MIN_MODEL_EFFICIENCY_TOTAL_TOKENS} total tokens, non-zero input/output tokens, and positive cost. ` + "Score is the mean of normalized output per dollar, output/input ratio, and cache coverage.";
});

// packages/core/dist/aggregation/explain.js
function collectEvents2(providers) {
  return providers.flatMap((provider) => provider.events ?? []);
}
function sortRows(rows) {
  return rows.slice().sort((left, right) => right.tokens - left.tokens || left.label.localeCompare(right.label));
}
function toEvidenceRows(rows, totalTokens, limit) {
  return sortRows(rows).filter((row) => row.tokens > 0).slice(0, limit).map((row) => ({
    label: row.label,
    tokens: row.tokens,
    cost: row.cost,
    share: totalTokens > 0 ? row.tokens / totalTokens : 0
  }));
}
function buildPreviousDates(targetDate, count) {
  const startMs = dateToUtcMs(targetDate);
  const dates = [];
  for (let offset = count;offset >= 1; offset--) {
    dates.push(formatDateStringUtc(new Date(startMs - offset * ONE_DAY_MS)));
  }
  return dates;
}
function averageForDates(byDate, dates) {
  if (dates.length === 0) {
    return 0;
  }
  let total = 0;
  for (const date of dates) {
    total += byDate.get(date) ?? 0;
  }
  return total / dates.length;
}
function buildMergedDailyTotals(providers) {
  const merged = mergeProviderData(providers);
  const totals = new Map;
  for (const day of merged) {
    totals.set(day.date, {
      tokens: day.totalTokens,
      cost: day.cost,
      inputTokens: day.inputTokens,
      cacheReadTokens: day.cacheReadTokens
    });
  }
  return totals;
}
function buildModelDailyMaps(providers) {
  const tokenByModelAndDate = new Map;
  const costByModelAndDate = new Map;
  for (const provider of providers) {
    for (const day of provider.daily) {
      for (const model of day.models) {
        let tokenDates = tokenByModelAndDate.get(model.model);
        if (!tokenDates) {
          tokenDates = new Map;
          tokenByModelAndDate.set(model.model, tokenDates);
        }
        tokenDates.set(day.date, (tokenDates.get(day.date) ?? 0) + model.totalTokens);
        let costDates = costByModelAndDate.get(model.model);
        if (!costDates) {
          costDates = new Map;
          costByModelAndDate.set(model.model, costDates);
        }
        costDates.set(day.date, (costDates.get(day.date) ?? 0) + model.cost);
      }
    }
  }
  return { tokenByModelAndDate, costByModelAndDate };
}
function buildProviderEvidenceRows(providers, targetDate, totalTokens) {
  const rows = providers.map((provider) => {
    const day = provider.daily.find((entry) => entry.date === targetDate);
    return {
      label: provider.displayName,
      tokens: day?.totalTokens ?? 0,
      cost: day?.cost ?? 0
    };
  });
  return toEvidenceRows(rows, totalTokens, PROVIDER_LIMIT);
}
function buildModelEvidenceRows(providers, targetDate, totalTokens) {
  const totals = new Map;
  for (const provider of providers) {
    const day = provider.daily.find((entry) => entry.date === targetDate);
    if (!day) {
      continue;
    }
    for (const model of day.models) {
      const existing = totals.get(model.model) ?? {
        label: model.model,
        tokens: 0,
        cost: 0
      };
      existing.tokens += model.totalTokens;
      existing.cost += model.cost;
      totals.set(model.model, existing);
    }
  }
  return toEvidenceRows([...totals.values()], totalTokens, MODEL_LIMIT);
}
function buildSessionLabel(session) {
  const suffix = session.directory && session.directory !== "." ? session.directory : session.projectId ?? session.label ?? session.sessionId;
  return `${session.provider}:${suffix}`;
}
function buildProjectLabel(project) {
  if (project.directory && project.directory !== ".") {
    return project.directory;
  }
  return project.projectId;
}
function buildSessionEvidenceRows(events, totalTokens) {
  const rows = buildSessionRollups(events).map((session) => ({
    label: buildSessionLabel(session),
    tokens: session.totalTokens,
    cost: session.cost
  }));
  return toEvidenceRows(rows, totalTokens, SESSION_LIMIT);
}
function buildProjectEvidenceRows(events, totalTokens) {
  const rows = buildProjectRollups(events).map((project) => ({
    label: buildProjectLabel(project),
    tokens: project.totalTokens,
    cost: project.cost
  }));
  return toEvidenceRows(rows, totalTokens, PROJECT_LIMIT);
}
function isSpike(currentTokens, averageTokens) {
  if (currentTokens < SPIKE_MIN_TOKENS) {
    return false;
  }
  if (averageTokens <= 0) {
    return currentTokens >= SPIKE_MIN_TOKENS;
  }
  return currentTokens >= averageTokens * SPIKE_MULTIPLIER && currentTokens - averageTokens >= SPIKE_MIN_DELTA;
}
function formatTokens(tokens) {
  return Math.round(tokens).toLocaleString("en-US");
}
function formatCompactTokens(tokens) {
  if (tokens >= 1e6) {
    return `${(tokens / 1e6).toFixed(1)}M`;
  }
  if (tokens >= 1000) {
    return `${(tokens / 1000).toFixed(1)}K`;
  }
  return `${Math.round(tokens)}`;
}
function formatCost(cost) {
  return `$${cost.toFixed(2)}`;
}
function formatPercent(rate) {
  return `${(rate * 100).toFixed(0)}%`;
}
function describeDelta(current, average) {
  const delta = current - average;
  const sign = delta >= 0 ? "+" : "-";
  return `${sign}${formatCompactTokens(Math.abs(delta))}`;
}
function buildHeadline(targetDate, totalTokens, average7dTokens, average30dTokens, topProviders) {
  if (totalTokens === 0) {
    return `No recorded token activity on ${targetDate}`;
  }
  const leadProvider = topProviders[0];
  const providerSuffix = leadProvider && leadProvider.share >= 0.5 ? ` led by ${leadProvider.label}` : "";
  if (average30dTokens > 0 && totalTokens >= average30dTokens * 3) {
    return `Spike day on ${targetDate}${providerSuffix}`;
  }
  if (average7dTokens > 0 && totalTokens >= average7dTokens * 1.5) {
    return `Above-baseline activity on ${targetDate}${providerSuffix}`;
  }
  if (average7dTokens > 0 && totalTokens <= average7dTokens * 0.5) {
    return `Quiet day on ${targetDate}${providerSuffix}`;
  }
  return `Typical activity on ${targetDate}${providerSuffix}`;
}
function buildSummaryLines(input) {
  if (input.totalTokens === 0) {
    return [
      `No provider reported activity on ${input.date}.`,
      `Trailing averages were ${formatCompactTokens(input.average7dTokens)} tokens/day over 7d and ${formatCompactTokens(input.average30dTokens)} tokens/day over 30d.`,
      "No anomaly flags were raised."
    ];
  }
  const first = `${formatCompactTokens(input.totalTokens)} tokens (${formatCost(input.totalCost)}) on ${input.date}, ${describeDelta(input.totalTokens, input.average7dTokens)} vs trailing 7d average and ${describeDelta(input.totalTokens, input.average30dTokens)} vs trailing 30d average.`;
  const provider = input.topProviders[0];
  const model = input.topModels[0];
  const second = provider && model ? `${provider.label} contributed ${formatPercent(provider.share)} of the day, and ${model.label} accounted for ${formatPercent(model.share)} of tokens.` : `Trailing cost baselines were ${formatCost(input.average7dCost)}/day over 7d and ${formatCost(input.average30dCost)}/day over 30d.`;
  const third = input.anomalies.length > 0 ? `${input.anomalies.length} anomaly flag${input.anomalies.length === 1 ? "" : "s"} raised. Cache hit rate was ${formatPercent(input.dayCacheHitRate)} versus a 7d average of ${formatPercent(input.average7dCacheHitRate)}.` : `No anomaly flags were raised. Cache hit rate was ${formatPercent(input.dayCacheHitRate)} versus a 7d average of ${formatPercent(input.average7dCacheHitRate)}.`;
  return [first, second, third];
}
function buildProviderSpikeAnomaly(providers, previous7Dates, targetDate) {
  const candidates = providers.map((provider) => {
    const byDate = new Map;
    for (const day of provider.daily) {
      byDate.set(day.date, day.totalTokens);
    }
    const currentTokens = byDate.get(targetDate) ?? 0;
    const averageTokens = averageForDates(byDate, previous7Dates);
    return {
      provider,
      currentTokens,
      averageTokens
    };
  });
  const winner = candidates.filter((entry) => isSpike(entry.currentTokens, entry.averageTokens)).sort((left, right) => right.currentTokens - left.currentTokens || left.provider.displayName.localeCompare(right.provider.displayName))[0];
  if (!winner) {
    return null;
  }
  return {
    type: "provider-spike",
    title: `${winner.provider.displayName} surged`,
    detail: `${winner.provider.displayName} reached ${formatTokens(winner.currentTokens)} tokens on ${targetDate} versus a trailing 7d average of ${formatTokens(winner.averageTokens)}.`
  };
}
function buildModelSpikeAnomaly(providers, previous7Dates, targetDate) {
  const { tokenByModelAndDate } = buildModelDailyMaps(providers);
  const candidates = [...tokenByModelAndDate.entries()].map(([model, byDate]) => ({
    model,
    currentTokens: byDate.get(targetDate) ?? 0,
    averageTokens: averageForDates(byDate, previous7Dates)
  }));
  const winner = candidates.filter((entry) => isSpike(entry.currentTokens, entry.averageTokens)).sort((left, right) => right.currentTokens - left.currentTokens || left.model.localeCompare(right.model))[0];
  if (!winner) {
    return null;
  }
  return {
    type: "model-spike",
    title: `${winner.model} spiked`,
    detail: `${winner.model} accounted for ${formatTokens(winner.currentTokens)} tokens on ${targetDate} versus a trailing 7d average of ${formatTokens(winner.averageTokens)}.`
  };
}
function buildCacheDropAnomaly(mergedDailyTotals, previous7Dates, targetDate) {
  const current = mergedDailyTotals.get(targetDate);
  if (!current || current.tokens < CACHE_DROP_MIN_TOKENS) {
    return null;
  }
  const currentRate = cacheHitRate([{
    date: targetDate,
    inputTokens: current.inputTokens,
    outputTokens: 0,
    cacheReadTokens: current.cacheReadTokens,
    cacheWriteTokens: 0,
    totalTokens: current.tokens,
    cost: current.cost,
    models: []
  }]);
  const previousEntries = previous7Dates.map((date) => {
    const totals = mergedDailyTotals.get(date);
    return {
      date,
      inputTokens: totals?.inputTokens ?? 0,
      outputTokens: 0,
      cacheReadTokens: totals?.cacheReadTokens ?? 0,
      cacheWriteTokens: 0,
      totalTokens: totals?.tokens ?? 0,
      cost: totals?.cost ?? 0,
      models: []
    };
  });
  const averageRate = cacheHitRate(previousEntries);
  if (averageRate - currentRate < CACHE_DROP_DELTA) {
    return null;
  }
  return {
    type: "cache-drop",
    title: "Cache reuse dropped",
    detail: `Cache hit rate fell to ${formatPercent(currentRate)} on ${targetDate} from a trailing 7d average of ${formatPercent(averageRate)}.`
  };
}
function buildLongSessionAnomaly(sessions) {
  const session = sessions.filter((entry) => (entry.durationMs ?? 0) >= LONG_SESSION_MS).sort((left, right) => (right.durationMs ?? 0) - (left.durationMs ?? 0) || right.totalTokens - left.totalTokens)[0];
  if (!session || session.durationMs === null) {
    return null;
  }
  const durationHours = (session.durationMs / 3600000).toFixed(1);
  return {
    type: "long-session",
    title: "A single session ran long",
    detail: `${buildSessionLabel(session)} lasted ${durationHours}h and used ${formatTokens(session.totalTokens)} tokens.`
  };
}
function buildDenseSessionAnomaly(sessions) {
  const candidates = sessions.filter((entry) => entry.durationMs !== null && entry.durationMs > 0 && entry.totalTokens >= DENSE_SESSION_MIN_TOKENS).map((entry) => ({
    session: entry,
    tokensPerHour: entry.totalTokens / (entry.durationMs / 3600000)
  })).filter((entry) => entry.tokensPerHour >= DENSE_SESSION_TOKENS_PER_HOUR).sort((left, right) => right.tokensPerHour - left.tokensPerHour || right.session.totalTokens - left.session.totalTokens)[0];
  if (!candidates) {
    return null;
  }
  return {
    type: "dense-session",
    title: "A session was unusually dense",
    detail: `${buildSessionLabel(candidates.session)} sustained ${formatCompactTokens(candidates.tokensPerHour)} tokens/hour across ${formatTokens(candidates.session.totalTokens)} tokens.`
  };
}
function compactAnomalies(anomalies) {
  return anomalies.filter((entry) => entry !== null);
}
function buildExplainReport(providers, targetDate) {
  const mergedDailyTotals = buildMergedDailyTotals(providers);
  const previous7Dates = buildPreviousDates(targetDate, LOOKBACK_7D);
  const previous30Dates = buildPreviousDates(targetDate, LOOKBACK_30D);
  const dayTotals = mergedDailyTotals.get(targetDate) ?? {
    tokens: 0,
    cost: 0,
    inputTokens: 0,
    cacheReadTokens: 0
  };
  const average7dTokens = averageForDates(new Map([...mergedDailyTotals.entries()].map(([date, totals]) => [date, totals.tokens])), previous7Dates);
  const average30dTokens = averageForDates(new Map([...mergedDailyTotals.entries()].map(([date, totals]) => [date, totals.tokens])), previous30Dates);
  const average7dCost = averageForDates(new Map([...mergedDailyTotals.entries()].map(([date, totals]) => [date, totals.cost])), previous7Dates);
  const average30dCost = averageForDates(new Map([...mergedDailyTotals.entries()].map(([date, totals]) => [date, totals.cost])), previous30Dates);
  const dayCacheHitRate = cacheHitRate([{
    date: targetDate,
    inputTokens: dayTotals.inputTokens,
    outputTokens: 0,
    cacheReadTokens: dayTotals.cacheReadTokens,
    cacheWriteTokens: 0,
    totalTokens: dayTotals.tokens,
    cost: dayTotals.cost,
    models: []
  }]);
  const average7dCacheHitRate = cacheHitRate(previous7Dates.map((date) => {
    const totals = mergedDailyTotals.get(date);
    return {
      date,
      inputTokens: totals?.inputTokens ?? 0,
      outputTokens: 0,
      cacheReadTokens: totals?.cacheReadTokens ?? 0,
      cacheWriteTokens: 0,
      totalTokens: totals?.tokens ?? 0,
      cost: totals?.cost ?? 0,
      models: []
    };
  }));
  const dayEvents = collectEvents2(providers).filter((event) => event.date === targetDate);
  const sessionRollups = buildSessionRollups(dayEvents);
  const topProviders = buildProviderEvidenceRows(providers, targetDate, dayTotals.tokens);
  const topModels2 = buildModelEvidenceRows(providers, targetDate, dayTotals.tokens);
  const anomalies = compactAnomalies([
    buildProviderSpikeAnomaly(providers, previous7Dates, targetDate),
    buildModelSpikeAnomaly(providers, previous7Dates, targetDate),
    buildCacheDropAnomaly(mergedDailyTotals, previous7Dates, targetDate),
    buildLongSessionAnomaly(sessionRollups),
    buildDenseSessionAnomaly(sessionRollups)
  ]);
  return {
    date: targetDate,
    totalTokens: dayTotals.tokens,
    totalCost: dayTotals.cost,
    comparedTo7dAverage: dayTotals.tokens - average7dTokens,
    comparedTo30dAverage: dayTotals.tokens - average30dTokens,
    headline: buildHeadline(targetDate, dayTotals.tokens, average7dTokens, average30dTokens, topProviders),
    summary: buildSummaryLines({
      date: targetDate,
      totalTokens: dayTotals.tokens,
      totalCost: dayTotals.cost,
      average7dTokens,
      average30dTokens,
      average7dCost,
      average30dCost,
      topProviders,
      topModels: topModels2,
      anomalies,
      dayCacheHitRate,
      average7dCacheHitRate
    }),
    topProviders,
    topSessions: buildSessionEvidenceRows(dayEvents, dayTotals.tokens),
    topProjects: buildProjectEvidenceRows(dayEvents, dayTotals.tokens),
    topModels: topModels2,
    anomalies
  };
}
var PROVIDER_LIMIT = 5, SESSION_LIMIT = 5, PROJECT_LIMIT = 5, MODEL_LIMIT = 5, LOOKBACK_7D = 7, LOOKBACK_30D = 30, SPIKE_MULTIPLIER = 2, SPIKE_MIN_DELTA = 5000, SPIKE_MIN_TOKENS = 7500, CACHE_DROP_MIN_TOKENS = 5000, CACHE_DROP_DELTA = 0.2, LONG_SESSION_MS, DENSE_SESSION_TOKENS_PER_HOUR = 40000, DENSE_SESSION_MIN_TOKENS = 3000;
var init_explain = __esm(() => {
  init_analytics();
  init_merge();
  LONG_SESSION_MS = 3 * 60 * 60 * 1000;
});

// packages/core/dist/aggregation/focus.js
function round(value, digits = 2) {
  const factor = 10 ** digits;
  return Math.round(value * factor) / factor;
}
function formatDuration(durationMs) {
  if (!durationMs || durationMs <= 0) {
    return "no duration";
  }
  const totalMinutes = Math.round(durationMs / 60000);
  const hours = Math.floor(totalMinutes / 60);
  const minutes = totalMinutes % 60;
  if (hours === 0) {
    return `${minutes}m`;
  }
  if (minutes === 0) {
    return `${hours}h`;
  }
  return `${hours}h ${minutes}m`;
}
function formatTokensPerHour(tokensPerHour) {
  return `${Math.round(tokensPerHour).toLocaleString("en-US")} tok/hr`;
}
function normalizeFocusScores(values) {
  if (values.length === 0) {
    return [];
  }
  if (values.every((value) => value === 0)) {
    return values.map(() => 0);
  }
  return normalizeScores(values);
}
function buildRationale(session, streak, durationScore, densityScore, streakScore, tokensPerHour) {
  const durationLine = durationScore >= 70 ? `${formatDuration(session.durationMs)} session window` : session.durationMs && session.durationMs > 0 ? `${formatDuration(session.durationMs)} runtime kept it active` : "single-event session with no duration signal";
  const densityLine = densityScore >= 70 ? `${formatTokensPerHour(tokensPerHour)} token density` : tokensPerHour > 0 ? `${formatTokensPerHour(tokensPerHour)} kept the pace up` : "insufficient duration for a density signal";
  const streakLine = streakScore >= 70 ? `${streak}-day project streak` : streak > 1 ? `${streak}-day streak support` : "single-day project streak";
  return [durationLine, densityLine, streakLine];
}
function buildFocusReport(events) {
  const sessions = buildSessionRollups(events);
  const streakByProject = new Map(buildProjectRollups(events).map((project) => [project.projectId, project.streak]));
  const durations = sessions.map((session) => Math.max(0, session.durationMs ?? 0));
  const densityValues = sessions.map((session) => session.durationMs && session.durationMs > 0 ? session.totalTokens / (session.durationMs / MS_PER_HOUR) : 0);
  const streakValues = sessions.map((session) => session.projectId ? streakByProject.get(session.projectId) ?? 1 : 1);
  const durationScores = normalizeFocusScores(durations).map((value) => round(value * 100, 1));
  const densityScores = normalizeFocusScores(densityValues).map((value) => round(value * 100, 1));
  const streakScores = normalizeFocusScores(streakValues).map((value) => round(value * 100, 1));
  const entries = sessions.map((session, index) => {
    const streak = streakValues[index] ?? 1;
    const durationScore = durationScores[index] ?? 0;
    const densityScore = densityScores[index] ?? 0;
    const streakScore = streakScores[index] ?? 0;
    const tokensPerHour = densityValues[index] ?? 0;
    const score = round(durationScore * FOCUS_WEIGHTS.duration + densityScore * FOCUS_WEIGHTS.density + streakScore * FOCUS_WEIGHTS.streak, 1);
    return {
      sessionId: session.sessionId,
      label: session.label,
      provider: session.provider,
      projectId: session.projectId,
      repoRoot: session.repoRoot,
      start: session.start,
      end: session.end,
      durationMs: session.durationMs,
      tokensPerHour: round(tokensPerHour, 2),
      totalTokens: session.totalTokens,
      cost: round(session.cost, 4),
      streak,
      score,
      scoreBreakdown: {
        duration: durationScore,
        density: densityScore,
        streak: streakScore
      },
      rationale: buildRationale(session, streak, durationScore, densityScore, streakScore, tokensPerHour)
    };
  }).sort((left, right) => right.score - left.score || right.totalTokens - left.totalTokens || (right.durationMs ?? 0) - (left.durationMs ?? 0) || left.start.localeCompare(right.start));
  return {
    method: "Deep-work score = duration 45% + token density 40% + project streak 15%, normalized across selected sessions.",
    entries
  };
}
var FOCUS_WEIGHTS, MS_PER_HOUR = 3600000;
var init_focus = __esm(() => {
  init_analytics();
  FOCUS_WEIGHTS = {
    duration: 0.45,
    density: 0.4,
    streak: 0.15
  };
});

// packages/core/dist/aggregation/replay.js
function parseIsoTime2(value) {
  const parsed = Date.parse(value);
  return Number.isFinite(parsed) ? parsed : null;
}
function truncateToMinute(iso) {
  const date = new Date(iso);
  date.setSeconds(0, 0);
  return date.toISOString();
}
function labelFlowBlock(durationMs, eventCount) {
  if (durationMs >= DEEP_FLOW_DURATION_MS || eventCount >= DEEP_FLOW_EVENT_COUNT) {
    return "Deep Flow";
  }
  if (durationMs <= QUICK_LOOKUP_DURATION_MS && eventCount <= QUICK_LOOKUP_EVENT_COUNT) {
    return "Quick Lookup";
  }
  return "Moderate Session";
}
function computeDominantModel(events) {
  const byModel = new Map;
  for (const event of events) {
    byModel.set(event.model, (byModel.get(event.model) ?? 0) + event.totalTokens);
  }
  let best = "";
  let bestTokens = -1;
  for (const [model, tokens] of byModel) {
    if (tokens > bestTokens || tokens === bestTokens && model < best) {
      best = model;
      bestTokens = tokens;
    }
  }
  return best;
}
function countModelSwitches(events) {
  let switches = 0;
  for (let i = 1;i < events.length; i++) {
    if (events[i].model !== events[i - 1].model) {
      switches++;
    }
  }
  return switches;
}
function computeCacheHitRateTrend(events) {
  return events.map((event) => {
    const denominator = event.inputTokens + event.cacheReadTokens;
    return denominator > 0 ? event.cacheReadTokens / denominator : 0;
  });
}
function clusterIntoFlowBlocks(sortedEvents) {
  if (sortedEvents.length === 0) {
    return [];
  }
  const blocks = [];
  let currentEvents = [sortedEvents[0]];
  for (let i = 1;i < sortedEvents.length; i++) {
    const prevTime = parseIsoTime2(sortedEvents[i - 1].timestamp);
    const currTime = parseIsoTime2(sortedEvents[i].timestamp);
    if (prevTime !== null && currTime !== null && currTime - prevTime >= FLOW_BLOCK_GAP_MS) {
      blocks.push(buildFlowBlock(currentEvents, blocks.length));
      currentEvents = [];
    }
    currentEvents.push(sortedEvents[i]);
  }
  blocks.push(buildFlowBlock(currentEvents, blocks.length));
  return blocks;
}
function buildFlowBlock(events, blockIndex) {
  const startTime = parseIsoTime2(events[0].timestamp) ?? 0;
  const endTime = parseIsoTime2(events[events.length - 1].timestamp) ?? 0;
  const durationMs = endTime - startTime;
  let inputTokens = 0;
  let outputTokens = 0;
  let cacheReadTokens = 0;
  let cacheWriteTokens = 0;
  let totalTokens = 0;
  let cost = 0;
  for (const event of events) {
    inputTokens += event.inputTokens;
    outputTokens += event.outputTokens;
    cacheReadTokens += event.cacheReadTokens;
    cacheWriteTokens += event.cacheWriteTokens;
    totalTokens += event.totalTokens;
    cost += event.cost;
  }
  return {
    blockIndex,
    label: labelFlowBlock(durationMs, events.length),
    start: events[0].timestamp,
    end: events[events.length - 1].timestamp,
    durationMs,
    eventCount: events.length,
    inputTokens,
    outputTokens,
    cacheReadTokens,
    cacheWriteTokens,
    totalTokens,
    cost,
    dominantModel: computeDominantModel(events),
    events,
    modelSwitches: countModelSwitches(events),
    cacheHitRateTrend: computeCacheHitRateTrend(events)
  };
}
function buildTokenVelocity(sortedEvents) {
  const buckets = new Map;
  for (const event of sortedEvents) {
    const minute = truncateToMinute(event.timestamp);
    buckets.set(minute, (buckets.get(minute) ?? 0) + event.totalTokens);
  }
  return [...buckets.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([minute, tokens]) => ({
    minute,
    tokensPerMinute: tokens / (VELOCITY_BUCKET_MS / 1000 / 60)
  }));
}
function buildDaySummary(sortedEvents, flowBlocks, tokenVelocity) {
  const sessionIds = new Set;
  for (const event of sortedEvents) {
    if (event.sessionId) {
      sessionIds.add(event.sessionId);
    }
  }
  let flowTimeMs = 0;
  for (const block of flowBlocks) {
    flowTimeMs += block.durationMs;
  }
  let thinkTimeMs = 0;
  for (let i = 1;i < flowBlocks.length; i++) {
    const prevEnd = parseIsoTime2(flowBlocks[i - 1].end);
    const currStart = parseIsoTime2(flowBlocks[i].start);
    if (prevEnd !== null && currStart !== null) {
      thinkTimeMs += currStart - prevEnd;
    }
  }
  const totalTimeMs = flowTimeMs + thinkTimeMs;
  const flowThinkRatio = totalTimeMs > 0 ? flowTimeMs / totalTimeMs : 0;
  let peakMinute = null;
  for (const point of tokenVelocity) {
    if (peakMinute === null || point.tokensPerMinute > peakMinute.tokensPerMinute) {
      peakMinute = point;
    }
  }
  return {
    totalSessions: sessionIds.size,
    totalEvents: sortedEvents.length,
    flowTimeMs,
    thinkTimeMs,
    flowThinkRatio,
    peakMinute
  };
}
function buildReplayReport(providers, targetDate) {
  const allEvents = providers.flatMap((provider) => provider.events ?? []);
  const dayEvents = allEvents.filter((event) => event.date === targetDate).sort((a, b) => a.timestamp.localeCompare(b.timestamp));
  const flowBlocks = clusterIntoFlowBlocks(dayEvents);
  const tokenVelocity = buildTokenVelocity(dayEvents);
  const summary = buildDaySummary(dayEvents, flowBlocks, tokenVelocity);
  return {
    date: targetDate,
    events: dayEvents,
    flowBlocks,
    tokenVelocity,
    summary
  };
}
var FLOW_BLOCK_GAP_MS, DEEP_FLOW_DURATION_MS, DEEP_FLOW_EVENT_COUNT = 5, QUICK_LOOKUP_DURATION_MS, QUICK_LOOKUP_EVENT_COUNT = 2, VELOCITY_BUCKET_MS;
var init_replay = __esm(() => {
  FLOW_BLOCK_GAP_MS = 15 * 60 * 1000;
  DEEP_FLOW_DURATION_MS = 45 * 60 * 1000;
  QUICK_LOOKUP_DURATION_MS = 10 * 60 * 1000;
  VELOCITY_BUCKET_MS = 60 * 1000;
});

// packages/core/dist/aggregation/index.js
var init_aggregation = __esm(() => {
  init_streaks();
  init_rolling_window();
  init_day_of_week();
  init_aggregate();
  init_merge();
  init_compare();
  init_more();
  init_explain();
  init_focus();
  init_replay();
  init_analytics();
});

// packages/core/dist/advisor/downgrade-paths.js
function normalizeModelName(model) {
  let normalized = model.toLowerCase();
  const slashIndex = normalized.lastIndexOf("/");
  if (slashIndex >= 0) {
    normalized = normalized.slice(slashIndex + 1);
  }
  normalized = normalized.replace(/-\d{4}-?\d{2}-?\d{2}$/, "");
  return normalized;
}
function getDowngradePath(model) {
  const normalized = normalizeModelName(model);
  return DOWNGRADE_PATHS[normalized] ?? null;
}
var DOWNGRADE_PATHS;
var init_downgrade_paths = __esm(() => {
  DOWNGRADE_PATHS = {
    "claude-opus-4-6": "claude-sonnet-4-6",
    "claude-opus-4": "claude-sonnet-4",
    "claude-opus-4-5": "claude-sonnet-4-5",
    "claude-sonnet-4-5": "claude-haiku-4-5",
    "claude-3-opus": "claude-3.5-sonnet",
    "claude-3-sonnet": "claude-3-haiku",
    "claude-3.5-sonnet": "claude-3.5-haiku",
    "gpt-4o": "gpt-4o-mini",
    o1: "o1-mini",
    o3: "o3-mini"
  };
});

// packages/core/dist/advisor/advisor.js
function collectModelStats(events) {
  const stats = new Map;
  for (const event of events) {
    let entry = stats.get(event.model);
    if (!entry) {
      entry = {
        model: event.model,
        eventCount: 0,
        inputTokens: 0,
        outputTokens: 0,
        cacheReadTokens: 0,
        cacheWriteTokens: 0,
        totalCost: 0
      };
      stats.set(event.model, entry);
    }
    entry.eventCount += 1;
    entry.inputTokens += event.inputTokens;
    entry.outputTokens += event.outputTokens;
    entry.cacheReadTokens += event.cacheReadTokens;
    entry.cacheWriteTokens += event.cacheWriteTokens;
    entry.totalCost += event.cost;
  }
  return stats;
}
function calculateCostWithPricing(stats, pricing) {
  return stats.inputTokens / TOKENS_PER_MILLION2 * pricing.input + stats.outputTokens / TOKENS_PER_MILLION2 * pricing.output + stats.cacheReadTokens / TOKENS_PER_MILLION2 * pricing.cacheRead + stats.cacheWriteTokens / TOKENS_PER_MILLION2 * pricing.cacheWrite;
}
function confidenceForEventCount(count) {
  if (count >= HIGH_CONFIDENCE_EVENTS)
    return "high";
  if (count >= MEDIUM_CONFIDENCE_EVENTS)
    return "medium";
  return "low";
}
function extrapolateToMonthly(cost, analyzedDays) {
  if (analyzedDays <= 0)
    return 0;
  return cost / analyzedDays * DAYS_PER_MONTH;
}
function detectModelDowngrades(modelStats, pricing, analyzedDays) {
  const recommendations = [];
  for (const [model, stats] of modelStats) {
    const downgradeTo = getDowngradePath(model);
    if (!downgradeTo)
      continue;
    const currentPricing = pricing[model];
    const downgradePricing = pricing[downgradeTo];
    if (!currentPricing || !downgradePricing)
      continue;
    const avgOutput = stats.eventCount > 0 ? stats.outputTokens / stats.eventCount : 0;
    if (avgOutput >= LOW_OUTPUT_THRESHOLD)
      continue;
    const currentCost = calculateCostWithPricing(stats, currentPricing);
    const projectedCost = calculateCostWithPricing(stats, downgradePricing);
    const savings = currentCost - projectedCost;
    if (savings <= 0)
      continue;
    const monthlyCurrent = extrapolateToMonthly(currentCost, analyzedDays);
    const monthlyProjected = extrapolateToMonthly(projectedCost, analyzedDays);
    const monthlySavings = monthlyCurrent - monthlyProjected;
    recommendations.push({
      type: "model-downgrade",
      title: `Switch ${model} to ${downgradeTo} for short sessions`,
      description: `You used ${model} for ${stats.eventCount} events averaging ` + `${Math.round(avgOutput)} output tokens. Switching to ${downgradeTo} ` + `for those sessions would save money.`,
      currentCost: monthlyCurrent,
      projectedCost: monthlyProjected,
      monthlySavings,
      confidence: confidenceForEventCount(stats.eventCount),
      details: {
        model,
        downgradeTo,
        eventCount: stats.eventCount,
        avgOutputTokens: Math.round(avgOutput),
        totalInputTokens: stats.inputTokens,
        totalOutputTokens: stats.outputTokens
      }
    });
  }
  return recommendations.sort((a, b) => b.monthlySavings - a.monthlySavings);
}
function detectCacheOptimizations(output, pricing, analyzedDays) {
  const recommendations = [];
  const cacheHitRate2 = output.aggregated.cacheHitRate;
  const cacheEconomics = output.more?.cacheEconomics;
  if (cacheEconomics && cacheEconomics.reuseRatio !== null && cacheEconomics.reuseRatio < CACHE_REUSE_LOW_THRESHOLD) {
    recommendations.push({
      type: "cache-optimization",
      title: "Reduce wasted cache writes",
      description: `Your cache reuse ratio is ${cacheEconomics.reuseRatio.toFixed(1)}x ` + `(reads/writes). A ratio below ${CACHE_REUSE_LOW_THRESHOLD}x means cache ` + `writes are not being effectively reused.`,
      currentCost: 0,
      projectedCost: 0,
      monthlySavings: 0,
      confidence: "low",
      details: {
        reuseRatio: cacheEconomics.reuseRatio,
        readTokens: cacheEconomics.readTokens,
        writeTokens: cacheEconomics.writeTokens
      }
    });
  }
  if (cacheHitRate2 >= CACHE_HIT_LOW_THRESHOLD)
    return recommendations;
  let totalInputTokens = 0;
  let totalCacheReadTokens = 0;
  for (const provider of output.providers) {
    for (const day of provider.daily) {
      totalInputTokens += day.inputTokens;
      totalCacheReadTokens += day.cacheReadTokens;
    }
  }
  const totalAddressable = totalInputTokens + totalCacheReadTokens;
  if (totalAddressable === 0)
    return recommendations;
  const currentCacheReads = totalCacheReadTokens;
  const targetCacheReads = totalAddressable * IMPROVED_CACHE_TARGET;
  const additionalCacheReads = Math.max(0, targetCacheReads - currentCacheReads);
  let avgInputPrice = 0;
  let avgCacheReadPrice = 0;
  let pricedModels = 0;
  for (const provider of output.providers) {
    for (const day of provider.daily) {
      for (const model of day.models) {
        const modelPricing = pricing[model.model];
        if (modelPricing) {
          avgInputPrice += modelPricing.input;
          avgCacheReadPrice += modelPricing.cacheRead;
          pricedModels += 1;
        }
      }
    }
  }
  if (pricedModels === 0)
    return recommendations;
  avgInputPrice /= pricedModels;
  avgCacheReadPrice /= pricedModels;
  const savingsPerToken = (avgInputPrice - avgCacheReadPrice) / TOKENS_PER_MILLION2;
  const totalSavings = additionalCacheReads * savingsPerToken;
  const monthlySavings = extrapolateToMonthly(totalSavings, analyzedDays);
  if (monthlySavings <= 0)
    return recommendations;
  const hitRatePercent = Math.round(cacheHitRate2 * 100);
  recommendations.push({
    type: "cache-optimization",
    title: "Improve cache reuse ratio",
    description: `Your cache hit rate is ${hitRatePercent}%. ` + `Improving to ${Math.round(IMPROVED_CACHE_TARGET * 100)}% would save on input costs.`,
    currentCost: 0,
    projectedCost: 0,
    monthlySavings,
    confidence: "medium",
    details: {
      currentHitRate: cacheHitRate2,
      targetHitRate: IMPROVED_CACHE_TARGET,
      reuseRatio: cacheEconomics?.reuseRatio ?? null
    }
  });
  return recommendations;
}
function detectUsagePatterns(output) {
  const recommendations = [];
  const totalCost = output.aggregated.totalCost;
  if (totalCost > 0) {
    for (const model of output.aggregated.topModels) {
      const costShare = model.cost / totalCost;
      if (costShare > CONCENTRATION_THRESHOLD) {
        recommendations.push({
          type: "usage-pattern",
          title: `High concentration on ${model.model}`,
          description: `${model.model} accounts for ${Math.round(costShare * 100)}% of your total spend. ` + `Consider diversifying to reduce risk from pricing changes.`,
          currentCost: 0,
          projectedCost: 0,
          monthlySavings: 0,
          confidence: "medium",
          details: {
            model: model.model,
            costShare,
            modelCost: model.cost,
            totalCost
          }
        });
        break;
      }
    }
  }
  const dailyCosts = new Map;
  for (const provider of output.providers) {
    for (const day of provider.daily) {
      dailyCosts.set(day.date, (dailyCosts.get(day.date) ?? 0) + day.cost);
    }
  }
  const sortedDates = [...dailyCosts.keys()].sort();
  if (sortedDates.length >= 4) {
    const mid = Math.floor(sortedDates.length / 2);
    const firstHalfDates = sortedDates.slice(0, mid);
    const secondHalfDates = sortedDates.slice(mid);
    let firstHalfCost = 0;
    for (const d of firstHalfDates) {
      firstHalfCost += dailyCosts.get(d) ?? 0;
    }
    let secondHalfCost = 0;
    for (const d of secondHalfDates) {
      secondHalfCost += dailyCosts.get(d) ?? 0;
    }
    const firstAvg = firstHalfDates.length > 0 ? firstHalfCost / firstHalfDates.length : 0;
    const secondAvg = secondHalfDates.length > 0 ? secondHalfCost / secondHalfDates.length : 0;
    if (firstAvg > 0 && (secondAvg - firstAvg) / firstAvg > COST_TREND_THRESHOLD) {
      recommendations.push({
        type: "usage-pattern",
        title: "Rising cost trend detected",
        description: `Your average daily cost increased from $${firstAvg.toFixed(2)} ` + `to $${secondAvg.toFixed(2)} between the first and second halves of the period.`,
        currentCost: 0,
        projectedCost: 0,
        monthlySavings: 0,
        confidence: "medium",
        details: {
          firstHalfAvg: firstAvg,
          secondHalfAvg: secondAvg,
          increase: (secondAvg - firstAvg) / firstAvg
        }
      });
    }
  }
  const avgDailyCost = output.aggregated.averageDailyCost;
  if (avgDailyCost > 0) {
    const burstDays = [];
    for (const [date, cost] of dailyCosts) {
      if (cost > avgDailyCost * BURST_MULTIPLIER) {
        burstDays.push({ date, cost });
      }
    }
    if (burstDays.length > 0) {
      burstDays.sort((a, b) => b.cost - a.cost);
      const topBurst = burstDays[0];
      recommendations.push({
        type: "usage-pattern",
        title: `${burstDays.length} burst day${burstDays.length > 1 ? "s" : ""} detected`,
        description: `${burstDays.length} day${burstDays.length > 1 ? "s" : ""} exceeded 3x your ` + `average daily cost ($${avgDailyCost.toFixed(2)}). ` + `Peak: ${topBurst.date} at $${topBurst.cost.toFixed(2)}.`,
        currentCost: 0,
        projectedCost: 0,
        monthlySavings: 0,
        confidence: "low",
        details: {
          burstDayCount: burstDays.length,
          averageDailyCost: avgDailyCost,
          burstThreshold: avgDailyCost * BURST_MULTIPLIER,
          topBurstDate: topBurst.date,
          topBurstCost: topBurst.cost
        }
      });
    }
  }
  return recommendations;
}
function analyzeEfficiency(output, modelPricing) {
  const allEvents = output.providers.flatMap((p) => p.events ?? []);
  const sinceDateMs = Date.parse(`${output.dateRange.since}T00:00:00Z`);
  const untilDateMs = Date.parse(`${output.dateRange.until}T00:00:00Z`);
  const analyzedDays = Math.max(1, Math.round((untilDateMs - sinceDateMs) / 86400000) + 1);
  const modelStats = collectModelStats(allEvents);
  const downgradeRecs = detectModelDowngrades(modelStats, modelPricing, analyzedDays);
  const cacheRecs = detectCacheOptimizations(output, modelPricing, analyzedDays);
  const patternRecs = detectUsagePatterns(output);
  const recommendations = [...downgradeRecs, ...cacheRecs, ...patternRecs];
  const totalCurrentMonthlyCost = extrapolateToMonthly(output.aggregated.totalCost, analyzedDays);
  const totalMonthlySavings = recommendations.reduce((sum, r) => sum + r.monthlySavings, 0);
  const totalProjectedMonthlyCost = Math.max(0, totalCurrentMonthlyCost - totalMonthlySavings);
  return {
    recommendations,
    totalCurrentMonthlyCost,
    totalProjectedMonthlyCost,
    totalMonthlySavings,
    analyzedDays,
    analyzedEvents: allEvents.length
  };
}
var TOKENS_PER_MILLION2 = 1e6, DAYS_PER_MONTH = 30, LOW_OUTPUT_THRESHOLD = 1000, HIGH_CONFIDENCE_EVENTS = 20, MEDIUM_CONFIDENCE_EVENTS = 5, CACHE_HIT_LOW_THRESHOLD = 0.3, CACHE_REUSE_LOW_THRESHOLD = 2, CONCENTRATION_THRESHOLD = 0.85, BURST_MULTIPLIER = 3, COST_TREND_THRESHOLD = 0.2, IMPROVED_CACHE_TARGET = 0.5;
var init_advisor = __esm(() => {
  init_downgrade_paths();
});

// packages/core/dist/advisor/index.js
var init_advisor2 = __esm(() => {
  init_advisor();
  init_downgrade_paths();
});

// packages/core/dist/index.js
var VERSION = "2.1.0";
var init_dist = __esm(() => {
  init_constants();
  init_aggregation();
  init_analytics();
  init_advisor2();
});

// packages/registry/dist/models/normalizer.js
function normalizeModelName2(model) {
  return model.replace(DATE_SUFFIX_PATTERN, "");
}
var DATE_SUFFIX_PATTERN;
var init_normalizer = __esm(() => {
  DATE_SUFFIX_PATTERN = /-\d{8}$/;
});

// packages/registry/dist/models/litellm.js
function parseLiteLLMData(raw) {
  const result = {};
  for (const [key, value] of Object.entries(raw)) {
    if (value === null || typeof value !== "object")
      continue;
    const entry = value;
    const inputPerToken = entry.input_cost_per_token;
    const outputPerToken = entry.output_cost_per_token;
    if (typeof inputPerToken !== "number" || inputPerToken <= 0)
      continue;
    if (typeof outputPerToken !== "number")
      continue;
    const pricing = {
      input: inputPerToken * PER_TOKEN_TO_PER_MILLION,
      output: outputPerToken * PER_TOKEN_TO_PER_MILLION,
      cacheRead: typeof entry.cache_read_input_token_cost === "number" ? entry.cache_read_input_token_cost * PER_TOKEN_TO_PER_MILLION : 0,
      cacheWrite: typeof entry.cache_creation_input_token_cost === "number" ? entry.cache_creation_input_token_cost * PER_TOKEN_TO_PER_MILLION : 0
    };
    result[key] = pricing;
    const slashIndex = key.indexOf("/");
    const unprefixed = slashIndex !== -1 ? key.slice(slashIndex + 1) : key;
    result[unprefixed] = pricing;
    const normalized = normalizeModelName2(unprefixed);
    result[normalized] = pricing;
  }
  return result;
}
async function fetchLiteLLMPricing() {
  const controller = new AbortController;
  const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
  try {
    const response = await fetch(LITELLM_URL, { signal: controller.signal });
    if (!response.ok) {
      throw new Error(`LiteLLM fetch failed: HTTP ${response.status}`);
    }
    const raw = await response.json();
    return parseLiteLLMData(raw);
  } finally {
    clearTimeout(timeout);
  }
}
var LITELLM_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json", FETCH_TIMEOUT_MS = 1e4, PER_TOKEN_TO_PER_MILLION = 1e6;
var init_litellm = __esm(() => {
  init_normalizer();
});

// packages/registry/dist/models/pricing-cache.js
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
import { homedir, tmpdir } from "os";
import { join } from "path";
function defaultCacheDir() {
  try {
    const home = homedir();
    return join(home, ".cache", "tokenleak");
  } catch {
    return join(tmpdir(), "tokenleak-cache");
  }
}
function cachePath(cacheDir) {
  return join(cacheDir ?? defaultCacheDir(), CACHE_FILENAME);
}
function isCacheValid(envelope) {
  return envelope.version === CACHE_VERSION && Date.now() - envelope.fetchedAt < CACHE_TTL_MS;
}
function readEnvelope(cacheDir) {
  const path = cachePath(cacheDir);
  try {
    if (!existsSync(path))
      return null;
    const raw = readFileSync(path, "utf-8");
    const parsed = JSON.parse(raw);
    if (typeof parsed !== "object" || parsed === null || typeof parsed.version !== "number" || typeof parsed.fetchedAt !== "number" || typeof parsed.data !== "object") {
      return null;
    }
    return parsed;
  } catch {
    return null;
  }
}
function readPricingCache(cacheDir) {
  const envelope = readEnvelope(cacheDir);
  if (envelope && isCacheValid(envelope))
    return envelope;
  return null;
}
function readStalePricingCache(cacheDir) {
  const envelope = readEnvelope(cacheDir);
  return envelope?.data ?? null;
}
function writePricingCache(data, cacheDir) {
  const dir = cacheDir ?? defaultCacheDir();
  const path = join(dir, CACHE_FILENAME);
  const tmpPath = `${path}.tmp`;
  try {
    mkdirSync(dir, { recursive: true });
    const envelope = {
      version: CACHE_VERSION,
      fetchedAt: Date.now(),
      data
    };
    writeFileSync(tmpPath, JSON.stringify(envelope), "utf-8");
    renameSync(tmpPath, path);
  } catch {
    try {
      rmSync(tmpPath, { force: true });
    } catch {}
  }
}
var CACHE_FILENAME = "pricing.json", CACHE_TTL_MS = 3600000, CACHE_VERSION = 1;
var init_pricing_cache = () => {};

// packages/registry/dist/models/pricing-resolver.js
async function initPricing() {
  if (initialized)
    return;
  try {
    const cached = readPricingCache();
    if (cached) {
      remotePricing = cached.data;
      initialized = true;
      return;
    }
  } catch {}
  try {
    const data = await fetchLiteLLMPricing();
    remotePricing = data;
    try {
      writePricingCache(data);
    } catch {}
    initialized = true;
    return;
  } catch {}
  try {
    const stale = readStalePricingCache();
    if (stale) {
      remotePricing = stale;
      initialized = true;
      return;
    }
  } catch {}
  initialized = true;
}
function getRemotePricing(model) {
  return remotePricing?.[model];
}
var remotePricing = null, initialized = false;
var init_pricing_resolver = __esm(() => {
  init_litellm();
  init_pricing_cache();
});

// packages/registry/dist/models/pricing.js
function getModelPricing(model) {
  return getRemotePricing(model) ?? MODEL_PRICING[model];
}
var TOKENS_PER_MILLION3 = 1e6, MODEL_PRICING;
var init_pricing = __esm(() => {
  init_pricing_resolver();
  MODEL_PRICING = {
    "claude-3-haiku": {
      input: 0.25,
      output: 1.25,
      cacheRead: 0.03,
      cacheWrite: 0.3
    },
    "claude-3-sonnet": {
      input: 3,
      output: 15,
      cacheRead: 0.3,
      cacheWrite: 3.75
    },
    "claude-3-opus": {
      input: 15,
      output: 75,
      cacheRead: 1.5,
      cacheWrite: 18.75
    },
    "claude-3.5-haiku": {
      input: 0.8,
      output: 4,
      cacheRead: 0.08,
      cacheWrite: 1
    },
    "claude-3.5-sonnet": {
      input: 3,
      output: 15,
      cacheRead: 0.3,
      cacheWrite: 3.75
    },
    "claude-haiku-4-5": {
      input: 0.8,
      output: 4,
      cacheRead: 0.08,
      cacheWrite: 1
    },
    "claude-sonnet-4-5": {
      input: 3,
      output: 15,
      cacheRead: 0.3,
      cacheWrite: 3.75
    },
    "claude-opus-4-5": {
      input: 15,
      output: 75,
      cacheRead: 1.5,
      cacheWrite: 18.75
    },
    "claude-sonnet-4": {
      input: 3,
      output: 15,
      cacheRead: 0.3,
      cacheWrite: 3.75
    },
    "claude-sonnet-4-6": {
      input: 3,
      output: 15,
      cacheRead: 0.3,
      cacheWrite: 3.75
    },
    "claude-opus-4": {
      input: 15,
      output: 75,
      cacheRead: 1.5,
      cacheWrite: 18.75
    },
    "claude-opus-4-6": {
      input: 15,
      output: 75,
      cacheRead: 1.5,
      cacheWrite: 18.75
    },
    "gpt-4o": {
      input: 2.5,
      output: 10,
      cacheRead: 1.25,
      cacheWrite: 2.5
    },
    "gpt-4o-mini": {
      input: 0.15,
      output: 0.6,
      cacheRead: 0.075,
      cacheWrite: 0.15
    },
    "gpt-5": {
      input: 1.25,
      output: 10,
      cacheRead: 0.125,
      cacheWrite: 1.25
    },
    "gpt-5.1": {
      input: 1.25,
      output: 10,
      cacheRead: 0.125,
      cacheWrite: 1.25
    },
    "gpt-5.2": {
      input: 1.75,
      output: 14,
      cacheRead: 0.175,
      cacheWrite: 1.75
    },
    "gpt-5.4": {
      input: 2.5,
      output: 15,
      cacheRead: 0.25,
      cacheWrite: 2.5
    },
    "gpt-5-codex": {
      input: 1.25,
      output: 10,
      cacheRead: 0.125,
      cacheWrite: 1.25
    },
    "gpt-5.1-codex": {
      input: 1.25,
      output: 10,
      cacheRead: 0.125,
      cacheWrite: 1.25
    },
    "gpt-5.1-codex-max": {
      input: 1.25,
      output: 10,
      cacheRead: 0.125,
      cacheWrite: 1.25
    },
    "gpt-5.2-codex": {
      input: 1.75,
      output: 14,
      cacheRead: 0.175,
      cacheWrite: 1.75
    },
    o1: {
      input: 15,
      output: 60,
      cacheRead: 7.5,
      cacheWrite: 15
    },
    "o1-mini": {
      input: 3,
      output: 12,
      cacheRead: 1.5,
      cacheWrite: 3
    },
    o3: {
      input: 10,
      output: 40,
      cacheRead: 5,
      cacheWrite: 10
    },
    "o3-mini": {
      input: 1.1,
      output: 4.4,
      cacheRead: 0.55,
      cacheWrite: 1.1
    },
    "o4-mini": {
      input: 1.1,
      output: 4.4,
      cacheRead: 0.55,
      cacheWrite: 1.1
    }
  };
});

// packages/registry/dist/models/cost.js
function estimateCostBreakdown(model, inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens) {
  const normalized = normalizeModelName2(model);
  const pricing = getModelPricing(normalized);
  if (!pricing) {
    return {
      normalizedModel: normalized,
      pricing: null,
      inputCost: 0,
      outputCost: 0,
      cacheReadCost: 0,
      cacheWriteCost: 0,
      totalCost: 0
    };
  }
  const inputCost = inputTokens / TOKENS_PER_MILLION3 * pricing.input;
  const outputCost = outputTokens / TOKENS_PER_MILLION3 * pricing.output;
  const cacheReadCost = cacheReadTokens / TOKENS_PER_MILLION3 * pricing.cacheRead;
  const cacheWriteCost = cacheWriteTokens / TOKENS_PER_MILLION3 * pricing.cacheWrite;
  return {
    normalizedModel: normalized,
    pricing,
    inputCost,
    outputCost,
    cacheReadCost,
    cacheWriteCost,
    totalCost: inputCost + outputCost + cacheReadCost + cacheWriteCost
  };
}
var init_cost = __esm(() => {
  init_normalizer();
  init_pricing();
});

// packages/registry/dist/models/index.js
var init_models = __esm(() => {
  init_normalizer();
  init_pricing();
  init_cost();
  init_pricing_resolver();
});

// packages/registry/dist/registry.js
class ProviderRegistry {
  providers = new Map;
  register(provider) {
    if (this.providers.has(provider.name)) {
      throw new Error(`Provider "${provider.name}" is already registered`);
    }
    this.providers.set(provider.name, provider);
  }
  getAll() {
    return [...this.providers.values()];
  }
  async getAvailable() {
    const results = await Promise.all(this.getAll().map(async (p) => ({
      provider: p,
      available: await p.isAvailable()
    })));
    return results.filter((r) => r.available).map((r) => r.provider);
  }
  async loadAll(range, concurrency = DEFAULT_CONCURRENCY) {
    const available = await this.getAvailable();
    const results = [];
    const queue = [...available];
    const runNext = async () => {
      while (queue.length > 0) {
        const provider = queue.shift();
        try {
          const data = await provider.load(range);
          results.push({ provider: provider.name, data, error: null });
        } catch (err) {
          const message = err instanceof Error ? err.message : String(err);
          results.push({ provider: provider.name, data: null, error: message });
        }
      }
    };
    const workers = Array.from({ length: Math.min(concurrency, available.length) }, () => runNext());
    await Promise.all(workers);
    return results;
  }
}
var init_registry = __esm(() => {
  init_dist();
});

// packages/registry/dist/parsers/jsonl-splitter.js
function getMaxRecordBytes() {
  const envValue = process.env["TOKENLEAK_MAX_JSONL_RECORD_BYTES"];
  if (envValue !== undefined && envValue !== "") {
    const parsed = Number(envValue);
    if (!Number.isFinite(parsed) || parsed <= 0) {
      throw new Error(`Invalid TOKENLEAK_MAX_JSONL_RECORD_BYTES value: "${envValue}". Must be a positive number.`);
    }
    return parsed;
  }
  return MAX_JSONL_RECORD_BYTES;
}
async function* splitJsonlRecords(filePath) {
  const maxBytes = getMaxRecordBytes();
  const file = Bun.file(filePath);
  const text = await file.text();
  const lines = text.split(`
`);
  let lineNumber = 0;
  for (const line of lines) {
    lineNumber++;
    if (line.trim() === "" || /^\x00+$/.test(line) || !/[^\x00]/.test(line)) {
      continue;
    }
    const byteLength = new TextEncoder().encode(line).byteLength;
    if (byteLength > maxBytes) {
      continue;
    }
    try {
      yield JSON.parse(line);
    } catch {
      continue;
    }
  }
}
var init_jsonl_splitter = __esm(() => {
  init_dist();
});

// packages/registry/dist/parsers/index.js
var init_parsers = __esm(() => {
  init_jsonl_splitter();
});

// packages/registry/dist/utils.js
function isInRange(date, range) {
  return date >= range.since && date <= range.until;
}

// packages/registry/dist/providers/claude-code.js
import { existsSync as existsSync2, readdirSync, statSync } from "fs";
import { dirname as dirname2, join as join2, relative as relative2, sep } from "path";
import { homedir as homedir2 } from "os";
function resolveBaseDir(baseDir) {
  if (baseDir) {
    return baseDir;
  }
  const configDir = process.env["CLAUDE_CONFIG_DIR"];
  return join2(configDir && configDir.length > 0 ? configDir : DEFAULT_CONFIG_DIR, "projects");
}
function collectJsonlFiles(dir) {
  const results = [];
  if (!existsSync2(dir)) {
    return results;
  }
  const entries = readdirSync(dir);
  for (const entry of entries) {
    const fullPath = join2(dir, entry);
    const stat = statSync(fullPath);
    if (stat.isDirectory()) {
      results.push(...collectJsonlFiles(fullPath));
    } else if (entry.endsWith(".jsonl")) {
      results.push(fullPath);
    }
  }
  return results;
}
function extractUsage(record) {
  if (typeof record !== "object" || record === null) {
    return null;
  }
  const rec = record;
  if (rec["type"] !== "assistant") {
    return null;
  }
  const timestamp = rec["timestamp"];
  if (typeof timestamp !== "string") {
    return null;
  }
  const message = rec["message"];
  if (typeof message !== "object" || message === null) {
    return null;
  }
  const msg = message;
  const usage = msg["usage"];
  if (typeof usage !== "object" || usage === null) {
    return null;
  }
  const model = msg["model"];
  if (typeof model !== "string") {
    return null;
  }
  const u = usage;
  const inputTokens = typeof u["input_tokens"] === "number" ? u["input_tokens"] : 0;
  const outputTokens = typeof u["output_tokens"] === "number" ? u["output_tokens"] : 0;
  const cacheReadTokens = typeof u["cache_read_input_tokens"] === "number" ? u["cache_read_input_tokens"] : 0;
  const cacheWriteTokens = typeof u["cache_creation_input_tokens"] === "number" ? u["cache_creation_input_tokens"] : 0;
  const totalTokens = inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens;
  if (totalTokens === 0) {
    return null;
  }
  const date = timestamp.slice(0, 10);
  if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
    return null;
  }
  return {
    date,
    timestamp,
    model,
    inputTokens,
    outputTokens,
    cacheReadTokens,
    cacheWriteTokens,
    messageId: typeof msg["id"] === "string" ? msg["id"] : undefined
  };
}
function toCachePricing(pricing) {
  if (!pricing) {
    return;
  }
  return {
    input: pricing.input,
    cacheRead: pricing.cacheRead,
    cacheWrite: pricing.cacheWrite
  };
}
function buildDailyUsage(records) {
  const byDate = new Map;
  for (const rec of records) {
    const normalizedModel = normalizeModelName2(rec.model);
    const costBreakdown = estimateCostBreakdown(rec.model, rec.inputTokens, rec.outputTokens, rec.cacheReadTokens, rec.cacheWriteTokens);
    const pricing = toCachePricing(costBreakdown.pricing);
    let dateModels = byDate.get(rec.date);
    if (!dateModels) {
      dateModels = new Map;
      byDate.set(rec.date, dateModels);
    }
    let mb = dateModels.get(normalizedModel);
    if (!mb) {
      mb = {
        model: normalizedModel,
        inputTokens: 0,
        outputTokens: 0,
        cacheReadTokens: 0,
        cacheWriteTokens: 0,
        totalTokens: 0,
        cost: 0,
        pricing
      };
      dateModels.set(normalizedModel, mb);
    } else if (!mb.pricing && pricing) {
      mb.pricing = pricing;
    }
    mb.inputTokens += rec.inputTokens;
    mb.outputTokens += rec.outputTokens;
    mb.cacheReadTokens += rec.cacheReadTokens;
    mb.cacheWriteTokens += rec.cacheWriteTokens;
    mb.totalTokens += rec.inputTokens + rec.outputTokens + rec.cacheReadTokens + rec.cacheWriteTokens;
    mb.cost += costBreakdown.totalCost;
  }
  const daily = [];
  for (const [date, dateModels] of byDate) {
    const models = [...dateModels.values()];
    const inputTokens = models.reduce((sum, m) => sum + m.inputTokens, 0);
    const outputTokens = models.reduce((sum, m) => sum + m.outputTokens, 0);
    const cacheReadTokens = models.reduce((sum, m) => sum + m.cacheReadTokens, 0);
    const cacheWriteTokens = models.reduce((sum, m) => sum + m.cacheWriteTokens, 0);
    const totalTokens = models.reduce((sum, m) => sum + m.totalTokens, 0);
    const cost = models.reduce((sum, m) => sum + m.cost, 0);
    daily.push({
      date,
      inputTokens,
      outputTokens,
      cacheReadTokens,
      cacheWriteTokens,
      totalTokens,
      cost,
      models
    });
  }
  daily.sort((a, b) => a.date.localeCompare(b.date));
  return daily;
}

class ClaudeCodeProvider {
  name = "claude-code";
  displayName = "Claude Code";
  colors = CLAUDE_CODE_COLORS;
  baseDir;
  constructor(baseDir) {
    this.baseDir = resolveBaseDir(baseDir);
  }
  async isAvailable() {
    try {
      return existsSync2(this.baseDir);
    } catch {
      return false;
    }
  }
  async load(range) {
    const files = collectJsonlFiles(this.baseDir);
    const allRecords = [];
    const allEvents = [];
    for (const file of files) {
      const latestRecordsByMessageId = new Map;
      const anonymousRecords = [];
      const relativeFile = relative2(this.baseDir, file).split(sep).join("/");
      const projectId = relative2(this.baseDir, dirname2(file)).split(sep).join("/");
      try {
        for await (const record of splitJsonlRecords(file)) {
          const usage = extractUsage(record);
          if (usage !== null && isInRange(usage.date, range)) {
            usage.sessionId = relativeFile;
            usage.projectId = projectId;
            if (usage.messageId) {
              latestRecordsByMessageId.set(usage.messageId, usage);
            } else {
              anonymousRecords.push(usage);
            }
          }
        }
      } catch {
        continue;
      }
      allRecords.push(...latestRecordsByMessageId.values(), ...anonymousRecords);
    }
    const daily = buildDailyUsage(allRecords);
    for (const record of allRecords) {
      const normalizedModel = normalizeModelName2(record.model);
      const costBreakdown = estimateCostBreakdown(record.model, record.inputTokens, record.outputTokens, record.cacheReadTokens, record.cacheWriteTokens);
      allEvents.push({
        provider: this.name,
        timestamp: record.timestamp,
        date: record.date,
        model: normalizedModel,
        inputTokens: record.inputTokens,
        outputTokens: record.outputTokens,
        cacheReadTokens: record.cacheReadTokens,
        cacheWriteTokens: record.cacheWriteTokens,
        totalTokens: record.inputTokens + record.outputTokens + record.cacheReadTokens + record.cacheWriteTokens,
        cost: costBreakdown.totalCost,
        pricing: toCachePricing(costBreakdown.pricing),
        sessionId: record.sessionId,
        projectId: record.projectId
      });
    }
    const totalTokens = daily.reduce((sum, d) => sum + d.totalTokens, 0);
    const totalCost = daily.reduce((sum, d) => sum + d.cost, 0);
    return {
      provider: this.name,
      displayName: this.displayName,
      daily,
      totalTokens,
      totalCost,
      colors: this.colors,
      events: allEvents
    };
  }
}
var DEFAULT_CONFIG_DIR, CLAUDE_CODE_COLORS;
var init_claude_code = __esm(() => {
  init_jsonl_splitter();
  init_normalizer();
  init_cost();
  DEFAULT_CONFIG_DIR = join2(homedir2(), ".claude");
  CLAUDE_CODE_COLORS = {
    primary: "#ff6b35",
    secondary: "#ffa366",
    gradient: ["#ff6b35", "#ffa366"]
  };
});

// packages/registry/dist/providers/codex.js
import { existsSync as existsSync3, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
import { dirname as dirname3, join as join3, relative as relative3, sep as sep2 } from "path";
import { homedir as homedir3 } from "os";
function parseResponseEvent(record) {
  if (typeof record !== "object" || record === null || !("type" in record)) {
    return null;
  }
  const obj = record;
  if (obj["type"] !== "response") {
    return null;
  }
  if (typeof obj["timestamp"] !== "string" || typeof obj["model"] !== "string" || typeof obj["usage"] !== "object" || obj["usage"] === null) {
    return null;
  }
  const usage = obj["usage"];
  if (typeof usage["input_tokens"] !== "number" || typeof usage["output_tokens"] !== "number" || typeof usage["total_tokens"] !== "number") {
    return null;
  }
  return {
    type: "response",
    timestamp: obj["timestamp"],
    model: obj["model"],
    usage: {
      input_tokens: usage["input_tokens"],
      output_tokens: usage["output_tokens"],
      total_tokens: usage["total_tokens"]
    }
  };
}
function compactModelDateSuffix(model) {
  return model.replace(DASHED_DATE_SUFFIX, "-$1$2$3");
}
function extractDate(timestamp) {
  const match = /^(\d{4}-\d{2}-\d{2})/.exec(timestamp);
  return match ? match[1] : null;
}
function toCachePricing2(pricing) {
  if (!pricing) {
    return;
  }
  return {
    input: pricing.input,
    cacheRead: pricing.cacheRead,
    cacheWrite: pricing.cacheWrite
  };
}
function collectJsonlFiles2(dir) {
  if (!existsSync3(dir)) {
    return [];
  }
  const files = [];
  for (const entry of readdirSync2(dir)) {
    const fullPath = join3(dir, entry);
    const stats = statSync2(fullPath);
    if (stats.isDirectory()) {
      files.push(...collectJsonlFiles2(fullPath));
    } else if (entry.endsWith(".jsonl")) {
      files.push(fullPath);
    }
  }
  return files;
}
function inferModelFromContext(record) {
  if (typeof record !== "object" || record === null) {
    return null;
  }
  const obj = record;
  if (obj["type"] !== "session_meta" && obj["type"] !== "turn_context") {
    return null;
  }
  const payload = obj["payload"];
  if (typeof payload !== "object" || payload === null) {
    return null;
  }
  const meta = payload;
  const directModelKeys = ["model", "model_name", "model_slug"];
  for (const key of directModelKeys) {
    if (typeof meta[key] === "string" && meta[key].trim()) {
      return meta[key].trim();
    }
  }
  const instructions = meta["base_instructions"];
  if (typeof instructions === "object" && instructions !== null) {
    const text = instructions["text"];
    if (typeof text === "string") {
      const match = /based on ([A-Za-z0-9.-]+)/i.exec(text);
      if (match?.[1]) {
        return match[1].toLowerCase();
      }
    }
  }
  return null;
}
function parseTokenCountUsage(record, context) {
  if (typeof record !== "object" || record === null) {
    return null;
  }
  const obj = record;
  if (obj["type"] !== "event_msg") {
    return null;
  }
  const timestamp = obj["timestamp"];
  const payload = obj["payload"];
  if (typeof timestamp !== "string" || typeof payload !== "object" || payload === null) {
    return null;
  }
  const eventPayload = payload;
  if (eventPayload["type"] !== "token_count") {
    return null;
  }
  const info = eventPayload["info"];
  if (typeof info !== "object" || info === null) {
    return null;
  }
  const usageInfo = info;
  const lastUsage = usageInfo["last_token_usage"];
  const totalUsage = usageInfo["total_token_usage"];
  const date = extractDate(timestamp);
  if (!date) {
    return null;
  }
  const parseUsage = (usage2) => {
    if (typeof usage2 !== "object" || usage2 === null) {
      return null;
    }
    const usageObj = usage2;
    const inputTokens2 = usageObj["input_tokens"];
    const outputTokens = usageObj["output_tokens"];
    const cachedInputTokens = usageObj["cached_input_tokens"];
    if (typeof inputTokens2 !== "number" || typeof outputTokens !== "number") {
      return null;
    }
    return {
      inputTokens: inputTokens2,
      outputTokens,
      cachedInputTokens: typeof cachedInputTokens === "number" ? cachedInputTokens : 0
    };
  };
  let usage = parseUsage(lastUsage);
  if (!usage) {
    const cumulative = parseUsage(totalUsage);
    if (!cumulative) {
      return null;
    }
    const previous = context.previousTotals ?? {
      inputTokens: 0,
      outputTokens: 0,
      cachedInputTokens: 0
    };
    usage = {
      inputTokens: Math.max(0, cumulative.inputTokens - previous.inputTokens),
      outputTokens: Math.max(0, cumulative.outputTokens - previous.outputTokens),
      cachedInputTokens: Math.max(0, cumulative.cachedInputTokens - previous.cachedInputTokens)
    };
    context.previousTotals = cumulative;
  } else if (parseUsage(totalUsage)) {
    context.previousTotals = parseUsage(totalUsage);
  }
  const cacheReadTokens = Math.min(usage.cachedInputTokens, usage.inputTokens);
  const inputTokens = Math.max(0, usage.inputTokens - cacheReadTokens);
  return {
    date,
    timestamp,
    model: context.model,
    inputTokens,
    outputTokens: usage.outputTokens,
    cacheReadTokens,
    cacheWriteTokens: 0
  };
}
function parseUsageRecord(record, context) {
  const inferredModel = inferModelFromContext(record);
  if (inferredModel) {
    if (context.model !== inferredModel) {
      context.model = inferredModel;
      context.previousTotals = null;
    }
    return null;
  }
  const tokenCountUsage = parseTokenCountUsage(record, context);
  if (tokenCountUsage) {
    return tokenCountUsage;
  }
  const legacyEvent = parseResponseEvent(record);
  if (!legacyEvent) {
    return null;
  }
  const date = extractDate(legacyEvent.timestamp);
  if (!date) {
    return null;
  }
  return {
    date,
    timestamp: legacyEvent.timestamp,
    model: compactModelDateSuffix(legacyEvent.model),
    inputTokens: legacyEvent.usage.input_tokens,
    outputTokens: legacyEvent.usage.output_tokens,
    cacheReadTokens: 0,
    cacheWriteTokens: 0
  };
}

class CodexProvider {
  name = "codex";
  displayName = "Codex";
  colors = CODEX_COLORS;
  sessionsDir;
  constructor(baseDir) {
    this.sessionsDir = baseDir ?? DEFAULT_SESSIONS_DIR;
  }
  async isAvailable() {
    try {
      return existsSync3(this.sessionsDir);
    } catch {
      return false;
    }
  }
  async load(range) {
    const dailyMap = new Map;
    const files = collectJsonlFiles2(this.sessionsDir);
    const events = [];
    for (const file of files) {
      const context = {
        model: "gpt-5",
        previousTotals: null
      };
      const relativeFile = relative3(this.sessionsDir, file).split(sep2).join("/");
      const projectDir = relative3(this.sessionsDir, dirname3(file)).split(sep2).join("/");
      try {
        for await (const record of splitJsonlRecords(file)) {
          const usage = parseUsageRecord(record, context);
          if (!usage) {
            continue;
          }
          if (!isInRange(usage.date, range)) {
            continue;
          }
          usage.sessionId = relativeFile;
          usage.projectId = projectDir === "." ? undefined : projectDir;
          const normalizedModel = normalizeModelName2(compactModelDateSuffix(usage.model));
          const inputTokens = usage.inputTokens;
          const outputTokens = usage.outputTokens;
          const cacheReadTokens = usage.cacheReadTokens;
          const cacheWriteTokens = usage.cacheWriteTokens;
          const costBreakdown = estimateCostBreakdown(normalizedModel, inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens);
          events.push({
            provider: this.name,
            timestamp: usage.timestamp,
            date: usage.date,
            model: normalizedModel,
            inputTokens,
            outputTokens,
            cacheReadTokens,
            cacheWriteTokens,
            totalTokens: inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens,
            cost: costBreakdown.totalCost,
            pricing: toCachePricing2(costBreakdown.pricing),
            sessionId: usage.sessionId,
            projectId: usage.projectId
          });
          if (!dailyMap.has(usage.date)) {
            dailyMap.set(usage.date, new Map);
          }
          const modelMap = dailyMap.get(usage.date);
          if (!modelMap.has(normalizedModel)) {
            modelMap.set(normalizedModel, {
              model: normalizedModel,
              inputTokens: 0,
              outputTokens: 0,
              cacheReadTokens: 0,
              cacheWriteTokens: 0,
              totalTokens: 0,
              cost: 0,
              pricing: toCachePricing2(costBreakdown.pricing)
            });
          }
          const breakdown = modelMap.get(normalizedModel);
          breakdown.inputTokens += inputTokens;
          breakdown.outputTokens += outputTokens;
          breakdown.cacheReadTokens += cacheReadTokens;
          breakdown.cacheWriteTokens += cacheWriteTokens;
          breakdown.totalTokens += inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens;
          breakdown.cost += costBreakdown.totalCost;
          if (!breakdown.pricing) {
            breakdown.pricing = toCachePricing2(costBreakdown.pricing);
          }
        }
      } catch {
        continue;
      }
    }
    const daily = [...dailyMap.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([date, modelMap]) => {
      const models = [...modelMap.values()];
      const inputTokens = models.reduce((s, m) => s + m.inputTokens, 0);
      const outputTokens = models.reduce((s, m) => s + m.outputTokens, 0);
      const cacheReadTokens = models.reduce((s, m) => s + m.cacheReadTokens, 0);
      const cacheWriteTokens = models.reduce((s, m) => s + m.cacheWriteTokens, 0);
      const totalTokens2 = models.reduce((s, m) => s + m.totalTokens, 0);
      const cost = models.reduce((s, m) => s + m.cost, 0);
      return {
        date,
        inputTokens,
        outputTokens,
        cacheReadTokens,
        cacheWriteTokens,
        totalTokens: totalTokens2,
        cost,
        models
      };
    });
    const totalTokens = daily.reduce((s, d) => s + d.totalTokens, 0);
    const totalCost = daily.reduce((s, d) => s + d.cost, 0);
    return {
      provider: this.name,
      displayName: this.displayName,
      daily,
      totalTokens,
      totalCost,
      colors: this.colors,
      events
    };
  }
}
var CODEX_COLORS, DEFAULT_SESSIONS_DIR, DASHED_DATE_SUFFIX;
var init_codex = __esm(() => {
  init_jsonl_splitter();
  init_normalizer();
  init_cost();
  CODEX_COLORS = {
    primary: "#10a37f",
    secondary: "#4ade80",
    gradient: ["#10a37f", "#4ade80"]
  };
  DEFAULT_SESSIONS_DIR = join3(process.env["CODEX_HOME"] ?? join3(homedir3(), ".codex"), "sessions");
  DASHED_DATE_SUFFIX = /-(\d{4})-(\d{2})-(\d{2})$/;
});

// packages/registry/dist/providers/cursor.js
import { existsSync as existsSync4, readdirSync as readdirSync3, readFileSync as readFileSync2, statSync as statSync3 } from "fs";
import { join as join4 } from "path";
import { homedir as homedir4 } from "os";
function resolveCacheDir(baseDir) {
  return baseDir ?? join4(process.env["TOKENLEAK_CURSOR_DIR"] ?? join4(homedir4(), ".config", "tokenleak"), "cursor-cache");
}
function isCursorUsageFile(name) {
  if (name === "usage.csv") {
    return true;
  }
  if (!name.startsWith("usage.") || !name.endsWith(".csv")) {
    return false;
  }
  const stem = name.slice("usage.".length, -".csv".length);
  return stem.length > 0;
}
function collectUsageFiles(dir) {
  if (!existsSync4(dir)) {
    return [];
  }
  const files = [];
  for (const entry of readdirSync3(dir)) {
    if (entry === "archive") {
      continue;
    }
    const fullPath = join4(dir, entry);
    const stats = statSync3(fullPath);
    if (stats.isFile() && isCursorUsageFile(entry)) {
      files.push(fullPath);
    }
  }
  return files.sort((left, right) => left.localeCompare(right));
}
function parseCsvLine(line) {
  const fields = [];
  let current = "";
  let inQuotes = false;
  for (let index = 0;index < line.length; index += 1) {
    const char = line[index];
    if (char === '"') {
      if (inQuotes && line[index + 1] === '"') {
        current += '"';
        index += 1;
      } else {
        inQuotes = !inQuotes;
      }
      continue;
    }
    if (char === "," && !inQuotes) {
      fields.push(current);
      current = "";
      continue;
    }
    current += char;
  }
  fields.push(current);
  return fields;
}
function extractDate2(timestamp) {
  const match = /^(\d{4}-\d{2}-\d{2})/.exec(timestamp);
  return match ? match[1] : null;
}
function toIsoTimestamp(value) {
  const trimmed = value.trim();
  if (!trimmed) {
    return null;
  }
  const dateOnlyMatch = /^(\d{4}-\d{2}-\d{2})$/.exec(trimmed);
  if (dateOnlyMatch) {
    return `${dateOnlyMatch[1]}T12:00:00.000Z`;
  }
  const millis = Date.parse(trimmed);
  if (!Number.isFinite(millis)) {
    return null;
  }
  return new Date(millis).toISOString();
}
function parseCost(value) {
  const cleaned = value.replaceAll("$", "").replaceAll(",", "").trim();
  if (!cleaned || cleaned.toLowerCase() === "nan") {
    return;
  }
  const parsed = Number(cleaned);
  return Number.isFinite(parsed) ? parsed : undefined;
}
function compactModelDateSuffix2(model) {
  return model.replace(DASHED_DATE_SUFFIX2, "-$1$2$3");
}
function toCachePricing3(pricing) {
  if (!pricing) {
    return;
  }
  return {
    input: pricing.input,
    cacheRead: pricing.cacheRead,
    cacheWrite: pricing.cacheWrite
  };
}
function parseUsageFile(filePath) {
  let raw;
  try {
    raw = readFileSync2(filePath, "utf8");
  } catch {
    return [];
  }
  const lines = raw.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
  if (lines.length <= 1) {
    return [];
  }
  const header = parseCsvLine(lines[0]);
  const hasKindColumn = header.includes("Kind");
  const modelIndex = hasKindColumn ? 2 : 1;
  const inputWithCacheWriteIndex = hasKindColumn ? 4 : 2;
  const inputWithoutCacheWriteIndex = hasKindColumn ? 5 : 3;
  const cacheReadIndex = hasKindColumn ? 6 : 4;
  const outputIndex = hasKindColumn ? 7 : 5;
  const costIndex = hasKindColumn ? 9 : 7;
  const accountId = filePath.endsWith("/usage.csv") || filePath.endsWith("\\usage.csv") ? "active" : filePath.split(/[/\\]/).pop()?.replace(/^usage\./, "").replace(/\.csv$/, "") || "unknown";
  const records = [];
  for (const line of lines.slice(1)) {
    const fields = parseCsvLine(line);
    if (fields.length <= costIndex) {
      continue;
    }
    const timestamp = toIsoTimestamp(fields[0] ?? "");
    if (!timestamp) {
      continue;
    }
    const date = extractDate2(timestamp);
    if (!date) {
      continue;
    }
    const rawModel = (fields[modelIndex] ?? "").trim();
    if (!rawModel) {
      continue;
    }
    const inputWithCacheWrite = Number((fields[inputWithCacheWriteIndex] ?? "").trim());
    const inputWithoutCacheWrite = Number((fields[inputWithoutCacheWriteIndex] ?? "").trim());
    const cacheReadTokens = Number((fields[cacheReadIndex] ?? "").trim());
    const outputTokens = Number((fields[outputIndex] ?? "").trim());
    if (!Number.isFinite(inputWithCacheWrite) || !Number.isFinite(inputWithoutCacheWrite) || !Number.isFinite(cacheReadTokens) || !Number.isFinite(outputTokens)) {
      continue;
    }
    const inputTokens = Math.max(0, inputWithoutCacheWrite);
    const cacheWriteTokens = Math.max(0, inputWithCacheWrite - inputWithoutCacheWrite);
    const totalTokens = inputTokens + outputTokens + Math.max(0, cacheReadTokens) + cacheWriteTokens;
    if (totalTokens === 0) {
      continue;
    }
    const model = compactModelDateSuffix2(rawModel);
    records.push({
      date,
      timestamp,
      model,
      normalizedModel: normalizeModelName2(model),
      inputTokens,
      outputTokens: Math.max(0, outputTokens),
      cacheReadTokens: Math.max(0, cacheReadTokens),
      cacheWriteTokens,
      explicitCost: parseCost(fields[costIndex] ?? ""),
      sessionId: `cursor-${accountId}-${timestamp}`
    });
  }
  return records;
}
function getRecordCost(record) {
  if (typeof record.explicitCost === "number" && Number.isFinite(record.explicitCost)) {
    return record.explicitCost;
  }
  return estimateCostBreakdown(record.normalizedModel, record.inputTokens, record.outputTokens, record.cacheReadTokens, record.cacheWriteTokens).totalCost;
}
function toUsageEvent(record) {
  const pricing = estimateCostBreakdown(record.normalizedModel, record.inputTokens, record.outputTokens, record.cacheReadTokens, record.cacheWriteTokens).pricing;
  return {
    provider: PROVIDER_NAME,
    timestamp: record.timestamp,
    date: record.date,
    model: record.normalizedModel,
    inputTokens: record.inputTokens,
    outputTokens: record.outputTokens,
    cacheReadTokens: record.cacheReadTokens,
    cacheWriteTokens: record.cacheWriteTokens,
    totalTokens: record.inputTokens + record.outputTokens + record.cacheReadTokens + record.cacheWriteTokens,
    cost: getRecordCost(record),
    pricing: toCachePricing3(pricing),
    sessionId: record.sessionId
  };
}
function buildProviderData(records) {
  const byDate = new Map;
  const events = records.map(toUsageEvent);
  for (const event of events) {
    let dateMap = byDate.get(event.date);
    if (!dateMap) {
      dateMap = new Map;
      byDate.set(event.date, dateMap);
    }
    const existing = dateMap.get(event.model);
    if (existing) {
      existing.inputTokens += event.inputTokens;
      existing.outputTokens += event.outputTokens;
      existing.cacheReadTokens += event.cacheReadTokens;
      existing.cacheWriteTokens += event.cacheWriteTokens;
      existing.totalTokens += event.totalTokens;
      existing.cost += event.cost;
      if (!existing.pricing && event.pricing) {
        existing.pricing = event.pricing;
      }
      continue;
    }
    dateMap.set(event.model, {
      model: event.model,
      inputTokens: event.inputTokens,
      outputTokens: event.outputTokens,
      cacheReadTokens: event.cacheReadTokens,
      cacheWriteTokens: event.cacheWriteTokens,
      totalTokens: event.totalTokens,
      cost: event.cost,
      pricing: event.pricing
    });
  }
  let totalTokens = 0;
  let totalCost = 0;
  const daily = [...byDate.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([date, modelMap]) => {
    const models = [...modelMap.values()].sort((left, right) => left.model.localeCompare(right.model));
    const inputTokens = models.reduce((sum, model) => sum + model.inputTokens, 0);
    const outputTokens = models.reduce((sum, model) => sum + model.outputTokens, 0);
    const cacheReadTokens = models.reduce((sum, model) => sum + model.cacheReadTokens, 0);
    const cacheWriteTokens = models.reduce((sum, model) => sum + model.cacheWriteTokens, 0);
    const dayTotal = models.reduce((sum, model) => sum + model.totalTokens, 0);
    const dayCost = models.reduce((sum, model) => sum + model.cost, 0);
    totalTokens += dayTotal;
    totalCost += dayCost;
    return {
      date,
      inputTokens,
      outputTokens,
      cacheReadTokens,
      cacheWriteTokens,
      totalTokens: dayTotal,
      cost: dayCost,
      models
    };
  });
  return {
    provider: PROVIDER_NAME,
    displayName: DISPLAY_NAME,
    daily,
    totalTokens,
    totalCost,
    colors: CURSOR_COLORS,
    events
  };
}

class CursorProvider {
  name = PROVIDER_NAME;
  displayName = DISPLAY_NAME;
  colors = CURSOR_COLORS;
  cacheDir;
  constructor(baseDir) {
    this.cacheDir = resolveCacheDir(baseDir);
  }
  async isAvailable() {
    try {
      return collectUsageFiles(this.cacheDir).length > 0;
    } catch {
      return false;
    }
  }
  async load(range) {
    const files = collectUsageFiles(this.cacheDir);
    const records = files.flatMap((filePath) => parseUsageFile(filePath)).filter((record) => isInRange(record.date, range));
    return buildProviderData(records);
  }
}
var PROVIDER_NAME = "cursor", DISPLAY_NAME = "Cursor", CURSOR_COLORS, DASHED_DATE_SUFFIX2;
var init_cursor = __esm(() => {
  init_normalizer();
  init_cost();
  CURSOR_COLORS = {
    primary: "#22c55e",
    secondary: "#86efac",
    gradient: ["#22c55e", "#86efac"]
  };
  DASHED_DATE_SUFFIX2 = /-(\d{4})-(\d{2})-(\d{2})$/;
});

// packages/registry/dist/providers/open-code.js
import { existsSync as existsSync5, readdirSync as readdirSync4, readFileSync as readFileSync3 } from "fs";
import { join as join5 } from "path";
import { homedir as homedir5 } from "os";
import { Database } from "bun:sqlite";
function resolveBaseDir2(baseDir) {
  if (baseDir) {
    return baseDir;
  }
  for (const candidate of [
    CURRENT_DEFAULT_BASE_DIR,
    LEGACY_DEFAULT_BASE_DIR,
    CONFIG_DEFAULT_BASE_DIR
  ]) {
    if (existsSync5(candidate)) {
      return candidate;
    }
  }
  return CURRENT_DEFAULT_BASE_DIR;
}
function extractDate3(createdAt) {
  const timestamp = typeof createdAt === "number" ? createdAt : Number.isNaN(Number(createdAt)) ? Date.parse(createdAt) : Number(createdAt);
  if (!Number.isFinite(timestamp)) {
    return null;
  }
  const millis = Math.abs(timestamp) >= 1000000000000 ? timestamp : timestamp * 1000;
  const date = new Date(millis);
  if (Number.isNaN(date.getTime())) {
    return null;
  }
  return date.toISOString().slice(0, 10);
}
function toTimestampMillis(createdAt) {
  const timestamp = typeof createdAt === "number" ? createdAt : Number.isNaN(Number(createdAt)) ? Date.parse(createdAt) : Number(createdAt);
  if (!Number.isFinite(timestamp)) {
    return null;
  }
  const millis = Math.abs(timestamp) >= 1000000000000 ? timestamp : timestamp * 1000;
  return Number.isFinite(millis) ? millis : null;
}
function toIsoTimestamp2(createdAt) {
  const millis = toTimestampMillis(createdAt);
  if (millis === null) {
    return null;
  }
  const date = new Date(millis);
  return Number.isNaN(date.getTime()) ? null : date.toISOString();
}
function toCachePricing4(pricing) {
  if (!pricing) {
    return;
  }
  return {
    input: pricing.input,
    cacheRead: pricing.cacheRead,
    cacheWrite: pricing.cacheWrite
  };
}
function getEstimatedCostBreakdown(record) {
  return estimateCostBreakdown(record.model, record.inputTokens, record.outputTokens, record.cacheReadTokens, record.cacheWriteTokens);
}
function getRecordCost2(record) {
  if (typeof record.explicitCost === "number" && Number.isFinite(record.explicitCost)) {
    return record.explicitCost;
  }
  return getEstimatedCostBreakdown(record).totalCost;
}
function toUsageEvent2(record) {
  const totalTokens = record.inputTokens + record.outputTokens + record.cacheReadTokens + record.cacheWriteTokens;
  const estimated = getEstimatedCostBreakdown(record);
  return {
    provider: PROVIDER_NAME2,
    timestamp: record.timestamp,
    date: record.date,
    model: normalizeModelName2(record.model),
    inputTokens: record.inputTokens,
    outputTokens: record.outputTokens,
    cacheReadTokens: record.cacheReadTokens,
    cacheWriteTokens: record.cacheWriteTokens,
    totalTokens,
    cost: getRecordCost2(record),
    pricing: toCachePricing4(estimated.pricing),
    sessionId: record.sessionId,
    projectId: record.projectId,
    durationMs: record.durationMs
  };
}
function buildProviderData2(records) {
  const byDate = new Map;
  for (const record of records) {
    let dateMap = byDate.get(record.date);
    if (!dateMap) {
      dateMap = new Map;
      byDate.set(record.date, dateMap);
    }
    const normalized = normalizeModelName2(record.model);
    const existing = dateMap.get(normalized);
    const estimated = getEstimatedCostBreakdown(record);
    const recordCost = typeof record.explicitCost === "number" && Number.isFinite(record.explicitCost) ? record.explicitCost : estimated.totalCost;
    const pricing = toCachePricing4(estimated.pricing);
    if (existing) {
      existing.inputTokens += record.inputTokens;
      existing.outputTokens += record.outputTokens;
      existing.cacheReadTokens += record.cacheReadTokens;
      existing.cacheWriteTokens += record.cacheWriteTokens;
      existing.totalTokens += record.inputTokens + record.outputTokens + record.cacheReadTokens + record.cacheWriteTokens;
      existing.cost += recordCost;
      if (!existing.pricing && pricing) {
        existing.pricing = pricing;
      }
    } else {
      dateMap.set(normalized, {
        model: normalized,
        inputTokens: record.inputTokens,
        outputTokens: record.outputTokens,
        cacheReadTokens: record.cacheReadTokens,
        cacheWriteTokens: record.cacheWriteTokens,
        totalTokens: record.inputTokens + record.outputTokens + record.cacheReadTokens + record.cacheWriteTokens,
        cost: recordCost,
        pricing
      });
    }
  }
  let totalTokens = 0;
  let totalCost = 0;
  const daily = [...byDate.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([date, modelMap]) => {
    const models = [...modelMap.values()];
    const inputTokens = models.reduce((sum, model) => sum + model.inputTokens, 0);
    const outputTokens = models.reduce((sum, model) => sum + model.outputTokens, 0);
    const cacheReadTokens = models.reduce((sum, model) => sum + model.cacheReadTokens, 0);
    const cacheWriteTokens = models.reduce((sum, model) => sum + model.cacheWriteTokens, 0);
    const dayTotal = inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens;
    const dayCost = models.reduce((sum, model) => sum + model.cost, 0);
    totalTokens += dayTotal;
    totalCost += dayCost;
    return {
      date,
      inputTokens,
      outputTokens,
      cacheReadTokens,
      cacheWriteTokens,
      totalTokens: dayTotal,
      cost: dayCost,
      models
    };
  });
  return {
    provider: PROVIDER_NAME2,
    displayName: DISPLAY_NAME2,
    daily,
    totalTokens,
    totalCost,
    colors: COLORS,
    events: records.map(toUsageEvent2)
  };
}
function loadFromSqlite(dbPath, range) {
  let db;
  try {
    db = new Database(dbPath, { readonly: true });
  } catch {
    return [];
  }
  try {
    const tables = db.query("SELECT name FROM sqlite_master WHERE type='table' AND name='messages'").all();
    if (tables.length === 0) {
      return [];
    }
    const rows = db.query("SELECT model, session_id, input_tokens, output_tokens, created_at FROM messages WHERE role = 'assistant'").all();
    const records = [];
    for (const row of rows) {
      const date = extractDate3(row.created_at);
      const timestamp = toIsoTimestamp2(row.created_at);
      if (date && timestamp && isInRange(date, range)) {
        records.push({
          date,
          timestamp,
          model: row.model,
          inputTokens: row.input_tokens,
          outputTokens: row.output_tokens,
          cacheReadTokens: 0,
          cacheWriteTokens: 0,
          sessionId: row.session_id
        });
      }
    }
    return records;
  } catch {
    return [];
  } finally {
    db.close();
  }
}
function loadFromLegacyJson(sessionsDir, range) {
  const files = readdirSync4(sessionsDir).filter((file) => file.endsWith(".json"));
  const records = [];
  for (const file of files) {
    try {
      const content = readFileSync3(join5(sessionsDir, file), "utf-8");
      const session = JSON.parse(content);
      if (!Array.isArray(session.messages)) {
        continue;
      }
      for (const msg of session.messages) {
        if (msg.role !== "assistant" || !msg.usage) {
          continue;
        }
        const date = extractDate3(msg.created_at);
        const timestamp = toIsoTimestamp2(msg.created_at);
        if (date && timestamp && isInRange(date, range)) {
          records.push({
            date,
            timestamp,
            model: msg.model,
            inputTokens: msg.usage.input_tokens,
            outputTokens: msg.usage.output_tokens,
            cacheReadTokens: 0,
            cacheWriteTokens: 0,
            sessionId: file
          });
        }
      }
    } catch {
      continue;
    }
  }
  return records;
}
function loadFromCurrentStorage(baseDir, range) {
  const messagesRoot = join5(baseDir, "storage", "message");
  if (!existsSync5(messagesRoot)) {
    return [];
  }
  const recordsById = new Map;
  const recordsWithoutId = [];
  for (const sessionDir of readdirSync4(messagesRoot)) {
    const sessionPath = join5(messagesRoot, sessionDir);
    let messageFiles;
    try {
      messageFiles = readdirSync4(sessionPath).filter((file) => file.endsWith(".json"));
    } catch {
      continue;
    }
    for (const file of messageFiles) {
      try {
        const content = readFileSync3(join5(sessionPath, file), "utf-8");
        const message = JSON.parse(content);
        if (message.role !== "assistant") {
          continue;
        }
        const model = message.modelID;
        const createdAt = message.time?.created;
        if (typeof model !== "string" || typeof createdAt !== "string" && typeof createdAt !== "number") {
          continue;
        }
        const date = extractDate3(createdAt);
        const timestamp = toIsoTimestamp2(createdAt);
        if (!date || !timestamp || !isInRange(date, range)) {
          continue;
        }
        const inputTokens = typeof message.tokens?.input === "number" ? message.tokens.input : 0;
        const outputTokens = typeof message.tokens?.output === "number" ? message.tokens.output : 0;
        const cacheReadTokens = typeof message.tokens?.cache?.read === "number" ? message.tokens.cache.read : 0;
        const cacheWriteTokens = typeof message.tokens?.cache?.write === "number" ? message.tokens.cache.write : 0;
        const record = {
          date,
          timestamp,
          model,
          inputTokens,
          outputTokens,
          cacheReadTokens,
          cacheWriteTokens,
          explicitCost: typeof message.cost === "number" ? message.cost : undefined,
          sessionId: typeof message.sessionID === "string" && message.sessionID || sessionDir
        };
        const completedAt = message.time?.completed;
        const completedMs = typeof completedAt === "string" || typeof completedAt === "number" ? toTimestampMillis(completedAt) : null;
        const createdMs = Date.parse(record.timestamp);
        if (completedMs !== null && Number.isFinite(createdMs) && completedMs > createdMs) {
          record.durationMs = completedMs - createdMs;
        }
        const totalTokens = inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens;
        if (totalTokens === 0 && !(typeof record.explicitCost === "number" && record.explicitCost > 0)) {
          continue;
        }
        if (typeof message.id === "string" && message.id.length > 0) {
          recordsById.set(message.id, record);
        } else {
          recordsWithoutId.push(record);
        }
      } catch {
        continue;
      }
    }
  }
  return [...recordsById.values(), ...recordsWithoutId];
}

class OpenCodeProvider {
  name = PROVIDER_NAME2;
  displayName = DISPLAY_NAME2;
  colors = COLORS;
  baseDir;
  constructor(baseDir) {
    this.baseDir = resolveBaseDir2(baseDir);
  }
  async isAvailable() {
    try {
      if (!existsSync5(this.baseDir)) {
        return false;
      }
      const hasCurrentStorage = existsSync5(join5(this.baseDir, "storage", "message"));
      const hasLegacyDb = existsSync5(join5(this.baseDir, "opencode.db")) || existsSync5(join5(this.baseDir, "sessions.db"));
      const hasLegacySessionsDir = existsSync5(join5(this.baseDir, "sessions"));
      return hasCurrentStorage || hasLegacyDb || hasLegacySessionsDir;
    } catch {
      return false;
    }
  }
  async load(range) {
    const currentMessagesRoot = join5(this.baseDir, "storage", "message");
    if (existsSync5(currentMessagesRoot)) {
      const currentRecords = loadFromCurrentStorage(this.baseDir, range);
      return buildProviderData2(currentRecords);
    }
    const opencodeDbPath = join5(this.baseDir, "opencode.db");
    const sessionsDbPath = join5(this.baseDir, "sessions.db");
    const sessionsDir = join5(this.baseDir, "sessions");
    let records = [];
    if (existsSync5(opencodeDbPath)) {
      records = loadFromSqlite(opencodeDbPath, range);
    } else if (existsSync5(sessionsDbPath)) {
      records = loadFromSqlite(sessionsDbPath, range);
    } else if (existsSync5(sessionsDir)) {
      records = loadFromLegacyJson(sessionsDir, range);
    }
    return buildProviderData2(records);
  }
}
var PROVIDER_NAME2 = "open-code", DISPLAY_NAME2 = "OpenCode", COLORS, CURRENT_DEFAULT_BASE_DIR, LEGACY_DEFAULT_BASE_DIR, CONFIG_DEFAULT_BASE_DIR;
var init_open_code = __esm(() => {
  init_normalizer();
  init_cost();
  COLORS = {
    primary: "#6366f1",
    secondary: "#a78bfa",
    gradient: ["#6366f1", "#a78bfa"]
  };
  CURRENT_DEFAULT_BASE_DIR = join5(homedir5(), ".local", "share", "opencode");
  LEGACY_DEFAULT_BASE_DIR = join5(homedir5(), ".opencode");
  CONFIG_DEFAULT_BASE_DIR = join5(homedir5(), ".config", "opencode");
});

// packages/registry/dist/providers/pi.js
import { existsSync as existsSync6 } from "fs";
import { readdir } from "fs/promises";
import { homedir as homedir6 } from "os";
import { join as join6, relative as relative4, sep as sep3 } from "path";
function resolveAgentDir(baseDir) {
  if (baseDir) {
    return baseDir;
  }
  return process.env["PI_CODING_AGENT_DIR"] ?? DEFAULT_AGENT_DIR;
}
function getSessionsDir(agentDir) {
  return join6(agentDir, "sessions");
}
async function collectJsonlFiles3(dir) {
  if (!existsSync6(dir)) {
    return [];
  }
  const files = [];
  for (const entry of await readdir(dir, { withFileTypes: true })) {
    const fullPath = join6(dir, entry.name);
    if (entry.isDirectory()) {
      files.push(...await collectJsonlFiles3(fullPath));
    } else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
      files.push(fullPath);
    }
  }
  return files;
}
function extractDate4(timestamp) {
  const match = /^(\d{4}-\d{2}-\d{2})/.exec(timestamp);
  return match ? match[1] : null;
}
function compactModelDateSuffix3(model) {
  return model.replace(DASHED_DATE_SUFFIX3, "-$1$2$3");
}
function toIsoTimestamp3(value) {
  if (typeof value === "string") {
    return extractDate4(value) ? value : null;
  }
  if (typeof value === "number") {
    const date = new Date(value);
    return Number.isNaN(date.getTime()) ? null : date.toISOString();
  }
  return null;
}
function toCachePricing5(pricing) {
  if (!pricing) {
    return;
  }
  return {
    input: pricing.input,
    cacheRead: pricing.cacheRead,
    cacheWrite: pricing.cacheWrite
  };
}
function isSessionHeader(record) {
  if (typeof record !== "object" || record === null) {
    return false;
  }
  return record["type"] === "session";
}
function parseUsageRecord2(record, fallbackProjectId, fallbackSessionId) {
  if (typeof record !== "object" || record === null) {
    return null;
  }
  const obj = record;
  if (obj["type"] !== "message") {
    return null;
  }
  const entryTimestamp = toIsoTimestamp3(obj["timestamp"]);
  const message = obj["message"];
  if (typeof message !== "object" || message === null) {
    return null;
  }
  const msg = message;
  if (msg["role"] !== "assistant") {
    return null;
  }
  const usage = msg["usage"];
  if (typeof usage !== "object" || usage === null) {
    return null;
  }
  const model = msg["model"];
  if (typeof model !== "string" || !model.trim()) {
    return null;
  }
  const usageObj = usage;
  const inputTokens = typeof usageObj["input"] === "number" ? usageObj["input"] : 0;
  const outputTokens = typeof usageObj["output"] === "number" ? usageObj["output"] : 0;
  const cacheReadTokens = typeof usageObj["cacheRead"] === "number" ? usageObj["cacheRead"] : 0;
  const cacheWriteTokens = typeof usageObj["cacheWrite"] === "number" ? usageObj["cacheWrite"] : 0;
  const totalTokens = inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens;
  if (totalTokens === 0) {
    return null;
  }
  const timestamp = entryTimestamp ?? toIsoTimestamp3(msg["timestamp"]);
  if (!timestamp) {
    return null;
  }
  const date = extractDate4(timestamp);
  if (!date) {
    return null;
  }
  const cost = typeof usageObj["cost"] === "object" && usageObj["cost"] !== null ? usageObj["cost"]["total"] : undefined;
  const normalizedModel = normalizeModelName2(compactModelDateSuffix3(model));
  return {
    date,
    timestamp,
    model,
    normalizedModel,
    inputTokens,
    outputTokens,
    cacheReadTokens,
    cacheWriteTokens,
    explicitCost: typeof cost === "number" ? cost : undefined,
    sessionId: fallbackSessionId,
    projectId: fallbackProjectId
  };
}
function getRecordCost3(record) {
  if (typeof record.explicitCost === "number" && Number.isFinite(record.explicitCost)) {
    return record.explicitCost;
  }
  return estimateCostBreakdown(record.normalizedModel, record.inputTokens, record.outputTokens, record.cacheReadTokens, record.cacheWriteTokens).totalCost;
}
function toUsageEvent3(record) {
  const totalTokens = record.inputTokens + record.outputTokens + record.cacheReadTokens + record.cacheWriteTokens;
  const pricing = toCachePricing5(estimateCostBreakdown(record.normalizedModel, record.inputTokens, record.outputTokens, record.cacheReadTokens, record.cacheWriteTokens).pricing);
  return {
    provider: PROVIDER_NAME3,
    timestamp: record.timestamp,
    date: record.date,
    model: record.normalizedModel,
    inputTokens: record.inputTokens,
    outputTokens: record.outputTokens,
    cacheReadTokens: record.cacheReadTokens,
    cacheWriteTokens: record.cacheWriteTokens,
    totalTokens,
    cost: getRecordCost3(record),
    pricing,
    sessionId: record.sessionId,
    projectId: record.projectId
  };
}
function buildProviderData3(records) {
  const byDate = new Map;
  const events = records.map(toUsageEvent3);
  for (const event of events) {
    let dateMap = byDate.get(event.date);
    if (!dateMap) {
      dateMap = new Map;
      byDate.set(event.date, dateMap);
    }
    const existing = dateMap.get(event.model);
    if (existing) {
      existing.inputTokens += event.inputTokens;
      existing.outputTokens += event.outputTokens;
      existing.cacheReadTokens += event.cacheReadTokens;
      existing.cacheWriteTokens += event.cacheWriteTokens;
      existing.totalTokens += event.totalTokens;
      existing.cost += event.cost;
      if (!existing.pricing && event.pricing) {
        existing.pricing = event.pricing;
      }
    } else {
      dateMap.set(event.model, {
        model: event.model,
        inputTokens: event.inputTokens,
        outputTokens: event.outputTokens,
        cacheReadTokens: event.cacheReadTokens,
        cacheWriteTokens: event.cacheWriteTokens,
        totalTokens: event.totalTokens,
        cost: event.cost,
        pricing: event.pricing
      });
    }
  }
  let totalTokens = 0;
  let totalCost = 0;
  const daily = [...byDate.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([date, modelMap]) => {
    const models = [...modelMap.values()];
    const inputTokens = models.reduce((sum, model) => sum + model.inputTokens, 0);
    const outputTokens = models.reduce((sum, model) => sum + model.outputTokens, 0);
    const cacheReadTokens = models.reduce((sum, model) => sum + model.cacheReadTokens, 0);
    const cacheWriteTokens = models.reduce((sum, model) => sum + model.cacheWriteTokens, 0);
    const dayTotal = inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens;
    const dayCost = models.reduce((sum, model) => sum + model.cost, 0);
    totalTokens += dayTotal;
    totalCost += dayCost;
    return {
      date,
      inputTokens,
      outputTokens,
      cacheReadTokens,
      cacheWriteTokens,
      totalTokens: dayTotal,
      cost: dayCost,
      models
    };
  });
  return {
    provider: PROVIDER_NAME3,
    displayName: DISPLAY_NAME3,
    daily,
    totalTokens,
    totalCost,
    colors: PI_COLORS,
    events: events.sort((a, b) => a.timestamp.localeCompare(b.timestamp))
  };
}

class PiProvider {
  name = PROVIDER_NAME3;
  displayName = DISPLAY_NAME3;
  colors = PI_COLORS;
  agentDir;
  constructor(baseDir) {
    this.agentDir = resolveAgentDir(baseDir);
  }
  async isAvailable() {
    try {
      return existsSync6(getSessionsDir(this.agentDir));
    } catch {
      return false;
    }
  }
  async load(range) {
    const sessionsDir = getSessionsDir(this.agentDir);
    const files = await collectJsonlFiles3(sessionsDir);
    const records = [];
    for (const file of files) {
      let projectId;
      const sessionId = relative4(sessionsDir, file).split(sep3).join("/");
      for await (const record of splitJsonlRecords(file)) {
        if (isSessionHeader(record)) {
          projectId = typeof record.cwd === "string" && record.cwd.trim() ? record.cwd : projectId;
          continue;
        }
        const usage = parseUsageRecord2(record, projectId, sessionId);
        if (usage !== null && isInRange(usage.date, range)) {
          records.push(usage);
        }
      }
    }
    return buildProviderData3(records);
  }
}
var PROVIDER_NAME3 = "pi", DISPLAY_NAME3 = "Pi", DEFAULT_AGENT_DIR, PI_COLORS, DASHED_DATE_SUFFIX3;
var init_pi = __esm(() => {
  init_jsonl_splitter();
  init_normalizer();
  init_cost();
  DEFAULT_AGENT_DIR = join6(homedir6(), ".pi", "agent");
  PI_COLORS = {
    primary: "#0ea5e9",
    secondary: "#67e8f9",
    gradient: ["#0ea5e9", "#67e8f9"]
  };
  DASHED_DATE_SUFFIX3 = /-(\d{4})-(\d{2})-(\d{2})$/;
});

// packages/registry/dist/providers/index.js
var init_providers = __esm(() => {
  init_claude_code();
  init_codex();
  init_cursor();
  init_open_code();
  init_pi();
});

// packages/registry/dist/cursor-auth.js
import { chmodSync, existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync4, readdirSync as readdirSync5, renameSync as renameSync2, rmSync as rmSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
import { createHash } from "crypto";
import { homedir as homedir7 } from "os";
import { basename as basename2, dirname as dirname4, join as join7 } from "path";
function getCursorRootDir() {
  return process.env["TOKENLEAK_CURSOR_DIR"] ?? join7(homedir7(), ".config", "tokenleak");
}
function getCursorCredentialsPath() {
  return join7(getCursorRootDir(), "cursor-credentials.json");
}
function getCursorCacheDir() {
  return join7(getCursorRootDir(), "cursor-cache");
}
function ensureDir(dirPath, mode) {
  if (!existsSync7(dirPath)) {
    mkdirSync2(dirPath, { recursive: true });
  }
  if (mode !== undefined && process.platform !== "win32") {
    chmodSync(dirPath, mode);
  }
}
function atomicWriteFile(path, contents, mode) {
  const dir = dirname4(path);
  ensureDir(dir);
  const tempPath = join7(dir, `.tmp-${basename2(path)}-${process.pid}`);
  writeFileSync2(tempPath, contents, "utf8");
  if (mode !== undefined && process.platform !== "win32") {
    chmodSync(tempPath, mode);
  }
  renameSync2(tempPath, path);
}
async function fetchWithTimeout(url, init) {
  const controller = new AbortController;
  const timeout = setTimeout(() => controller.abort(), CURSOR_FETCH_TIMEOUT_MS);
  try {
    return await fetch(url, {
      ...init,
      signal: controller.signal
    });
  } catch (error) {
    if (error instanceof Error && error.name === "AbortError") {
      throw new CursorAuthError(`Failed to connect: request timed out after ${CURSOR_FETCH_TIMEOUT_MS}ms`, "network");
    }
    throw error;
  } finally {
    clearTimeout(timeout);
  }
}
function buildCursorHeaders(sessionToken) {
  return {
    Accept: "*/*",
    "Accept-Language": "en-US,en;q=0.9",
    Cookie: `WorkosCursorSessionToken=${sessionToken}`,
    Referer: "https://www.cursor.com/settings",
    "User-Agent": `tokenleak/${VERSION} (+https://github.com/ya-nsh/tokenleak)`
  };
}
function sanitizeAccountIdForFilename(accountId) {
  const sanitized = accountId.trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
  return sanitized.length > 0 ? sanitized.slice(0, 80) : "account";
}
function extractUserIdFromSessionToken(token) {
  const trimmed = token.trim();
  if (trimmed.includes("%3A%3A")) {
    return trimmed.split("%3A%3A")[0]?.trim() || undefined;
  }
  if (trimmed.includes("::")) {
    return trimmed.split("::")[0]?.trim() || undefined;
  }
  return;
}
function deriveAccountId(sessionToken) {
  const userId = extractUserIdFromSessionToken(sessionToken);
  if (userId) {
    return userId;
  }
  const hash = createHash("sha256").update(sessionToken).digest("hex");
  return `anon-${hash.slice(0, 12)}`;
}
function countCursorCsvRows(csvText) {
  const rows = csvText.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
  return rows.length > 0 ? rows.length - 1 : 0;
}
function archiveCacheFile(path, label) {
  if (!existsSync7(path)) {
    return;
  }
  const archiveDir = join7(getCursorCacheDir(), "archive");
  ensureDir(archiveDir, 448);
  const timestamp = new Date().toISOString().replaceAll(":", "-");
  renameSync2(path, join7(archiveDir, `${sanitizeAccountIdForFilename(label)}-${timestamp}.csv`));
}
function resolveAccountId(store, nameOrId) {
  const needle = nameOrId.trim();
  if (!needle) {
    return;
  }
  if (store.accounts[needle]) {
    return needle;
  }
  const lowered = needle.toLowerCase();
  for (const [id, account] of Object.entries(store.accounts)) {
    if (account.label?.toLowerCase() === lowered) {
      return id;
    }
  }
  return;
}
function getActiveAccountMeta(store) {
  if (!store) {
    return {};
  }
  const active = store.accounts[store.activeAccountId];
  return {
    activeAccountId: store.activeAccountId,
    activeAccountLabel: active?.label
  };
}
function toFailureReason(error) {
  if (error instanceof CursorAuthError) {
    return error.code;
  }
  return "unknown";
}
function isCursorAuthFailureReason(reason) {
  return reason === "auth" || reason === "not_authenticated";
}
function loadCursorCredentialsStore() {
  const path = getCursorCredentialsPath();
  if (!existsSync7(path)) {
    return null;
  }
  try {
    const parsed = JSON.parse(readFileSync4(path, "utf8"));
    if (typeof parsed !== "object" || parsed === null || typeof parsed.activeAccountId !== "string" || typeof parsed.accounts !== "object" || parsed.accounts === null) {
      return null;
    }
    return {
      version: typeof parsed.version === "number" ? parsed.version : 1,
      activeAccountId: parsed.activeAccountId,
      accounts: parsed.accounts
    };
  } catch {
    return null;
  }
}
function saveCursorCredentialsStore(store) {
  ensureDir(getCursorRootDir(), 448);
  atomicWriteFile(getCursorCredentialsPath(), `${JSON.stringify(store, null, 2)}
`, process.platform === "win32" ? undefined : 384);
}
function listCursorAccounts() {
  const store = loadCursorCredentialsStore();
  if (!store) {
    return [];
  }
  return Object.entries(store.accounts).map(([id, account]) => ({
    id,
    label: account.label,
    userId: account.userId,
    createdAt: account.createdAt,
    isActive: id === store.activeAccountId
  })).sort((left, right) => {
    if (left.isActive !== right.isActive) {
      return left.isActive ? -1 : 1;
    }
    return (left.label ?? left.id).localeCompare(right.label ?? right.id);
  });
}
function hasCursorUsageCache() {
  const cacheDir = getCursorCacheDir();
  if (!existsSync7(cacheDir)) {
    return false;
  }
  return readdirSync5(cacheDir).some((entry) => {
    if (entry === "archive") {
      return false;
    }
    return entry === "usage.csv" || /^usage\.[^.].*\.csv$/.test(entry);
  });
}
function isCursorLoggedIn() {
  const store = loadCursorCredentialsStore();
  return store !== null && Object.keys(store.accounts).length > 0;
}
function saveCursorCredentials(token, label) {
  const accountId = deriveAccountId(token);
  const store = loadCursorCredentialsStore() ?? {
    version: 1,
    activeAccountId: accountId,
    accounts: {}
  };
  const normalizedLabel = label?.trim();
  if (normalizedLabel) {
    for (const [id, account] of Object.entries(store.accounts)) {
      if (id === accountId) {
        continue;
      }
      if (account.label?.trim().toLowerCase() === normalizedLabel.toLowerCase()) {
        throw new CursorAuthError(`Cursor account label already exists: ${normalizedLabel}`);
      }
    }
  }
  store.accounts[accountId] = {
    sessionToken: token,
    userId: extractUserIdFromSessionToken(token),
    createdAt: new Date().toISOString(),
    label: normalizedLabel
  };
  store.activeAccountId = accountId;
  saveCursorCredentialsStore(store);
  return accountId;
}
function removeCursorAccount(nameOrId, purgeCache) {
  const store = loadCursorCredentialsStore();
  if (!store) {
    throw new CursorAuthError("No saved Cursor accounts");
  }
  const accountId = resolveAccountId(store, nameOrId);
  if (!accountId) {
    throw new CursorAuthError(`Account not found: ${nameOrId}`);
  }
  const wasActive = accountId === store.activeAccountId;
  const cacheDir = getCursorCacheDir();
  const accountCachePath = join7(cacheDir, `usage.${sanitizeAccountIdForFilename(accountId)}.csv`);
  const activeCachePath = join7(cacheDir, "usage.csv");
  if (existsSync7(accountCachePath)) {
    if (purgeCache) {
      unlinkSync(accountCachePath);
    } else {
      archiveCacheFile(accountCachePath, `usage.${accountId}`);
    }
  }
  if (wasActive && existsSync7(activeCachePath)) {
    if (purgeCache) {
      unlinkSync(activeCachePath);
    } else {
      archiveCacheFile(activeCachePath, `usage.active.${accountId}`);
    }
  }
  delete store.accounts[accountId];
  const remainingIds = Object.keys(store.accounts);
  if (remainingIds.length === 0) {
    if (existsSync7(getCursorCredentialsPath())) {
      unlinkSync(getCursorCredentialsPath());
    }
    return;
  }
  if (wasActive) {
    const nextAccountId = remainingIds[0];
    store.activeAccountId = nextAccountId;
    const nextCachePath = join7(cacheDir, `usage.${sanitizeAccountIdForFilename(nextAccountId)}.csv`);
    if (existsSync7(nextCachePath)) {
      renameSync2(nextCachePath, activeCachePath);
    }
  }
  saveCursorCredentialsStore(store);
}
function removeAllCursorAccounts(purgeCache) {
  const cacheDir = getCursorCacheDir();
  if (existsSync7(cacheDir)) {
    for (const entry of readdirSync5(cacheDir)) {
      if (entry === "archive") {
        if (purgeCache) {
          rmSync2(join7(cacheDir, entry), { recursive: true, force: true });
        }
        continue;
      }
      if (entry === "usage.csv" || /^usage\.[^.].*\.csv$/.test(entry)) {
        const fullPath = join7(cacheDir, entry);
        if (purgeCache) {
          rmSync2(fullPath, { force: true });
        } else {
          archiveCacheFile(fullPath, `usage.all.${entry}`);
        }
      }
    }
  }
  if (existsSync7(getCursorCredentialsPath())) {
    unlinkSync(getCursorCredentialsPath());
  }
}
function resetCursorProviderState() {
  removeAllCursorAccounts(true);
}
function setActiveCursorAccount(nameOrId) {
  const store = loadCursorCredentialsStore();
  if (!store) {
    throw new CursorAuthError("No saved Cursor accounts");
  }
  const accountId = resolveAccountId(store, nameOrId);
  if (!accountId) {
    throw new CursorAuthError(`Account not found: ${nameOrId}`);
  }
  if (accountId === store.activeAccountId) {
    return;
  }
  const cacheDir = getCursorCacheDir();
  const activeCachePath = join7(cacheDir, "usage.csv");
  const oldActivePath = join7(cacheDir, `usage.${sanitizeAccountIdForFilename(store.activeAccountId)}.csv`);
  const newActivePath = join7(cacheDir, `usage.${sanitizeAccountIdForFilename(accountId)}.csv`);
  if (existsSync7(activeCachePath)) {
    if (existsSync7(oldActivePath)) {
      archiveCacheFile(oldActivePath, `usage.${store.activeAccountId}`);
    }
    renameSync2(activeCachePath, oldActivePath);
  }
  if (existsSync7(newActivePath)) {
    renameSync2(newActivePath, activeCachePath);
  }
  store.activeAccountId = accountId;
  saveCursorCredentialsStore(store);
}
function getActiveCursorCredentials() {
  const store = loadCursorCredentialsStore();
  if (!store) {
    return null;
  }
  return store.accounts[store.activeAccountId] ?? null;
}
function getCursorCredentialsFor(nameOrId) {
  const store = loadCursorCredentialsStore();
  if (!store) {
    return null;
  }
  const accountId = resolveAccountId(store, nameOrId);
  return accountId ? store.accounts[accountId] ?? null : null;
}
async function validateCursorSession(sessionToken) {
  let response;
  try {
    response = await fetchWithTimeout(CURSOR_USAGE_SUMMARY_ENDPOINT, {
      headers: buildCursorHeaders(sessionToken)
    });
  } catch (error) {
    return {
      valid: false,
      error: `Failed to connect: ${error instanceof Error ? error.message : String(error)}`,
      reason: "network"
    };
  }
  if (response.status === 401 || response.status === 403) {
    return {
      valid: false,
      error: "Session token expired or invalid",
      reason: "auth"
    };
  }
  if (!response.ok) {
    return {
      valid: false,
      error: `API returned status ${response.status}`,
      reason: "api"
    };
  }
  try {
    const payload = await response.json();
    const billingCycleStart = payload["billingCycleStart"];
    const billingCycleEnd = payload["billingCycleEnd"];
    if (typeof billingCycleStart !== "string" || typeof billingCycleEnd !== "string") {
      return {
        valid: false,
        error: "Invalid response format",
        reason: "parse"
      };
    }
    return {
      valid: true,
      membershipType: typeof payload["membershipType"] === "string" ? payload["membershipType"] : undefined
    };
  } catch (error) {
    return {
      valid: false,
      error: `Failed to parse response: ${error instanceof Error ? error.message : String(error)}`,
      reason: "parse"
    };
  }
}
async function fetchCursorUsageCsv(sessionToken) {
  let response;
  try {
    response = await fetchWithTimeout(CURSOR_USAGE_CSV_ENDPOINT, {
      headers: buildCursorHeaders(sessionToken)
    });
  } catch (error) {
    if (error instanceof CursorAuthError) {
      throw error;
    }
    throw new CursorAuthError(`Failed to connect: ${error instanceof Error ? error.message : String(error)}`, "network");
  }
  if (response.status === 401 || response.status === 403) {
    throw new CursorAuthError("Cursor session expired. Please run 'tokenleak cursor login' to re-authenticate.", "auth");
  }
  if (!response.ok) {
    throw new CursorAuthError(`Cursor API returned status ${response.status}`, "api");
  }
  const text = await response.text();
  if (!text.startsWith("Date,")) {
    throw new CursorAuthError("Invalid response from Cursor API - expected CSV format", "parse");
  }
  return text;
}
async function syncCursorCache() {
  const store = loadCursorCredentialsStore();
  if (!store || Object.keys(store.accounts).length === 0) {
    return { synced: false, rows: 0, error: "Not authenticated", reason: "not_authenticated" };
  }
  const cacheDir = getCursorCacheDir();
  ensureDir(cacheDir, 448);
  let totalRows = 0;
  let successCount = 0;
  const errors = [];
  let activeAccountSynced = false;
  let activeAccountFailure = null;
  for (const [accountId, credentials] of Object.entries(store.accounts)) {
    try {
      const csvText = await fetchCursorUsageCsv(credentials.sessionToken);
      const filePath = accountId === store.activeAccountId ? join7(cacheDir, "usage.csv") : join7(cacheDir, `usage.${sanitizeAccountIdForFilename(accountId)}.csv`);
      atomicWriteFile(filePath, csvText, process.platform === "win32" ? undefined : 384);
      if (accountId === store.activeAccountId) {
        const activeDupPath = join7(cacheDir, `usage.${sanitizeAccountIdForFilename(store.activeAccountId)}.csv`);
        if (existsSync7(activeDupPath)) {
          unlinkSync(activeDupPath);
        }
      }
      successCount += 1;
      totalRows += countCursorCsvRows(csvText);
      if (accountId === store.activeAccountId) {
        activeAccountSynced = true;
      }
    } catch (error) {
      const failure = {
        accountId,
        message: error instanceof Error ? error.message : String(error),
        reason: toFailureReason(error)
      };
      errors.push(failure);
      if (accountId === store.activeAccountId) {
        activeAccountFailure = {
          message: failure.message,
          reason: failure.reason
        };
      }
    }
  }
  if (successCount === 0 || !activeAccountSynced) {
    return {
      synced: false,
      rows: 0,
      error: activeAccountFailure?.message ?? errors[0]?.message ?? "Cursor sync failed",
      reason: activeAccountFailure?.reason ?? errors[0]?.reason ?? "unknown",
      activeAccountSynced
    };
  }
  return {
    synced: true,
    rows: totalRows,
    error: errors.length > 0 ? `Some accounts failed to sync (${errors.length}/${Object.keys(store.accounts).length})` : undefined,
    reason: errors.length > 0 ? "partial" : undefined,
    activeAccountSynced
  };
}
async function shouldSyncCursorForRun(config) {
  const hasProviderFilter = Boolean(config.provider || config.cursor || config.claude || config.codex || config.pi || config.openCode);
  const requestedCursor = config.cursor || (config.provider?.split(",").some((token) => {
    const normalized = token.trim().toLowerCase().replace(/\s+/g, "-");
    return normalized === "cursor" || normalized === "cursor-ide" || normalized === "cursoride";
  }) ?? false);
  if (!isCursorLoggedIn()) {
    return { attempted: false };
  }
  if (!requestedCursor && hasProviderFilter && !config.allProviders) {
    return { attempted: false };
  }
  const result = await syncCursorCache();
  return {
    attempted: true,
    error: result.error
  };
}
async function resolveCursorSetupStatus(options = {}) {
  const store = loadCursorCredentialsStore();
  const hasCredentials = Boolean(store && Object.keys(store.accounts).length > 0);
  const hasCache = hasCursorUsageCache();
  const activeMeta = getActiveAccountMeta(store);
  if (!hasCredentials) {
    return {
      state: hasCache ? "ready" : "needs_auth",
      hasCredentials,
      hasCache,
      ...activeMeta
    };
  }
  if (!options.attemptSync) {
    return {
      state: hasCache ? "ready" : "needs_sync",
      hasCredentials,
      hasCache,
      ...activeMeta
    };
  }
  const syncResult = await syncCursorCache();
  const nextHasCache = hasCursorUsageCache();
  if (syncResult.synced) {
    return {
      state: "ready",
      hasCredentials,
      hasCache: nextHasCache,
      error: syncResult.error,
      reason: syncResult.reason,
      ...activeMeta
    };
  }
  if (isCursorAuthFailureReason(syncResult.reason)) {
    return {
      state: "needs_reauth",
      hasCredentials,
      hasCache: nextHasCache,
      error: syncResult.error,
      reason: syncResult.reason,
      ...activeMeta
    };
  }
  return {
    state: nextHasCache ? "sync_failed_cached" : "needs_sync",
    hasCredentials,
    hasCache: nextHasCache,
    error: syncResult.error,
    reason: syncResult.reason,
    ...activeMeta
  };
}
var CURSOR_USAGE_CSV_ENDPOINT = "https://cursor.com/api/dashboard/export-usage-events-csv?strategy=tokens", CURSOR_USAGE_SUMMARY_ENDPOINT = "https://cursor.com/api/usage-summary", CursorAuthError, CURSOR_FETCH_TIMEOUT_MS = 1e4;
var init_cursor_auth = __esm(() => {
  init_dist();
  CursorAuthError = class CursorAuthError extends Error {
    code;
    constructor(message, code = "unknown") {
      super(message);
      this.name = "CursorAuthError";
      this.code = code;
    }
  };
});

// packages/registry/dist/index.js
var init_dist2 = __esm(() => {
  init_models();
  init_registry();
  init_parsers();
  init_providers();
  init_cursor_auth();
});

// packages/renderers/dist/json/json-renderer.js
class JsonRenderer {
  format = "json";
  async render(output, _options) {
    return JSON.stringify(output, null, 2);
  }
}

// packages/renderers/dist/json/index.js
var init_json = () => {};

// packages/renderers/dist/svg/utils.js
function escapeXml(str) {
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
}
function rect(x, y, w, h, fill, rx) {
  const rxAttr = rx !== undefined ? ` rx="${rx}"` : "";
  return `<rect x="${x}" y="${y}" width="${w}" height="${h}" fill="${escapeXml(fill)}"${rxAttr}/>`;
}
function text(x, y, content, attrs) {
  const attrStr = attrs ? Object.entries(attrs).map(([k, v]) => ` ${k}="${typeof v === "string" ? escapeXml(v) : v}"`).join("") : "";
  return `<text x="${x}" y="${y}"${attrStr}>${escapeXml(content)}</text>`;
}
function formatNumber(n) {
  if (n >= 1e6) {
    const millions = Number((n / 1e6).toFixed(1));
    if (millions >= 1000) {
      return `${(n / 1e9).toFixed(1)}B`;
    }
    return `${millions.toFixed(1)}M`;
  }
  if (n >= 1000) {
    const thousands = Number((n / 1000).toFixed(1));
    if (thousands >= 1000) {
      return `${(n / 1e6).toFixed(1)}M`;
    }
    return `${thousands.toFixed(1)}K`;
  }
  return n.toFixed(0);
}
function formatCost2(cost) {
  if (cost >= 100) {
    return `$${cost.toFixed(0)}`;
  }
  if (cost >= 1) {
    return `$${cost.toFixed(2)}`;
  }
  return `$${cost.toFixed(4)}`;
}

// packages/renderers/dist/card/layout.js
var CARD_PADDING = 48, TITLEBAR_HEIGHT = 48, DOT_RADIUS = 6, DOT_GAP = 8, CELL_SIZE = 16, CELL_GAP = 4, STAT_GRID_COLS = 3, MODEL_BAR_HEIGHT = 11, DAY_LABEL_WIDTH = 44, MONTH_LABEL_HEIGHT = 24, PROVIDER_SECTION_GAP = 36, MIN_CONTENT_WIDTH = 700, MODEL_NAME_WIDTH = 220, MODEL_BAR_GAP = 36, MODEL_PERCENT_WIDTH = 40;

// packages/renderers/dist/png/terminal-card.js
function getCardTheme(mode) {
  if (mode === "dark") {
    return {
      bg: "#09090b",
      fg: "#f0f0f0",
      muted: "#6b7280",
      labelFg: "#b0b8c4",
      border: "rgba(255,255,255,0.08)",
      accent: "#34d399",
      heatmapEmpty: "#1a1a22",
      barTrack: "#151520",
      titlebarBorder: "rgba(255,255,255,0.08)"
    };
  }
  return {
    bg: "#fafafa",
    fg: "#18181b",
    muted: "#a1a1aa",
    labelFg: "#71717a",
    border: "rgba(0,0,0,0.08)",
    accent: "#059669",
    heatmapEmpty: "#e4e4e7",
    barTrack: "#e5e5e5",
    titlebarBorder: "rgba(0,0,0,0.08)"
  };
}
function buildHeatmapScale(colors, isDark) {
  const [startHex, endHex] = colors.gradient;
  const s = hexToRgb(startHex);
  const e = hexToRgb(endHex);
  const opacities = isDark ? [0.25, 0.5, 0.75, 1] : [0.2, 0.4, 0.65, 1];
  return [
    "transparent",
    ...opacities.map((t) => {
      const r = Math.round(s.r + (e.r - s.r) * t);
      const g = Math.round(s.g + (e.g - s.g) * t);
      const b = Math.round(s.b + (e.b - s.b) * t);
      return rgbToHex(r, g, b);
    })
  ];
}
function hexToRgb(hex) {
  const h = hex.replace("#", "");
  return {
    r: parseInt(h.slice(0, 2), 16),
    g: parseInt(h.slice(2, 4), 16),
    b: parseInt(h.slice(4, 6), 16)
  };
}
function rgbToHex(r, g, b) {
  const toHex = (n) => n.toString(16).padStart(2, "0");
  return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
function computeQuantiles(values) {
  const nonZero = values.filter((v) => v > 0).sort((a, b) => a - b);
  if (nonZero.length === 0)
    return [0, 0, 0];
  const q = (p) => {
    const idx = Math.floor(p * (nonZero.length - 1));
    return nonZero[idx] ?? 0;
  };
  return [q(0.25), q(0.5), q(0.75)];
}
function getLevel(tokens, quantiles) {
  if (tokens <= 0)
    return 0;
  if (tokens <= quantiles[0])
    return 1;
  if (tokens <= quantiles[1])
    return 2;
  if (tokens <= quantiles[2])
    return 3;
  return 4;
}
function formatDateRange(since, until) {
  const s = new Date(since + "T00:00:00Z");
  const u = new Date(until + "T00:00:00Z");
  const diffMs = u.getTime() - s.getTime();
  const days = Math.round(diffMs / (1000 * 60 * 60 * 24));
  const sMonth = MONTH_NAMES_FULL[s.getUTCMonth()] ?? "";
  const uMonth = MONTH_NAMES_FULL[u.getUTCMonth()] ?? "";
  return `${sMonth} ${s.getUTCFullYear()} \u2014 ${uMonth} ${u.getUTCFullYear()} \xB7 ${days} DAYS`;
}
function formatPercentage(rate) {
  return `${(rate * 100).toFixed(1)}%`;
}
function formatStreak(n) {
  return `${n} day${n !== 1 ? "s" : ""}`;
}
function formatRatio(value, suffix = "x") {
  if (value === null || !Number.isFinite(value)) {
    return "n/a";
  }
  return `${value.toFixed(value >= 10 ? 1 : 2)}${suffix}`;
}
function formatPercentPoints(value) {
  const prefix = value >= 0 ? "+" : "";
  return `${prefix}${(value * 100).toFixed(1)}pp`;
}
function formatHour(hour) {
  return `${hour.toString().padStart(2, "0")}:00`;
}
function formatDuration2(durationMs) {
  if (durationMs === null || durationMs === undefined || durationMs <= 0) {
    return "n/a";
  }
  const totalMinutes = Math.round(durationMs / 60000);
  if (totalMinutes < 60) {
    return `${totalMinutes}m`;
  }
  const hours = Math.floor(totalMinutes / 60);
  const minutes = totalMinutes % 60;
  return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
}
function truncateText(value, maxLength) {
  return value.length > maxLength ? `${value.slice(0, maxLength - 1)}\u2026` : value;
}
function formatSessionSummary(summary) {
  const duration = formatDuration2(summary.durationMs);
  if (duration === "n/a") {
    return truncateText(summary.label, 20);
  }
  return truncateText(`${summary.label} \xB7 ${duration}`, 24);
}
function renderProviderHeatmap(daily, since, until, heatmapColors, emptyColor) {
  const tokenMap = new Map;
  for (const d of daily) {
    tokenMap.set(d.date, (tokenMap.get(d.date) ?? 0) + d.totalTokens);
  }
  const dates = daily.map((d) => d.date).sort();
  const endStr = until ?? dates[dates.length - 1] ?? new Date().toISOString().slice(0, 10);
  const startStr = since ?? dates[0] ?? endStr;
  const end = new Date(endStr + "T00:00:00Z");
  const start = new Date(startStr + "T00:00:00Z");
  start.setUTCDate(start.getUTCDate() - start.getUTCDay());
  const allTokens = Array.from(tokenMap.values());
  const quantiles = computeQuantiles(allTokens);
  const cells = [];
  const monthLabels = [];
  let lastMonth = -1;
  let col = 0;
  const current = new Date(start);
  while (current <= end) {
    const row = current.getUTCDay();
    const dateStr = current.toISOString().slice(0, 10);
    const tokens = tokenMap.get(dateStr) ?? 0;
    const level = getLevel(tokens, quantiles);
    const x = DAY_LABEL_WIDTH + col * (CELL_SIZE + CELL_GAP);
    const y = MONTH_LABEL_HEIGHT + row * (CELL_SIZE + CELL_GAP);
    const fill = level === 0 ? emptyColor : heatmapColors[level];
    const title = `${dateStr}: ${tokens.toLocaleString()} tokens`;
    cells.push(`<rect x="${x}" y="${y}" width="${CELL_SIZE}" height="${CELL_SIZE}" fill="${escapeXml(fill)}" rx="3"><title>${escapeXml(title)}</title></rect>`);
    const month = current.getUTCMonth();
    if (month !== lastMonth && row === 0) {
      lastMonth = month;
      monthLabels.push(`<text x="${x}" y="${MONTH_LABEL_HEIGHT - 8}" fill="__MUTED__" font-size="11" font-family="${escapeXml(FONT_FAMILY)}">${escapeXml(MONTH_NAMES[month] ?? "")}</text>`);
    }
    if (row === 6)
      col++;
    current.setUTCDate(current.getUTCDate() + 1);
  }
  const dayLabels = [
    { label: "Sun", row: 0 },
    { label: "Mon", row: 1 },
    { label: "Tue", row: 2 },
    { label: "Wed", row: 3 },
    { label: "Thu", row: 4 },
    { label: "Fri", row: 5 },
    { label: "Sat", row: 6 }
  ].map((d) => {
    const y = MONTH_LABEL_HEIGHT + d.row * (CELL_SIZE + CELL_GAP) + CELL_SIZE - 2;
    return `<text x="0" y="${y}" fill="__MUTED__" font-size="11" font-family="${escapeXml(FONT_FAMILY)}">${escapeXml(d.label)}</text>`;
  }).join("");
  const totalCols = col + 1;
  const gridWidth = DAY_LABEL_WIDTH + totalCols * (CELL_SIZE + CELL_GAP);
  const height = MONTH_LABEL_HEIGHT + 7 * (CELL_SIZE + CELL_GAP);
  const svg = [dayLabels, ...monthLabels, ...cells].join(`
`);
  return { svg, gridWidth, height };
}
function renderSectionHeader(x, y, title, theme, cardAccent) {
  const parts = [];
  parts.push(`<rect x="${x}" y="${y - 8}" width="3" height="10" rx="1.5" fill="${escapeXml(cardAccent)}" opacity="0.6"/>`);
  parts.push(`<text x="${x + 12}" y="${y}" fill="${escapeXml(theme.labelFg)}" font-size="11" font-family="${escapeXml(FONT_FAMILY)}" font-weight="700" letter-spacing="1.8">${escapeXml(title)}</text>`);
  return parts.join(`
`);
}
function renderMetricCard(x, y, width, title, lines, theme, cardAccent) {
  const parts = [];
  const height = 38 + lines.length * 22;
  parts.push(`<rect x="${x}" y="${y}" width="${width}" height="${height}" rx="10" fill="${escapeXml(theme.barTrack)}" stroke="${escapeXml(theme.border)}" stroke-width="1"/>`);
  parts.push(`<text x="${x + 18}" y="${y + 22}" fill="${escapeXml(theme.labelFg)}" font-size="10" font-family="${escapeXml(FONT_FAMILY)}" font-weight="700" letter-spacing="1.6">${escapeXml(title)}</text>`);
  lines.forEach((line, index) => {
    const lineY = y + 48 + index * 22;
    parts.push(`<text x="${x + 18}" y="${lineY}" fill="${escapeXml(theme.fg)}" font-size="11" font-family="${escapeXml(FONT_FAMILY)}" font-weight="600">${escapeXml(line.label)}</text>`);
    parts.push(`<text x="${x + width - 18}" y="${lineY}" fill="${escapeXml(line.accent ? cardAccent : theme.fg)}" font-size="12" font-family="${escapeXml(FONT_FAMILY)}" font-weight="700" text-anchor="end">${escapeXml(line.value)}</text>`);
  });
  return parts.join(`
`);
}
function buildProviderHourBuckets(providers) {
  return providers.map((p) => {
    const hours = new Array(24).fill(0);
    for (const event of p.events ?? []) {
      const date = new Date(event.timestamp);
      if (!Number.isNaN(date.getTime())) {
        const h = date.getUTCHours();
        hours[h] += event.totalTokens;
      }
    }
    return { provider: p.provider, color: p.colors.primary, hours };
  });
}
function renderHourOfDayChart(x, y, width, hourOfDay, theme, cardAccent, providers, isDark) {
  const chartHeight = 140;
  const innerHeight = 72;
  const baselineY = y + 92;
  const barAreaX = x + 18;
  const barAreaWidth = width - 36;
  const barGap = 4;
  const barWidth = (barAreaWidth - barGap * 23) / 24;
  const maxTokens = Math.max(...hourOfDay.map((entry) => entry.tokens), 0);
  const busiest = hourOfDay.reduce((best, entry) => best === null || entry.tokens > best.tokens ? entry : best, null);
  const isMulti = providers.length > 1;
  const providerBuckets = isMulti ? buildProviderHourBuckets(providers) : [];
  let legendSvg = "";
  if (isMulti && providerBuckets.length > 0) {
    const titleWidth = 105;
    let legendX = x + 18 + titleWidth + 12;
    const legendY = y + 22;
    for (const bucket of providerBuckets) {
      const displayName = providers.find((p) => p.provider === bucket.provider)?.displayName ?? bucket.provider;
      legendSvg += `<rect x="${legendX}" y="${legendY - 8}" width="8" height="8" rx="2" fill="${escapeXml(bucket.color)}" opacity="0.85"/>` + `<text x="${legendX + 12}" y="${legendY - 1}" fill="${escapeXml(theme.fg)}" font-size="9" font-family="${escapeXml(FONT_FAMILY)}" font-weight="600">${escapeXml(displayName)}</text>`;
      legendX += 12 + displayName.length * 5.5 + 16;
    }
  }
  const bars = [
    `<rect x="${x}" y="${y}" width="${width}" height="${chartHeight}" rx="10" fill="${escapeXml(theme.barTrack)}" stroke="${escapeXml(theme.border)}" stroke-width="1"/>`,
    `<text x="${x + 18}" y="${y + 22}" fill="${escapeXml(theme.labelFg)}" font-size="10" font-family="${escapeXml(FONT_FAMILY)}" font-weight="700" letter-spacing="1.6">HOUR OF DAY</text>`,
    legendSvg,
    `<text x="${x + width - 18}" y="${y + 22}" fill="${escapeXml(theme.labelFg)}" font-size="11" font-family="${escapeXml(FONT_FAMILY)}" font-weight="500" text-anchor="end">${escapeXml(busiest ? `${formatHour(busiest.hour)} peak` : "No session events")}</text>`,
    `<line x1="${barAreaX}" y1="${baselineY}" x2="${barAreaX + barAreaWidth}" y2="${baselineY}" stroke="${escapeXml(theme.border)}" stroke-width="1"/>`
  ];
  bars.push(`<defs><filter id="peakGlow" x="-50%" y="-50%" width="200%" height="200%">` + `<feGaussianBlur stdDeviation="4" result="blur"/>` + `<feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>` + `</filter></defs>`);
  if (isMulti) {
    const provBaseOpacity = isDark ? "0.45" : "0.3";
    const provMidOpacity = isDark ? "0.85" : "0.75";
    for (let bi = 0;bi < providerBuckets.length; bi++) {
      const gradId = `hod-prov-${bi}`;
      bars.push(`<defs><linearGradient id="${escapeXml(gradId)}" x1="0%" y1="100%" x2="0%" y2="0%">` + `<stop offset="0%" stop-color="${escapeXml(providerBuckets[bi].color)}" stop-opacity="${provBaseOpacity}"/>` + `<stop offset="60%" stop-color="${escapeXml(providerBuckets[bi].color)}" stop-opacity="${provMidOpacity}"/>` + `<stop offset="100%" stop-color="${escapeXml(providerBuckets[bi].color)}" stop-opacity="1"/>` + `</linearGradient></defs>`);
    }
    hourOfDay.forEach((entry, index) => {
      if (entry.tokens <= 0)
        return;
      const totalRatio = entry.tokens / maxTokens;
      const totalBarHeight = Math.max(4, totalRatio * innerHeight);
      const colX = barAreaX + index * (barWidth + barGap);
      const isPeak = busiest !== null && entry.hour === busiest.hour;
      if (isPeak) {
        const topY2 = baselineY - totalBarHeight;
        bars.push(`<rect x="${colX - 2}" y="${topY2 - 2}" width="${barWidth + 4}" height="${totalBarHeight + 4}" rx="5" fill="${escapeXml(providerBuckets[0]?.color ?? cardAccent)}" opacity="0.12" filter="url(#peakGlow)"/>`);
      }
      const clipId = `hod-clip-${index}`;
      const topY = baselineY - totalBarHeight;
      bars.push(`<defs><clipPath id="${escapeXml(clipId)}">` + `<rect x="${colX}" y="${topY}" width="${barWidth}" height="${totalBarHeight}" rx="3"/>` + `</clipPath></defs>`);
      let offsetY = 0;
      for (let bi = 0;bi < providerBuckets.length; bi++) {
        const tokens = providerBuckets[bi].hours[index] ?? 0;
        if (tokens <= 0)
          continue;
        const segHeight = tokens / entry.tokens * totalBarHeight;
        const segY = baselineY - offsetY - segHeight;
        bars.push(`<rect x="${colX}" y="${segY}" width="${barWidth}" height="${segHeight}" fill="url(#hod-prov-${bi})" clip-path="url(#${escapeXml(clipId)})"/>`);
        offsetY += segHeight;
      }
    });
  } else {
    const hodGradId = "hod-bar-grad";
    const hodBaseOpacity = isDark ? "0.25" : "0.1";
    const hodMidOpacity = isDark ? "0.75" : "0.6";
    bars.push(`<defs><linearGradient id="${escapeXml(hodGradId)}" x1="0%" y1="100%" x2="0%" y2="0%">` + `<stop offset="0%" stop-color="${escapeXml(cardAccent)}" stop-opacity="${hodBaseOpacity}"/>` + `<stop offset="40%" stop-color="${escapeXml(cardAccent)}" stop-opacity="${hodMidOpacity}"/>` + `<stop offset="100%" stop-color="${escapeXml(cardAccent)}" stop-opacity="1"/>` + `</linearGradient></defs>`);
    hourOfDay.forEach((entry, index) => {
      const ratio = maxTokens > 0 ? entry.tokens / maxTokens : 0;
      const barHeight = maxTokens > 0 ? Math.max(4, ratio * innerHeight) : 4;
      const colX = barAreaX + index * (barWidth + barGap);
      const colY = baselineY - barHeight;
      const isPeak = busiest !== null && entry.hour === busiest.hour && entry.tokens > 0;
      if (isPeak) {
        bars.push(`<rect x="${colX - 2}" y="${colY - 2}" width="${barWidth + 4}" height="${barHeight + 4}" rx="5" fill="${escapeXml(cardAccent)}" opacity="0.15" filter="url(#peakGlow)"/>`);
      }
      bars.push(`<rect x="${colX}" y="${colY}" width="${barWidth}" height="${barHeight}" rx="3" fill="url(#${escapeXml(hodGradId)})" opacity="${0.35 + ratio * 0.65}"/>`);
    });
  }
  [0, 3, 6, 9, 12, 15, 18, 21].forEach((hour) => {
    const labelX = barAreaX + hour * (barWidth + barGap) + barWidth / 2;
    bars.push(`<text x="${labelX}" y="${y + 116}" fill="${escapeXml(theme.labelFg)}" font-size="9" font-family="${escapeXml(FONT_FAMILY)}" font-weight="500" text-anchor="middle">${escapeXml(hour.toString().padStart(2, "0"))}</text>`);
  });
  return {
    svg: bars.join(`
`),
    height: chartHeight
  };
}
function renderModelMixShift(x, y, width, more, theme, cardAccent) {
  if (!more.compare || more.compare.modelMixShift.length === 0) {
    return { svg: "", height: 0 };
  }
  const rows = more.compare.modelMixShift.slice(0, 4);
  const height = 38 + rows.length * 24;
  const parts = [
    `<rect x="${x}" y="${y}" width="${width}" height="${height}" rx="10" fill="${escapeXml(theme.barTrack)}" stroke="${escapeXml(theme.border)}" stroke-width="1"/>`,
    `<text x="${x + 18}" y="${y + 22}" fill="${escapeXml(theme.labelFg)}" font-size="10" font-family="${escapeXml(FONT_FAMILY)}" font-weight="700" letter-spacing="1.6">MODEL MIX SHIFT</text>`,
    `<text x="${x + width - 18}" y="${y + 22}" fill="${escapeXml(theme.labelFg)}" font-size="11" font-family="${escapeXml(FONT_FAMILY)}" font-weight="500" text-anchor="end">${escapeXml(`${more.compare.previousRange.since} \u2192 ${more.compare.previousRange.until}`)}</text>`
  ];
  rows.forEach((row, index) => {
    const lineY = y + 48 + index * 24;
    parts.push(`<text x="${x + 18}" y="${lineY}" fill="${escapeXml(theme.fg)}" font-size="12" font-family="${escapeXml(FONT_FAMILY)}" font-weight="600">${escapeXml(truncateText(row.model, 28))}</text>`);
    parts.push(`<text x="${x + width - 18}" y="${lineY}" fill="${escapeXml(row.deltaShare >= 0 ? cardAccent : "#f97316")}" font-size="12" font-family="${escapeXml(FONT_FAMILY)}" font-weight="700" text-anchor="end">${escapeXml(formatPercentPoints(row.deltaShare))}</text>`);
    parts.push(`<text x="${x + width - 110}" y="${lineY}" fill="${escapeXml(theme.labelFg)}" font-size="11" font-family="${escapeXml(FONT_FAMILY)}" font-weight="500" text-anchor="end">${escapeXml(`${(row.previousShare * 100).toFixed(1)}% \u2192 ${(row.currentShare * 100).toFixed(1)}%`)}</text>`);
  });
  return { svg: parts.join(`
`), height };
}
function renderTerminalCardSvg(output, options) {
  const theme = getCardTheme(options.theme);
  const isDark = options.theme === "dark";
  const pad = CARD_PADDING;
  const stats = output.aggregated;
  const { since, until } = output.dateRange;
  const providers = output.providers;
  const cardAccent = providers.length === 1 ? providers[0]?.colors.primary ?? theme.accent : theme.accent;
  const barAccent = providers.length > 1 ? isDark ? "#c4d0e0" : "#000000" : cardAccent;
  const providerHeatmaps = providers.map((p) => {
    const heatmapColors = buildHeatmapScale(p.colors, isDark);
    return {
      provider: p,
      heatmap: renderProviderHeatmap(p.daily, since, until, heatmapColors, theme.heatmapEmpty),
      heatmapColors
    };
  });
  const maxHeatmapWidth = providerHeatmaps.reduce((max, ph) => Math.max(max, ph.heatmap.gridWidth), 0);
  const minContentWidth = Math.max(maxHeatmapWidth, MIN_CONTENT_WIDTH);
  const cardWidth = minContentWidth + pad * 2;
  const contentWidth = cardWidth - pad * 2;
  let y = 0;
  const sections = [];
  sections.push(`<rect width="${cardWidth}" height="__CARD_HEIGHT__" rx="12" fill="${escapeXml(theme.bg)}" stroke="${escapeXml(theme.border)}" stroke-width="1"/>`);
  sections.push(`<clipPath id="titlebar-clip"><rect width="${cardWidth}" height="${TITLEBAR_HEIGHT}" rx="12"/></clipPath>`);
  sections.push(`<rect width="${cardWidth}" height="${TITLEBAR_HEIGHT}" fill="${escapeXml(theme.bg)}" clip-path="url(#titlebar-clip)"/>`);
  const dotY = TITLEBAR_HEIGHT / 2;
  const dotStartX = pad;
  const dots = [
    { color: "#ff5f57", cx: dotStartX },
    { color: "#febc2e", cx: dotStartX + DOT_RADIUS * 2 + DOT_GAP },
    { color: "#28c840", cx: dotStartX + (DOT_RADIUS * 2 + DOT_GAP) * 2 }
  ];
  for (const dot of dots) {
    sections.push(`<circle cx="${dot.cx}" cy="${dotY}" r="${DOT_RADIUS}" fill="${escapeXml(dot.color)}"/>`);
  }
  sections.push(`<line x1="0" y1="${TITLEBAR_HEIGHT}" x2="${cardWidth}" y2="${TITLEBAR_HEIGHT}" stroke="${escapeXml(theme.titlebarBorder)}" stroke-width="1"/>`);
  y = TITLEBAR_HEIGHT + pad * 0.6;
  sections.push(`<text x="${pad}" y="${y + 16}" font-size="15" font-family="${escapeXml(MONO_FONT_FAMILY)}" font-weight="500">` + `<tspan fill="${escapeXml(cardAccent)}">$</tspan>` + `<tspan fill="${escapeXml(theme.fg)}"> tokenleak</tspan>` + `<tspan fill="${escapeXml(cardAccent)}">_</tspan>` + `</text>`);
  y += 40;
  const dateRangeText = formatDateRange(since, until);
  sections.push(`<text x="${pad}" y="${y + 14}" fill="${escapeXml(theme.muted)}" font-size="12" font-family="${escapeXml(FONT_FAMILY)}" font-weight="600" letter-spacing="2">${escapeXml(dateRangeText)}</text>`);
  y += 40;
  for (let pi = 0;pi < providerHeatmaps.length; pi++) {
    const { provider, heatmap, heatmapColors } = providerHeatmaps[pi];
    const provDotRadius = 7;
    const provColor = provider.colors.primary;
    sections.push(`<circle cx="${pad + provDotRadius}" cy="${y + 10}" r="${provDotRadius}" fill="${escapeXml(provColor)}"/>`);
    sections.push(`<text x="${pad + provDotRadius * 2 + 12}" y="${y + 15}" fill="${escapeXml(theme.fg)}" font-size="17" font-family="${escapeXml(FONT_FAMILY)}" font-weight="700">${escapeXml(provider.displayName)}</text>`);
    const summaryText = `${formatNumber(provider.totalTokens)} tokens \xB7 ${formatCost2(provider.totalCost)}`;
    sections.push(`<text x="${cardWidth - pad}" y="${y + 15}" fill="${escapeXml(theme.muted)}" font-size="12" font-family="${escapeXml(FONT_FAMILY)}" font-weight="500" text-anchor="end">${escapeXml(summaryText)}</text>`);
    y += 32;
    const heatmapSvg = heatmap.svg.replace(/__MUTED__/g, escapeXml(theme.muted));
    sections.push(`<g transform="translate(${pad}, ${y})">`);
    sections.push(heatmapSvg);
    sections.push("</g>");
    y += heatmap.height;
    if (pi < providerHeatmaps.length - 1) {
      y += 12;
      sections.push(`<line x1="${pad}" y1="${y}" x2="${cardWidth - pad}" y2="${y}" stroke="${escapeXml(theme.border)}" stroke-width="1"/>`);
      y += PROVIDER_SECTION_GAP - 12;
    } else {
      y += 24;
    }
  }
  if (providers.length === 0) {
    sections.push(`<text x="${pad}" y="${y + 14}" fill="${escapeXml(theme.muted)}" font-size="12" font-family="${escapeXml(FONT_FAMILY)}" font-weight="500">${escapeXml("No provider data")}</text>`);
    y += 32;
  }
  sections.push(`<line x1="${pad}" y1="${y}" x2="${cardWidth - pad}" y2="${y}" stroke="${escapeXml(theme.border)}" stroke-width="1"/>`);
  y += 28;
  if (providers.length > 1) {
    sections.push(`<text x="${pad}" y="${y}" fill="${escapeXml(theme.muted)}" font-size="10" font-family="${escapeXml(FONT_FAMILY)}" font-weight="600" letter-spacing="2">${escapeXml("OVERALL")}</text>`);
    y += 24;
  }
  const statColWidth = contentWidth / STAT_GRID_COLS;
  const statsRow1 = [
    { label: "CURRENT STREAK", value: formatStreak(stats.currentStreak), accent: true },
    { label: "LONGEST STREAK", value: formatStreak(stats.longestStreak), accent: false },
    { label: "TOTAL TOKENS", value: formatNumber(stats.totalTokens), accent: true }
  ];
  const statsRow2 = [
    { label: "TOTAL COST", value: formatCost2(stats.totalCost), accent: false },
    { label: "30-DAY TOKENS", value: formatNumber(stats.rolling30dTokens), accent: false },
    { label: "CACHE HIT RATE", value: formatPercentage(stats.cacheHitRate), accent: false }
  ];
  function renderStatRow(row, startY) {
    for (let i = 0;i < row.length; i++) {
      const stat = row[i];
      const x = pad + i * statColWidth;
      sections.push(`<text x="${x}" y="${startY}" fill="${escapeXml(theme.muted)}" font-size="10" font-family="${escapeXml(FONT_FAMILY)}" font-weight="600" letter-spacing="1.5">${escapeXml(stat.label)}</text>`);
      const valueColor = stat.accent && providers.length === 1 ? cardAccent : theme.fg;
      sections.push(`<text x="${x}" y="${startY + 28}" fill="${escapeXml(valueColor)}" font-size="22" font-family="${escapeXml(FONT_FAMILY)}" font-weight="700">${escapeXml(stat.value)}</text>`);
    }
  }
  renderStatRow(statsRow1, y);
  y += 60;
  renderStatRow(statsRow2, y);
  y += 60;
  y += 8;
  sections.push(`<line x1="${pad}" y1="${y}" x2="${cardWidth - pad}" y2="${y}" stroke="${escapeXml(theme.border)}" stroke-width="1"/>`);
  y += 28;
  sections.push(renderSectionHeader(pad, y, "TOP MODELS", theme, cardAccent));
  y += 24;
  const topModels2 = stats.topModels.slice(0, 3);
  const rankWidth = 28;
  const modelNameWidth = MODEL_NAME_WIDTH;
  const barGap = MODEL_BAR_GAP;
  const percentX = cardWidth - pad;
  const barX = pad + rankWidth + modelNameWidth;
  const barMaxWidth = Math.max(48, percentX - barX - barGap);
  for (const [index, model] of topModels2.entries()) {
    const barWidth = Math.max(4, model.percentage / 100 * barMaxWidth);
    sections.push(`<text x="${pad}" y="${y + MODEL_BAR_HEIGHT - 1}" fill="${escapeXml(cardAccent)}" font-size="12" font-family="${escapeXml(FONT_FAMILY)}" font-weight="700" opacity="0.7">${escapeXml(String(index + 1))}</text>`);
    sections.push(`<text x="${pad + rankWidth}" y="${y + MODEL_BAR_HEIGHT - 1}" fill="${escapeXml(theme.fg)}" font-size="12" font-family="${escapeXml(FONT_FAMILY)}" font-weight="500">${escapeXml(model.model)}</text>`);
    const trackColor = isDark ? "rgba(255,255,255,0.10)" : "rgba(0,0,0,0.06)";
    sections.push(`<rect x="${barX}" y="${y}" width="${barMaxWidth}" height="${MODEL_BAR_HEIGHT}" rx="6" fill="${escapeXml(trackColor)}"/>`);
    const gradId = `grad-${index}-${model.model.replace(/[^a-zA-Z0-9]/g, "")}`;
    sections.push(`<defs><linearGradient id="${escapeXml(gradId)}" x1="0%" y1="0%" x2="100%" y2="0%">` + `<stop offset="0%" stop-color="${escapeXml(barAccent)}" stop-opacity="${isDark ? "0.45" : "0.27"}"/>` + `<stop offset="100%" stop-color="${escapeXml(barAccent)}" stop-opacity="1"/>` + `</linearGradient></defs>`);
    sections.push(`<rect x="${barX}" y="${y}" width="${barWidth}" height="${MODEL_BAR_HEIGHT}" rx="6" fill="url(#${escapeXml(gradId)})"/>`);
    sections.push(`<text x="${percentX}" y="${y + MODEL_BAR_HEIGHT - 1}" fill="${escapeXml(theme.fg)}" font-size="12" font-family="${escapeXml(FONT_FAMILY)}" font-weight="600" text-anchor="end">${escapeXml(`${model.percentage.toFixed(0)}%`)}</text>`);
    y += 32;
  }
  if (options.more && output.more) {
    const more = output.more;
    const cardGap = 16;
    const detailCardWidth = (contentWidth - cardGap) / 2;
    y += 8;
    sections.push(`<line x1="${pad}" y1="${y}" x2="${cardWidth - pad}" y2="${y}" stroke="${escapeXml(theme.border)}" stroke-width="1"/>`);
    y += 28;
    sections.push(renderSectionHeader(pad, y, "MORE", theme, cardAccent));
    y += 24;
    const efficiencyLines = [
      {
        label: "Input / Output",
        value: more.inputOutput.inputPerOutput === null ? "n/a" : `${more.inputOutput.inputPerOutput.toFixed(2)} : 1`,
        accent: true
      },
      {
        label: "Output / Input",
        value: formatRatio(more.inputOutput.outputPerInput)
      },
      {
        label: "Output Share",
        value: formatPercentage(more.inputOutput.outputShare)
      }
    ];
    sections.push(renderMetricCard(pad, y, detailCardWidth, "INPUT / OUTPUT", efficiencyLines, theme, cardAccent));
    const burnLines = [
      {
        label: "Projected Cost",
        value: formatCost2(more.monthlyBurn.projectedCost),
        accent: true
      },
      {
        label: "Projected Tokens",
        value: formatNumber(more.monthlyBurn.projectedTokens)
      },
      {
        label: "Based On",
        value: `${more.monthlyBurn.observedDays} / ${more.monthlyBurn.calendarDays} days`
      }
    ];
    sections.push(renderMetricCard(pad + detailCardWidth + cardGap, y, detailCardWidth, "PROJECTED MONTHLY BURN", burnLines, theme, cardAccent));
    y += 38 + Math.max(efficiencyLines.length, burnLines.length) * 22 + 16;
    const cacheLines = [
      {
        label: "Cache Reads",
        value: formatNumber(more.cacheEconomics.readTokens),
        accent: true
      },
      {
        label: "Cache Writes",
        value: formatNumber(more.cacheEconomics.writeTokens)
      },
      {
        label: "Read Coverage",
        value: formatPercentage(more.cacheEconomics.readCoverage)
      },
      {
        label: "Reuse Ratio",
        value: formatRatio(more.cacheEconomics.reuseRatio)
      }
    ];
    sections.push(renderMetricCard(pad, y, detailCardWidth, "CACHE ECONOMICS", cacheLines, theme, cardAccent));
    const sessionLines = [
      {
        label: "Sessions",
        value: String(more.sessionMetrics.totalSessions),
        accent: true
      },
      {
        label: "Avg Tokens",
        value: formatNumber(more.sessionMetrics.averageTokens)
      },
      {
        label: "Avg Messages",
        value: more.sessionMetrics.averageMessages.toFixed(1)
      },
      {
        label: "Avg Duration",
        value: formatDuration2(more.sessionMetrics.averageDurationMs)
      },
      {
        label: "Longest Session",
        value: more.sessionMetrics.longestSession ? formatSessionSummary(more.sessionMetrics.longestSession) : "n/a"
      },
      {
        label: "Top Project",
        value: more.sessionMetrics.topProject ? truncateText(more.sessionMetrics.topProject.name, 20) : "n/a"
      }
    ];
    sections.push(renderMetricCard(pad + detailCardWidth + cardGap, y, detailCardWidth, "SESSION STATS", sessionLines, theme, cardAccent));
    y += 38 + Math.max(cacheLines.length, sessionLines.length) * 22 + 16;
    const hourChart = renderHourOfDayChart(pad, y, contentWidth, more.hourOfDay, theme, cardAccent, providers, isDark);
    sections.push(hourChart.svg);
    y += hourChart.height + 16;
    const mixShift = renderModelMixShift(pad, y, contentWidth, more, theme, cardAccent);
    if (mixShift.height > 0) {
      sections.push(mixShift.svg);
      y += mixShift.height + 12;
    }
  }
  y += pad * 0.5;
  const cardHeight = y;
  const svg = sections.join(`
`).replace("__CARD_HEIGHT__", String(cardHeight));
  return [
    `<svg xmlns="http://www.w3.org/2000/svg" width="${cardWidth}" height="${cardHeight}" viewBox="0 0 ${cardWidth} ${cardHeight}" shape-rendering="geometricPrecision" text-rendering="optimizeLegibility" color-rendering="optimizeQuality">`,
    svg,
    "</svg>"
  ].join(`
`);
}
var FONT_FAMILY = "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif", MONO_FONT_FAMILY = "'JetBrains Mono', 'SF Mono', 'Cascadia Code', 'Fira Code', monospace", MONTH_NAMES, MONTH_NAMES_FULL;
var init_terminal_card = __esm(() => {
  MONTH_NAMES = [
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec"
  ];
  MONTH_NAMES_FULL = [
    "JAN",
    "FEB",
    "MAR",
    "APR",
    "MAY",
    "JUN",
    "JUL",
    "AUG",
    "SEP",
    "OCT",
    "NOV",
    "DEC"
  ];
});

// packages/renderers/dist/svg/svg-renderer.js
class SvgRenderer {
  format = "svg";
  async render(output, options) {
    return renderTerminalCardSvg(output, {
      ...options,
      format: "svg"
    });
  }
}
var init_svg_renderer = __esm(() => {
  init_terminal_card();
});

// packages/renderers/dist/svg/theme.js
function getTheme(mode) {
  return mode === "dark" ? DARK_THEME : LIGHT_THEME;
}
var DARK_THEME, LIGHT_THEME;
var init_theme = __esm(() => {
  DARK_THEME = {
    background: "#0d1117",
    foreground: "#e6edf3",
    muted: "#7d8590",
    border: "#30363d",
    cardBackground: "#161b22",
    heatmap: ["#161b22", "#1e3a5f", "#2563eb", "#3b82f6", "#1d4ed8"],
    accent: "#58a6ff",
    accentSecondary: "#bc8cff",
    barFill: "#3b82f6",
    barBackground: "#21262d"
  };
  LIGHT_THEME = {
    background: "#ffffff",
    foreground: "#1a1a2e",
    muted: "#8b8fa3",
    border: "#e5e7eb",
    cardBackground: "#f8f9fc",
    heatmap: ["#ebedf0", "#c6d4f7", "#8da4ef", "#5b6abf", "#2f3778"],
    accent: "#3b5bdb",
    accentSecondary: "#7048e8",
    barFill: "#5b6abf",
    barBackground: "#ebedf0"
  };
});

// packages/renderers/dist/svg/layout.js
var FONT_FAMILY2 = "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif";

// packages/renderers/dist/svg/wrapped.js
function buildWrappedStats(output) {
  const stats = output.aggregated;
  const topProvider = output.providers.length > 0 ? output.providers.reduce((a, b) => a.totalTokens >= b.totalTokens ? a : b).displayName : "None";
  return [
    { label: "Current Streak", value: `${stats.currentStreak} days` },
    { label: "Total Tokens", value: formatNumber(stats.totalTokens) },
    { label: "Total Cost", value: formatCost2(stats.totalCost) },
    { label: "Top Provider", value: topProvider },
    {
      label: "Peak Day",
      value: stats.peakDay ? `${stats.peakDay.date} (${formatNumber(stats.peakDay.tokens)})` : "N/A"
    },
    { label: "Active Days", value: `${stats.activeDays}` }
  ];
}
function renderWrappedCard(output, themeMode = "dark") {
  const theme = getTheme(themeMode);
  const stats = buildWrappedStats(output);
  const sections = [];
  sections.push(rect(0, 0, WRAPPED_WIDTH, WRAPPED_HEIGHT, theme.background, 16));
  sections.push(`<rect x="0" y="0" width="${WRAPPED_WIDTH}" height="6" fill="${escapeXml(theme.accent)}" rx="0"/>`);
  let y = WRAPPED_PADDING + TITLE_SIZE;
  sections.push(text(WRAPPED_PADDING, y, "Tokenleak Wrapped", {
    fill: theme.foreground,
    "font-size": TITLE_SIZE,
    "font-family": FONT_FAMILY2,
    "font-weight": "bold"
  }));
  y += 28;
  sections.push(text(WRAPPED_PADDING, y, `${output.dateRange.since} \u2014 ${output.dateRange.until}`, {
    fill: theme.muted,
    "font-size": 16,
    "font-family": FONT_FAMILY2
  }));
  const gridStartY = y + 48;
  const gridStartX = WRAPPED_PADDING;
  for (let i = 0;i < stats.length; i++) {
    const stat = stats[i];
    if (!stat)
      continue;
    const col = i % 3;
    const row = Math.floor(i / 3);
    const sx = gridStartX + col * STAT_COLUMN_WIDTH;
    const sy = gridStartY + row * STAT_ROW_HEIGHT;
    const cardWidth = STAT_COLUMN_WIDTH - 16;
    const cardHeight = STAT_ROW_HEIGHT - 12;
    sections.push(rect(sx, sy, cardWidth, cardHeight, theme.cardBackground, 8));
    sections.push(text(sx + 16, sy + 32, stat.value, {
      fill: theme.accent,
      "font-size": STAT_VALUE_SIZE,
      "font-family": FONT_FAMILY2,
      "font-weight": "bold"
    }));
    sections.push(text(sx + 16, sy + 52, stat.label, {
      fill: theme.muted,
      "font-size": STAT_LABEL_SIZE,
      "font-family": FONT_FAMILY2
    }));
  }
  if (output.providers.length > 0) {
    const badgeY = gridStartY + 2 * STAT_ROW_HEIGHT + 24;
    const providerNames = output.providers.map((p) => p.displayName).join("  \xB7  ");
    sections.push(text(WRAPPED_PADDING, badgeY, providerNames, {
      fill: theme.accentSecondary,
      "font-size": 16,
      "font-family": FONT_FAMILY2
    }));
  }
  sections.push(text(WRAPPED_WIDTH - WRAPPED_PADDING, WRAPPED_HEIGHT - 24, "tokenleak", {
    fill: theme.muted,
    "font-size": WATERMARK_SIZE,
    "font-family": FONT_FAMILY2,
    "text-anchor": "end",
    opacity: "0.6"
  }));
  return [
    `<svg xmlns="http://www.w3.org/2000/svg" width="${WRAPPED_WIDTH}" height="${WRAPPED_HEIGHT}" viewBox="0 0 ${WRAPPED_WIDTH} ${WRAPPED_HEIGHT}">`,
    ...sections,
    "</svg>"
  ].join(`
`);
}
var WRAPPED_WIDTH = 1200, WRAPPED_HEIGHT = 630, WRAPPED_PADDING = 48, TITLE_SIZE = 32, STAT_LABEL_SIZE = 14, STAT_VALUE_SIZE = 28, WATERMARK_SIZE = 12, STAT_COLUMN_WIDTH = 240, STAT_ROW_HEIGHT = 80;
var init_wrapped = __esm(() => {
  init_theme();
});

// packages/renderers/dist/svg/badge.js
function renderBadge(stats) {
  const valueText = `${stats.currentStreak} days`;
  const valueWidth = valueText.length * 7 + VALUE_PADDING;
  const totalWidth = LABEL_WIDTH + valueWidth;
  return [
    `<svg xmlns="http://www.w3.org/2000/svg" width="${totalWidth}" height="${BADGE_HEIGHT}" viewBox="0 0 ${totalWidth} ${BADGE_HEIGHT}">`,
    "<style>",
    "  @media (prefers-color-scheme: dark) {",
    "    .badge-label { fill: #555 }",
    "    .badge-value { fill: #4c1 }",
    "    .badge-shadow { fill: #010101; fill-opacity: .3 }",
    "    .badge-text { fill: #fff }",
    "  }",
    "  @media (prefers-color-scheme: light) {",
    "    .badge-label { fill: #555 }",
    "    .badge-value { fill: #97ca00 }",
    "    .badge-shadow { fill: #010101; fill-opacity: .3 }",
    "    .badge-text { fill: #fff }",
    "  }",
    "</style>",
    `<rect class="badge-label" width="${LABEL_WIDTH}" height="${BADGE_HEIGHT}" rx="3"/>`,
    `<rect class="badge-value" x="${LABEL_WIDTH}" width="${valueWidth}" height="${BADGE_HEIGHT}" rx="3"/>`,
    `<rect x="${LABEL_WIDTH}" width="4" height="${BADGE_HEIGHT}"/>`,
    '<g text-anchor="middle">',
    `  <text class="badge-shadow" x="${LABEL_WIDTH / 2}" y="${BADGE_HEIGHT - 5}" font-family="${escapeXml(FONT_FAMILY3)}" font-size="${FONT_SIZE}">${escapeXml(LABEL_TEXT)}</text>`,
    `  <text class="badge-text" x="${LABEL_WIDTH / 2}" y="${BADGE_HEIGHT - 6}" font-family="${escapeXml(FONT_FAMILY3)}" font-size="${FONT_SIZE}">${escapeXml(LABEL_TEXT)}</text>`,
    `  <text class="badge-shadow" x="${LABEL_WIDTH + valueWidth / 2}" y="${BADGE_HEIGHT - 5}" font-family="${escapeXml(FONT_FAMILY3)}" font-size="${FONT_SIZE}">${escapeXml(valueText)}</text>`,
    `  <text class="badge-text" x="${LABEL_WIDTH + valueWidth / 2}" y="${BADGE_HEIGHT - 6}" font-family="${escapeXml(FONT_FAMILY3)}" font-size="${FONT_SIZE}">${escapeXml(valueText)}</text>`,
    "</g>",
    "</svg>"
  ].join(`
`);
}
var BADGE_HEIGHT = 20, LABEL_TEXT = "streak", FONT_SIZE = 11, FONT_FAMILY3 = "Verdana,Geneva,DejaVu Sans,sans-serif", LABEL_WIDTH = 46, VALUE_PADDING = 12;
var init_badge = () => {};

// packages/renderers/dist/svg/wrapped-slides.js
function getWrappedTheme(mode) {
  const base = getTheme(mode);
  if (mode === "dark") {
    return {
      base,
      mode,
      sectionBgs: [
        ["#08080c", "#0c0c14"],
        ["#0a0a12", "#0e0e18"],
        ["#0c0a08", "#100e0c"],
        ["#080c14", "#0c1018"],
        ["#0a0a0e", "#0e0e12"],
        ["#080c14", "#0c1018"],
        ["#0c0814", "#100c18"],
        ["#080e0c", "#0c1210"],
        ["#0c0a06", "#100e0a"],
        ["#08080c", "#0c0c14"],
        ["#0a0c10", "#0e1014"],
        ["#060608", "#060608"]
      ],
      heroAccent: "#a78bfa",
      warmAccent: "#fb923c",
      coolAccent: "#38bdf8",
      greenAccent: "#4ade80",
      goldAccent: "#fbbf24",
      purpleAccent: "#c084fc",
      narrativeColor: "#d1d5db",
      subtitleColor: "#6b7280"
    };
  }
  return {
    base,
    mode,
    sectionBgs: [
      ["#fafaf9", "#f5f5f4"],
      ["#f5f5f4", "#fafaf9"],
      ["#fefce8", "#fef9c3"],
      ["#eff6ff", "#dbeafe"],
      ["#fafaf9", "#f5f5f4"],
      ["#eff6ff", "#dbeafe"],
      ["#faf5ff", "#f3e8ff"],
      ["#ecfdf5", "#d1fae5"],
      ["#fffbeb", "#fef3c7"],
      ["#faf5ff", "#f3e8ff"],
      ["#eff6ff", "#dbeafe"],
      ["#fafaf9", "#fafaf9"]
    ],
    heroAccent: "#7c3aed",
    warmAccent: "#ea580c",
    coolAccent: "#2563eb",
    greenAccent: "#16a34a",
    goldAccent: "#ca8a04",
    purpleAccent: "#7c3aed",
    narrativeColor: "#1f2937",
    subtitleColor: "#6b7280"
  };
}
function svgIconFire(x, y, size, color) {
  const s = size / 24;
  return `<g transform="translate(${x},${y}) scale(${s})">` + `<path d="M12 2C6 8 4 12 4 15.5C4 19.09 7.58 22 12 22C16.42 22 20 19.09 20 15.5C20 12 18 8 12 2Z" ` + `fill="${escapeXml(color)}" opacity="0.85"/>` + `<path d="M12 8C9 12 8 14 8 15.5C8 17.71 9.79 19.5 12 19.5C14.21 19.5 16 17.71 16 15.5C16 14 15 12 12 8Z" ` + `fill="${escapeXml(color)}" opacity="0.5"/>` + `</g>`;
}
function svgIconStar(x, y, size, color) {
  const s = size / 24;
  return `<g transform="translate(${x},${y}) scale(${s})">` + `<path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z" ` + `fill="${escapeXml(color)}" opacity="0.85"/>` + `</g>`;
}
function svgIconCircle(x, y, size, color) {
  const r = size / 2;
  return `<circle cx="${x + r}" cy="${y + r}" r="${r}" fill="${escapeXml(color)}" opacity="0.85"/>`;
}
function svgIconDiamond(x, y, size, color) {
  const s = size / 2;
  const cx = x + s;
  const cy = y + s;
  return `<path d="M${cx} ${cy - s} L${cx + s} ${cy} L${cx} ${cy + s} L${cx - s} ${cy} Z" ` + `fill="${escapeXml(color)}" opacity="0.85"/>`;
}
function svgIconBolt(x, y, size, color) {
  const s = size / 24;
  return `<g transform="translate(${x},${y}) scale(${s})">` + `<path d="M13 2L3 14H12L11 22L21 10H12L13 2Z" fill="${escapeXml(color)}" opacity="0.85"/>` + `</g>`;
}
function svgIconTrophy(x, y, size, color) {
  const s = size / 24;
  return `<g transform="translate(${x},${y}) scale(${s})">` + `<path d="M7 4V2H17V4H20V8C20 9.1 19.1 10 18 10H16.76C16.34 11.8 14.84 13.17 13 13.44V16H16V18H8V16H11V13.44C9.16 13.17 7.66 11.8 7.24 10H6C4.9 10 4 9.1 4 8V4H7Z" ` + `fill="${escapeXml(color)}" opacity="0.85"/>` + `</g>`;
}
function svgIconTarget(x, y, size, color) {
  const cx = x + size / 2;
  const cy = y + size / 2;
  const r = size / 2;
  return `<circle cx="${cx}" cy="${cy}" r="${r}" fill="none" stroke="${escapeXml(color)}" stroke-width="2" opacity="0.6"/>` + `<circle cx="${cx}" cy="${cy}" r="${r * 0.6}" fill="none" stroke="${escapeXml(color)}" stroke-width="2" opacity="0.7"/>` + `<circle cx="${cx}" cy="${cy}" r="${r * 0.25}" fill="${escapeXml(color)}" opacity="0.85"/>`;
}
function svgIconMountain(x, y, size, color) {
  const s = size / 24;
  return `<g transform="translate(${x},${y}) scale(${s})">` + `<path d="M14 6L20 18H4L10 8L13 12.5L14 6Z" fill="${escapeXml(color)}" opacity="0.85"/>` + `</g>`;
}
function svgIconPalette(x, y, size, color) {
  const s = size / 24;
  return `<g transform="translate(${x},${y}) scale(${s})">` + `<path d="M12 2C6.49 2 2 6.49 2 12C2 17.51 6.49 22 12 22C12.83 22 13.5 21.33 13.5 20.5C13.5 20.12 13.37 19.78 13.15 19.52C12.93 19.26 12.82 18.93 12.82 18.57C12.82 17.75 13.5 17.07 14.32 17.07H16.5C19.54 17.07 22 14.61 22 11.57C22 6.28 17.51 2 12 2Z" ` + `fill="${escapeXml(color)}" opacity="0.85"/>` + `</g>`;
}
function svgIconCalendar(x, y, size, color) {
  const s = size / 24;
  return `<g transform="translate(${x},${y}) scale(${s})">` + `<path d="M19 4H18V2H16V4H8V2H6V4H5C3.89 4 3 4.9 3 6V20C3 21.1 3.89 22 5 22H19C20.1 22 21 21.1 21 20V6C21 4.9 20.1 4 19 4ZM19 20H5V10H19V20ZM19 8H5V6H19V8Z" ` + `fill="${escapeXml(color)}" opacity="0.85"/>` + `</g>`;
}
function svgIconMoon(x, y, size, color) {
  const s = size / 24;
  return `<g transform="translate(${x},${y}) scale(${s})">` + `<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79Z" fill="${escapeXml(color)}" opacity="0.85"/>` + `</g>`;
}
function svgIconSun(x, y, size, color) {
  const cx = x + size / 2;
  const cy = y + size / 2;
  const r = size * 0.3;
  let svg = `<circle cx="${cx}" cy="${cy}" r="${r}" fill="${escapeXml(color)}" opacity="0.85"/>`;
  for (let i = 0;i < 8; i++) {
    const angle = i * 45 * Math.PI / 180;
    const x1 = cx + r * 1.4 * Math.cos(angle);
    const y1 = cy + r * 1.4 * Math.sin(angle);
    const x2 = cx + r * 2 * Math.cos(angle);
    const y2 = cy + r * 2 * Math.sin(angle);
    svg += `<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="${escapeXml(color)}" stroke-width="2" stroke-linecap="round" opacity="0.7"/>`;
  }
  return svg;
}
function svgIconRocket(x, y, size, color) {
  const s = size / 24;
  return `<g transform="translate(${x},${y}) scale(${s})">` + `<path d="M12 2.5C12 2.5 7 8 7 13.5C7 16.81 9.24 19.5 12 19.5C14.76 19.5 17 16.81 17 13.5C17 8 12 2.5 12 2.5Z" ` + `fill="${escapeXml(color)}" opacity="0.85"/>` + `<circle cx="12" cy="13" r="2" fill="${escapeXml(color)}" opacity="0.4"/>` + `</g>`;
}
function renderIcon(name, x, y, size, color) {
  const fns = {
    fire: svgIconFire,
    star: svgIconStar,
    circle: svgIconCircle,
    diamond: svgIconDiamond,
    bolt: svgIconBolt,
    trophy: svgIconTrophy,
    target: svgIconTarget,
    mountain: svgIconMountain,
    palette: svgIconPalette,
    calendar: svgIconCalendar,
    moon: svgIconMoon,
    sun: svgIconSun,
    rocket: svgIconRocket
  };
  return fns[name](x, y, size, color);
}
function computeAchievements(output) {
  const stats = output.aggregated;
  const more = output.more;
  const providers = output.providers;
  const all = [];
  if (stats.longestStreak > 30) {
    all.push({ icon: "fire", title: "Streak Master", subtitle: `${stats.longestStreak} day streak`, color: "#f59e0b" });
  }
  if (more?.hourOfDay) {
    const totalTokens = more.hourOfDay.reduce((s, e) => s + e.tokens, 0);
    const nightTokens = more.hourOfDay.filter((e) => e.hour >= 22 || e.hour < 6).reduce((s, e) => s + e.tokens, 0);
    if (totalTokens > 0 && nightTokens / totalTokens > 0.4) {
      all.push({ icon: "moon", title: "Night Owl", subtitle: `${(nightTokens / totalTokens * 100).toFixed(0)}% between 10pm-6am`, color: "#818cf8" });
    }
  }
  if (more?.hourOfDay) {
    const totalTokens = more.hourOfDay.reduce((s, e) => s + e.tokens, 0);
    const morningTokens = more.hourOfDay.filter((e) => e.hour < 12).reduce((s, e) => s + e.tokens, 0);
    if (totalTokens > 0 && morningTokens / totalTokens > 0.4) {
      all.push({ icon: "sun", title: "Early Bird", subtitle: `${(morningTokens / totalTokens * 100).toFixed(0)}% before noon`, color: "#fbbf24" });
    }
  }
  if (stats.totalCost > 100) {
    all.push({ icon: "diamond", title: "Big Spender", subtitle: `${formatCost2(stats.totalCost)} total`, color: "#34d399" });
  }
  if (stats.cacheHitRate > 0.5) {
    all.push({ icon: "target", title: "Cache Master", subtitle: `${(stats.cacheHitRate * 100).toFixed(0)}% hit rate`, color: "#f472b6" });
  }
  if (stats.topModels.length >= 4) {
    all.push({ icon: "circle", title: "Model Hopper", subtitle: `${stats.topModels.length} models used`, color: "#a78bfa" });
  }
  if (stats.totalDays > 0 && stats.activeDays / stats.totalDays > 0.8) {
    all.push({ icon: "calendar", title: "Daily Driver", subtitle: `${stats.activeDays}/${stats.totalDays} days active`, color: "#38bdf8" });
  }
  if (stats.averageDailyTokens > 1e4) {
    all.push({ icon: "bolt", title: "Power User", subtitle: `${formatNumber(stats.averageDailyTokens)} avg/day`, color: "#fbbf24" });
  }
  if (stats.peakDay && stats.peakDay.tokens > 50000) {
    all.push({ icon: "mountain", title: "Summit Day", subtitle: `${formatNumber(stats.peakDay.tokens)} in one day`, color: "#34d399" });
  }
  if (providers.length >= 3) {
    all.push({ icon: "palette", title: "Multi-Tool", subtitle: `${providers.length} providers`, color: "#c084fc" });
  }
  if (all.length < 3) {
    if (all.length < 3 && stats.longestStreak > 7 && !all.some((a) => a.title === "Streak Master")) {
      all.push({ icon: "fire", title: "Streak Builder", subtitle: `${stats.longestStreak} day streak`, color: "#f59e0b" });
    }
    if (all.length < 3 && stats.totalTokens > 1000) {
      all.push({ icon: "rocket", title: "Getting Started", subtitle: `${formatNumber(stats.totalTokens)} tokens used`, color: "#38bdf8" });
    }
    if (all.length < 3 && stats.activeDays > 0) {
      all.push({ icon: "star", title: "Active Coder", subtitle: `${stats.activeDays} active days`, color: "#fbbf24" });
    }
    if (all.length < 3 && stats.totalTokens > 0) {
      all.push({ icon: "bolt", title: "Token User", subtitle: `${formatNumber(stats.totalTokens)} tokens`, color: "#a78bfa" });
    }
    if (all.length < 3) {
      all.push({ icon: "rocket", title: "Just Getting Started", subtitle: "Your journey begins", color: "#38bdf8" });
    }
  }
  return all.slice(0, 6);
}
function sectionBg(y, height, gradColors, gradId) {
  return [
    `<defs><linearGradient id="${escapeXml(gradId)}" x1="0%" y1="0%" x2="100%" y2="100%">`,
    `<stop offset="0%" stop-color="${escapeXml(gradColors[0])}"/>`,
    `<stop offset="100%" stop-color="${escapeXml(gradColors[1])}"/>`,
    `</linearGradient></defs>`,
    `<rect x="0" y="${y}" width="${WIDTH}" height="${height}" fill="url(#${escapeXml(gradId)})"/>`
  ].join("");
}
function svgText(x, y, content, opts = {}) {
  const attrs = [
    `x="${x}"`,
    `y="${y}"`,
    `fill="${escapeXml(opts.fill ?? "#ffffff")}"`,
    `font-size="${opts.size ?? 14}"`,
    `font-family="${escapeXml(opts.family ?? BODY_FONT)}"`,
    `font-weight="${opts.weight ?? 400}"`
  ];
  if (opts.anchor)
    attrs.push(`text-anchor="${escapeXml(opts.anchor)}"`);
  if (opts.spacing !== undefined)
    attrs.push(`letter-spacing="${opts.spacing}"`);
  if (opts.opacity !== undefined)
    attrs.push(`opacity="${opts.opacity}"`);
  return `<text ${attrs.join(" ")}>${escapeXml(content)}</text>`;
}
function rect2(x, y, w, h, fill, rx = 4, opts = {}) {
  const extra = [];
  if (opts.opacity !== undefined)
    extra.push(`opacity="${opts.opacity}"`);
  if (opts.stroke)
    extra.push(`stroke="${escapeXml(opts.stroke)}" stroke-width="${opts.strokeWidth ?? 1}"`);
  return `<rect x="${x}" y="${y}" width="${w}" height="${h}" rx="${rx}" fill="${escapeXml(fill)}" ${extra.join(" ")}/>`;
}
function describeArc(cx, cy, radius, startAngle, endAngle) {
  const start = polarToCartesian(cx, cy, radius, endAngle);
  const end = polarToCartesian(cx, cy, radius, startAngle);
  const largeArc = endAngle - startAngle <= 180 ? "0" : "1";
  return `M ${start.x} ${start.y} A ${radius} ${radius} 0 ${largeArc} 0 ${end.x} ${end.y}`;
}
function polarToCartesian(cx, cy, radius, angleDeg) {
  const rad = (angleDeg - 90) * Math.PI / 180;
  return { x: cx + radius * Math.cos(rad), y: cy + radius * Math.sin(rad) };
}
function cornerMark(x, y, size, color, corner) {
  const s = size;
  const paths = {
    tl: `M${x} ${y + s} L${x} ${y} L${x + s} ${y}`,
    tr: `M${x - s} ${y} L${x} ${y} L${x} ${y + s}`,
    bl: `M${x} ${y - s} L${x} ${y} L${x + s} ${y}`,
    br: `M${x - s} ${y} L${x} ${y} L${x} ${y - s}`
  };
  return `<path d="${paths[corner]}" fill="none" stroke="${escapeXml(color)}" stroke-width="1.5" opacity="0.3"/>`;
}
function sectionLabel(x, y, text2, color, accent) {
  return [
    `<line x1="${x}" y1="${y - 4}" x2="${x + 24}" y2="${y - 4}" stroke="${escapeXml(accent)}" stroke-width="2" opacity="0.6"/>`,
    svgText(x + 32, y, text2, { fill: color, size: 11, weight: 600, spacing: 3, family: MONO_FONT })
  ].join(`
`);
}
function rule(x, y, width, color, opacity = 0.1) {
  return `<line x1="${x}" y1="${y}" x2="${x + width}" y2="${y}" stroke="${escapeXml(color)}" stroke-width="1" opacity="${opacity}"/>`;
}
function dotGrid(x, y, w, h, color, spacing = 24, radius = 1) {
  const dots = [];
  for (let gx = x;gx <= x + w; gx += spacing) {
    for (let gy = y;gy <= y + h; gy += spacing) {
      dots.push(`<circle cx="${gx}" cy="${gy}" r="${radius}" fill="${escapeXml(color)}" opacity="0.06"/>`);
    }
  }
  return dots.join(`
`);
}
function formatDateLong(dateStr) {
  const d = new Date(dateStr + "T00:00:00Z");
  if (Number.isNaN(d.getTime()))
    return dateStr;
  const month = MONTH_NAMES2[d.getUTCMonth()] ?? "";
  return `${month} ${d.getUTCDate()}, ${d.getUTCFullYear()}`;
}
function globalDefs(isDark) {
  const noiseOpacity = isDark ? 0.035 : 0.025;
  return [
    "<defs>",
    '<filter id="grain" x="0" y="0" width="100%" height="100%">',
    '<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="4" stitchTiles="stitch" result="noise"/>',
    '<feColorMatrix type="saturate" values="0" in="noise" result="mono"/>',
    `<feBlend in="SourceGraphic" in2="mono" mode="multiply"/>`,
    "</filter>",
    "</defs>",
    `<rect width="${WIDTH}" height="99999" fill="transparent" filter="url(#grain)" opacity="${noiseOpacity}" pointer-events="none"/>`
  ].join(`
`);
}
function renderTitleSlide(output, theme) {
  const height = 300;
  const p = [];
  const gc = theme.sectionBgs[0] ?? ["#08080c", "#0c0c14"];
  p.push(sectionBg(0, height, gc, "title-bg"));
  const gridColor = theme.mode === "dark" ? "#ffffff" : "#000000";
  p.push(dotGrid(WIDTH - 300, 30, 220, 120, gridColor, 20, 1.2));
  p.push(cornerMark(PAD - 16, 40, 20, theme.heroAccent, "tl"));
  p.push(cornerMark(WIDTH - PAD + 16, height - 40, 20, theme.heroAccent, "br"));
  const titleColor = theme.mode === "dark" ? "#e5e7eb" : "#1f2937";
  p.push(svgText(PAD, 100, "Your AI Coding", {
    fill: titleColor,
    size: 36,
    weight: 300,
    family: DISPLAY_FONT,
    spacing: -0.5
  }));
  p.push(svgText(PAD, 160, "Wrapped", {
    fill: theme.heroAccent,
    size: 80,
    weight: 800,
    family: DISPLAY_FONT,
    spacing: -3
  }));
  p.push(`<line x1="${PAD}" y1="${178}" x2="${PAD + 120}" y2="${178}" stroke="${escapeXml(theme.heroAccent)}" stroke-width="2" opacity="0.4"/>`);
  const { since, until } = output.dateRange;
  const rangeText = `${formatDateLong(since)} \u2014 ${formatDateLong(until)}`;
  p.push(svgText(PAD, 210, rangeText, {
    fill: theme.subtitleColor,
    size: 14,
    weight: 400,
    family: MONO_FONT
  }));
  p.push(svgText(PAD, 248, "tokenleak", {
    fill: theme.heroAccent,
    size: 13,
    weight: 500,
    family: MONO_FONT,
    opacity: 0.4
  }));
  p.push(rule(PAD, height - 1, WIDTH - PAD * 2, theme.mode === "dark" ? "#ffffff" : "#000000", 0.06));
  return { svg: p.join(`
`), height };
}
function renderBigNumbersSlide(output, theme) {
  const height = 260;
  const p = [];
  const stats = output.aggregated;
  const gc = theme.sectionBgs[1] ?? ["#0a0a12", "#0e0e18"];
  p.push(sectionBg(0, height, gc, "bignums-bg"));
  p.push(sectionLabel(PAD, 40, "THE BIG NUMBERS", theme.subtitleColor, theme.heroAccent));
  const numColor = theme.mode === "dark" ? "#f9fafb" : "#111827";
  p.push(svgText(PAD, 130, formatNumber(stats.totalTokens), {
    fill: numColor,
    size: 96,
    weight: 800,
    family: MONO_FONT,
    spacing: -4
  }));
  p.push(svgText(PAD, 158, "total tokens", {
    fill: theme.subtitleColor,
    size: 14,
    weight: 500,
    family: BODY_FONT,
    spacing: 1
  }));
  const statsY = 200;
  const colW = (WIDTH - PAD * 2) / 3;
  const supportStats = [
    { value: formatCost2(stats.totalCost), label: "TOTAL COST", accent: true },
    { value: `${stats.activeDays}`, label: "ACTIVE DAYS", accent: false },
    { value: `${stats.totalDays}`, label: "TOTAL DAYS", accent: false }
  ];
  for (let i = 0;i < supportStats.length; i++) {
    const sx = PAD + i * colW;
    const stat = supportStats[i];
    if (i > 0) {
      p.push(`<line x1="${sx}" y1="${statsY - 10}" x2="${sx}" y2="${statsY + 32}" stroke="${theme.mode === "dark" ? "#ffffff" : "#000000"}" stroke-width="1" opacity="0.08"/>`);
    }
    p.push(svgText(sx + (i > 0 ? 20 : 0), statsY + 4, stat.value, {
      fill: stat.accent ? theme.greenAccent : numColor,
      size: 28,
      weight: 700,
      family: MONO_FONT
    }));
    p.push(svgText(sx + (i > 0 ? 20 : 0), statsY + 28, stat.label, {
      fill: theme.subtitleColor,
      size: 10,
      weight: 600,
      spacing: 2,
      family: MONO_FONT
    }));
  }
  p.push(rule(PAD, height - 1, WIDTH - PAD * 2, theme.mode === "dark" ? "#ffffff" : "#000000", 0.06));
  return { svg: p.join(`
`), height };
}
function renderStreakSlide(output, theme) {
  const height = 250;
  const p = [];
  const stats = output.aggregated;
  const gc = theme.sectionBgs[2] ?? ["#0c0a08", "#100e0c"];
  p.push(sectionBg(0, height, gc, "streak-bg"));
  p.push(sectionLabel(PAD, 40, "STREAK STORY", theme.subtitleColor, theme.warmAccent));
  const narrative = stats.longestStreak > 0 ? `Your longest coding streak was ${stats.longestStreak} days` : "Start your first coding streak!";
  p.push(svgText(PAD, 85, narrative, {
    fill: theme.narrativeColor,
    size: 20,
    weight: 500,
    family: DISPLAY_FONT
  }));
  p.push(svgText(PAD, 170, `${stats.longestStreak}`, {
    fill: theme.warmAccent,
    size: 88,
    weight: 800,
    family: MONO_FONT,
    spacing: -4
  }));
  const numWidth = Math.max(60, `${stats.longestStreak}`.length * 50);
  p.push(svgText(PAD + numWidth + 8, 170, "days", {
    fill: theme.subtitleColor,
    size: 20,
    weight: 400,
    family: DISPLAY_FONT
  }));
  p.push(svgIconFire(PAD + numWidth + 8, 120, 40, theme.warmAccent));
  p.push(svgText(WIDTH - PAD, 170, `Current: ${stats.currentStreak}`, {
    fill: theme.subtitleColor,
    size: 14,
    weight: 500,
    family: MONO_FONT,
    anchor: "end"
  }));
  const barY = 198;
  const barW = WIDTH - PAD * 2;
  const barH = 6;
  const streakRatio = Math.min(stats.longestStreak / 30, 1);
  const trackColor = theme.mode === "dark" ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.04)";
  p.push(rect2(PAD, barY, barW, barH, trackColor, 3));
  if (streakRatio > 0) {
    p.push(rect2(PAD, barY, Math.max(8, streakRatio * barW), barH, theme.warmAccent, 3, { opacity: 0.7 }));
  }
  for (let i = 0;i <= 30 && i <= stats.longestStreak; i += 5) {
    if (i === 0)
      continue;
    const tx = PAD + i / 30 * barW;
    p.push(`<line x1="${tx}" y1="${barY + barH + 2}" x2="${tx}" y2="${barY + barH + 6}" stroke="${escapeXml(theme.subtitleColor)}" stroke-width="1" opacity="0.3"/>`);
  }
  p.push(rule(PAD, height - 1, WIDTH - PAD * 2, theme.mode === "dark" ? "#ffffff" : "#000000", 0.06));
  return { svg: p.join(`
`), height };
}
function renderTopModelSlide(output, theme) {
  const height = 300;
  const p = [];
  const stats = output.aggregated;
  const topModels2 = stats.topModels.slice(0, 3);
  const gc = theme.sectionBgs[3] ?? ["#080c14", "#0c1018"];
  p.push(sectionBg(0, height, gc, "model-bg"));
  p.push(sectionLabel(PAD, 40, "YOUR TOP MODEL", theme.subtitleColor, theme.coolAccent));
  if (topModels2.length === 0) {
    p.push(svgText(PAD, 160, "No model data available", {
      fill: theme.subtitleColor,
      size: 18,
      weight: 500
    }));
    return { svg: p.join(`
`), height };
  }
  const topModel = topModels2[0];
  const arcColors = [theme.coolAccent, theme.purpleAccent, theme.greenAccent, theme.warmAccent];
  p.push(svgText(PAD, 100, topModel.model, {
    fill: theme.coolAccent,
    size: 32,
    weight: 700,
    family: MONO_FONT,
    spacing: -1
  }));
  p.push(svgText(PAD, 128, `${topModel.percentage.toFixed(0)}% of all tokens`, {
    fill: theme.subtitleColor,
    size: 14,
    weight: 500
  }));
  const segBarY = 150;
  const segBarH = 20;
  const segBarW = WIDTH - PAD * 2;
  const trackBg = theme.mode === "dark" ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.04)";
  p.push(rect2(PAD, segBarY, segBarW, segBarH, trackBg, 4));
  let segX = PAD;
  for (let i = 0;i < topModels2.length; i++) {
    const model = topModels2[i];
    const w = Math.max(4, model.percentage / 100 * segBarW);
    const gap = i > 0 ? 2 : 0;
    p.push(rect2(segX + gap, segBarY, w - gap, segBarH, arcColors[i % arcColors.length], 4, { opacity: 0.85 }));
    segX += w;
  }
  const listY = 195;
  for (let i = 0;i < topModels2.length; i++) {
    const model = topModels2[i];
    const my = listY + i * 32;
    p.push(`<rect x="${PAD}" y="${my + 2}" width="4" height="16" rx="2" fill="${escapeXml(arcColors[i % arcColors.length])}" opacity="0.9"/>`);
    p.push(svgText(PAD + 16, my + 14, `${model.model}`, {
      fill: theme.mode === "dark" ? "#e5e7eb" : "#1f2937",
      size: 14,
      weight: 600,
      family: MONO_FONT
    }));
    p.push(svgText(WIDTH - PAD, my + 14, `${model.percentage.toFixed(0)}%`, {
      fill: arcColors[i % arcColors.length],
      size: 14,
      weight: 700,
      family: MONO_FONT,
      anchor: "end"
    }));
    const barW = Math.max(4, model.percentage / 100 * (segBarW - 200));
    p.push(rect2(PAD + 16, my + 20, barW, 4, arcColors[i % arcColors.length], 2, { opacity: 0.4 }));
  }
  p.push(rule(PAD, height - 1, WIDTH - PAD * 2, theme.mode === "dark" ? "#ffffff" : "#000000", 0.06));
  return { svg: p.join(`
`), height };
}
function renderProviderMixSlide(output, theme) {
  const providers = output.providers;
  const perRow = 52;
  const height = Math.max(180, 100 + providers.length * perRow);
  const p = [];
  const gc = theme.sectionBgs[4] ?? ["#0a0a0e", "#0e0e12"];
  p.push(sectionBg(0, height, gc, "provider-bg"));
  p.push(sectionLabel(PAD, 40, "PROVIDER MIX", theme.subtitleColor, theme.purpleAccent));
  if (providers.length === 0) {
    p.push(svgText(PAD, 110, "No provider data", { fill: theme.subtitleColor, size: 16, weight: 500 }));
    return { svg: p.join(`
`), height: 180 };
  }
  const totalTokens = providers.reduce((s, pv) => s + pv.totalTokens, 0);
  const topProvider = providers.reduce((a, b) => a.totalTokens >= b.totalTokens ? a : b);
  const topPct = totalTokens > 0 ? (topProvider.totalTokens / totalTokens * 100).toFixed(0) : "0";
  p.push(svgText(PAD, 80, `${topProvider.displayName} \u2014 ${topPct}%`, {
    fill: theme.narrativeColor,
    size: 20,
    weight: 600,
    family: DISPLAY_FONT
  }));
  const barMaxWidth = WIDTH - PAD * 2 - 160;
  for (let i = 0;i < providers.length; i++) {
    const pv = providers[i];
    const py = 105 + i * perRow;
    const pct = totalTokens > 0 ? pv.totalTokens / totalTokens * 100 : 0;
    p.push(`<rect x="${PAD}" y="${py + 4}" width="4" height="14" rx="2" fill="${escapeXml(pv.colors.primary)}"/>`);
    p.push(svgText(PAD + 16, py + 15, pv.displayName, {
      fill: theme.mode === "dark" ? "#e5e7eb" : "#1f2937",
      size: 14,
      weight: 600,
      family: MONO_FONT
    }));
    p.push(svgText(WIDTH - PAD, py + 15, `${pct.toFixed(0)}%`, {
      fill: theme.subtitleColor,
      size: 13,
      weight: 700,
      anchor: "end",
      family: MONO_FONT
    }));
    const trackBg = theme.mode === "dark" ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.04)";
    p.push(rect2(PAD + 16, py + 24, barMaxWidth, 8, trackBg, 4));
    const barW = Math.max(4, pct / 100 * barMaxWidth);
    p.push(rect2(PAD + 16, py + 24, barW, 8, pv.colors.primary, 4, { opacity: 0.75 }));
  }
  p.push(rule(PAD, height - 1, WIDTH - PAD * 2, theme.mode === "dark" ? "#ffffff" : "#000000", 0.06));
  return { svg: p.join(`
`), height };
}
function renderDayOfWeekSlide(output, theme) {
  const height = 340;
  const p = [];
  const dow = output.aggregated.dayOfWeek;
  const gc = theme.sectionBgs[5] ?? ["#080c14", "#0c1018"];
  p.push(sectionBg(0, height, gc, "dow-bg"));
  p.push(sectionLabel(PAD, 40, "CODING DAYS", theme.subtitleColor, theme.coolAccent));
  if (dow.length === 0) {
    p.push(svgText(PAD, 170, "No day-of-week data", { fill: theme.subtitleColor, size: 16, weight: 500 }));
    return { svg: p.join(`
`), height };
  }
  const peak = dow.reduce((a, b) => a.tokens >= b.tokens ? a : b);
  const peakName = DAY_NAMES[peak.day] ?? "Unknown";
  const maxTokens = Math.max(...dow.map((d) => d.tokens), 1);
  p.push(svgText(PAD, 80, `${peakName}s are your power day`, {
    fill: theme.narrativeColor,
    size: 20,
    weight: 600,
    family: DISPLAY_FONT
  }));
  const chartX = PAD;
  const chartY = 110;
  const barAreaWidth = WIDTH - PAD * 2;
  const gapSize = 12;
  const barWidth = Math.floor((barAreaWidth - 6 * gapSize) / 7);
  const barMaxHeight = 170;
  for (let i = 0;i < 7 && i < dow.length; i++) {
    const entry = dow[i];
    const bx = chartX + i * (barWidth + gapSize);
    const ratio = maxTokens > 0 ? entry.tokens / maxTokens : 0;
    const barH = Math.max(4, ratio * barMaxHeight);
    const by = chartY + barMaxHeight - barH;
    const isPeak = entry.day === peak.day;
    const barColor = isPeak ? theme.coolAccent : theme.mode === "dark" ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.06)";
    p.push(rect2(bx, by, barWidth, barH, barColor, 4, { opacity: isPeak ? 1 : 0.7 }));
    if (isPeak) {
      p.push(`<line x1="${bx}" y1="${by}" x2="${bx + barWidth}" y2="${by}" stroke="${escapeXml(theme.coolAccent)}" stroke-width="3" opacity="0.8"/>`);
    }
    const dayLabel = DAY_SHORT[i] ?? "";
    p.push(svgText(bx + barWidth / 2, chartY + barMaxHeight + 20, dayLabel, {
      fill: isPeak ? theme.coolAccent : theme.subtitleColor,
      size: 11,
      weight: isPeak ? 700 : 500,
      anchor: "middle",
      family: MONO_FONT
    }));
    if (isPeak) {
      p.push(svgText(bx + barWidth / 2, by - 10, formatNumber(entry.tokens), {
        fill: theme.coolAccent,
        size: 11,
        weight: 700,
        anchor: "middle",
        family: MONO_FONT
      }));
    }
  }
  p.push(rule(PAD, height - 1, WIDTH - PAD * 2, theme.mode === "dark" ? "#ffffff" : "#000000", 0.06));
  return { svg: p.join(`
`), height };
}
function renderTimeOfDaySlide(output, theme) {
  const more = output.more;
  if (!more?.hourOfDay)
    return { svg: "", height: 0 };
  const hourOfDay = more.hourOfDay;
  const totalTokens = hourOfDay.reduce((s, e) => s + e.tokens, 0);
  if (totalTokens === 0)
    return { svg: "", height: 0 };
  const height = 320;
  const p = [];
  const gc = theme.sectionBgs[6] ?? ["#0c0814", "#100c18"];
  p.push(sectionBg(0, height, gc, "tod-bg"));
  p.push(sectionLabel(PAD, 40, "WHEN YOU CODE", theme.subtitleColor, theme.purpleAccent));
  const morning = hourOfDay.filter((e) => e.hour >= 6 && e.hour < 12).reduce((s, e) => s + e.tokens, 0);
  const afternoon = hourOfDay.filter((e) => e.hour >= 12 && e.hour < 18).reduce((s, e) => s + e.tokens, 0);
  const evening = hourOfDay.filter((e) => e.hour >= 18 && e.hour < 22).reduce((s, e) => s + e.tokens, 0);
  const night = hourOfDay.filter((e) => e.hour >= 22 || e.hour < 6).reduce((s, e) => s + e.tokens, 0);
  const periods = [
    { label: "Morning", icon: "sun", tokens: morning, color: theme.warmAccent, hours: "6am\u201312pm" },
    { label: "Afternoon", icon: "star", tokens: afternoon, color: theme.goldAccent, hours: "12\u20136pm" },
    { label: "Evening", icon: "fire", tokens: evening, color: theme.purpleAccent, hours: "6\u201310pm" },
    { label: "Night", icon: "moon", tokens: night, color: theme.coolAccent, hours: "10pm\u20136am" }
  ];
  const dominant = periods.reduce((a, b) => a.tokens >= b.tokens ? a : b);
  const dominantPct = totalTokens > 0 ? (dominant.tokens / totalTokens * 100).toFixed(0) : "0";
  let narrativeText = "";
  if (dominant.label === "Night")
    narrativeText = `You're a night owl -- ${dominantPct}% of tokens between 10pm-6am`;
  else if (dominant.label === "Evening")
    narrativeText = `You're an evening coder -- ${dominantPct}% between 6-10pm`;
  else if (dominant.label === "Morning")
    narrativeText = `You're an early bird -- ${dominantPct}% before noon`;
  else
    narrativeText = `Afternoons are your peak -- ${dominantPct}% from 12-6pm`;
  p.push(svgText(PAD, 80, narrativeText, {
    fill: theme.narrativeColor,
    size: 18,
    weight: 500,
    family: DISPLAY_FONT
  }));
  const cardGap = 16;
  const cardWidth = (WIDTH - PAD * 2 - 3 * cardGap) / 4;
  const cardsY = 110;
  const cardH = 170;
  for (let i = 0;i < periods.length; i++) {
    const period = periods[i];
    const cx = PAD + i * (cardWidth + cardGap);
    const pct = totalTokens > 0 ? period.tokens / totalTokens * 100 : 0;
    const isDominant = period.label === dominant.label;
    const cardBg = theme.mode === "dark" ? "rgba(255,255,255,0.03)" : "rgba(0,0,0,0.02)";
    const borderColor = isDominant ? period.color : "transparent";
    p.push(rect2(cx, cardsY, cardWidth, cardH, cardBg, 6, {
      stroke: borderColor,
      strokeWidth: isDominant ? 1.5 : 0,
      opacity: 1
    }));
    if (isDominant) {
      p.push(`<line x1="${cx}" y1="${cardsY}" x2="${cx + cardWidth}" y2="${cardsY}" stroke="${escapeXml(period.color)}" stroke-width="2" opacity="0.8"/>`);
    }
    p.push(renderIcon(period.icon, cx + cardWidth / 2 - 12, cardsY + 20, 24, period.color));
    p.push(svgText(cx + cardWidth / 2, cardsY + 65, period.label, {
      fill: theme.subtitleColor,
      size: 11,
      weight: 600,
      anchor: "middle",
      family: MONO_FONT,
      spacing: 1
    }));
    p.push(svgText(cx + cardWidth / 2, cardsY + 110, `${pct.toFixed(0)}%`, {
      fill: period.color,
      size: 36,
      weight: 800,
      anchor: "middle",
      family: MONO_FONT
    }));
    p.push(svgText(cx + cardWidth / 2, cardsY + 135, formatNumber(period.tokens), {
      fill: theme.subtitleColor,
      size: 11,
      weight: 400,
      anchor: "middle",
      family: MONO_FONT
    }));
    p.push(svgText(cx + cardWidth / 2, cardsY + 155, period.hours, {
      fill: theme.subtitleColor,
      size: 10,
      weight: 400,
      anchor: "middle",
      family: MONO_FONT,
      opacity: 0.5
    }));
  }
  p.push(rule(PAD, height - 1, WIDTH - PAD * 2, theme.mode === "dark" ? "#ffffff" : "#000000", 0.06));
  return { svg: p.join(`
`), height };
}
function renderCacheSlide(output, theme) {
  const height = 280;
  const p = [];
  const stats = output.aggregated;
  const gc = theme.sectionBgs[7] ?? ["#080e0c", "#0c1210"];
  p.push(sectionBg(0, height, gc, "cache-bg"));
  p.push(sectionLabel(PAD, 40, "CACHE EFFICIENCY", theme.subtitleColor, theme.greenAccent));
  const hitRate = stats.cacheHitRate;
  const hitPct = (hitRate * 100).toFixed(1);
  const gaugeCx = WIDTH - 220;
  const gaugeCy = 160;
  const gaugeR = 80;
  const gaugeWidth = 14;
  const trackColor = theme.mode === "dark" ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.05)";
  const bgArc = describeArc(gaugeCx, gaugeCy, gaugeR, -90, 270);
  p.push(`<path d="${bgArc}" fill="none" stroke="${trackColor}" stroke-width="${gaugeWidth}" stroke-linecap="round"/>`);
  if (hitRate > 0) {
    const sweepAngle = Math.min(hitRate * 360, 359);
    const fillArc = describeArc(gaugeCx, gaugeCy, gaugeR, -90, -90 + sweepAngle);
    p.push(`<path d="${fillArc}" fill="none" stroke="${escapeXml(theme.greenAccent)}" stroke-width="${gaugeWidth}" stroke-linecap="round"/>`);
  }
  p.push(svgText(gaugeCx, gaugeCy + 8, `${hitPct}%`, {
    fill: theme.greenAccent,
    size: 28,
    weight: 800,
    anchor: "middle",
    family: MONO_FONT
  }));
  p.push(svgText(gaugeCx, gaugeCy + 28, "hit rate", {
    fill: theme.subtitleColor,
    size: 11,
    weight: 500,
    anchor: "middle",
    family: MONO_FONT
  }));
  p.push(svgText(PAD, 100, `${hitPct}% Cache Hit Rate`, {
    fill: theme.narrativeColor,
    size: 22,
    weight: 600,
    family: DISPLAY_FONT
  }));
  const cacheEcon = output.more?.cacheEconomics;
  if (cacheEcon) {
    const statItems = [
      { label: "Cache Reads", value: formatNumber(cacheEcon.readTokens) },
      { label: "Cache Writes", value: formatNumber(cacheEcon.writeTokens) }
    ];
    if (cacheEcon.reuseRatio !== null && Number.isFinite(cacheEcon.reuseRatio)) {
      statItems.push({ label: "Reuse Ratio", value: `${cacheEcon.reuseRatio.toFixed(1)}x` });
    }
    for (let i = 0;i < statItems.length; i++) {
      const item = statItems[i];
      const iy = 135 + i * 34;
      p.push(svgText(PAD, iy, item.value, {
        fill: theme.mode === "dark" ? "#e5e7eb" : "#1f2937",
        size: 18,
        weight: 700,
        family: MONO_FONT
      }));
      p.push(svgText(PAD + 140, iy, item.label, {
        fill: theme.subtitleColor,
        size: 12,
        weight: 500,
        family: MONO_FONT
      }));
    }
  }
  p.push(rule(PAD, height - 1, WIDTH - PAD * 2, theme.mode === "dark" ? "#ffffff" : "#000000", 0.06));
  return { svg: p.join(`
`), height };
}
function renderPeakDaySlide(output, theme) {
  const height = 240;
  const p = [];
  const stats = output.aggregated;
  const gc = theme.sectionBgs[8] ?? ["#0c0a06", "#100e0a"];
  p.push(sectionBg(0, height, gc, "peak-bg"));
  p.push(sectionLabel(PAD, 40, "PEAK DAY SPOTLIGHT", theme.subtitleColor, theme.goldAccent));
  if (!stats.peakDay) {
    p.push(svgText(PAD, 130, "No usage data recorded yet", {
      fill: theme.subtitleColor,
      size: 16,
      weight: 500
    }));
    return { svg: p.join(`
`), height };
  }
  const formattedDate = formatDateLong(stats.peakDay.date);
  p.push(svgText(PAD, 85, `${formattedDate} was your biggest day`, {
    fill: theme.narrativeColor,
    size: 20,
    weight: 500,
    family: DISPLAY_FONT
  }));
  p.push(svgText(PAD, 160, formatNumber(stats.peakDay.tokens), {
    fill: theme.goldAccent,
    size: 72,
    weight: 800,
    family: MONO_FONT,
    spacing: -3
  }));
  p.push(svgText(PAD, 190, "tokens in a single day", {
    fill: theme.subtitleColor,
    size: 14,
    weight: 500
  }));
  const badgeCx = WIDTH - 180;
  const badgeCy = 140;
  p.push(rect2(badgeCx - 40, badgeCy - 36, 80, 72, theme.mode === "dark" ? "rgba(255,255,255,0.03)" : "rgba(0,0,0,0.02)", 6));
  p.push(cornerMark(badgeCx - 40, badgeCy - 36, 12, theme.goldAccent, "tl"));
  p.push(cornerMark(badgeCx + 40, badgeCy + 36, 12, theme.goldAccent, "br"));
  p.push(svgIconTrophy(badgeCx - 20, badgeCy - 20, 40, theme.goldAccent));
  p.push(rule(PAD, height - 1, WIDTH - PAD * 2, theme.mode === "dark" ? "#ffffff" : "#000000", 0.06));
  return { svg: p.join(`
`), height };
}
function renderAchievementsSlide(output, theme) {
  const achievements = computeAchievements(output);
  const rows = Math.ceil(achievements.length / 2);
  const rowHeight = 80;
  const height = Math.max(200, 90 + rows * rowHeight + 20);
  const p = [];
  const gc = theme.sectionBgs[9] ?? ["#08080c", "#0c0c14"];
  p.push(sectionBg(0, height, gc, "achieve-bg"));
  p.push(sectionLabel(PAD, 40, "ACHIEVEMENTS UNLOCKED", theme.subtitleColor, theme.purpleAccent));
  if (achievements.length === 0) {
    p.push(svgText(PAD, 120, "Keep coding to unlock achievements!", {
      fill: theme.subtitleColor,
      size: 16,
      weight: 500
    }));
    return { svg: p.join(`
`), height: 200 };
  }
  const colWidth = (WIDTH - PAD * 2 - 20) / 2;
  for (let i = 0;i < achievements.length; i++) {
    const a = achievements[i];
    const col = i % 2;
    const row = Math.floor(i / 2);
    const ax = PAD + col * (colWidth + 20);
    const ay = 70 + row * rowHeight;
    const cardBg = theme.mode === "dark" ? "rgba(255,255,255,0.03)" : "rgba(0,0,0,0.02)";
    p.push(rect2(ax, ay, colWidth, 66, cardBg, 6));
    p.push(`<rect x="${ax}" y="${ay}" width="3" height="66" rx="1.5" fill="${escapeXml(a.color)}" opacity="0.7"/>`);
    p.push(renderIcon(a.icon, ax + 16, ay + 17, 32, a.color));
    p.push(svgText(ax + 60, ay + 28, a.title, {
      fill: theme.mode === "dark" ? "#f3f4f6" : "#1f2937",
      size: 15,
      weight: 700,
      family: DISPLAY_FONT
    }));
    p.push(svgText(ax + 60, ay + 48, a.subtitle, {
      fill: theme.subtitleColor,
      size: 12,
      weight: 500,
      family: MONO_FONT
    }));
  }
  p.push(rule(PAD, height - 1, WIDTH - PAD * 2, theme.mode === "dark" ? "#ffffff" : "#000000", 0.06));
  return { svg: p.join(`
`), height };
}
function renderMonthlyBurnSlide(output, theme) {
  const height = 260;
  const p = [];
  const gc = theme.sectionBgs[10] ?? ["#0a0c10", "#0e1014"];
  p.push(sectionBg(0, height, gc, "burn-bg"));
  p.push(sectionLabel(PAD, 40, "MONTHLY PROJECTION", theme.subtitleColor, theme.coolAccent));
  const burn = output.more?.monthlyBurn;
  if (!burn) {
    const avgDailyCost = output.aggregated.averageDailyCost;
    const projected = avgDailyCost * 30;
    p.push(svgText(PAD, 90, "At this rate, you will spend about", {
      fill: theme.narrativeColor,
      size: 18,
      weight: 500,
      family: DISPLAY_FONT
    }));
    p.push(svgText(PAD, 160, formatCost2(projected), {
      fill: theme.coolAccent,
      size: 64,
      weight: 800,
      family: MONO_FONT,
      spacing: -3
    }));
    p.push(svgText(PAD, 190, "per month", {
      fill: theme.subtitleColor,
      size: 14,
      weight: 500
    }));
    return { svg: p.join(`
`), height };
  }
  p.push(svgText(PAD, 90, "At this rate, you will spend", {
    fill: theme.narrativeColor,
    size: 18,
    weight: 500,
    family: DISPLAY_FONT
  }));
  p.push(svgText(PAD, 155, formatCost2(burn.projectedCost), {
    fill: theme.coolAccent,
    size: 64,
    weight: 800,
    family: MONO_FONT,
    spacing: -3
  }));
  p.push(svgText(PAD, 185, "this month", {
    fill: theme.subtitleColor,
    size: 14,
    weight: 500
  }));
  const barY = 210;
  const barWidth = WIDTH - PAD * 2;
  const barHeight = 10;
  const progress = burn.calendarDays > 0 ? burn.observedDays / burn.calendarDays : 0;
  const trackBg = theme.mode === "dark" ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.04)";
  p.push(rect2(PAD, barY, barWidth, barHeight, trackBg, 5));
  p.push(rect2(PAD, barY, Math.max(6, progress * barWidth), barHeight, theme.coolAccent, 5, { opacity: 0.7 }));
  p.push(svgText(PAD, barY + 30, `Based on ${burn.observedDays} of ${burn.calendarDays} days`, {
    fill: theme.subtitleColor,
    size: 11,
    weight: 400,
    family: MONO_FONT
  }));
  p.push(rule(PAD, height - 1, WIDTH - PAD * 2, theme.mode === "dark" ? "#ffffff" : "#000000", 0.06));
  return { svg: p.join(`
`), height };
}
function renderFooterSlide(_output, theme) {
  const height = 100;
  const p = [];
  const gc = theme.sectionBgs[11] ?? ["#060608", "#060608"];
  p.push(sectionBg(0, height, gc, "footer-bg"));
  p.push(cornerMark(PAD - 16, height - 16, 16, theme.heroAccent, "bl"));
  p.push(svgText(PAD, 40, "Generated by tokenleak", {
    fill: theme.subtitleColor,
    size: 12,
    weight: 500,
    family: MONO_FONT
  }));
  const now = new Date().toISOString().replace("T", " ").slice(0, 19) + " UTC";
  p.push(svgText(PAD, 60, now, {
    fill: theme.subtitleColor,
    size: 11,
    weight: 400,
    family: MONO_FONT,
    opacity: 0.5
  }));
  p.push(svgText(WIDTH - PAD, 50, "tokenleak", {
    fill: theme.heroAccent,
    size: 16,
    weight: 700,
    anchor: "end",
    family: MONO_FONT,
    opacity: 0.4
  }));
  return { svg: p.join(`
`), height };
}
function renderWrappedSlidesSvg(output, options) {
  const theme = getWrappedTheme(options.theme);
  const slides = [
    renderTitleSlide(output, theme),
    renderBigNumbersSlide(output, theme),
    renderStreakSlide(output, theme),
    renderTopModelSlide(output, theme),
    renderProviderMixSlide(output, theme),
    renderDayOfWeekSlide(output, theme),
    renderTimeOfDaySlide(output, theme),
    renderCacheSlide(output, theme),
    renderPeakDaySlide(output, theme),
    renderAchievementsSlide(output, theme),
    renderMonthlyBurnSlide(output, theme),
    renderFooterSlide(output, theme)
  ].filter((s) => s.height > 0);
  let totalHeight = 0;
  const stackedSections = [];
  for (const slide of slides) {
    stackedSections.push(`<g transform="translate(0, ${totalHeight})">`, slide.svg, "</g>");
    totalHeight += slide.height;
  }
  const bgColor = theme.mode === "dark" ? "#060608" : "#fafaf9";
  return [
    `<svg xmlns="http://www.w3.org/2000/svg" width="${WIDTH}" height="${totalHeight}" viewBox="0 0 ${WIDTH} ${totalHeight}" shape-rendering="geometricPrecision" text-rendering="optimizeLegibility" color-rendering="optimizeQuality">`,
    `<rect width="${WIDTH}" height="${totalHeight}" fill="${escapeXml(bgColor)}"/>`,
    globalDefs(theme.mode === "dark"),
    ...stackedSections,
    "</svg>"
  ].join(`
`);
}
var WIDTH = 1200, PAD = 80, DISPLAY_FONT = "'SF Pro Display', 'Helvetica Neue', 'Segoe UI', -apple-system, sans-serif", MONO_FONT = "'SF Mono', 'Menlo', 'JetBrains Mono', 'Cascadia Code', 'Fira Code', monospace", BODY_FONT = "'SF Pro Text', 'Helvetica Neue', 'Segoe UI', -apple-system, sans-serif", DAY_NAMES, DAY_SHORT, MONTH_NAMES2;
var init_wrapped_slides = __esm(() => {
  init_theme();
  DAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
  DAY_SHORT = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
  MONTH_NAMES2 = [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December"
  ];
});

// packages/renderers/dist/svg/wrapped-single-page.js
function txt(x, y, content, opts = {}) {
  const attrs = [
    `x="${x}"`,
    `y="${y}"`,
    `fill="${escapeXml(opts.fill ?? "#e8e2cc")}"`,
    `font-size="${opts.size ?? 14}"`,
    `font-family="${escapeXml(opts.family ?? BODY)}"`,
    `font-weight="${opts.weight ?? 400}"`
  ];
  if (opts.anchor)
    attrs.push(`text-anchor="${escapeXml(opts.anchor)}"`);
  if (opts.spacing !== undefined)
    attrs.push(`letter-spacing="${opts.spacing}"`);
  if (opts.opacity !== undefined)
    attrs.push(`opacity="${opts.opacity}"`);
  if (opts.dominantBaseline)
    attrs.push(`dominant-baseline="${opts.dominantBaseline}"`);
  return `<text ${attrs.join(" ")}>${escapeXml(content)}</text>`;
}
function box(x, y, w, h, fill, rx = 2, opts = {}) {
  const extra = [];
  if (opts.opacity !== undefined)
    extra.push(`opacity="${opts.opacity}"`);
  if (opts.stroke)
    extra.push(`stroke="${escapeXml(opts.stroke)}" stroke-width="${opts.strokeWidth ?? 1}"`);
  return `<rect x="${x}" y="${y}" width="${w}" height="${h}" rx="${rx}" fill="${escapeXml(fill)}" ${extra.join(" ")}/>`;
}
function line(x1, y1, x2, y2, color, width = 1, opacity = 1) {
  return `<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="${escapeXml(color)}" stroke-width="${width}" opacity="${opacity}"/>`;
}
function formatDateShort(dateStr) {
  const d = new Date(dateStr + "T00:00:00Z");
  return `${MONTH_NAMES3[d.getUTCMonth()]?.slice(0, 3)} ${d.getUTCDate()}, ${d.getUTCFullYear()}`;
}
function formatDateLong2(dateStr) {
  const d = new Date(dateStr + "T00:00:00Z");
  return `${MONTH_NAMES3[d.getUTCMonth()] ?? ""} ${d.getUTCDate()}, ${d.getUTCFullYear()}`;
}
function getProviderColor(provider, mode) {
  const entry = PROVIDER_COLORS[provider.toLowerCase()];
  if (entry)
    return entry[mode];
  return mode === "dark" ? "#555555" : "#888888";
}
function describeArc2(cx, cy, r, startDeg, endDeg) {
  const toRad = (deg) => (deg - 90) * Math.PI / 180;
  const start = { x: cx + r * Math.cos(toRad(endDeg)), y: cy + r * Math.sin(toRad(endDeg)) };
  const end = { x: cx + r * Math.cos(toRad(startDeg)), y: cy + r * Math.sin(toRad(startDeg)) };
  const large = endDeg - startDeg <= 180 ? "0" : "1";
  return `M ${start.x} ${start.y} A ${r} ${r} 0 ${large} 0 ${end.x} ${end.y}`;
}
function sectionTag(x, y, label, C) {
  return txt(x, y, label, {
    fill: C.muted,
    size: 10,
    weight: 400,
    family: MONO,
    spacing: 2.5
  });
}
function noiseDef(isDark) {
  const opacity = isDark ? 0.03 : 0.02;
  return [
    "<defs>",
    '<filter id="grain" x="0" y="0" width="100%" height="100%">',
    '<feTurbulence type="fractalNoise" baseFrequency="0.78" numOctaves="4" stitchTiles="stitch" result="noise"/>',
    '<feColorMatrix type="saturate" values="0" in="noise" result="mono"/>',
    '<feBlend in="SourceGraphic" in2="mono" mode="multiply"/>',
    "</filter>",
    "</defs>",
    `<!-- noise opacity: ${opacity} -->`
  ].join(`
`);
}
function renderWrappedSinglePageSvg(output, options = { theme: "dark" }) {
  const stats = output.aggregated;
  const more = output.more;
  const providers = output.providers;
  const { since, until } = output.dateRange;
  const achievements = computeAchievements(output);
  const isDark = options.theme === "dark";
  const C = isDark ? DARK : LIGHT;
  const parts = [];
  let y = 0;
  const headerH = 200;
  parts.push(box(0, y, WIDTH2, headerH, C.bg));
  if (isDark) {
    parts.push(`<defs><radialGradient id="amb1" cx="10%" cy="10%" r="60%"><stop offset="0%" stop-color="rgba(44,70,120,0.07)"/><stop offset="100%" stop-color="transparent"/></radialGradient></defs>`);
    parts.push(`<rect x="0" y="${y}" width="${WIDTH2}" height="${headerH}" fill="url(#amb1)"/>`);
  }
  parts.push(line(0, y, WIDTH2, y, C.gold, 1, 0.5));
  const year = until.slice(0, 4);
  parts.push(txt(PAD2, y + 68, "AI Wrapped", {
    fill: C.ivory,
    size: 68,
    weight: 800,
    family: DISPLAY,
    spacing: -3
  }));
  parts.push(txt(PAD2 + 460, y + 68, `'${year.slice(2)}`, {
    fill: C.gold,
    size: 68,
    weight: 800,
    family: DISPLAY,
    spacing: -3
  }));
  parts.push(txt(PAD2, y + 96, `${formatDateShort(since)} \u2014 ${formatDateShort(until)}`, {
    fill: C.muted,
    size: 13,
    weight: 400,
    family: MONO,
    spacing: 1
  }));
  parts.push(txt(PAD2, y + 126, "Every prompt has a price. Here's yours.", {
    fill: C.ivoryDim,
    size: 15,
    weight: 400,
    family: BODY
  }));
  const stampW = 140;
  const stampX = WIDTH2 - PAD2 - stampW;
  parts.push(box(stampX, y + 78, stampW, 36, "transparent", 2, { stroke: C.borderHi, strokeWidth: 1 }));
  parts.push(txt(stampX + stampW / 2, y + 101, "TokenLeak", {
    fill: C.gold,
    size: 16,
    weight: 800,
    family: DISPLAY,
    spacing: -0.5,
    anchor: "middle"
  }));
  const totalDays = Math.round((new Date(until + "T00:00:00Z").getTime() - new Date(since + "T00:00:00Z").getTime()) / (1000 * 60 * 60 * 24)) + 1;
  parts.push(`<circle cx="${PAD2 + 4}" cy="${y + 156}" r="3" fill="${C.gold}"/>`);
  parts.push(txt(PAD2 + 14, y + 160, `${totalDays} DAYS OF DATA`, {
    fill: C.muted,
    size: 9,
    weight: 400,
    family: MONO,
    spacing: 2
  }));
  parts.push(line(PAD2, y + headerH - 1, WIDTH2 - PAD2, y + headerH - 1, C.gold, 1, 0.15));
  y += headerH;
  const bigNumH = 140;
  parts.push(box(0, y, WIDTH2, bigNumH, C.surface));
  parts.push(sectionTag(PAD2, y + 24, "THE BIG NUMBERS", C));
  const cardW = (INNER - 30) / 4;
  const cardH = 82;
  const cardY = y + 38;
  const bigStats = [
    { label: "TOTAL TOKENS", value: formatNumber(stats.totalTokens), unit: "TOKENS", gold: false },
    { label: "TOTAL COST", value: formatCost2(stats.totalCost), unit: "USD", gold: true },
    { label: "ACTIVE DAYS", value: `${stats.activeDays}`, unit: `OF ${stats.totalDays}`, gold: false },
    { label: "AVG / DAY", value: formatNumber(stats.averageDailyTokens), unit: "TOKENS", gold: false }
  ];
  for (let i = 0;i < bigStats.length; i++) {
    const stat = bigStats[i];
    const cx = PAD2 + i * (cardW + 10);
    parts.push(box(cx, cardY, cardW, cardH, C.surface2, 2, { stroke: C.border, strokeWidth: 1 }));
    parts.push(txt(cx + 16, cardY + 20, stat.label, {
      fill: C.muted,
      size: 9,
      weight: 400,
      family: MONO,
      spacing: 2
    }));
    parts.push(txt(cx + 16, cardY + 52, stat.value, {
      fill: stat.gold ? C.gold : C.ivory,
      size: 30,
      weight: 800,
      family: DISPLAY,
      spacing: -1
    }));
    parts.push(txt(cx + 16, cardY + 68, stat.unit, {
      fill: C.gold,
      size: 9,
      weight: 400,
      family: MONO,
      spacing: 1.5
    }));
  }
  y += bigNumH;
  const colW = (INNER - 24) / 2;
  const leftX = PAD2;
  const rightX = PAD2 + colW + 24;
  const topModels2 = stats.topModels.slice(0, 3);
  const totalProviderTokens = providers.reduce((s, p) => s + p.totalTokens, 0);
  const providerMix = providers.map((p) => ({
    name: p.displayName,
    pct: totalProviderTokens > 0 ? p.totalTokens / totalProviderTokens * 100 : 0,
    color: getProviderColor(p.provider, options.theme)
  })).sort((a, b) => b.pct - a.pct);
  const modelSectionH = 28 + 22 + topModels2.length * 42;
  const providerSectionH = 18 + 22 + Math.max(150, providerMix.length * 30 + 50);
  const leftColH = modelSectionH + providerSectionH;
  const dow = stats.dayOfWeek;
  const dowH = dow.length > 0 ? 28 + 22 + 26 + 100 + 28 : 60;
  const todH = 20 + 22 + 65 + 8 + 65;
  const rightColH = dowH + todH;
  const midH = Math.max(leftColH, rightColH) + 20;
  parts.push(box(0, y, WIDTH2, midH, C.bg));
  let ly = y + 28;
  parts.push(sectionTag(leftX, ly, "YOUR TOP MODELS", C));
  ly += 22;
  if (topModels2.length > 0) {
    const maxPct = Math.max(...topModels2.map((m) => m.percentage), 1);
    for (let i = 0;i < topModels2.length; i++) {
      const m = topModels2[i];
      const barMaxW = colW - 80;
      const barW = Math.max(4, m.percentage / maxPct * barMaxW);
      const opacity = i === 0 ? 1 : i === 1 ? 0.6 : 0.35;
      parts.push(txt(leftX, ly + 14, m.model, {
        fill: C.text,
        size: 14,
        weight: 500,
        family: BODY
      }));
      parts.push(txt(leftX + colW, ly + 14, `${m.percentage.toFixed(1)}%`, {
        fill: C.gold,
        size: 13,
        weight: 700,
        family: MONO,
        anchor: "end"
      }));
      parts.push(line(leftX, ly + 26, leftX + colW, ly + 26, C.barTrack, 1));
      parts.push(line(leftX, ly + 26, leftX + barW, ly + 26, C.gold, 1, opacity));
      ly += 42;
    }
  }
  ly += 18;
  parts.push(sectionTag(leftX, ly, "PROVIDER MIX", C));
  ly += 22;
  const donutCx = leftX + 70;
  const donutCy = ly + 70;
  const donutR = 50;
  const donutStroke = 14;
  parts.push(`<circle cx="${donutCx}" cy="${donutCy}" r="${donutR}" fill="none" stroke="${C.trackStroke}" stroke-width="${donutStroke}"/>`);
  let startAngle = 0;
  for (const p of providerMix) {
    const sweep = p.pct / 100 * 360;
    if (sweep < 0.1)
      continue;
    const endAngle = Math.min(startAngle + sweep, 360);
    if (sweep >= 359.9) {
      parts.push(`<circle cx="${donutCx}" cy="${donutCy}" r="${donutR}" fill="none" stroke="${escapeXml(p.color)}" stroke-width="${donutStroke}"/>`);
    } else {
      const arc = describeArc2(donutCx, donutCy, donutR, startAngle, endAngle);
      parts.push(`<path d="${arc}" fill="none" stroke="${escapeXml(p.color)}" stroke-width="${donutStroke}" stroke-linecap="butt"/>`);
    }
    startAngle = endAngle;
  }
  parts.push(txt(donutCx, donutCy + 5, `${providers.length}`, {
    fill: C.ivory,
    size: 22,
    weight: 800,
    family: DISPLAY,
    anchor: "middle"
  }));
  parts.push(txt(donutCx, donutCy + 20, "providers", {
    fill: C.muted,
    size: 8,
    weight: 400,
    family: MONO,
    anchor: "middle",
    spacing: 1
  }));
  const legendX = leftX + 155;
  for (let i = 0;i < providerMix.length; i++) {
    const p = providerMix[i];
    const py = ly + 35 + i * 28;
    parts.push(box(legendX, py, 8, 8, p.color, 1));
    parts.push(txt(legendX + 16, py + 8, p.name, {
      fill: C.text,
      size: 13,
      weight: 500,
      family: BODY
    }));
    const pctLabel = p.pct > 0 && p.pct < 1 ? "<1%" : `${p.pct.toFixed(0)}%`;
    parts.push(txt(leftX + colW, py + 8, pctLabel, {
      fill: C.gold,
      size: 12,
      weight: 700,
      family: MONO,
      anchor: "end"
    }));
  }
  let ry = y + 28;
  parts.push(sectionTag(rightX, ry, "CODING DAYS", C));
  ry += 22;
  const dowOrder = [1, 2, 3, 4, 5, 6, 0];
  const dowEntries = dowOrder.map((dayNum) => {
    const entry = dow.find((e) => e.day === dayNum);
    return { label: DAY_NAMES2[dayNum] ?? "", tokens: entry?.tokens ?? 0 };
  });
  const maxDowTokens = Math.max(...dowEntries.map((e) => e.tokens), 1);
  if (dow.length > 0) {
    const peakDow = dowEntries.reduce((a, b) => b.tokens > a.tokens ? b : a);
    const peakDowFull = DAY_NAMES_FULL[dowOrder[dowEntries.indexOf(peakDow)] ?? 0] ?? "";
    parts.push(txt(rightX, ry + 14, `${peakDowFull} is your peak`, {
      fill: C.ivory,
      size: 18,
      weight: 700,
      family: DISPLAY,
      spacing: -0.5
    }));
    ry += 30;
    const barGap = 8;
    const barW = (colW - 6 * barGap) / 7;
    const barMaxH = 100;
    for (let i = 0;i < 7; i++) {
      const entry = dowEntries[i];
      const bx = rightX + i * (barW + barGap);
      const ratio = entry.tokens / maxDowTokens;
      const barH = Math.max(3, ratio * barMaxH);
      const by = ry + barMaxH - barH;
      const isPeak = entry.tokens === maxDowTokens;
      const opacity = ratio < 0.35 ? 0.35 : ratio < 0.55 ? 0.6 : 1;
      parts.push(box(bx, by, barW, barH, C.gold, 1, { opacity }));
      parts.push(txt(bx + barW / 2, ry + barMaxH + 16, entry.label, {
        fill: isPeak ? C.gold : C.muted,
        size: 9,
        weight: isPeak ? 700 : 400,
        family: MONO,
        anchor: "middle",
        spacing: 0.5
      }));
    }
    ry += barMaxH + 28;
  }
  ry += 20;
  parts.push(sectionTag(rightX, ry, "WHEN YOU CODE", C));
  ry += 22;
  const hourOfDay = more?.hourOfDay;
  let todPeriods = [
    { label: "Morning", range: "6am-12pm", pct: 0 },
    { label: "Afternoon", range: "12-6pm", pct: 0 },
    { label: "Evening", range: "6-10pm", pct: 0 },
    { label: "Night", range: "10pm-6am", pct: 0 }
  ];
  if (hourOfDay) {
    const total = hourOfDay.reduce((s, e) => s + e.tokens, 0);
    if (total > 0) {
      const morning = hourOfDay.filter((e) => e.hour >= 6 && e.hour < 12).reduce((s, e) => s + e.tokens, 0);
      const afternoon = hourOfDay.filter((e) => e.hour >= 12 && e.hour < 18).reduce((s, e) => s + e.tokens, 0);
      const evening = hourOfDay.filter((e) => e.hour >= 18 && e.hour < 22).reduce((s, e) => s + e.tokens, 0);
      const morningPct = Math.round(morning / total * 100);
      const afternoonPct = Math.round(afternoon / total * 100);
      const eveningPct = Math.round(evening / total * 100);
      const nightPct = Math.max(0, 100 - morningPct - afternoonPct - eveningPct);
      todPeriods = [
        { label: "Morning", range: "6am-12pm", pct: morningPct },
        { label: "Afternoon", range: "12-6pm", pct: afternoonPct },
        { label: "Evening", range: "6-10pm", pct: eveningPct },
        { label: "Night", range: "10pm-6am", pct: nightPct }
      ];
    }
  }
  const peakPeriod = todPeriods.reduce((a, b) => b.pct > a.pct ? b : a);
  const todCellW = (colW - 8) / 2;
  const todCellH = 65;
  for (let i = 0;i < 4; i++) {
    const period = todPeriods[i];
    const col = i % 2;
    const row = Math.floor(i / 2);
    const cx = rightX + col * (todCellW + 8);
    const cy = ry + row * (todCellH + 8);
    const isPeak = period.label === peakPeriod.label;
    parts.push(box(cx, cy, todCellW, todCellH, C.surface2, 2, {
      stroke: isPeak ? C.borderHi : C.border,
      strokeWidth: isPeak ? 1.5 : 1
    }));
    if (isPeak) {
      parts.push(line(cx + 2, cy, cx + todCellW - 2, cy, C.gold, 2, 0.6));
    }
    parts.push(txt(cx + 14, cy + 20, period.label.toUpperCase(), {
      fill: isPeak ? C.gold : C.muted,
      size: 8,
      weight: 400,
      family: MONO,
      spacing: 1.5
    }));
    parts.push(txt(cx + 14, cy + 44, `${period.pct}%`, {
      fill: isPeak ? C.gold : C.ivory,
      size: 22,
      weight: 800,
      family: DISPLAY,
      spacing: -0.5
    }));
    parts.push(txt(cx + todCellW - 12, cy + 44, period.range, {
      fill: C.muted,
      size: 9,
      weight: 400,
      family: MONO,
      anchor: "end"
    }));
  }
  y += midH;
  const bottomH = 260;
  parts.push(box(0, y, WIDTH2, bottomH, C.surface));
  parts.push(line(PAD2, y, WIDTH2 - PAD2, y, C.gold, 1, 0.15));
  const col3W = (INNER - 32) / 3;
  const c1x = PAD2;
  let c1y = y + 24;
  parts.push(sectionTag(c1x, c1y, "STREAK", C));
  c1y += 20;
  parts.push(txt(c1x, c1y + 42, `${stats.longestStreak}`, {
    fill: C.gold,
    size: 60,
    weight: 800,
    family: DISPLAY,
    spacing: -2
  }));
  parts.push(txt(c1x, c1y + 62, "DAY LONGEST STREAK", {
    fill: C.muted,
    size: 9,
    weight: 400,
    family: MONO,
    spacing: 2
  }));
  parts.push(txt(c1x, c1y + 86, `Current: ${stats.currentStreak} days`, {
    fill: C.muted,
    size: 11,
    weight: 400,
    family: MONO,
    spacing: 0.5
  }));
  c1y += 102;
  const activeDates = new Set;
  for (const prov of providers) {
    for (const d of prov.daily) {
      if (d.totalTokens > 0)
        activeDates.add(d.date);
    }
  }
  const dotSize = 10;
  const dotGap = 4;
  const dotsPerRow = Math.floor(col3W / (dotSize + dotGap));
  for (let i = 0;i < 30; i++) {
    const dDate = new Date(new Date(until + "T00:00:00Z").getTime() - (29 - i) * 86400000);
    const dateStr = dDate.toISOString().slice(0, 10);
    const isActive = activeDates.has(dateStr);
    const isCurrentStreak = i >= 30 - stats.currentStreak;
    const col = i % dotsPerRow;
    const row = Math.floor(i / dotsPerRow);
    const dx = c1x + col * (dotSize + dotGap);
    const dy = c1y + row * (dotSize + dotGap);
    let dotColor = C.dotInactive;
    let dotBorder = C.dotInactiveBorder;
    if (isCurrentStreak) {
      dotColor = C.gold;
      dotBorder = C.gold;
    } else if (isActive) {
      dotColor = C.goldDim;
      dotBorder = C.goldDim;
    }
    parts.push(box(dx, dy, dotSize, dotSize, dotColor, 2, { stroke: dotBorder, strokeWidth: 1 }));
  }
  const c2x = PAD2 + col3W + 16;
  let c2y = y + 24;
  parts.push(sectionTag(c2x, c2y, "CACHE", C));
  c2y += 20;
  const hitRate = stats.cacheHitRate;
  const hitPct = Math.round(hitRate * 100);
  const ringCx = c2x + col3W / 2;
  const ringCy = c2y + 68;
  const ringR = 48;
  const ringStroke = 10;
  parts.push(`<circle cx="${ringCx}" cy="${ringCy}" r="${ringR}" fill="none" stroke="${C.trackStroke}" stroke-width="${ringStroke}"/>`);
  if (hitRate > 0) {
    const sweep = Math.min(hitRate * 360, 359);
    const arc = describeArc2(ringCx, ringCy, ringR, 0, sweep);
    parts.push(`<path d="${arc}" fill="none" stroke="${C.gold}" stroke-width="${ringStroke}" stroke-linecap="butt"/>`);
  }
  parts.push(txt(ringCx, ringCy + 5, `${hitPct}%`, {
    fill: C.gold,
    size: 28,
    weight: 800,
    family: DISPLAY,
    anchor: "middle"
  }));
  parts.push(txt(ringCx, ringCy + 20, "HIT RATE", {
    fill: C.muted,
    size: 8,
    weight: 400,
    family: MONO,
    anchor: "middle",
    spacing: 1.5
  }));
  c2y += 136;
  const cacheEcon = more?.cacheEconomics;
  if (cacheEcon) {
    const cacheStatItems = [
      { label: "READS", value: formatNumber(cacheEcon.readTokens), highlight: false },
      { label: "WRITES", value: formatNumber(cacheEcon.writeTokens), highlight: false }
    ];
    if (cacheEcon.reuseRatio !== null && Number.isFinite(cacheEcon.reuseRatio)) {
      cacheStatItems.push({ label: "REUSE", value: `${cacheEcon.reuseRatio.toFixed(1)}x`, highlight: true });
    }
    const cacheCardW = (col3W - (cacheStatItems.length - 1) * 6) / cacheStatItems.length;
    const cacheCardH = 52;
    for (let i = 0;i < cacheStatItems.length; i++) {
      const item = cacheStatItems[i];
      const ix = c2x + i * (cacheCardW + 6);
      const iy = c2y;
      parts.push(box(ix, iy, cacheCardW, cacheCardH, C.surface2, 2, {
        stroke: item.highlight ? C.borderHi : C.border,
        strokeWidth: 1
      }));
      parts.push(txt(ix + cacheCardW / 2, iy + 16, item.label, {
        fill: C.muted,
        size: 8,
        weight: 400,
        family: MONO,
        anchor: "middle",
        spacing: 1.5
      }));
      parts.push(txt(ix + cacheCardW / 2, iy + 38, item.value, {
        fill: item.highlight ? C.gold : C.ivory,
        size: 16,
        weight: 700,
        family: DISPLAY,
        anchor: "middle",
        spacing: -0.5
      }));
    }
  }
  const c3x = PAD2 + 2 * (col3W + 16);
  let c3y = y + 24;
  parts.push(sectionTag(c3x, c3y, "PEAK DAY", C));
  c3y += 20;
  if (stats.peakDay) {
    parts.push(box(c3x, c3y, col3W, 130, C.surface2, 2, { stroke: C.borderHi, strokeWidth: 1 }));
    parts.push(txt(c3x + col3W / 2, c3y + 24, formatDateLong2(stats.peakDay.date).toUpperCase(), {
      fill: C.muted,
      size: 9,
      weight: 400,
      family: MONO,
      anchor: "middle",
      spacing: 2.5
    }));
    parts.push(txt(c3x + col3W / 2, c3y + 72, formatNumber(stats.peakDay.tokens), {
      fill: C.gold,
      size: 46,
      weight: 800,
      family: DISPLAY,
      anchor: "middle",
      spacing: -2
    }));
    parts.push(txt(c3x + col3W / 2, c3y + 94, "TOKENS IN ONE DAY", {
      fill: C.muted,
      size: 9,
      weight: 400,
      family: MONO,
      anchor: "middle",
      spacing: 2
    }));
    const multiplier = stats.averageDailyTokens > 0 ? (stats.peakDay.tokens / stats.averageDailyTokens).toFixed(1) : "0";
    parts.push(txt(c3x + col3W / 2, c3y + 118, `${multiplier}x your daily average`, {
      fill: C.muted,
      size: 11,
      weight: 400,
      family: BODY,
      anchor: "middle"
    }));
  } else {
    parts.push(txt(c3x, c3y + 60, "No peak day data", {
      fill: C.muted,
      size: 14,
      weight: 400,
      family: BODY
    }));
  }
  c3y += 148;
  const projectedCost = more?.monthlyBurn?.projectedCost ?? stats.averageDailyCost * 30;
  parts.push(txt(c3x, c3y, "PROJECTED / MONTH", {
    fill: C.muted,
    size: 9,
    weight: 400,
    family: MONO,
    spacing: 2
  }));
  parts.push(txt(c3x, c3y + 28, formatCost2(projectedCost), {
    fill: C.ivory,
    size: 30,
    weight: 800,
    family: DISPLAY,
    spacing: -1
  }));
  const avgDailyCostStr = stats.averageDailyCost >= 1 ? `$${stats.averageDailyCost.toFixed(2)}` : `$${stats.averageDailyCost.toFixed(4)}`;
  parts.push(txt(c3x, c3y + 44, `${avgDailyCostStr} avg/day`, {
    fill: C.muted,
    size: 11,
    weight: 400,
    family: MONO,
    spacing: 0.5
  }));
  y += bottomH;
  const achH = 180;
  parts.push(box(0, y, WIDTH2, achH, C.bg));
  parts.push(line(PAD2, y, WIDTH2 - PAD2, y, C.gold, 1, 0.15));
  const ALL_BADGES = [
    { title: "Streak Master", sub: ">30d streak" },
    { title: "Night Owl", sub: ">40% night" },
    { title: "Big Spender", sub: ">$100 total" },
    { title: "Cache Master", sub: ">50% hit rate" },
    { title: "Daily Driver", sub: ">80% active" },
    { title: "Power User", sub: ">10k avg/day" },
    { title: "Summit Day", sub: "Peak >50k" },
    { title: "Multi-Tool", sub: "3+ providers" },
    { title: "Early Bird", sub: ">40% morning" },
    { title: "Model Hopper", sub: "4+ models" }
  ];
  const badgeTitleSet = new Set(ALL_BADGES.map((b) => b.title));
  const earnedTitles = new Set(achievements.filter((a) => badgeTitleSet.has(a.title)).map((a) => a.title));
  const earnedCount = earnedTitles.size;
  parts.push(sectionTag(PAD2, y + 24, `ACHIEVEMENTS \xB7 ${earnedCount} UNLOCKED`, C));
  const badgeCols = 5;
  const badgeGapX = 10;
  const badgeGapY = 8;
  const badgeW = (INNER - (badgeCols - 1) * badgeGapX) / badgeCols;
  const badgeH = 54;
  const badgeStartY = y + 40;
  for (let i = 0;i < ALL_BADGES.length; i++) {
    const badge = ALL_BADGES[i];
    const isEarned = earnedTitles.has(badge.title);
    const col = i % badgeCols;
    const row = Math.floor(i / badgeCols);
    const bx = PAD2 + col * (badgeW + badgeGapX);
    const by = badgeStartY + row * (badgeH + badgeGapY);
    parts.push(`<g opacity="${isEarned ? 1 : 0.2}">`);
    parts.push(box(bx, by, badgeW, badgeH, C.surface2, 2, {
      stroke: isEarned ? C.borderHi : C.border,
      strokeWidth: 1
    }));
    parts.push(txt(bx + badgeW / 2, by + 24, badge.title, {
      fill: isEarned ? C.ivory : C.muted,
      size: 11,
      weight: 600,
      family: BODY,
      anchor: "middle"
    }));
    parts.push(txt(bx + badgeW / 2, by + 42, badge.sub, {
      fill: C.muted,
      size: 9,
      weight: 400,
      family: MONO,
      anchor: "middle",
      spacing: 0.5
    }));
    parts.push("</g>");
  }
  y += achH;
  const footH = 44;
  parts.push(box(0, y, WIDTH2, footH, C.bg));
  parts.push(line(PAD2, y, WIDTH2 - PAD2, y, C.gold, 1, 0.15));
  const generatedTs = output.generated ? output.generated.replace("T", " ").slice(0, 19) + " UTC" : new Date().toISOString().replace("T", " ").slice(0, 19) + " UTC";
  parts.push(txt(PAD2, y + 28, `Generated ${generatedTs}`, {
    fill: C.muted2,
    size: 9,
    weight: 400,
    family: MONO,
    spacing: 1
  }));
  parts.push(txt(WIDTH2 - PAD2, y + 28, "tokenleak.devaa.dev", {
    fill: C.gold,
    size: 11,
    weight: 700,
    family: MONO,
    anchor: "end",
    opacity: 0.5,
    spacing: 0.5
  }));
  y += footH;
  const totalHeight = y;
  const noiseOpacity = isDark ? 0.03 : 0.02;
  return [
    `<svg xmlns="http://www.w3.org/2000/svg" width="${WIDTH2}" height="${totalHeight}" viewBox="0 0 ${WIDTH2} ${totalHeight}" shape-rendering="geometricPrecision" text-rendering="optimizeLegibility">`,
    `<rect width="${WIDTH2}" height="${totalHeight}" fill="${C.bg}"/>`,
    noiseDef(isDark),
    `<rect width="${WIDTH2}" height="${totalHeight}" fill="transparent" filter="url(#grain)" opacity="${noiseOpacity}" pointer-events="none"/>`,
    ...parts,
    "</svg>"
  ].join(`
`);
}
var WIDTH2 = 1200, PAD2 = 56, INNER, DISPLAY = "'Bricolage Grotesque', 'SF Pro Display', 'Helvetica Neue', sans-serif", MONO = "'Space Mono', 'SF Mono', 'Menlo', monospace", BODY = "'Space Grotesk', 'SF Pro Text', 'Helvetica Neue', sans-serif", DARK, LIGHT, PROVIDER_COLORS, DAY_NAMES2, DAY_NAMES_FULL, MONTH_NAMES3;
var init_wrapped_single_page = __esm(() => {
  init_wrapped_slides();
  INNER = WIDTH2 - PAD2 * 2;
  DARK = {
    bg: "#09090b",
    surface: "#111114",
    surface2: "#16161a",
    border: "rgba(255,255,255,0.07)",
    borderHi: "rgba(212,175,95,0.24)",
    gold: "#d4af5f",
    goldDim: "#a08040",
    ivory: "#f0ead6",
    ivoryDim: "rgba(240,234,214,0.52)",
    text: "#e8e2cc",
    muted: "rgba(232,226,204,0.38)",
    muted2: "rgba(232,226,204,0.18)",
    providerDefault: "#555555",
    trackStroke: "rgba(255,255,255,0.05)",
    barTrack: "rgba(255,255,255,0.09)",
    dotInactive: "#16161a",
    dotInactiveBorder: "rgba(255,255,255,0.07)"
  };
  LIGHT = {
    bg: "#fafaf9",
    surface: "#f0efed",
    surface2: "#e8e6e3",
    border: "rgba(0,0,0,0.08)",
    borderHi: "rgba(160,128,64,0.3)",
    gold: "#9a7b3a",
    goldDim: "#b8985a",
    ivory: "#1a1a18",
    ivoryDim: "rgba(26,26,24,0.6)",
    text: "#2c2c28",
    muted: "rgba(44,44,40,0.42)",
    muted2: "rgba(44,44,40,0.22)",
    providerDefault: "#888888",
    trackStroke: "rgba(0,0,0,0.06)",
    barTrack: "rgba(0,0,0,0.08)",
    dotInactive: "#e8e6e3",
    dotInactiveBorder: "rgba(0,0,0,0.08)"
  };
  PROVIDER_COLORS = {
    anthropic: { dark: "#d4af5f", light: "#9a7b3a" },
    "claude-code": { dark: "#d4af5f", light: "#9a7b3a" },
    openai: { dark: "#3a5070", light: "#4a6a90" },
    codex: { dark: "#3a5070", light: "#4a6a90" },
    google: { dark: "#6a2535", light: "#8a3548" },
    cursor: { dark: "#7c5cbf", light: "#6a4aaa" },
    pi: { dark: "#5a4a70", light: "#706088" }
  };
  DAY_NAMES2 = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
  DAY_NAMES_FULL = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
  MONTH_NAMES3 = [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December"
  ];
});

// packages/renderers/dist/svg/index.js
var init_svg = __esm(() => {
  init_svg_renderer();
  init_wrapped();
  init_badge();
  init_wrapped_slides();
  init_wrapped_single_page();
});

// packages/renderers/dist/png/png-renderer.js
import sharp from "sharp";

class PngRenderer {
  format = "png";
  async render(output, options) {
    const svgString = renderTerminalCardSvg(output, options);
    const pngBuffer = await sharp(Buffer.from(svgString), {
      density: PNG_DENSITY
    }).png({
      adaptiveFiltering: true,
      compressionLevel: 9,
      force: true
    }).toBuffer();
    return pngBuffer;
  }
}
var PNG_DENSITY = 432;
var init_png_renderer = __esm(() => {
  init_terminal_card();
});

// packages/renderers/dist/png/wrapped-card.js
import sharp2 from "sharp";
async function renderWrappedPng(output, options) {
  const svgString = renderWrappedSinglePageSvg(output, { theme: options.theme });
  const pngBuffer = await sharp2(Buffer.from(svgString), {
    density: PNG_DENSITY2
  }).png({
    adaptiveFiltering: true,
    compressionLevel: 9,
    force: true
  }).toBuffer();
  return pngBuffer;
}
var PNG_DENSITY2 = 216;
var init_wrapped_card = __esm(() => {
  init_wrapped_single_page();
});

// packages/renderers/dist/png/index.js
var init_png = __esm(() => {
  init_png_renderer();
  init_wrapped_card();
});

// packages/renderers/dist/terminal/colors.js
function colorize256(text2, code, noColor2) {
  if (noColor2)
    return text2;
  return `${ESC}38;5;${code}m${text2}${RESET}`;
}
function background256(text2, code, noColor2) {
  if (noColor2)
    return text2;
  return `${ESC}48;5;${code}m${text2}${RESET}`;
}
function bold256(text2, code, noColor2) {
  if (noColor2)
    return text2;
  return `${ESC}1;38;5;${code}m${text2}${RESET}`;
}
function inverse256(text2, code, noColor2) {
  if (noColor2)
    return text2;
  return `${ESC}7;38;5;${code}m${text2}${RESET}`;
}
function dim(text2, noColor2) {
  if (noColor2)
    return text2;
  return `${ESC}2m${text2}${RESET}`;
}
function bold2(text2, noColor2) {
  if (noColor2)
    return text2;
  return `${ESC}1m${text2}${RESET}`;
}
var ESC = "\x1B[", RESET, SEMANTIC, DOW_COLORS, TOD_COLORS, MODEL_COLORS, PROJECT_COLORS;
var init_colors = __esm(() => {
  RESET = `${ESC}0m`;
  SEMANTIC = {
    INPUT: 68,
    OUTPUT: 71,
    ACCENT: 173,
    NEGATIVE: 167,
    ACTIVE: 68,
    HINT: 179
  };
  DOW_COLORS = {
    Sun: 174,
    Mon: 68,
    Tue: 71,
    Wed: 179,
    Thu: 140,
    Fri: 115,
    Sat: 173
  };
  TOD_COLORS = {
    "After midnight": 140,
    Morning: 179,
    Afternoon: 71,
    Evening: 68,
    Night: 96
  };
  MODEL_COLORS = [
    68,
    71,
    173,
    140,
    179,
    174,
    139,
    73,
    167,
    115
  ];
  PROJECT_COLORS = [
    71,
    68,
    173,
    139,
    179,
    140,
    174,
    73,
    167,
    115
  ];
});

// packages/renderers/dist/terminal/layout.js
function stripAnsi(text2) {
  return text2.replace(/\u001B\[[0-9;?]*[A-Za-z]/g, "");
}
function visibleLength(text2) {
  return stripAnsi(text2).length;
}
function padVisible(text2, width) {
  const padding = Math.max(0, width - visibleLength(text2));
  return text2 + " ".repeat(padding);
}
function truncateVisible(text2, width) {
  if (width <= 0)
    return "";
  const plain = stripAnsi(text2);
  if (plain.length <= width)
    return text2;
  const limit = width <= 1 ? width : width - 1;
  let visibleCount = 0;
  let index = 0;
  let result = "";
  let sawAnsi = false;
  while (index < text2.length && visibleCount < limit) {
    if (text2[index] === "\x1B") {
      const match = text2.slice(index).match(/^\u001B\[[0-9;?]*[A-Za-z]/);
      if (match) {
        result += match[0];
        index += match[0].length;
        sawAnsi = true;
        continue;
      }
    }
    result += text2[index];
    index += 1;
    visibleCount += 1;
  }
  return sawAnsi ? `${result}\u2026\x1B[0m` : `${result}\u2026`;
}
function renderColumns(left, right, totalWidth, leftRatio = 0.5, gutter = 3) {
  const safeWidth = Math.max(12, totalWidth);
  const leftWidth = Math.max(18, Math.floor((safeWidth - gutter) * leftRatio));
  const rightWidth = Math.max(18, safeWidth - leftWidth - gutter);
  const rows = Math.max(left.length, right.length);
  const lines = [];
  for (let index = 0;index < rows; index += 1) {
    const leftLine = truncateVisible(left[index] ?? "", leftWidth);
    const rightLine = truncateVisible(right[index] ?? "", rightWidth);
    lines.push(`${padVisible(leftLine, leftWidth)}${" ".repeat(gutter)}${rightLine}`);
  }
  return lines;
}

// packages/renderers/dist/terminal/compact.js
function boxedHeader(title, width, noColor2) {
  const inner = Math.max(1, width - 2);
  const padded = ` ${title} `;
  const remaining = Math.max(0, inner - padded.length);
  const left = Math.floor(remaining / 2);
  const right = remaining - left;
  const titleLine = `${BOX_V}${" ".repeat(left)}${bold2(padded, noColor2)}${" ".repeat(right)}${BOX_V}`;
  return [
    `${BOX_TL}${BOX_H.repeat(inner)}${BOX_TR}`,
    titleLine,
    `${BOX_BL}${BOX_H.repeat(inner)}${BOX_BR}`
  ].join(`
`);
}
function renderSummaryParts(parts, width, noColor2) {
  const left = parts.filter((_, index) => index % 2 === 0).map((part) => colorize256(part, SEMANTIC.INPUT, noColor2));
  const right = parts.filter((_, index) => index % 2 === 1).map((part) => colorize256(part, SEMANTIC.OUTPUT, noColor2));
  return renderColumns(left, right, Math.max(24, width - 2), 0.5, 2).map((line2) => `  ${line2}`).join(`
`);
}
function renderCompactDashboard(model, options) {
  const width = options.width;
  const noColor2 = options.noColor;
  const lines = [
    boxedHeader("Tokenleak", width, noColor2),
    "",
    truncateVisible(`  Range ${model.rangeLabel}`, width),
    "",
    renderSummaryParts(model.overview.summary, width, noColor2),
    ...model.overview.trend ? ["", truncateVisible(`  Recent Trend ${model.overview.trend}`, width)] : [],
    ""
  ];
  if (model.overview.metrics.length > 0) {
    const keyMetrics = model.overview.metrics.slice(0, 4).map((metric) => {
      const text2 = `${metric.label}: ${metric.value}`;
      return `  ${truncateVisible(text2, width - 2)}`;
    });
    lines.push(...keyMetrics, "");
  }
  if (model.activeProviders.length > 0) {
    lines.push(`  ${bold2("Providers", noColor2)}`);
    for (const provider of model.activeProviders.slice(0, 4)) {
      const tokensMetric = provider.metrics.find((entry) => entry.label === "Total Tokens");
      const summary = `${provider.provider.displayName} ${tokensMetric?.value ?? ""} ${provider.lastActiveDate ? `| ${provider.lastActiveDate}` : ""}`.trim();
      lines.push(truncateVisible(`  ${summary}`, width));
    }
    lines.push("");
  }
  if (model.inactiveProviders.length > 0) {
    lines.push(truncateVisible(`  No activity: ${model.inactiveProviders.join(", ")}`, width));
  } else if (model.activeProviders.length === 0) {
    lines.push("  No provider activity in the selected range.");
  }
  return lines.filter((line2, index, array) => !(line2 === "" && array[index - 1] === "")).join(`
`);
}
var BOX_H = "\u2500", BOX_V = "\u2502", BOX_TL = "\u256D", BOX_TR = "\u256E", BOX_BL = "\u2570", BOX_BR = "\u256F";
var init_compact = __esm(() => {
  init_colors();
});

// packages/renderers/dist/terminal/dashboard-model.js
function formatTokens2(count) {
  if (count >= 1e6) {
    return `${(count / 1e6).toFixed(1)}M`;
  }
  if (count >= 1000) {
    return `${(count / 1000).toFixed(0)}K`;
  }
  return String(count);
}
function formatCost3(cost) {
  return `$${cost.toFixed(2)}`;
}
function formatPercent2(rate) {
  return `${(rate * 100).toFixed(1)}%`;
}
function formatSharePercent(percentage) {
  return `${percentage.toFixed(0)}%`;
}
function buildRangeLabel(output) {
  return `${output.dateRange.since} -> ${output.dateRange.until}`;
}
function buildSparkline(daily, points = 14) {
  const blocks = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
  if (daily.length === 0)
    return "\xB7".repeat(points);
  const values = daily.slice().sort((left, right) => left.date.localeCompare(right.date)).slice(-points).map((entry) => entry.totalTokens);
  const max = Math.max(...values, 0);
  if (max <= 0) {
    return "\xB7".repeat(values.length);
  }
  return values.map((value) => {
    const index = Math.min(blocks.length - 1, Math.round(value / max * (blocks.length - 1)));
    return blocks[index] ?? blocks[0];
  }).join("");
}
function getLastActiveDate(provider) {
  const activeDays = provider.daily.filter((entry) => entry.totalTokens > 0);
  return activeDays.at(-1)?.date ?? null;
}
function buildMetricEntries(stats, cacheRoiSummary = null) {
  const metrics = [
    { label: "Current Streak", value: `${stats.currentStreak}d` },
    { label: "Longest Streak", value: `${stats.longestStreak}d` },
    { label: "Total Tokens", value: formatTokens2(stats.totalTokens) },
    { label: "Total Cost", value: formatCost3(stats.totalCost) }
  ];
  if (stats.rolling30dTokens > 0 || stats.rolling30dCost > 0) {
    metrics.push({ label: "30d Tokens", value: formatTokens2(stats.rolling30dTokens) });
    metrics.push({ label: "30d Cost", value: formatCost3(stats.rolling30dCost) });
  }
  if (stats.rolling7dTokens > 0 || stats.rolling7dCost > 0) {
    metrics.push({ label: "7d Tokens", value: formatTokens2(stats.rolling7dTokens) });
    metrics.push({ label: "7d Cost", value: formatCost3(stats.rolling7dCost) });
  }
  if (stats.activeDays > 0) {
    metrics.push({ label: "Avg Daily Tokens", value: formatTokens2(stats.averageDailyTokens) });
    metrics.push({ label: "Avg Daily Cost", value: formatCost3(stats.averageDailyCost) });
  }
  if (stats.totalTokens > 0) {
    metrics.push({ label: "Cache Hit Rate", value: formatPercent2(stats.cacheHitRate) });
  }
  metrics.push({ label: "Active Days", value: `${stats.activeDays} / ${stats.totalDays}` });
  if (stats.peakDay) {
    metrics.push({
      label: "Peak Day",
      value: `${stats.peakDay.date} (${formatTokens2(stats.peakDay.tokens)})`
    });
  }
  if (cacheRoiSummary) {
    metrics.push({
      label: "Cache ROI",
      value: `${cacheRoiSummary.netSavings >= 0 ? "+" : "-"}${formatCost3(Math.abs(cacheRoiSummary.netSavings))}`
    });
    if (cacheRoiSummary.paybackRatio !== null) {
      metrics.push({
        label: "Cache Payback",
        value: `${cacheRoiSummary.paybackRatio.toFixed(1)}x`
      });
    }
  }
  return metrics;
}
function buildProviderSummary(provider, stats) {
  const parts = [
    `${formatTokens2(stats.totalTokens)} tokens`,
    formatCost3(stats.totalCost),
    `${stats.activeDays} active day${stats.activeDays === 1 ? "" : "s"}`
  ];
  const lastActiveDate = getLastActiveDate(provider);
  if (lastActiveDate) {
    parts.push(`last active ${lastActiveDate}`);
  }
  if (stats.topModels[0]) {
    parts.push(`${stats.topModels[0].model} ${formatSharePercent(stats.topModels[0].percentage)}`);
  }
  return parts;
}
function buildInsights(stats) {
  const insights = [];
  if (stats.currentStreak >= 7) {
    insights.push(`${stats.currentStreak}-day streak is still alive.`);
  }
  if (stats.cacheHitRate >= 0.5) {
    insights.push(`Cache reuse is strong at ${formatPercent2(stats.cacheHitRate)}.`);
  } else if (stats.cacheHitRate < 0.1 && stats.totalTokens > 0) {
    insights.push("Cache reuse is low. There is room to improve prompt caching.");
  }
  if (stats.peakDay) {
    insights.push(`Peak usage hit ${formatTokens2(stats.peakDay.tokens)} on ${stats.peakDay.date}.`);
  }
  if (stats.topModels[0] && stats.topModels[0].percentage >= 70) {
    insights.push(`${stats.topModels[0].model} dominates at ${formatSharePercent(stats.topModels[0].percentage)}.`);
  }
  return insights;
}
function buildDayOfWeekPatterns(stats) {
  const maxTokens = Math.max(...stats.dayOfWeek.map((entry) => entry.tokens), 0);
  if (maxTokens <= 0) {
    return [];
  }
  return stats.dayOfWeek.filter((entry) => entry.tokens > 0).map((entry) => ({
    label: entry.label,
    value: formatTokens2(entry.tokens),
    share: entry.tokens / maxTokens
  }));
}
function buildTopModelPatterns(stats) {
  return stats.topModels.slice(0, 5).filter((entry) => entry.tokens > 0).map((entry) => ({
    label: entry.model,
    value: formatSharePercent(entry.percentage),
    share: Math.max(0.03, entry.percentage / 100)
  }));
}
function buildProviderModel(provider, until) {
  const stats = aggregate(provider.daily, until);
  if (stats.totalTokens <= 0) {
    return null;
  }
  return {
    provider,
    stats,
    summary: buildProviderSummary(provider, stats),
    trend: buildSparkline(provider.daily),
    metrics: buildMetricEntries(stats),
    dayOfWeek: buildDayOfWeekPatterns(stats),
    topModels: buildTopModelPatterns(stats),
    insights: buildInsights(stats),
    lastActiveDate: getLastActiveDate(provider)
  };
}
function buildOverview(output, activeProviders) {
  const mergedDaily = activeProviders.length > 0 ? mergeProviderData(activeProviders.map((entry) => entry.provider)) : [];
  const summary = [
    `${formatTokens2(output.aggregated.totalTokens)} tokens`,
    formatCost3(output.aggregated.totalCost),
    `${activeProviders.length} active provider${activeProviders.length === 1 ? "" : "s"}`,
    `${output.aggregated.activeDays} active day${output.aggregated.activeDays === 1 ? "" : "s"}`
  ];
  const metrics = buildMetricEntries(output.aggregated, output.more?.cacheRoi?.summary ?? null);
  const maxProviderTokens = Math.max(...activeProviders.map((entry) => entry.stats.totalTokens), 0);
  const providerLeaders = activeProviders.slice().sort((left, right) => right.stats.totalTokens - left.stats.totalTokens).map((entry) => ({
    label: entry.provider.displayName,
    value: formatTokens2(entry.stats.totalTokens),
    share: maxProviderTokens > 0 ? entry.stats.totalTokens / maxProviderTokens : 0
  }));
  return {
    summary,
    trend: buildSparkline(mergedDaily),
    metrics,
    providerLeaders
  };
}
function resolveDashboardMode(width) {
  if (width < 32)
    return "summary";
  if (width < 56)
    return "compact";
  return "full";
}
function buildDashboardModel(output, options) {
  const activeProviders = [];
  const inactiveProviders = [];
  for (const provider of output.providers) {
    const model = buildProviderModel(provider, output.dateRange.until);
    if (model) {
      activeProviders.push(model);
    } else {
      inactiveProviders.push(provider.displayName);
    }
  }
  return {
    mode: resolveDashboardMode(options.width),
    rangeLabel: buildRangeLabel(output),
    activeProviders,
    inactiveProviders,
    overview: buildOverview(output, activeProviders)
  };
}
var init_dashboard_model = __esm(() => {
  init_dist();
});

// packages/renderers/dist/shared/heatmap-model.js
function formatDate(date) {
  const year = date.getUTCFullYear();
  const month = String(date.getUTCMonth() + 1).padStart(2, "0");
  const day = String(date.getUTCDate()).padStart(2, "0");
  return `${year}-${month}-${day}`;
}
function buildUsageMap(daily) {
  const map = new Map;
  for (const entry of daily) {
    map.set(entry.date, entry);
  }
  return map;
}
function inferModelFamily(model) {
  const normalized = model.trim().toLowerCase();
  if (normalized.startsWith("claude"))
    return "Claude";
  if (normalized.startsWith("gpt") || normalized.startsWith("o1") || normalized.startsWith("o3") || normalized.startsWith("o4")) {
    return "GPT";
  }
  if (normalized.startsWith("gemini"))
    return "Gemini";
  if (normalized.startsWith("llama") || normalized.startsWith("meta-llama"))
    return "Llama";
  if (normalized.startsWith("deepseek"))
    return "DeepSeek";
  if (normalized.startsWith("qwen"))
    return "Qwen";
  return "Other";
}
function getDominantModelMeta(entry) {
  if (!entry || entry.models.length === 0 || entry.totalTokens <= 0) {
    return {
      dominantModelFamily: null,
      dominantModelLabel: null,
      dominantModelShare: 0,
      mixedModelCount: 0
    };
  }
  const ranked = entry.models.filter((model) => model.totalTokens > 0).slice().sort((left, right) => right.totalTokens - left.totalTokens);
  const dominant = ranked[0];
  if (!dominant) {
    return {
      dominantModelFamily: null,
      dominantModelLabel: null,
      dominantModelShare: 0,
      mixedModelCount: 0
    };
  }
  return {
    dominantModelFamily: inferModelFamily(dominant.model),
    dominantModelLabel: dominant.model,
    dominantModelShare: dominant.totalTokens / entry.totalTokens,
    mixedModelCount: ranked.length
  };
}
function computeQuantiles2(values) {
  const nonZero = values.filter((value) => value > 0).sort((a, b) => a - b);
  if (nonZero.length === 0)
    return [0, 0, 0];
  const quantile = (ratio) => {
    const index = Math.floor(ratio * (nonZero.length - 1));
    return nonZero[index] ?? 0;
  };
  return [quantile(0.25), quantile(0.5), quantile(0.75)];
}
function getLevel2(tokens, quantiles) {
  if (tokens <= 0)
    return 0;
  if (tokens <= quantiles[0])
    return 1;
  if (tokens <= quantiles[1])
    return 2;
  if (tokens <= quantiles[2])
    return 3;
  return 4;
}
function alignToSunday(date) {
  const aligned = new Date(date);
  aligned.setUTCDate(aligned.getUTCDate() - aligned.getUTCDay());
  return aligned;
}
function buildHeatmapModel(daily, range) {
  if (daily.length === 0) {
    return null;
  }
  const dates = daily.map((entry) => entry.date).sort();
  const since = range?.since ?? dates[0];
  const until = range?.until ?? dates[dates.length - 1];
  const startDate = alignToSunday(new Date(`${since}T00:00:00Z`));
  const endDate = new Date(`${until}T00:00:00Z`);
  const usageMap = buildUsageMap(daily);
  const usageValues = Array.from(usageMap.values()).map((entry) => entry.totalTokens);
  const quantiles = computeQuantiles2(usageValues);
  const maxTokens = usageValues.reduce((max, value) => value > max ? value : max, 0);
  const weeks = [];
  const monthMarkers = [];
  let weekIndex = 0;
  let lastMonth = -1;
  for (let cursor = new Date(startDate);cursor <= endDate; weekIndex += 1) {
    const weekDays = [];
    const month = cursor.getUTCMonth();
    const year = cursor.getUTCFullYear();
    if (month !== lastMonth) {
      monthMarkers.push({
        label: MONTH_LABELS[month] ?? "",
        month,
        year,
        weekIndex
      });
      lastMonth = month;
    }
    const dayCursor = new Date(cursor);
    for (let dayIndex = 0;dayIndex < 7; dayIndex += 1) {
      const dateString = formatDate(dayCursor);
      const usageEntry = usageMap.get(dateString);
      const tokens = usageEntry?.totalTokens ?? 0;
      const cost = usageEntry?.cost ?? 0;
      const modelMeta = getDominantModelMeta(usageEntry);
      weekDays.push({
        date: dateString,
        tokens,
        cost,
        level: getLevel2(tokens, quantiles),
        dayIndex,
        weekIndex,
        ...modelMeta
      });
      dayCursor.setUTCDate(dayCursor.getUTCDate() + 1);
    }
    weeks.push({
      index: weekIndex,
      days: weekDays
    });
    cursor.setUTCDate(cursor.getUTCDate() + 7);
  }
  return {
    weeks,
    monthMarkers,
    maxTokens,
    since,
    until
  };
}
var MONTH_LABELS;
var init_heatmap_model = __esm(() => {
  MONTH_LABELS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
});

// packages/renderers/dist/terminal/heatmap.js
function getDisplayMode(width) {
  return width >= FULL_MODE_THRESHOLD ? "full" : "compact";
}
function getCellWidth(mode) {
  return mode === "full" ? 2 : 1;
}
function getGap(mode) {
  return mode === "full" ? " " : "";
}
function getWeekColumnWidth(mode) {
  return getCellWidth(mode) + getGap(mode).length;
}
function renderCell(level, family, mode, noColor2) {
  const cellWidth = getCellWidth(mode);
  if (noColor2) {
    const blocks = mode === "full" ? ["\xB7\xB7", "\u2591\u2591", "\u2592\u2592", "\u2593\u2593", "\u2588\u2588"] : ["\xB7", "\u2591", "\u2592", "\u2593", "\u2588"];
    return blocks[level] ?? blocks[0];
  }
  const palette = FAMILY_PALETTES[family ?? "Other"] ?? FAMILY_PALETTES["Other"];
  const colorCode = level <= 0 ? EMPTY_CELL_CODE : palette[Math.max(0, Math.min(palette.length - 1, level - 1))] ?? EMPTY_CELL_CODE;
  return background256(" ".repeat(cellWidth), colorCode, noColor2);
}
function getPrimaryFamily(visibleWeeks) {
  const familyDays = new Map;
  for (const cell of visibleWeeks.flatMap((week) => week.days)) {
    if (!cell.dominantModelFamily)
      continue;
    familyDays.set(cell.dominantModelFamily, (familyDays.get(cell.dominantModelFamily) ?? 0) + 1);
  }
  return [...familyDays.entries()].sort((left, right) => right[1] - left[1])[0]?.[0] ?? "Other";
}
function buildMonthHeader(model, visibleStartWeek, displayWeekCount, mode) {
  const weekColWidth = getWeekColumnWidth(mode);
  const totalCols = displayWeekCount * weekColWidth;
  const header = Array.from({ length: totalCols }, () => " ");
  let nextFreeIndex = 0;
  let placedLabels = 0;
  const visibleMarkers = model.monthMarkers.filter((marker) => marker.weekIndex >= visibleStartWeek);
  for (const marker of visibleMarkers) {
    const startIndex = Math.max((marker.weekIndex - visibleStartWeek) * weekColWidth, nextFreeIndex);
    const remaining = header.length - startIndex;
    if (remaining < 3)
      continue;
    for (let offset = 0;offset < marker.label.length; offset += 1) {
      if (startIndex + offset < header.length) {
        header[startIndex + offset] = marker.label[offset] ?? " ";
      }
    }
    nextFreeIndex = startIndex + marker.label.length + 1;
    placedLabels += 1;
  }
  const line2 = header.some((cell) => cell !== " ") ? `${" ".repeat(DAY_LABEL_WIDTH2)}${header.join("")}` : null;
  const uniqueVisibleMonths = visibleMarkers.map((marker) => `${marker.label} ${String(marker.year)}`).filter((value, index, values) => values.indexOf(value) === index);
  const caption = placedLabels === 0 && uniqueVisibleMonths.length === 1 ? `${" ".repeat(DAY_LABEL_WIDTH2)}${uniqueVisibleMonths[0]}` : null;
  return { caption, line: line2 };
}
function buildIntensityLegend(family, mode, noColor2) {
  const cellWidth = getCellWidth(mode);
  const palette = FAMILY_PALETTES[family] ?? FAMILY_PALETTES.Other;
  const gap = getGap(mode);
  const swatches = noColor2 ? mode === "full" ? ["\xB7\xB7", "\u2591\u2591", "\u2592\u2592", "\u2593\u2593", "\u2588\u2588"] : ["\xB7", "\u2591", "\u2592", "\u2593", "\u2588"] : [
    background256(" ".repeat(cellWidth), EMPTY_CELL_CODE, noColor2),
    background256(" ".repeat(cellWidth), palette[0], noColor2),
    background256(" ".repeat(cellWidth), palette[1], noColor2),
    background256(" ".repeat(cellWidth), palette[2], noColor2),
    background256(" ".repeat(cellWidth), palette[3], noColor2)
  ];
  return `Less ${swatches.join(gap)} More`;
}
function buildFamilyLegend(families, mode, width, noColor2) {
  if (families.length === 0)
    return [];
  const cellWidth = getCellWidth(mode);
  const chunks = families.map((family) => {
    const palette = FAMILY_PALETTES[family] ?? FAMILY_PALETTES["Other"];
    const swatch = noColor2 ? mode === "full" ? "\u2588\u2588" : "\u2588" : background256(" ".repeat(cellWidth), palette[3] ?? EMPTY_CELL_CODE, noColor2);
    return `${swatch} ${family}`;
  });
  const lines = [];
  let current = "";
  for (const chunk of chunks) {
    const candidate = current.length === 0 ? chunk : `${current}  ${chunk}`;
    if (visibleLength(candidate) > width && current.length > 0) {
      lines.push(current);
      current = chunk;
      continue;
    }
    current = candidate;
  }
  lines.push(current);
  return lines;
}
function renderTerminalHeatmap(daily, options) {
  const model = buildHeatmapModel(daily);
  if (!model) {
    return "  No usage data available in the selected range.";
  }
  const mode = getDisplayMode(options.width);
  const weekColWidth = getWeekColumnWidth(mode);
  const availableColumns = Math.max(weekColWidth, options.width - DAY_LABEL_WIDTH2);
  const maxWeeks = Math.max(1, Math.floor(availableColumns / weekColWidth));
  const displayWeeks = model.weeks.slice(Math.max(0, model.weeks.length - maxWeeks));
  const visibleStartWeek = model.weeks.length - displayWeeks.length;
  const { caption, line: line2 } = buildMonthHeader(model, visibleStartWeek, displayWeeks.length, mode);
  const lines = [];
  if (caption)
    lines.push(caption);
  if (line2)
    lines.push(line2);
  const gap = getGap(mode);
  for (let dayIndex = 0;dayIndex < 7; dayIndex += 1) {
    const label = LABELED_DAYS[dayIndex] ?? "";
    const paddedLabel = (label + " ".repeat(DAY_LABEL_WIDTH2)).slice(0, DAY_LABEL_WIDTH2);
    const cells = [];
    for (const week of displayWeeks) {
      const cell = week.days[dayIndex] ?? {
        level: 0,
        tokens: 0,
        dominantModelFamily: null
      };
      cells.push(renderCell(cell.level, cell.dominantModelFamily, mode, options.noColor));
    }
    const row = paddedLabel + cells.join(gap);
    lines.push(row.trimEnd());
  }
  const visibleFamilies = Array.from(new Set(displayWeeks.flatMap((week) => week.days).map((cell) => cell.dominantModelFamily).filter((family) => family !== null)));
  const primaryFamily = getPrimaryFamily(displayWeeks);
  lines.push("");
  const intensityLegend = buildIntensityLegend(primaryFamily, mode, options.noColor);
  const familyLines = buildFamilyLegend(visibleFamilies, mode, options.width - DAY_LABEL_WIDTH2, options.noColor);
  if (familyLines.length === 1) {
    const combined = `${intensityLegend}   ${familyLines[0]}`;
    if (visibleLength(combined) <= options.width - DAY_LABEL_WIDTH2) {
      lines.push(`${" ".repeat(DAY_LABEL_WIDTH2)}${combined}`);
      return lines.join(`
`);
    }
  }
  lines.push(`${" ".repeat(DAY_LABEL_WIDTH2)}${intensityLegend}`);
  if (familyLines.length > 0) {
    for (const familyLine of familyLines) {
      lines.push(`${" ".repeat(DAY_LABEL_WIDTH2)}${familyLine}`);
    }
  }
  return lines.join(`
`);
}
var DAY_LABEL_WIDTH2 = 5, LABELED_DAYS, FULL_MODE_THRESHOLD = 40, EMPTY_CELL_CODE = 237, FAMILY_PALETTES;
var init_heatmap = __esm(() => {
  init_heatmap_model();
  init_colors();
  LABELED_DAYS = { 1: "Mon", 3: "Wed", 5: "Fri" };
  FAMILY_PALETTES = {
    Claude: [223, 215, 208, 166],
    GPT: [120, 78, 42, 35],
    Gemini: [189, 147, 105, 99],
    Llama: [153, 111, 69, 27],
    DeepSeek: [159, 117, 81, 45],
    Qwen: [225, 183, 141, 97],
    Other: [252, 250, 247, 244]
  };
});

// packages/renderers/dist/terminal/dashboard.js
function divider(width, noColor2) {
  return dim(BOX_H2.repeat(width), noColor2);
}
function boxedHeader2(title, width, noColor2) {
  const inner = Math.max(1, width - 2);
  const padded = ` ${title} `;
  const remaining = Math.max(0, inner - padded.length);
  const left = Math.floor(remaining / 2);
  const right = remaining - left;
  const titleLine = `${BOX_V2}${" ".repeat(left)}${bold2(padded, noColor2)}${" ".repeat(right)}${BOX_V2}`;
  return [
    `${BOX_TL2}${BOX_H2.repeat(inner)}${BOX_TR2}`,
    titleLine,
    `${BOX_BL2}${BOX_H2.repeat(inner)}${BOX_BR2}`
  ].join(`
`);
}
function renderSectionTitle(title, noColor2) {
  return `  ${colorize256("\u25B8", SEMANTIC.ACCENT, noColor2)} ${bold2(title, noColor2)}`;
}
function renderSummary(parts, width, noColor2) {
  if (parts.length === 0)
    return [];
  const colored = parts.map((part, index) => colorize256(part, index % 2 === 0 ? SEMANTIC.INPUT : SEMANTIC.OUTPUT, noColor2));
  const line2 = colored.join(dim("  \xB7  ", noColor2));
  return [truncateVisible(`  ${line2}`, width)];
}
function renderTrend(trend, width, noColor2) {
  if (!trend)
    return [];
  return [
    truncateVisible(`  ${bold2("Recent Trend", noColor2)}  ${colorize256(trend, SEMANTIC.OUTPUT, noColor2)}`, width)
  ];
}
function renderMetricLine(entry, width, noColor2) {
  const label = entry.label;
  const value = colorize256(entry.value, SEMANTIC.INPUT, noColor2);
  const gutter = 2;
  const safeWidth = Math.max(12, width);
  const valueWidth = Math.min(Math.max(6, visibleLength(entry.value)), Math.max(6, Math.floor(safeWidth * 0.45)));
  const labelWidth = Math.max(4, safeWidth - valueWidth - gutter);
  return `${truncateVisible(label, labelWidth)}${" ".repeat(gutter)}${padVisible(value, valueWidth)}`;
}
function renderMetrics(entries, width, noColor2) {
  if (entries.length === 0)
    return [];
  const innerWidth = Math.max(16, width - 2);
  if (width >= 86 && entries.length > 3) {
    const midpoint = Math.ceil(entries.length / 2);
    const left = entries.slice(0, midpoint).map((entry) => `  ${renderMetricLine(entry, Math.floor((innerWidth - 3) / 2), noColor2)}`);
    const right = entries.slice(midpoint).map((entry) => `  ${renderMetricLine(entry, Math.floor((innerWidth - 3) / 2), noColor2)}`);
    return renderColumns(left, right, innerWidth, 0.5, 3);
  }
  return entries.map((entry) => `  ${renderMetricLine(entry, innerWidth, noColor2)}`);
}
function renderPatternList(title, entries, width, noColor2) {
  if (entries.length === 0)
    return [];
  const lines = [renderSectionTitle(title, noColor2)];
  const innerWidth = Math.max(18, width - 2);
  const nameWidth = Math.min(22, Math.max(8, Math.floor(innerWidth * 0.35)));
  const valueWidth = 6;
  const barWidth = Math.max(6, innerWidth - nameWidth - valueWidth - 6);
  for (const entry of entries) {
    const fillLength = Math.max(1, Math.round(entry.share * barWidth));
    const fill = colorize256(BAR_CHAR.repeat(fillLength), SEMANTIC.OUTPUT, noColor2);
    const track = TRACK_CHAR.repeat(Math.max(0, barWidth - fillLength));
    const line2 = `  ${colorize256(truncateVisible(entry.label, nameWidth).padEnd(nameWidth), SEMANTIC.ACCENT, noColor2)}  ${fill}${track}  ${entry.value.padStart(valueWidth)}`;
    lines.push(truncateVisible(line2, width));
  }
  return lines;
}
function renderPatternColumns(provider, width, noColor2) {
  const dayLines = renderPatternList("Day of Week", provider.dayOfWeek, Math.floor((width - 3) / 2), noColor2);
  const modelLines = renderPatternList("Top Models", provider.topModels, Math.floor((width - 3) / 2), noColor2);
  if (dayLines.length > 0 && modelLines.length > 0 && width >= 96) {
    return renderColumns(dayLines, modelLines, width - 2, 0.5, 3).map((line2) => `  ${line2}`);
  }
  return [...dayLines, ...dayLines.length > 0 && modelLines.length > 0 ? [""] : [], ...modelLines];
}
function renderInsights(insights, width, noColor2) {
  if (insights.length === 0)
    return [];
  return [
    renderSectionTitle("Insights", noColor2),
    ...insights.map((insight) => truncateVisible(`  ${colorize256("\u25B8", SEMANTIC.OUTPUT, noColor2)} ${insight}`, width))
  ];
}
function renderProviderSection(provider, width, noColor2, showInsights) {
  const sections = [
    boxedHeader2(provider.provider.displayName, width, noColor2),
    ...renderSummary(provider.summary, width, noColor2),
    ...renderTrend(provider.trend, width, noColor2),
    "",
    renderSectionTitle("Heatmap", noColor2),
    renderTerminalHeatmap(provider.provider.daily, { width: width - 2, noColor: noColor2 }),
    "",
    renderSectionTitle("Stats", noColor2),
    ...renderMetrics(provider.metrics, width, noColor2)
  ];
  const patternLines = renderPatternColumns(provider, width, noColor2);
  if (patternLines.length > 0) {
    sections.push("", ...patternLines);
  }
  const insightLines = showInsights ? renderInsights(provider.insights, width, noColor2) : [];
  if (insightLines.length > 0) {
    sections.push("", ...insightLines);
  }
  return sections.join(`
`);
}
function renderOverview(model, width, noColor2) {
  const sections = [
    boxedHeader2("Overview", width, noColor2),
    ...renderSummary(model.overview.summary, width, noColor2),
    ...renderTrend(model.overview.trend, width, noColor2),
    "",
    ...renderMetrics(model.overview.metrics, width, noColor2)
  ];
  if (model.overview.providerLeaders.length > 1) {
    sections.push("", ...renderPatternList("Provider Mix", model.overview.providerLeaders, width, noColor2));
  }
  return sections.join(`
`);
}
function renderDashboardModel(model, options) {
  const width = options.width;
  const noColor2 = options.noColor;
  const sections = [
    boxedHeader2("Tokenleak", width, noColor2),
    ...renderSummary([model.rangeLabel, ...model.overview.summary], width, noColor2)
  ];
  if (model.activeProviders.length === 0) {
    sections.push("");
    sections.push("  No provider activity in the selected range.");
    if (model.inactiveProviders.length > 0) {
      sections.push(truncateVisible(`  Checked: ${model.inactiveProviders.join(", ")}`, width));
    }
    return sections.join(`
`);
  }
  sections.push("", renderOverview(model, width, noColor2));
  for (const provider of model.activeProviders) {
    const providerSection = renderProviderSection(provider, width, noColor2, options.showInsights);
    sections.push("", divider(width, noColor2), "", providerSection);
  }
  if (model.inactiveProviders.length > 0) {
    sections.push("");
    sections.push(truncateVisible(`  No activity in range: ${model.inactiveProviders.join(", ")}`, width));
  }
  return sections.join(`
`);
}
var BOX_H2 = "\u2500", BOX_V2 = "\u2502", BOX_TL2 = "\u256D", BOX_TR2 = "\u256E", BOX_BL2 = "\u2570", BOX_BR2 = "\u256F", BAR_CHAR = "\u2588", TRACK_CHAR = "\u2591";
var init_dashboard = __esm(() => {
  init_colors();
  init_dashboard_model();
  init_heatmap();
});

// packages/renderers/dist/terminal/oneliner.js
function countActiveProviders(providers) {
  return providers.filter((provider) => provider.daily.some((entry) => entry.totalTokens > 0)).length;
}
function renderOneliner(output, options) {
  const streak = output.aggregated.currentStreak;
  const tokens = formatTokens2(output.aggregated.totalTokens);
  const cost = formatCost3(output.aggregated.totalCost);
  const providerCount = countActiveProviders(output.providers);
  if (providerCount === 0) {
    return `no activity | ${tokens} tokens | ${cost}`;
  }
  return `${streak}d streak | ${tokens} tokens | ${cost} | ${providerCount} active`;
}
var init_oneliner = __esm(() => {
  init_dashboard();
});

// packages/renderers/dist/terminal/tab-views/tab-bar.js
function renderTabBar(activeRange, activeTab, width, noColor2) {
  const rangeParts = TIME_RANGES.map((r) => {
    if (r === activeRange) {
      return inverse256(` ${r} `, ACTIVE_COLOR, noColor2);
    }
    return dim(` ${r} `, noColor2);
  });
  const tabParts = METRIC_TABS.map((t) => {
    if (t === activeTab) {
      return inverse256(` ${TAB_LABELS[t]} `, ACTIVE_COLOR, noColor2);
    }
    return dim(` ${TAB_LABELS[t]} `, noColor2);
  });
  const separator = dim(" \u2502 ", noColor2);
  const rangeLine = `  ${rangeParts.join(" ")}${separator}${tabParts.join(" ")}`;
  const hints = [
    `${bold256("\u2190/\u2192", HINT_COLOR, noColor2)} range`,
    `${bold256("tab", HINT_COLOR, noColor2)} metric`,
    `${bold256("1-9", HINT_COLOR, noColor2)} jump`,
    `${bold256("\u2191/\u2193", HINT_COLOR, noColor2)} scroll`,
    `${bold256("q", HINT_COLOR, noColor2)} close`
  ];
  const hintLine = `  ${hints.join(dim("  \xB7  ", noColor2))}`;
  return [
    truncateVisible(rangeLine, width),
    truncateVisible(hintLine, width)
  ].join(`
`);
}
var TIME_RANGES, METRIC_TABS, TAB_LABELS, ACTIVE_COLOR, HINT_COLOR;
var init_tab_bar = __esm(() => {
  init_colors();
  TIME_RANGES = ["7d", "30d", "90d", "365d"];
  METRIC_TABS = ["overview", "delta", "provider", "sess", "tok", "model", "cwd", "dow", "tod"];
  TAB_LABELS = {
    overview: "overview",
    delta: "delta",
    provider: "provider",
    sess: "sess",
    tok: "tok",
    model: "model",
    cwd: "cwd",
    dow: "dow",
    tod: "tod"
  };
  ACTIVE_COLOR = SEMANTIC.ACTIVE;
  HINT_COLOR = SEMANTIC.HINT;
});

// packages/renderers/dist/terminal/tab-views/overview-view.js
function renderOverviewView(output, options) {
  return renderDashboardModel(buildDashboardModel(output, options), options);
}
var init_overview_view = __esm(() => {
  init_dashboard();
  init_dashboard_model();
});

// packages/renderers/dist/terminal/tab-views/compare-view.js
function formatTokens3(n) {
  if (Math.abs(n) >= 1e6)
    return `${(n / 1e6).toFixed(1)}M`;
  if (Math.abs(n) >= 1000)
    return `${(n / 1000).toFixed(0)}K`;
  return String(Math.round(n));
}
function formatCost4(cost) {
  return `$${cost.toFixed(2)}`;
}
function formatPercent3(rate) {
  return `${(rate * 100).toFixed(1)}%`;
}
function colorDelta(text2, value, noColor2) {
  if (value > 0)
    return colorize256(`\u2191 ${text2}`, SEMANTIC.OUTPUT, noColor2);
  if (value < 0)
    return colorize256(`\u2193 ${text2}`, SEMANTIC.NEGATIVE, noColor2);
  return dim(`\xB7 ${text2}`, noColor2);
}
function formatSignedNumber(value, formatter) {
  const sign = value > 0 ? "+" : value < 0 ? "-" : " ";
  return `${sign}${formatter(Math.abs(value))}`;
}
function formatSignedPercentPoints(value) {
  const sign = value > 0 ? "+" : value < 0 ? "-" : " ";
  return `${sign}${(Math.abs(value) * 100).toFixed(1)}pp`;
}
function renderDeltaRow(label, current, previous, delta, deltaValue, width, noColor2) {
  const labelWidth = 18;
  const currentWidth = 11;
  const previousWidth = 11;
  const deltaWidth = 13;
  return truncateVisible(`  ${dim(label.padEnd(labelWidth), noColor2)} ${bold2(current.padStart(currentWidth), noColor2)} ${bold2(previous.padStart(previousWidth), noColor2)} ${colorDelta(delta.padStart(deltaWidth), deltaValue, noColor2)}`, width);
}
function renderModelShift(label, currentShare, previousShare, deltaShare, width, noColor2) {
  const delta = formatSignedPercentPoints(deltaShare);
  const shareSummary = `now ${(currentShare * 100).toFixed(0)}% prev ${(previousShare * 100).toFixed(0)}%`;
  return truncateVisible(`  ${colorize256(label, SEMANTIC.INPUT, noColor2)}  ${colorDelta(delta, deltaShare, noColor2)}  ${dim(shareSummary, noColor2)}`, width);
}
function renderCompareView(output, width, noColor2) {
  const compare = output.more?.compare;
  if (!compare) {
    return `  ${dim("No compare data available. Run with --compare auto to unlock this tab.", noColor2)}`;
  }
  const previousStats = compare.previousStats;
  const deltas = compare.deltas;
  const lines = [bold2("  Compare", noColor2), ""];
  lines.push(truncateVisible(`  ${dim("Current", noColor2)} ${output.dateRange.since} \u2192 ${output.dateRange.until}`, width));
  lines.push(truncateVisible(`  ${dim("Previous", noColor2)} ${compare.previousRange.since} \u2192 ${compare.previousRange.until}`, width));
  lines.push("");
  lines.push(truncateVisible(`  ${dim("Metric".padEnd(18), noColor2)} ${dim("Current".padStart(11), noColor2)} ${dim("Previous".padStart(11), noColor2)} ${dim("Delta".padStart(11), noColor2)}`, width));
  lines.push(renderDeltaRow("Total Tokens", formatTokens3(output.aggregated.totalTokens), formatTokens3(previousStats.totalTokens), formatSignedNumber(deltas.tokens, formatTokens3), deltas.tokens, width, noColor2));
  lines.push(renderDeltaRow("Total Cost", formatCost4(output.aggregated.totalCost), formatCost4(previousStats.totalCost), formatSignedNumber(deltas.cost, formatCost4), deltas.cost, width, noColor2));
  lines.push(renderDeltaRow("Active Days", String(output.aggregated.activeDays), String(previousStats.activeDays), formatSignedNumber(deltas.activeDays, (value) => String(Math.round(value))), deltas.activeDays, width, noColor2));
  lines.push(renderDeltaRow("Current Streak", `${output.aggregated.currentStreak}d`, `${previousStats.currentStreak}d`, formatSignedNumber(deltas.streak, (value) => `${Math.round(value)}d`), deltas.streak, width, noColor2));
  lines.push(renderDeltaRow("Avg Daily Tok", formatTokens3(output.aggregated.averageDailyTokens), formatTokens3(previousStats.averageDailyTokens), formatSignedNumber(deltas.averageDailyTokens, formatTokens3), deltas.averageDailyTokens, width, noColor2));
  lines.push(renderDeltaRow("Cache Hit Rate", formatPercent3(output.aggregated.cacheHitRate), formatPercent3(previousStats.cacheHitRate), formatSignedPercentPoints(deltas.cacheHitRate), deltas.cacheHitRate, width, noColor2));
  if (compare.modelMixShift.length > 0) {
    lines.push("");
    lines.push(`  ${bold2("Model Mix Shift", noColor2)}`);
    for (const entry of compare.modelMixShift) {
      lines.push(renderModelShift(entry.model, entry.currentShare, entry.previousShare, entry.deltaShare, width, noColor2));
    }
  }
  return lines.join(`
`);
}
var init_compare_view = __esm(() => {
  init_colors();
});

// packages/renderers/dist/terminal/tab-views/cache-roi.js
function formatTokens4(n) {
  if (n >= 1e6)
    return `${(n / 1e6).toFixed(1)}M`;
  if (n >= 1000)
    return `${(n / 1000).toFixed(0)}K`;
  return String(n);
}
function formatCost5(cost) {
  return `$${Math.abs(cost).toFixed(4)}`;
}
function formatSignedCost(cost) {
  const sign = cost > 0 ? "+" : cost < 0 ? "-" : "";
  return `${sign}${formatCost5(cost)}`;
}
function formatRatio2(value) {
  return value === null ? "-" : `${value.toFixed(1)}x`;
}
function renderCacheRoiSummary(summary, width, noColor2, title = "Prompt Cache ROI") {
  const lines = [`  ${bold2(title, noColor2)}`];
  const labelWidth = 20;
  const netColor = summary.netSavings >= 0 ? SEMANTIC.OUTPUT : SEMANTIC.NEGATIVE;
  const addLine = (label, value, colorCode) => {
    const renderedValue = colorCode === undefined ? bold2(value, noColor2) : bold256(value, colorCode, noColor2);
    lines.push(truncateVisible(`  ${dim(label.padEnd(labelWidth), noColor2)} ${renderedValue}`, width));
  };
  addLine("Read savings", formatCost5(summary.readSavings), SEMANTIC.OUTPUT);
  addLine("Write cost", formatCost5(summary.writeCost), SEMANTIC.ACCENT);
  addLine("Net savings", formatSignedCost(summary.netSavings), netColor);
  addLine("Payback ratio", formatRatio2(summary.paybackRatio));
  addLine("Reuse ratio", formatRatio2(summary.reuseRatio));
  addLine("Read / write", `${formatTokens4(summary.readTokens)} / ${formatTokens4(summary.writeTokens)}`);
  return lines;
}
function renderCacheRoiBreakdowns(title, breakdowns, width, noColor2, limit = 5) {
  if (breakdowns.length === 0) {
    return [];
  }
  const rows = breakdowns.slice(0, limit);
  const lines = [`  ${bold2(title, noColor2)}`];
  const labelWidth = Math.min(28, Math.max(12, Math.floor(width * 0.32)));
  for (let index = 0;index < rows.length; index += 1) {
    const entry = rows[index];
    const colorCode = PROJECT_COLORS[index % PROJECT_COLORS.length] ?? SEMANTIC.ACCENT;
    const name = entry.label.length > labelWidth ? `${entry.label.slice(0, labelWidth - 1)}\u2026` : entry.label.padEnd(labelWidth);
    const netText = formatSignedCost(entry.netSavings).padStart(10);
    const paybackText = formatRatio2(entry.paybackRatio).padStart(6);
    const reuseText = formatRatio2(entry.reuseRatio).padStart(6);
    const volumeText = `${formatTokens4(entry.readTokens)} / ${formatTokens4(entry.writeTokens)}`;
    const netColor = entry.netSavings >= 0 ? SEMANTIC.OUTPUT : SEMANTIC.NEGATIVE;
    lines.push(truncateVisible(`  ${colorize256(name, colorCode, noColor2)} ${bold256(netText, netColor, noColor2)} ${paybackText} ${reuseText} ${volumeText}`, width));
  }
  lines.push(truncateVisible(`  ${dim("Columns: net, payback, reuse, read/write tokens", noColor2)}`, width));
  return lines;
}
var init_cache_roi = __esm(() => {
  init_colors();
});

// packages/renderers/dist/terminal/tab-views/provider-view.js
function formatTokens5(n) {
  if (n >= 1e6)
    return `${(n / 1e6).toFixed(1)}M`;
  if (n >= 1000)
    return `${(n / 1000).toFixed(0)}K`;
  return String(n);
}
function formatCost6(cost) {
  return `$${cost.toFixed(2)}`;
}
function getLastActiveDate2(output, providerName) {
  const provider = output.providers.find((entry) => entry.provider === providerName);
  const activeDays = provider?.daily.filter((entry) => entry.totalTokens > 0) ?? [];
  return activeDays.at(-1)?.date ?? null;
}
function renderProviderView(output, width, noColor2) {
  const rows = output.providers.map((provider) => {
    const stats = aggregate(provider.daily, output.dateRange.until);
    return {
      provider,
      stats,
      lastActiveDate: getLastActiveDate2(output, provider.provider)
    };
  }).filter((entry) => entry.stats.totalTokens > 0).sort((left, right) => right.stats.totalTokens - left.stats.totalTokens);
  if (rows.length === 0) {
    return `  ${dim("No provider activity in the selected range.", noColor2)}`;
  }
  const lines = [bold2("  Providers", noColor2), ""];
  const maxTokens = Math.max(...rows.map((entry) => entry.stats.totalTokens), 0);
  const totalTokens = rows.reduce((sum, entry) => sum + entry.stats.totalTokens, 0);
  const nameWidth = Math.min(18, Math.max(10, Math.floor(width * 0.2)));
  const shareWidth = 6;
  const valueWidth = 8;
  const costWidth = 10;
  const dateWidth = 10;
  const barWidth = Math.max(8, width - nameWidth - shareWidth - valueWidth - costWidth - dateWidth - 12);
  for (let index = 0;index < rows.length; index += 1) {
    const entry = rows[index];
    const colorCode = PROJECT_COLORS[index % PROJECT_COLORS.length] ?? 33;
    const ratio = maxTokens > 0 ? entry.stats.totalTokens / maxTokens : 0;
    const share = totalTokens > 0 ? entry.stats.totalTokens / totalTokens : 0;
    const fillLen = Math.max(ratio > 0 ? 1 : 0, Math.round(ratio * barWidth));
    const bar = colorize256(BAR_CHAR2.repeat(fillLen), colorCode, noColor2) + dim(TRACK_CHAR2.repeat(Math.max(0, barWidth - fillLen)), noColor2);
    const shareStr = `${(share * 100).toFixed(0)}%`.padStart(shareWidth);
    const tokenStr = formatTokens5(entry.stats.totalTokens).padStart(valueWidth);
    const costStr = formatCost6(entry.stats.totalCost).padStart(costWidth);
    const dateStr = (entry.lastActiveDate ?? "-").padStart(dateWidth);
    const name = entry.provider.displayName.length > nameWidth ? `${entry.provider.displayName.slice(0, nameWidth - 1)}\u2026` : entry.provider.displayName.padEnd(nameWidth);
    lines.push(truncateVisible(`  ${colorize256(name, colorCode, noColor2)} ${bar} ${shareStr} ${tokenStr} ${costStr} ${dateStr}`, width));
  }
  lines.push("");
  lines.push(truncateVisible(`  ${dim("Columns: share, tokens, cost, last active", noColor2)}`, width));
  const roiLines = renderCacheRoiBreakdowns("Cache ROI by Provider", output.more?.cacheRoi?.byProvider ?? [], width, noColor2);
  if (roiLines.length > 0) {
    lines.push("", ...roiLines);
  }
  return lines.join(`
`);
}
var BAR_CHAR2 = "\u2588", TRACK_CHAR2 = "\u2591";
var init_provider_view = __esm(() => {
  init_dist();
  init_colors();
  init_cache_roi();
});

// packages/renderers/dist/terminal/tab-views/dow-view.js
function formatTokens6(count) {
  if (count >= 1e6)
    return `${(count / 1e6).toFixed(1)}M`;
  if (count >= 1000)
    return `${(count / 1000).toFixed(0)}K`;
  return String(count);
}
function formatCost7(cost) {
  return `$${cost.toFixed(2)}`;
}
function renderDowView(output, width, noColor2) {
  const dow = output.aggregated.dayOfWeek;
  if (dow.length === 0) {
    return `  ${dim("No day-of-week data available.", noColor2)}`;
  }
  const maxTokens = Math.max(...dow.map((d) => d.tokens), 0);
  const totalTokens = dow.reduce((sum, d) => sum + d.tokens, 0);
  if (maxTokens <= 0) {
    return `  ${dim("No activity in the selected range.", noColor2)}`;
  }
  const lines = [bold2("  Day of Week", noColor2), ""];
  const nameWidth = 5;
  const valueWidth = 8;
  const costWidth = 10;
  const shareWidth = 6;
  const barWidth = Math.max(8, width - nameWidth - valueWidth - costWidth - shareWidth - 10);
  for (const entry of dow) {
    const label = DAY_NAMES3[entry.day] ?? "???";
    const colorCode = DOW_COLORS[label] ?? 33;
    const share = totalTokens > 0 ? entry.tokens / totalTokens : 0;
    const ratio = maxTokens > 0 ? entry.tokens / maxTokens : 0;
    const fillLen = Math.max(ratio > 0 ? 1 : 0, Math.round(ratio * barWidth));
    const bar = colorize256(BAR_CHAR3.repeat(fillLen), colorCode, noColor2) + dim(TRACK_CHAR3.repeat(Math.max(0, barWidth - fillLen)), noColor2);
    const shareStr = `${(share * 100).toFixed(0)}%`.padStart(shareWidth);
    const tokStr = formatTokens6(entry.tokens).padStart(valueWidth);
    const costStr = formatCost7(entry.cost).padStart(costWidth);
    lines.push(truncateVisible(`  ${colorize256(label.padEnd(nameWidth), colorCode, noColor2)} ${bar} ${shareStr} ${tokStr} ${costStr}`, width));
  }
  return lines.join(`
`);
}
var BAR_CHAR3 = "\u2588", TRACK_CHAR3 = "\u2591", DAY_NAMES3;
var init_dow_view = __esm(() => {
  init_colors();
  DAY_NAMES3 = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
});

// packages/renderers/dist/terminal/tab-views/tod-view.js
function groupIntoBuckets(hourOfDay) {
  return BUCKET_RANGES.map(({ label, hours, start, end }) => {
    let tokens = 0;
    let cost = 0;
    let count = 0;
    for (let h = start;h <= end; h++) {
      const entry = hourOfDay[h];
      if (entry) {
        tokens += entry.tokens;
        cost += entry.cost;
        count += entry.count;
      }
    }
    return { label, hours, tokens, cost, count };
  });
}
function formatTokens7(n) {
  if (n >= 1e6)
    return `${(n / 1e6).toFixed(1)}M`;
  if (n >= 1000)
    return `${(n / 1000).toFixed(0)}K`;
  return String(n);
}
function formatCost8(cost) {
  return `$${cost.toFixed(2)}`;
}
function renderTodView(output, width, noColor2) {
  const hourOfDay = output.more?.hourOfDay;
  if (!hourOfDay || hourOfDay.length === 0) {
    return `  ${dim("No event-level data available for time-of-day analysis.", noColor2)}`;
  }
  const buckets = groupIntoBuckets(hourOfDay);
  const maxTokens = Math.max(...buckets.map((b) => b.tokens), 0);
  const totalTokens = buckets.reduce((sum, b) => sum + b.tokens, 0);
  if (maxTokens <= 0) {
    return `  ${dim("No activity in the selected range.", noColor2)}`;
  }
  const lines = [bold2("  Time of Day (UTC)", noColor2), ""];
  const labelWidth = 16;
  const valueWidth = 8;
  const costWidth = 10;
  const shareWidth = 6;
  const barWidth = Math.max(8, width - labelWidth - valueWidth - costWidth - shareWidth - 10);
  for (const bucket of buckets) {
    const colorCode = TOD_COLORS[bucket.label] ?? 33;
    const share = totalTokens > 0 ? bucket.tokens / totalTokens : 0;
    const ratio = maxTokens > 0 ? bucket.tokens / maxTokens : 0;
    const fillLen = Math.max(ratio > 0 ? 1 : 0, Math.round(ratio * barWidth));
    const bar = colorize256(BAR_CHAR4.repeat(fillLen), colorCode, noColor2) + dim(TRACK_CHAR4.repeat(Math.max(0, barWidth - fillLen)), noColor2);
    const shareStr = `${(share * 100).toFixed(0)}%`.padStart(shareWidth);
    const tokStr = formatTokens7(bucket.tokens).padStart(valueWidth);
    const costStr = formatCost8(bucket.cost).padStart(costWidth);
    lines.push(truncateVisible(`  ${colorize256(bucket.label.padEnd(labelWidth), colorCode, noColor2)} ${bar} ${shareStr} ${tokStr} ${costStr}`, width));
  }
  lines.push("");
  lines.push(`  ${dim(`Hours shown in UTC. ${buckets.reduce((s, b) => s + b.count, 0)} events total.`, noColor2)}`);
  return lines.join(`
`);
}
var BAR_CHAR4 = "\u2588", TRACK_CHAR4 = "\u2591", BUCKET_RANGES;
var init_tod_view = __esm(() => {
  init_colors();
  BUCKET_RANGES = [
    { label: "After midnight", hours: "0-5", start: 0, end: 5 },
    { label: "Morning", hours: "6-11", start: 6, end: 11 },
    { label: "Afternoon", hours: "12-16", start: 12, end: 16 },
    { label: "Evening", hours: "17-21", start: 17, end: 21 },
    { label: "Night", hours: "22-23", start: 22, end: 23 }
  ];
});

// packages/renderers/dist/terminal/tab-views/session-view.js
function formatTokens8(n) {
  if (n >= 1e6)
    return `${(n / 1e6).toFixed(1)}M`;
  if (n >= 1000)
    return `${(n / 1000).toFixed(0)}K`;
  return String(n);
}
function formatCost9(cost) {
  return `$${cost.toFixed(2)}`;
}
function formatDuration3(ms) {
  if (ms < 60000)
    return `${(ms / 1000).toFixed(0)}s`;
  if (ms < 3600000)
    return `${(ms / 60000).toFixed(1)}m`;
  return `${(ms / 3600000).toFixed(1)}h`;
}
function clampLabel(value, width) {
  return value.length > width ? `${value.slice(0, Math.max(1, width - 1))}\u2026` : value.padEnd(width);
}
function renderSessionView(output, width, noColor2) {
  const metrics = output.more?.sessionMetrics;
  if (!metrics || metrics.totalSessions === 0) {
    return `  ${dim("No event-level data available for session analysis.", noColor2)}`;
  }
  const lines = [bold2("  Sessions", noColor2), ""];
  const parts = [
    bold256(`${metrics.totalSessions}`, SEMANTIC.INPUT, noColor2) + " sessions",
    bold256(formatCost9(metrics.averageCost), SEMANTIC.OUTPUT, noColor2) + " avg/session",
    bold256(formatTokens8(metrics.averageTokens), SEMANTIC.ACCENT, noColor2) + " avg tokens/session"
  ];
  lines.push(truncateVisible(`  ${parts.join(dim("  \xB7  ", noColor2))}`, width));
  lines.push("");
  const labelWidth = 24;
  const addMetric = (label, value) => {
    lines.push(truncateVisible(`  ${dim(label.padEnd(labelWidth), noColor2)} ${bold2(value, noColor2)}`, width));
  };
  addMetric("Total sessions", String(metrics.totalSessions));
  addMetric("Avg tokens/session", formatTokens8(metrics.averageTokens));
  addMetric("Avg cost/session", formatCost9(metrics.averageCost));
  addMetric("Avg messages/session", metrics.averageMessages.toFixed(1));
  if (metrics.averageDurationMs !== null) {
    addMetric("Avg duration", formatDuration3(metrics.averageDurationMs));
  }
  addMetric("Projects", String(metrics.projectCount));
  const drilldown = output.more?.sessionDrilldown ?? [];
  if (drilldown.length > 0) {
    lines.push("");
    lines.push(`  ${bold2("Top Sessions", noColor2)}`);
    const sessions = drilldown.slice(0, 5);
    const sessionLabelWidth = Math.min(28, Math.max(12, width - 46));
    const providerWidth = Math.min(12, Math.max(8, Math.floor(width * 0.15)));
    const tokenWidth = 7;
    const costWidth = 7;
    const durationWidth = 7;
    const eventWidth = 5;
    for (let index = 0;index < sessions.length; index += 1) {
      const session = sessions[index];
      const color = PROJECT_COLORS[index % PROJECT_COLORS.length];
      const duration = session.durationMs === null ? "-".padStart(durationWidth) : formatDuration3(session.durationMs).padStart(durationWidth);
      const eventLabel = `${session.eventCount} ev`.padStart(eventWidth);
      const detailParts = [
        session.provider,
        session.topModels.length > 0 ? `models ${session.topModels.map((model) => model.model).join(", ")}` : null,
        session.projectId && session.projectId !== session.label ? `project ${session.projectId}` : null,
        session.directory && session.directory !== session.label ? `dir ${session.directory}` : null
      ].filter((value) => Boolean(value));
      lines.push(truncateVisible(`  ${dim(`${index + 1}.`, noColor2)} ${colorize256(clampLabel(session.label, sessionLabelWidth), color, noColor2)} ${clampLabel(session.provider, providerWidth)} ${formatTokens8(session.totalTokens).padStart(tokenWidth)} ${formatCost9(session.cost).padStart(costWidth)} ${duration} ${eventLabel}`, width));
      lines.push(truncateVisible(`     ${dim(detailParts.join("  \xB7  "), noColor2)}`, width));
    }
  } else if (metrics.longestSession) {
    lines.push("");
    lines.push(`  ${bold2("Longest Session", noColor2)}`);
    addMetric("  Label", metrics.longestSession.label);
    addMetric("  Tokens", formatTokens8(metrics.longestSession.tokens));
    addMetric("  Cost", formatCost9(metrics.longestSession.cost));
    addMetric("  Messages", String(metrics.longestSession.count));
    if (metrics.longestSession.durationMs !== null) {
      addMetric("  Duration", formatDuration3(metrics.longestSession.durationMs));
    }
  }
  if (metrics.topProject) {
    lines.push("");
    lines.push(truncateVisible(`  ${dim("Top project:", noColor2)} ${bold256(metrics.topProject.name, SEMANTIC.OUTPUT, noColor2)} (${formatTokens8(metrics.topProject.tokens)})`, width));
  }
  return lines.join(`
`);
}
var init_session_view = __esm(() => {
  init_colors();
});

// packages/renderers/dist/terminal/tab-views/model-view.js
function formatTokens9(n) {
  if (n >= 1e6)
    return `${(n / 1e6).toFixed(1)}M`;
  if (n >= 1000)
    return `${(n / 1000).toFixed(0)}K`;
  return String(n);
}
function formatCost10(cost) {
  return `$${cost.toFixed(2)}`;
}
function formatCompactCost(cost) {
  if (cost >= 100)
    return `$${cost.toFixed(0)}`;
  if (cost >= 10)
    return `$${cost.toFixed(1)}`;
  return `$${cost.toFixed(2)}`;
}
function formatRatio3(value) {
  return value >= 10 ? value.toFixed(1) : value.toFixed(2);
}
function renderEfficiencyRow(entry, width, noColor2) {
  const nameWidth = Math.min(24, Math.max(12, width - 43));
  const name = entry.model.length > nameWidth ? `${entry.model.slice(0, nameWidth - 1)}\u2026` : entry.model.padEnd(nameWidth);
  return truncateVisible(`  ${colorize256(name, SEMANTIC.ACCENT, noColor2)} ` + `${bold2(`${(entry.score * 100).toFixed(0)}`.padStart(5), noColor2)} ` + `${formatTokens9(entry.outputPerDollar).padStart(7)} ` + `${formatRatio3(entry.outputInputRatio).padStart(6)} ` + `${`${(entry.cacheCoverage * 100).toFixed(0)}%`.padStart(6)} ` + `${formatCompactCost(entry.costPer1MTotal).padStart(8)}`, width);
}
function renderModelEfficiencySection(output, width, noColor2, options = {}) {
  const efficiency = output.more?.modelEfficiency;
  if (!efficiency) {
    return "";
  }
  const title = options.title ?? "Efficiency Ranking";
  const rankings = efficiency.rankings.slice(0, options.limit ?? 5);
  const includeMethod = options.includeMethod ?? true;
  const includeIneligible = options.includeIneligible ?? true;
  const lines = [`  ${bold2(title, noColor2)}`];
  if (includeMethod) {
    lines.push(truncateVisible(`  ${dim(efficiency.method, noColor2)}`, width));
  }
  if (rankings.length > 0) {
    lines.push(truncateVisible(`  ${dim("model".padEnd(Math.min(24, Math.max(12, width - 43))), noColor2)} ${dim("score".padStart(5), noColor2)} ${dim("out/$".padStart(7), noColor2)} ${dim("out/in".padStart(6), noColor2)} ${dim("cache".padStart(6), noColor2)} ${dim("$ / 1M".padStart(8), noColor2)}`, width));
    for (const entry of rankings) {
      lines.push(renderEfficiencyRow(entry, width, noColor2));
      lines.push(truncateVisible(`    ${dim("why", noColor2)} ` + `${dim(`out/$ ${(entry.scoreBreakdown.outputPerDollar * 100).toFixed(0)}%`, noColor2)} ` + `${dim(`out/in ${(entry.scoreBreakdown.outputInputRatio * 100).toFixed(0)}%`, noColor2)} ` + `${dim(`cache ${(entry.scoreBreakdown.cacheCoverage * 100).toFixed(0)}%`, noColor2)}`, width));
    }
  } else {
    lines.push(`  ${dim("No eligible models yet.", noColor2)}`);
  }
  if (includeIneligible && efficiency.ineligibleModels.length > 0) {
    lines.push("");
    lines.push(`  ${bold2("Ineligible", noColor2)}`);
    for (const entry of efficiency.ineligibleModels.slice(0, 4)) {
      lines.push(truncateVisible(`  ${entry.model} ${dim(`(${entry.eventCount} evt, ${formatTokens9(entry.totalTokens)} tok)`, noColor2)} ${dim(entry.reason, noColor2)}`, width));
    }
    if (efficiency.ineligibleModels.length > 4) {
      lines.push(truncateVisible(`  ${dim(`+${efficiency.ineligibleModels.length - 4} more ineligible models`, noColor2)}`, width));
    }
  }
  return lines.join(`
`);
}
function renderModelView(output, width, noColor2) {
  const models = output.aggregated.topModels;
  if (models.length === 0) {
    return `  ${dim("No model data available.", noColor2)}`;
  }
  const lines = [bold2("  Models", noColor2), ""];
  const nameWidth = Math.min(28, Math.max(12, Math.floor(width * 0.25)));
  const valueWidth = 8;
  const costWidth = 10;
  const shareWidth = 6;
  const barWidth = Math.max(8, width - nameWidth - valueWidth - costWidth - shareWidth - 10);
  const maxTokens = Math.max(...models.map((m) => m.tokens), 0);
  for (let i = 0;i < models.length; i++) {
    const model = models[i];
    const colorCode = MODEL_COLORS[i % MODEL_COLORS.length];
    const ratio = maxTokens > 0 ? model.tokens / maxTokens : 0;
    const fillLen = Math.max(ratio > 0 ? 1 : 0, Math.round(ratio * barWidth));
    const bar = colorize256(BAR_CHAR5.repeat(fillLen), colorCode, noColor2) + dim(TRACK_CHAR5.repeat(Math.max(0, barWidth - fillLen)), noColor2);
    const shareStr = `${model.percentage.toFixed(0)}%`.padStart(shareWidth);
    const tokStr = formatTokens9(model.tokens).padStart(valueWidth);
    const costStr = formatCost10(model.cost).padStart(costWidth);
    const name = model.model.length > nameWidth ? model.model.slice(0, nameWidth - 1) + "\u2026" : model.model.padEnd(nameWidth);
    lines.push(truncateVisible(`  ${colorize256(name, colorCode, noColor2)} ${bar} ${shareStr} ${tokStr} ${costStr}`, width));
  }
  const io = output.more?.inputOutput;
  if (io) {
    lines.push("");
    lines.push(`  ${bold2("Input / Output Ratio", noColor2)}`);
    const inputShare = 1 - io.outputShare;
    const ioBarWidth = Math.max(10, width - 20);
    const inputLen = Math.round(inputShare * ioBarWidth);
    const outputLen = ioBarWidth - inputLen;
    const ioBar = colorize256(BAR_CHAR5.repeat(inputLen), SEMANTIC.INPUT, noColor2) + colorize256(BAR_CHAR5.repeat(outputLen), SEMANTIC.OUTPUT, noColor2);
    lines.push(truncateVisible(`  ${ioBar}  ${dim(`input ${(inputShare * 100).toFixed(0)}%`, noColor2)} ${dim(`output ${(io.outputShare * 100).toFixed(0)}%`, noColor2)}`, width));
  }
  const roiLines = renderCacheRoiBreakdowns("Cache ROI by Model", output.more?.cacheRoi?.byModel ?? [], width, noColor2);
  if (roiLines.length > 0) {
    lines.push("", ...roiLines);
  }
  const efficiencySection = renderModelEfficiencySection(output, width, noColor2, {
    title: "Efficiency Ranking",
    limit: 6,
    includeMethod: true,
    includeIneligible: true
  });
  if (efficiencySection) {
    lines.push("", efficiencySection);
  }
  return lines.join(`
`);
}
var BAR_CHAR5 = "\u2588", TRACK_CHAR5 = "\u2591";
var init_model_view = __esm(() => {
  init_colors();
  init_cache_roi();
});

// packages/renderers/dist/terminal/tab-views/token-view.js
function formatTokens10(n) {
  if (n >= 1e6)
    return `${(n / 1e6).toFixed(1)}M`;
  if (n >= 1000)
    return `${(n / 1000).toFixed(0)}K`;
  return String(n);
}
function formatCost11(cost) {
  return `$${cost.toFixed(2)}`;
}
function renderTokenView(output, width, noColor2) {
  const stats = output.aggregated;
  const lines = [bold2("  Tokens", noColor2), ""];
  const parts = [
    bold256(formatTokens10(stats.totalTokens), SEMANTIC.INPUT, noColor2) + " total",
    bold256(formatCost11(stats.totalCost), SEMANTIC.OUTPUT, noColor2) + " cost",
    bold256(`${stats.activeDays}`, SEMANTIC.ACCENT, noColor2) + " active days"
  ];
  lines.push(truncateVisible(`  ${parts.join(dim("  \xB7  ", noColor2))}`, width));
  lines.push("");
  lines.push(`  ${bold2("Heatmap", noColor2)}`);
  const merged = output.providers.flatMap((p) => p.daily);
  lines.push(renderTerminalHeatmap(merged, { width: width - 2, noColor: noColor2 }));
  lines.push("");
  const io = output.more?.inputOutput;
  if (io) {
    lines.push(`  ${bold2("Input / Output", noColor2)}`);
    const inputShare = 1 - io.outputShare;
    const barWidth = Math.max(10, width - 20);
    const inputLen = Math.round(inputShare * barWidth);
    const outputLen = barWidth - inputLen;
    const bar = colorize256(BAR_CHAR6.repeat(inputLen), SEMANTIC.INPUT, noColor2) + colorize256(BAR_CHAR6.repeat(outputLen), SEMANTIC.OUTPUT, noColor2);
    lines.push(truncateVisible(`  ${bar}  ${dim(`in ${(inputShare * 100).toFixed(0)}%`, noColor2)} ${dim(`out ${(io.outputShare * 100).toFixed(0)}%`, noColor2)}`, width));
    lines.push("");
  }
  const cache = output.more?.cacheEconomics;
  if (cache) {
    lines.push(`  ${bold2("Cache Economics", noColor2)}`);
    const labelWidth = 20;
    const addLine = (label, value) => {
      lines.push(truncateVisible(`  ${dim(label.padEnd(labelWidth), noColor2)} ${bold2(value, noColor2)}`, width));
    };
    addLine("Read tokens", formatTokens10(cache.readTokens));
    addLine("Write tokens", formatTokens10(cache.writeTokens));
    addLine("Read coverage", `${(cache.readCoverage * 100).toFixed(1)}%`);
    if (cache.reuseRatio !== null) {
      addLine("Reuse ratio", `${cache.reuseRatio.toFixed(1)}x`);
    }
    lines.push("");
  }
  const cacheRoi = output.more?.cacheRoi;
  if (cacheRoi) {
    lines.push(...renderCacheRoiSummary(cacheRoi.summary, width, noColor2));
    lines.push("");
  }
  const burn = output.more?.monthlyBurn;
  if (burn) {
    lines.push(`  ${bold2("Monthly Burn Projection", noColor2)}`);
    const labelWidth = 20;
    lines.push(truncateVisible(`  ${dim("Projected tokens".padEnd(labelWidth), noColor2)} ${bold2(formatTokens10(burn.projectedTokens), noColor2)}`, width));
    lines.push(truncateVisible(`  ${dim("Projected cost".padEnd(labelWidth), noColor2)} ${bold2(formatCost11(burn.projectedCost), noColor2)}`, width));
    lines.push(truncateVisible(`  ${dim("Observed days".padEnd(labelWidth), noColor2)} ${bold2(`${burn.observedDays} / ${burn.calendarDays}`, noColor2)}`, width));
  }
  return lines.join(`
`);
}
var BAR_CHAR6 = "\u2588";
var init_token_view = __esm(() => {
  init_colors();
  init_heatmap();
  init_cache_roi();
});

// packages/renderers/dist/terminal/tab-views/cwd-view.js
function formatTokens11(n) {
  if (n >= 1e6)
    return `${(n / 1e6).toFixed(1)}M`;
  if (n >= 1000)
    return `${(n / 1000).toFixed(0)}K`;
  return String(n);
}
function formatCost12(cost) {
  return `$${cost.toFixed(2)}`;
}
function clampLabel2(value, width) {
  return value.length > width ? `${value.slice(0, Math.max(1, width - 1))}\u2026` : value.padEnd(width);
}
function formatClusterMeta(cluster) {
  const parts = [
    cluster.taskStyle.replace(/-/g, " "),
    `${cluster.sessionCount} sess`,
    `${cluster.activeDays} day${cluster.activeDays === 1 ? "" : "s"}`
  ];
  if (cluster.providers.length > 0) {
    parts.push(cluster.providers.join(", "));
  }
  if (cluster.models[0]) {
    parts.push(cluster.models[0]);
  }
  return parts.join(" \xB7 ");
}
function getAttribution(output) {
  return output.more?.attribution ?? null;
}
function renderAttributionView(output, width, noColor2) {
  const attribution = getAttribution(output);
  if (!attribution || attribution.length === 0) {
    return `  ${dim("No event-level data available for attribution.", noColor2)}`;
  }
  const lines = [bold2("  Attribution", noColor2), ""];
  const maxTokens = Math.max(...attribution.map((entry) => entry.tokens), 0);
  const totalTokens = attribution.reduce((sum, entry) => sum + entry.tokens, 0);
  if (maxTokens <= 0) {
    return `  ${dim("No attributable activity in the selected range.", noColor2)}`;
  }
  const nameWidth = Math.min(28, Math.max(12, Math.floor(width * 0.28)));
  const valueWidth = 8;
  const shareWidth = 6;
  const barWidth = Math.max(8, width - nameWidth - valueWidth - shareWidth - 8);
  for (let i = 0;i < Math.min(attribution.length, 8); i++) {
    const cluster = attribution[i];
    const colorCode = PROJECT_COLORS[i % PROJECT_COLORS.length];
    const ratio = cluster.tokens / maxTokens;
    const share = totalTokens > 0 ? cluster.tokens / totalTokens : 0;
    const fillLen = Math.max(ratio > 0 ? 1 : 0, Math.round(ratio * barWidth));
    const bar = colorize256(BAR_CHAR7.repeat(fillLen), colorCode, noColor2) + dim(TRACK_CHAR6.repeat(Math.max(0, barWidth - fillLen)), noColor2);
    const shareStr = `${(share * 100).toFixed(0)}%`.padStart(shareWidth);
    const tokStr = formatTokens11(cluster.tokens).padStart(valueWidth);
    const name = cluster.label.length > nameWidth ? cluster.label.slice(0, nameWidth - 1) + "\u2026" : cluster.label.padEnd(nameWidth);
    lines.push(truncateVisible(`  ${colorize256(name, colorCode, noColor2)} ${bar} ${shareStr} ${tokStr}`, width));
    const meta = formatClusterMeta(cluster);
    const root = cluster.directory && cluster.repoRoot ? `${cluster.repoRoot}/${cluster.directory}` : cluster.repoRoot ?? cluster.directory;
    const window = cluster.timeWindows[0] ? `${cluster.timeWindows[0].start.slice(0, 16)} -> ${cluster.timeWindows.at(-1)?.end.slice(0, 16)}` : null;
    const detailParts = [meta];
    if (root) {
      detailParts.push(root);
    }
    if (window) {
      detailParts.push(window);
    }
    lines.push(truncateVisible(`    ${dim(detailParts.join("  |  "), noColor2)}`, width));
  }
  lines.push("");
  lines.push(`  ${dim(`${Math.min(attribution.length, 8)} cluster${attribution.length === 1 ? "" : "s"} shown`, noColor2)}`);
  return lines.join(`
`);
}
function renderProjectBreakdown(output, width, noColor2) {
  const projectDrilldown = output.more?.projectDrilldown ?? [];
  const breakdown = output.more?.sessionMetrics?.projectBreakdown;
  if (projectDrilldown.length === 0 && (!breakdown || breakdown.length === 0)) {
    return `  ${dim("No event-level data available for project breakdown.", noColor2)}`;
  }
  const lines = [bold2("  Projects", noColor2), ""];
  const rankedProjects = projectDrilldown.length > 0 ? projectDrilldown.slice(0, 5) : breakdown.map((project) => ({
    projectId: project.name,
    sessionCount: 0,
    activeDays: 0,
    streak: 0,
    totalTokens: project.tokens,
    cost: 0,
    directory: null,
    topModels: []
  }));
  const maxTokens = Math.max(...rankedProjects.map((project) => project.totalTokens), 0);
  const totalTokens = rankedProjects.reduce((sum, project) => sum + project.totalTokens, 0);
  if (maxTokens <= 0) {
    return `  ${dim("No project activity in the selected range.", noColor2)}`;
  }
  const nameWidth = Math.min(26, Math.max(12, Math.floor(width * 0.26)));
  const shareWidth = 6;
  const valueWidth = 7;
  const costWidth = 7;
  const barWidth = Math.max(8, width - nameWidth - valueWidth - costWidth - shareWidth - 10);
  if (projectDrilldown.length > 0) {
    const sessionTotal = projectDrilldown.reduce((sum, project) => sum + project.sessionCount, 0);
    lines.push(truncateVisible(`  ${dim(`${projectDrilldown.length} projects  \xB7  ${sessionTotal} sessions ranked by total tokens`, noColor2)}`, width));
    lines.push("");
  }
  for (let index = 0;index < rankedProjects.length; index += 1) {
    const project = rankedProjects[index];
    const colorCode = PROJECT_COLORS[index % PROJECT_COLORS.length];
    const ratio = maxTokens > 0 ? project.totalTokens / maxTokens : 0;
    const share = totalTokens > 0 ? project.totalTokens / totalTokens : 0;
    const fillLen = Math.max(ratio > 0 ? 1 : 0, Math.round(ratio * barWidth));
    const bar = colorize256(BAR_CHAR7.repeat(fillLen), colorCode, noColor2) + dim(TRACK_CHAR6.repeat(Math.max(0, barWidth - fillLen)), noColor2);
    lines.push(truncateVisible(`  ${colorize256(clampLabel2(project.projectId, nameWidth), colorCode, noColor2)} ${bar} ${`${(share * 100).toFixed(0)}%`.padStart(shareWidth)} ${formatTokens11(project.totalTokens).padStart(valueWidth)} ${formatCost12(project.cost).padStart(costWidth)}`, width));
    if (projectDrilldown.length > 0) {
      const detailParts = [
        `${project.sessionCount} sess`,
        `${project.activeDays} active day${project.activeDays === 1 ? "" : "s"}`,
        `${project.streak}d streak`,
        project.topModels.length > 0 ? `models ${project.topModels.slice(0, 2).map((model) => model.model).join(", ")}` : null,
        project.directory && project.directory !== project.projectId ? `dir ${project.directory}` : null
      ].filter((value) => Boolean(value));
      lines.push(truncateVisible(`     ${dim(detailParts.join("  \xB7  "), noColor2)}`, width));
    }
  }
  lines.push("");
  lines.push(`  ${dim(`${rankedProjects.length} project${rankedProjects.length === 1 ? "" : "s"} shown`, noColor2)}`);
  const roiLines = renderCacheRoiBreakdowns("Cache ROI by Project", output.more?.cacheRoi?.byProject ?? [], width, noColor2);
  if (roiLines.length > 0) {
    lines.push("", ...roiLines);
  }
  return lines.join(`
`);
}
function renderCwdView(output, width, noColor2) {
  const attribution = getAttribution(output);
  const projectView = renderProjectBreakdown(output, width, noColor2);
  if (attribution && attribution.length > 0) {
    return `${renderAttributionView(output, width, noColor2)}

${projectView}`;
  }
  return projectView;
}
var BAR_CHAR7 = "\u2588", TRACK_CHAR6 = "\u2591";
var init_cwd_view = __esm(() => {
  init_colors();
  init_cache_roi();
});

// packages/renderers/dist/terminal/tab-views/index.js
var init_tab_views = __esm(() => {
  init_tab_bar();
  init_tab_bar();
  init_overview_view();
  init_compare_view();
  init_provider_view();
  init_dow_view();
  init_tod_view();
  init_session_view();
  init_model_view();
  init_token_view();
  init_cwd_view();
});

// packages/renderers/dist/terminal/terminal-renderer.js
function appendCompareSection(rendered, output, options) {
  if (!output.more?.compare) {
    return rendered;
  }
  return `${rendered}

${renderCompareView(output, options.width, options.noColor)}`;
}
function formatTokens12(value) {
  if (value >= 1e6)
    return `${(value / 1e6).toFixed(1)}M`;
  if (value >= 1000)
    return `${(value / 1000).toFixed(0)}K`;
  return String(Math.round(value));
}
function formatMoney(value) {
  return `$${value.toFixed(2)}`;
}
function appendCacheRoiSection(rendered, output, options) {
  if (!options.more || !output.more?.cacheRoi) {
    return rendered;
  }
  const roi = output.more.cacheRoi;
  const bestProject = roi.byProject[0];
  const lines = [
    "Cache ROI",
    `  Net savings ${formatMoney(roi.summary.netSavings)}  Read savings ${formatMoney(roi.summary.readSavings)}  Write cost ${formatMoney(roi.summary.writeCost)}`,
    `  Reuse ${roi.summary.reuseRatio === null ? "n/a" : `${roi.summary.reuseRatio.toFixed(2)}x`}  Payback ${roi.summary.paybackRatio === null ? "n/a" : `${roi.summary.paybackRatio.toFixed(2)}x`}  Cache reads ${formatTokens12(roi.summary.readTokens)}`
  ];
  if (bestProject) {
    lines.push(`  Top project ${bestProject.label} (${formatMoney(bestProject.netSavings)} net)`);
  }
  return `${rendered}

${lines.join(`
`)}`;
}
function appendModelEfficiencySection(rendered, output, options) {
  if (!options.more || options.width < MIN_COMPACT_WIDTH || !output.more?.modelEfficiency) {
    return rendered;
  }
  const section = renderModelEfficiencySection(output, options.width, options.noColor, {
    title: "Model Efficiency",
    limit: 3,
    includeMethod: true,
    includeIneligible: true
  });
  if (!section) {
    return rendered;
  }
  return `${rendered}

${section}`;
}

class TerminalRenderer {
  format = "terminal";
  async render(output, options) {
    const effectiveOptions = {
      ...options,
      noColor: options.noColor
    };
    if (effectiveOptions.width < MIN_COMPACT_WIDTH) {
      return appendCompareSection(renderOneliner(output, effectiveOptions), output, effectiveOptions);
    }
    const model = buildDashboardModel(output, effectiveOptions);
    if (model.mode === "compact") {
      return appendModelEfficiencySection(appendCacheRoiSection(appendCompareSection(renderCompactDashboard(model, effectiveOptions), output, effectiveOptions), output, effectiveOptions), output, effectiveOptions);
    }
    return appendModelEfficiencySection(appendCacheRoiSection(appendCompareSection(renderDashboardModel(model, effectiveOptions), output, effectiveOptions), output, effectiveOptions), output, effectiveOptions);
  }
}
var MIN_COMPACT_WIDTH = 32;
var init_terminal_renderer = __esm(() => {
  init_compact();
  init_dashboard();
  init_dashboard_model();
  init_oneliner();
  init_tab_views();
  init_model_view();
});

// packages/renderers/dist/terminal/ansi.js
var ESC2 = "\x1B[", CODES;
var init_ansi = __esm(() => {
  CODES = {
    green: `${ESC2}32m`,
    yellow: `${ESC2}33m`,
    red: `${ESC2}31m`,
    cyan: `${ESC2}36m`,
    bold: `${ESC2}1m`,
    dim: `${ESC2}2m`,
    reset: `${ESC2}0m`
  };
});

// packages/renderers/dist/terminal/advisor-view.js
function formatDollars(amount) {
  return `$${amount.toFixed(2)}`;
}
function formatPercent4(ratio) {
  return `${Math.round(ratio * 100)}%`;
}
function confidenceColor(confidence) {
  switch (confidence) {
    case "high":
      return COLOR_HIGH;
    case "medium":
      return COLOR_MEDIUM;
    case "low":
      return COLOR_LOW;
  }
}
function renderRecommendation(rec, width, noColor2) {
  const lines = [];
  const indent = "  ";
  const contentWidth = width - 4;
  const badge = rec.confidence.toUpperCase();
  const badgeColor = confidenceColor(rec.confidence);
  const icon = noColor2 ? "*" : "\uD83D\uDCA1";
  const title = bold256(`${icon} ${rec.title}`, COLOR_TITLE, noColor2);
  lines.push(`${indent}${title}`);
  const descLines = wrapText(rec.description, contentWidth - 2);
  for (const line2 of descLines) {
    lines.push(`${indent}   ${dim(line2, noColor2)}`);
  }
  if (rec.currentCost > 0 || rec.projectedCost > 0) {
    const current = bold2(`${formatDollars(rec.currentCost)}/mo`, noColor2);
    const projected = bold256(`${formatDollars(rec.projectedCost)}/mo`, COLOR_SAVINGS, noColor2);
    lines.push(`${indent}   Current cost: ${current}  ->  Projected: ${projected}`);
  }
  if (rec.monthlySavings > 0) {
    const savingsText = bold256(`${formatDollars(rec.monthlySavings)}/mo`, COLOR_SAVINGS, noColor2);
    let reductionText = "";
    if (rec.currentCost > 0) {
      reductionText = ` (${formatPercent4(rec.monthlySavings / rec.currentCost)} reduction)`;
    }
    const savingsLine = `Savings: ${savingsText}${reductionText}`;
    const badgeStr = bold256(badge, badgeColor, noColor2);
    const savingsPlain = stripAnsi(savingsLine);
    const badgePlain = stripAnsi(badgeStr);
    const gap = Math.max(1, contentWidth - 2 - savingsPlain.length - badgePlain.length);
    lines.push(`${indent}   ${savingsLine}${" ".repeat(gap)}${badgeStr}`);
  } else {
    const badgeStr = bold256(badge, badgeColor, noColor2);
    const badgePlain = stripAnsi(badgeStr);
    const gap = Math.max(1, contentWidth - 2 - badgePlain.length);
    lines.push(`${indent}   ${" ".repeat(gap)}${badgeStr}`);
  }
  return lines;
}
function wrapText(text2, maxWidth) {
  if (maxWidth <= 0)
    return [text2];
  const words = text2.split(" ");
  const lines = [];
  let current = "";
  for (const word of words) {
    if (current.length === 0) {
      current = word;
    } else if (current.length + 1 + word.length <= maxWidth) {
      current += " " + word;
    } else {
      lines.push(current);
      current = word;
    }
  }
  if (current.length > 0) {
    lines.push(current);
  }
  return lines.length > 0 ? lines : [""];
}
function renderBox(title, subtitle, width, noColor2) {
  const innerWidth = Math.max(20, width - 4);
  const top = `  \u250C${"\u2500".repeat(innerWidth)}\u2510`;
  const bottom = `  \u2514${"\u2500".repeat(innerWidth)}\u2518`;
  const titleStr = bold256(`  ${title}`, COLOR_TITLE, noColor2);
  const titlePad = Math.max(0, innerWidth - stripAnsi(titleStr).length);
  const titleLine = `  \u2502${titleStr}${" ".repeat(titlePad)}\u2502`;
  const subtitleStr = dim(`  ${subtitle}`, noColor2);
  const subtitlePad = Math.max(0, innerWidth - stripAnsi(subtitleStr).length);
  const subtitleLine = `  \u2502${subtitleStr}${" ".repeat(subtitlePad)}\u2502`;
  return [top, titleLine, subtitleLine, bottom];
}
function renderAdvisorView(report, options) {
  const { width, noColor: noColor2 } = options;
  const lines = [];
  const subtitle = `Analyzed ${report.analyzedDays} days \xB7 ${report.analyzedEvents.toLocaleString()} events`;
  lines.push(...renderBox("Model Efficiency Advisor", subtitle, width, noColor2));
  if (report.recommendations.length === 0) {
    lines.push("");
    lines.push(`  ${dim("No recommendations -- your usage looks efficient!", noColor2)}`);
    lines.push("");
    return lines.join(`
`);
  }
  lines.push("");
  for (let i = 0;i < report.recommendations.length; i++) {
    const rec = report.recommendations[i];
    lines.push(...renderRecommendation(rec, width, noColor2));
    if (i < report.recommendations.length - 1) {
      lines.push("");
    }
  }
  lines.push("");
  const sepWidth = Math.max(10, width - 4);
  lines.push(`  ${"\u2500".repeat(sepWidth)}`);
  lines.push("");
  lines.push(`  ${bold2("Summary", noColor2)}`);
  const currentLabel = "  Current projected monthly cost";
  const projectedLabel = "  Optimized projected monthly cost";
  const savingsLabel = "  Total potential savings";
  const currentVal = bold2(formatDollars(report.totalCurrentMonthlyCost), noColor2);
  const projectedVal = bold256(formatDollars(report.totalProjectedMonthlyCost), COLOR_SAVINGS, noColor2);
  let savingsVal;
  if (report.totalCurrentMonthlyCost > 0) {
    const pct = formatPercent4(report.totalMonthlySavings / report.totalCurrentMonthlyCost);
    savingsVal = bold256(`${formatDollars(report.totalMonthlySavings)}/mo (${pct})`, COLOR_SAVINGS, noColor2);
  } else {
    savingsVal = bold256(`${formatDollars(report.totalMonthlySavings)}/mo`, COLOR_SAVINGS, noColor2);
  }
  const labelWidth = Math.max(currentLabel.length, projectedLabel.length, savingsLabel.length);
  lines.push(`${currentLabel.padEnd(labelWidth)}  ${currentVal}`);
  lines.push(`${projectedLabel.padEnd(labelWidth)}  ${projectedVal}`);
  lines.push(`${savingsLabel.padEnd(labelWidth)}  ${savingsVal}`);
  lines.push("");
  return lines.join(`
`);
}
var COLOR_TITLE = 68, COLOR_SAVINGS = 71, COLOR_HIGH = 71, COLOR_MEDIUM = 179, COLOR_LOW = 140;
var init_advisor_view = __esm(() => {
  init_colors();
});

// packages/renderers/dist/terminal/index.js
var init_terminal = __esm(() => {
  init_terminal_renderer();
  init_dashboard();
  init_oneliner();
  init_heatmap();
  init_ansi();
  init_colors();
  init_tab_views();
  init_advisor_view();
});

// packages/renderers/dist/live/template.js
function formatDateRange2(since, until) {
  const s = new Date(since + "T00:00:00Z");
  const u = new Date(until + "T00:00:00Z");
  const diffMs = u.getTime() - s.getTime();
  const days = Math.round(diffMs / (1000 * 60 * 60 * 24));
  const sMonth = MONTH_NAMES_FULL2[s.getUTCMonth()] ?? "";
  const uMonth = MONTH_NAMES_FULL2[u.getUTCMonth()] ?? "";
  return `${sMonth} ${s.getUTCFullYear()} &mdash; ${uMonth} ${u.getUTCFullYear()} &middot; ${days} DAYS`;
}
function formatPercentage2(rate) {
  return `${(rate * 100).toFixed(1)}%`;
}
function formatStreak2(n) {
  return `${n} day${n !== 1 ? "s" : ""}`;
}
function esc(s) {
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
}
function hexToRgb2(hex) {
  const h = hex.replace("#", "");
  return {
    r: parseInt(h.slice(0, 2), 16),
    g: parseInt(h.slice(2, 4), 16),
    b: parseInt(h.slice(4, 6), 16)
  };
}
function rgbToHex2(r, g, b) {
  const toHex = (n) => n.toString(16).padStart(2, "0");
  return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
function buildHeatmapScale2(colors, isDark) {
  const [startHex, endHex] = colors.gradient;
  const s = hexToRgb2(startHex);
  const e = hexToRgb2(endHex);
  const opacities = isDark ? [0.15, 0.35, 0.6, 1] : [0.2, 0.4, 0.65, 1];
  return [
    "transparent",
    ...opacities.map((t) => {
      const r = Math.round(s.r + (e.r - s.r) * t);
      const g = Math.round(s.g + (e.g - s.g) * t);
      const b = Math.round(s.b + (e.b - s.b) * t);
      return rgbToHex2(r, g, b);
    })
  ];
}
function buildHeatmapCells(provider, since, until) {
  const model = buildHeatmapModel(provider.daily, { since, until });
  if (!model) {
    return { cells: [], months: [], totalCols: 0 };
  }
  const cells = [];
  const months = [];
  for (const marker of model.monthMarkers) {
    months.push({ label: marker.label, col: marker.weekIndex });
  }
  for (const week of model.weeks) {
    for (const day of week.days) {
      cells.push({
        date: day.date,
        tokens: day.tokens,
        level: day.level,
        row: day.dayIndex,
        col: week.index
      });
    }
  }
  return { cells, months, totalCols: model.weeks.length };
}
function renderProviderHeatmapHtml(provider, since, until, isDark, emptyCell) {
  const heatmapColors = buildHeatmapScale2(provider.colors, isDark);
  const { cells, months, totalCols } = buildHeatmapCells(provider, since, until);
  const heatmapWidth = DAY_LABEL_WIDTH + totalCols * (CELL_SIZE + CELL_GAP);
  const heatmapHeight = MONTH_LABEL_HEIGHT + 7 * (CELL_SIZE + CELL_GAP);
  const cellsHtml = cells.map((c) => {
    const x = DAY_LABEL_WIDTH + c.col * (CELL_SIZE + CELL_GAP);
    const y = MONTH_LABEL_HEIGHT + c.row * (CELL_SIZE + CELL_GAP);
    const fill = c.level === 0 ? emptyCell : heatmapColors[c.level];
    return `<div class="heatmap-cell" style="left:${x}px;top:${y}px;background:${fill}" data-date="${esc(c.date)}" data-tokens="${c.tokens}"></div>`;
  }).join(`
`);
  const monthLabelsHtml = months.map((m) => {
    const x = DAY_LABEL_WIDTH + m.col * (CELL_SIZE + CELL_GAP);
    return `<span class="month-label" style="left:${x}px">${esc(m.label)}</span>`;
  }).join(`
`);
  const dayLabelsHtml = [
    { label: "Mon", row: 1 },
    { label: "Wed", row: 3 },
    { label: "Fri", row: 5 },
    { label: "Sun", row: 0 }
  ].map((d) => {
    const y = MONTH_LABEL_HEIGHT + d.row * (CELL_SIZE + CELL_GAP) + CELL_SIZE - 2;
    return `<span class="day-label" style="top:${y - 10}px">${d.label}</span>`;
  }).join(`
`);
  const summaryText = `${esc(formatNumber(provider.totalTokens))} tokens &middot; ${esc(formatCost2(provider.totalCost))}`;
  return `<div class="provider-section" data-provider="${esc(provider.provider)}">
    <div class="provider-header">
      <div class="provider-name-row">
        <span class="provider-dot" style="background:${esc(provider.colors.primary)}"></span>
        <span class="provider-name">${esc(provider.displayName)}</span>
      </div>
      <span class="provider-summary">${summaryText}</span>
    </div>
    <div class="heatmap-container" style="width:${heatmapWidth}px;height:${heatmapHeight}px">
      ${dayLabelsHtml}
      ${monthLabelsHtml}
      ${cellsHtml}
    </div>
  </div>`;
}
function generateHtml(output, options) {
  const isDark = options.theme === "dark";
  const stats = output.aggregated;
  const { since, until } = output.dateRange;
  const providers = output.providers;
  const bg = isDark ? "#0c0c0c" : "#fafafa";
  const fg = isDark ? "#ffffff" : "#18181b";
  const muted = isDark ? "#52525b" : "#a1a1aa";
  const accent = isDark ? "#10b981" : "#059669";
  const border = isDark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.08)";
  const emptyCell = isDark ? "#1a1a1a" : "#e4e4e7";
  const barTrack = isDark ? "#1c1c1c" : "#e5e5e5";
  const providerSectionsHtml = providers.map((p, i) => {
    const section = renderProviderHeatmapHtml(p, since, until, isDark, emptyCell);
    const divider2 = i < providers.length - 1 ? '<hr class="provider-divider">' : "";
    return section + divider2;
  }).join(`
`);
  const statRows = [
    [
      { label: "CURRENT STREAK", value: esc(formatStreak2(stats.currentStreak)), accent: true },
      { label: "LONGEST STREAK", value: esc(formatStreak2(stats.longestStreak)), accent: false },
      { label: "TOTAL TOKENS", value: esc(formatNumber(stats.totalTokens)), accent: true }
    ],
    [
      { label: "TOTAL COST", value: esc(formatCost2(stats.totalCost)), accent: false },
      { label: "30-DAY TOKENS", value: esc(formatNumber(stats.rolling30dTokens)), accent: false },
      { label: "CACHE HIT RATE", value: esc(formatPercentage2(stats.cacheHitRate)), accent: false }
    ]
  ];
  const statsHtml = statRows.map((row) => `<div class="stat-row">${row.map((s) => `<div class="stat"><div class="stat-label">${s.label}</div><div class="stat-value${s.accent ? " accent" : ""}">${s.value}</div></div>`).join("")}</div>`).join("");
  const topModels2 = stats.topModels.slice(0, 3);
  const modelsHtml = topModels2.map((m) => {
    const width = Math.max(2, m.percentage);
    return `<div class="model-row">
      <span class="model-name">${esc(m.model)}</span>
      <div class="model-bar-track"><div class="model-bar-fill" style="width:${width}%"></div></div>
      <span class="model-pct">${m.percentage.toFixed(0)}%</span>
    </div>`;
  }).join("");
  const overallLabel = providers.length > 1 ? '<div class="overall-label">OVERALL</div>' : "";
  return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>tokenleak \u2014 live dashboard</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    font-family: 'JetBrains Mono', 'SF Mono', 'Cascadia Code', 'Fira Code', monospace;
    background: ${isDark ? "#000" : "#f4f4f5"};
    display: flex;
    justify-content: center;
    align-items: flex-start;
    padding: 48px 24px;
    min-height: 100vh;
  }
  .card {
    background: ${bg};
    border-radius: 12px;
    border: 1px solid ${border};
    box-shadow: 0 20px 60px -12px ${isDark ? "rgba(0,0,0,0.7)" : "rgba(0,0,0,0.15)"}, 0 0 80px ${isDark ? "rgba(16,185,129,0.1)" : "rgba(5,150,105,0.08)"};
    max-width: 900px;
    width: 100%;
    overflow: hidden;
  }
  .titlebar {
    display: flex;
    align-items: center;
    height: 48px;
    padding: 0 20px;
    border-bottom: 1px solid ${border};
    gap: 8px;
  }
  .dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }
  .dot-red { background: #ff5f57; }
  .dot-yellow { background: #febc2e; }
  .dot-green { background: #28c840; }
  .titlebar-label { color: ${muted}; font-size: 13px; font-weight: 500; margin-left: 12px; }
  .content { padding: 28px 48px 48px; }
  .prompt { font-size: 15px; font-weight: 500; margin-bottom: 24px; }
  .prompt .dollar { color: ${accent}; }
  .prompt .cmd { color: ${fg}; }
  .prompt .cursor { color: ${accent}; animation: blink 1s step-end infinite; }
  @keyframes blink { 50% { opacity: 0; } }
  .date-range { color: ${muted}; font-size: 12px; font-weight: 600; letter-spacing: 2px; margin-bottom: 24px; }

  /* Provider sections */
  .provider-section { margin-bottom: 12px; }
  .provider-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
  .provider-name-row { display: flex; align-items: center; gap: 10px; }
  .provider-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
  .provider-name { color: ${fg}; font-size: 14px; font-weight: 600; }
  .provider-summary { color: ${muted}; font-size: 11px; font-weight: 500; }
  .provider-divider { border: none; border-top: 1px solid ${border}; margin: 24px 0; }

  .heatmap-container { position: relative; margin-bottom: 8px; }
  .heatmap-cell {
    position: absolute;
    width: ${CELL_SIZE}px;
    height: ${CELL_SIZE}px;
    border-radius: 3px;
    cursor: pointer;
  }
  .heatmap-cell:hover { outline: 2px solid ${accent}; outline-offset: 1px; }
  .month-label { position: absolute; top: 0; color: ${muted}; font-size: 11px; }
  .day-label { position: absolute; left: 0; color: ${muted}; font-size: 11px; }
  .tooltip {
    display: none;
    position: fixed;
    background: ${isDark ? "#1c1c1c" : "#fff"};
    color: ${fg};
    border: 1px solid ${border};
    border-radius: 6px;
    padding: 6px 10px;
    font-size: 11px;
    pointer-events: none;
    z-index: 100;
    white-space: nowrap;
    box-shadow: 0 4px 12px ${isDark ? "rgba(0,0,0,0.5)" : "rgba(0,0,0,0.1)"};
  }

  .divider { border: none; border-top: 1px solid ${border}; margin: 0 0 28px; }
  .overall-label { color: ${muted}; font-size: 10px; font-weight: 600; letter-spacing: 2px; margin-bottom: 16px; }
  .stat-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 20px; }
  .stat-label { color: ${muted}; font-size: 10px; font-weight: 600; letter-spacing: 1.5px; margin-bottom: 8px; }
  .stat-value { color: ${fg}; font-size: 22px; font-weight: 700; }
  .stat-value.accent { color: ${accent}; }
  .models-section { margin-top: 8px; }
  .models-label { color: ${muted}; font-size: 10px; font-weight: 600; letter-spacing: 2px; margin-bottom: 16px; }
  .model-row {
    display: grid;
    grid-template-columns: ${MODEL_NAME_WIDTH}px minmax(0, 1fr) ${MODEL_PERCENT_WIDTH}px;
    align-items: center;
    column-gap: ${MODEL_BAR_GAP}px;
    margin-bottom: 16px;
  }
  .model-name { color: ${muted}; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .model-bar-track { width: 100%; height: 8px; background: ${barTrack}; border-radius: 4px; overflow: hidden; }
  .model-bar-fill { height: 100%; border-radius: 4px; background: linear-gradient(90deg, ${accent}44, ${accent}); }
  .model-pct { color: ${muted}; font-size: 12px; text-align: right; }
  .refresh-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 24px;
    padding: 8px 16px;
    background: ${isDark ? "#1c1c1c" : "#e5e5e5"};
    color: ${muted};
    border: 1px solid ${border};
    border-radius: 6px;
    font-family: inherit;
    font-size: 12px;
    cursor: pointer;
    transition: background 0.15s;
  }
  .refresh-btn:hover { background: ${isDark ? "#262626" : "#d4d4d8"}; color: ${fg}; }
</style>
</head>
<body>
<div class="card">
  <div class="titlebar">
    <div class="dot dot-red"></div>
    <div class="dot dot-yellow"></div>
    <div class="dot dot-green"></div>
    <span class="titlebar-label">tokenleak</span>
  </div>
  <div class="content">
    <div class="prompt">
      <span class="dollar">$</span>
      <span class="cmd"> tokenleak</span>
      <span class="cursor">_</span>
    </div>
    <div class="date-range">${formatDateRange2(since, until)}</div>
    ${providerSectionsHtml}
    <hr class="divider">
    ${overallLabel}
    ${statsHtml}
    <hr class="divider" style="margin-top:8px">
    <div class="models-section">
      <div class="models-label">TOP MODELS</div>
      ${modelsHtml}
    </div>
    <button class="refresh-btn" onclick="location.reload()">&#x21bb; Refresh</button>
  </div>
</div>
<div class="tooltip" id="tooltip"></div>
<script>
  const tooltip = document.getElementById('tooltip');
  document.querySelectorAll('.heatmap-cell').forEach(cell => {
    const section = cell.closest('.provider-section');
    const provider = section ? section.dataset.provider : '';
    cell.addEventListener('mouseenter', e => {
      const date = cell.dataset.date;
      const tokens = Number(cell.dataset.tokens).toLocaleString();
      tooltip.textContent = (provider ? provider + ' \u2014 ' : '') + date + ': ' + tokens + ' tokens';
      tooltip.style.display = 'block';
    });
    cell.addEventListener('mousemove', e => {
      tooltip.style.left = (e.clientX + 12) + 'px';
      tooltip.style.top = (e.clientY - 30) + 'px';
    });
    cell.addEventListener('mouseleave', () => {
      tooltip.style.display = 'none';
    });
  });
</script>
</body>
</html>`;
}
var MONTH_NAMES_FULL2;
var init_template = __esm(() => {
  init_heatmap_model();
  MONTH_NAMES_FULL2 = [
    "JAN",
    "FEB",
    "MAR",
    "APR",
    "MAY",
    "JUN",
    "JUL",
    "AUG",
    "SEP",
    "OCT",
    "NOV",
    "DEC"
  ];
});

// packages/renderers/dist/live/live-server.js
function tryServe(html, port) {
  try {
    const server = Bun.serve({
      port,
      fetch(_req) {
        return new Response(html, {
          headers: { "Content-Type": "text/html; charset=utf-8" }
        });
      }
    });
    return { server, error: null };
  } catch (err) {
    return { server: null, error: err };
  }
}
function isAddrInUse(err) {
  if (err && typeof err === "object") {
    const obj = err;
    if (obj["code"] === "EADDRINUSE")
      return true;
  }
  if (err instanceof Error) {
    const msg = err.message;
    if (msg.includes("EADDRINUSE") || msg.includes("address already in use"))
      return true;
  }
  return false;
}
async function startLiveServer(output, options) {
  const html = generateHtml(output, options);
  const startPort = options.port ?? 3333;
  const maxAttempts = 20;
  let port = startPort;
  for (let attempt = 0;attempt < maxAttempts; attempt++) {
    const result = tryServe(html, port);
    if (result.server) {
      const actualPort = result.server.port ?? port;
      process.stderr.write(`Server running at http://localhost:${String(actualPort)}
`);
      return { port: actualPort, stop: () => result.server.stop(true) };
    }
    if (isAddrInUse(result.error)) {
      port++;
      continue;
    }
    throw result.error;
  }
  throw new Error(`Could not find a free port after ${maxAttempts} attempts starting from ${startPort}`);
}
var init_live_server = __esm(() => {
  init_template();
});

// packages/renderers/dist/live/wrapped-live-template.js
function esc2(s) {
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
}
function formatDate2(dateStr) {
  const d = new Date(dateStr + "T00:00:00Z");
  return `${MONTH_SHORT[d.getUTCMonth()]} ${String(d.getUTCDate()).padStart(2, "0")}`;
}
function formatDateLong3(dateStr) {
  const d = new Date(dateStr + "T00:00:00Z");
  return `${MONTH_NAMES4[d.getUTCMonth()]} ${d.getUTCDate()}, ${d.getUTCFullYear()}`;
}
function diffDays(since, until) {
  const s = new Date(since + "T00:00:00Z");
  const u = new Date(until + "T00:00:00Z");
  return Math.round((u.getTime() - s.getTime()) / (1000 * 60 * 60 * 24)) + 1;
}
function guessProvider(model) {
  const lower = model.toLowerCase();
  if (lower.includes("claude") || lower.includes("anthropic"))
    return "Anthropic";
  if (lower.includes("gpt") || lower.includes("o1") || lower.includes("o3") || lower.includes("o4"))
    return "OpenAI";
  if (lower.includes("gemini") || lower.includes("google"))
    return "Google";
  return "Other";
}
function getProviderColor2(provider) {
  return PROVIDER_COLORS2[provider.toLowerCase()] ?? "#555555";
}
function costValue(cost) {
  const raw = formatCost2(cost);
  return raw.startsWith("$") ? raw.slice(1) : raw;
}
function generateWrappedLiveHtml(output) {
  const stats = output.aggregated;
  const more = output.more;
  const providers = output.providers;
  const { since, until } = output.dateRange;
  const achievements = computeAchievements(output);
  const totalDaysInRange = diffDays(since, until);
  const activeDates = new Set;
  for (const p of providers) {
    for (const d of p.daily) {
      if (d.totalTokens > 0)
        activeDates.add(d.date);
    }
  }
  const year = until.slice(0, 4);
  const stamp = `<div class="stamp"><span class="stamp-name">TokenLeak</span><span class="stamp-sep"></span><span class="stamp-tag">Built with TokenLeak</span></div>`;
  let morningPct = 25;
  let afternoonPct = 25;
  let eveningPct = 25;
  let nightPct = 25;
  let peakTimeName = "Night";
  if (more?.hourOfDay) {
    const total = more.hourOfDay.reduce((s, e) => s + e.tokens, 0);
    if (total > 0) {
      const morning = more.hourOfDay.filter((e) => e.hour >= 6 && e.hour < 12).reduce((s, e) => s + e.tokens, 0);
      const afternoon = more.hourOfDay.filter((e) => e.hour >= 12 && e.hour < 18).reduce((s, e) => s + e.tokens, 0);
      const evening = more.hourOfDay.filter((e) => e.hour >= 18 && e.hour < 22).reduce((s, e) => s + e.tokens, 0);
      const night = total - morning - afternoon - evening;
      morningPct = Math.round(morning / total * 100);
      afternoonPct = Math.round(afternoon / total * 100);
      eveningPct = Math.round(evening / total * 100);
      nightPct = 100 - morningPct - afternoonPct - eveningPct;
      const max = Math.max(morningPct, afternoonPct, eveningPct, nightPct);
      if (max === morningPct)
        peakTimeName = "Morning";
      else if (max === afternoonPct)
        peakTimeName = "Afternoon";
      else if (max === eveningPct)
        peakTimeName = "Evening";
      else
        peakTimeName = "Night";
    }
  }
  const dowOrder = [1, 2, 3, 4, 5, 6, 0];
  const dowEntries = dowOrder.map((dayNum) => {
    const entry = stats.dayOfWeek.find((e) => e.day === dayNum);
    return {
      label: DAY_NAMES_MON_FIRST[dowOrder.indexOf(dayNum)],
      tokens: entry?.tokens ?? 0
    };
  });
  const maxDowTokens = Math.max(...dowEntries.map((e) => e.tokens), 1);
  const dowData = dowEntries.map((e) => ({
    d: e.label,
    p: Math.round(e.tokens / maxDowTokens * 100)
  }));
  const peakDowEntry = dowEntries.reduce((a, b) => b.tokens > a.tokens ? b : a, dowEntries[0]);
  const dayNameMap = {
    Mon: "Monday",
    Tue: "Tuesday",
    Wed: "Wednesday",
    Thu: "Thursday",
    Fri: "Friday",
    Sat: "Saturday",
    Sun: "Sunday"
  };
  const peakDowName = dayNameMap[peakDowEntry.label] ?? peakDowEntry.label;
  const minDowEntry = dowEntries.reduce((a, b) => b.tokens < a.tokens ? b : a, dowEntries[0]);
  const minDowPct = maxDowTokens > 0 ? Math.round(minDowEntry.tokens / maxDowTokens * 100) : 0;
  const minDowName = dayNameMap[minDowEntry.label] ?? minDowEntry.label;
  const totalProviderTokens = providers.reduce((s, p) => s + p.totalTokens, 0);
  const providerMix = providers.map((p) => ({
    name: p.displayName,
    pct: totalProviderTokens > 0 ? Math.round(p.totalTokens / totalProviderTokens * 100) : 0,
    color: getProviderColor2(p.provider)
  })).sort((a, b) => b.pct - a.pct);
  const pctSum = providerMix.reduce((s, p) => s + p.pct, 0);
  if (providerMix.length > 0 && pctSum !== 100) {
    providerMix[0].pct += 100 - pctSum;
  }
  const topModels2 = stats.topModels.slice(0, 3);
  const cacheHitPct = Math.round(stats.cacheHitRate * 100);
  const cacheReads = more?.cacheEconomics?.readTokens ?? 0;
  const cacheWrites = more?.cacheEconomics?.writeTokens ?? 0;
  const reuseRatio = more?.cacheEconomics?.reuseRatio ?? (cacheWrites > 0 ? cacheReads / cacheWrites : 0);
  const peakDay = stats.peakDay;
  const peakMultiplier = peakDay && stats.averageDailyTokens > 0 ? (peakDay.tokens / stats.averageDailyTokens).toFixed(1) : "0";
  const projectedCost = more?.monthlyBurn?.projectedCost ?? stats.averageDailyCost * 30;
  const projectedDollars = Math.floor(projectedCost);
  const projectedCents = Math.round((projectedCost - projectedDollars) * 100);
  const avgDailyCostStr = stats.averageDailyCost >= 1 ? `$${stats.averageDailyCost.toFixed(2)}` : `$${stats.averageDailyCost.toFixed(4)}`;
  const ALL_BADGES = [
    { emoji: "\uD83D\uDD25", name: "Streak Master", sub: ">30 day streak" },
    { emoji: "\uD83E\uDD89", name: "Night Owl", sub: ">40% night tokens" },
    { emoji: "\uD83D\uDCB8", name: "Big Spender", sub: ">$100 total" },
    { emoji: "\u26A1", name: "Cache Master", sub: ">50% hit rate" },
    { emoji: "\uD83D\uDCC5", name: "Daily Driver", sub: ">80% active days" },
    { emoji: "\u26A1", name: "Power User", sub: ">10k avg tok/day" },
    { emoji: "\uD83C\uDFD4", name: "Summit Day", sub: "Peak >50k tokens" },
    { emoji: "\uD83D\uDD00", name: "Multi-Tool", sub: "\u22653 providers" },
    { emoji: "\uD83C\uDF05", name: "Early Bird", sub: ">40% morning" },
    { emoji: "\uD83C\uDFB2", name: "Model Hopper", sub: "\u22654 models" }
  ];
  const earnedTitles = new Set(achievements.map((a) => a.title));
  const badgeHtml = ALL_BADGES.map((b) => {
    const on = earnedTitles.has(b.name);
    return `<div class="badge ${on ? "on" : "off"}"><span class="ico">${b.emoji}</span><div><div class="b-name">${esc2(b.name)}</div><div class="b-sub">${esc2(b.sub)}</div></div></div>`;
  }).join(`
`);
  const earnedCount = ALL_BADGES.filter((b) => earnedTitles.has(b.name)).length;
  const circumference = 2 * Math.PI * 56;
  let donutSegments = "";
  let offset = circumference / 4;
  for (const p of providerMix) {
    const dash = p.pct / 100 * circumference;
    donutSegments += `<circle cx="75" cy="75" r="56" fill="none" stroke="${p.color}" stroke-width="16" stroke-linecap="butt" stroke-dasharray="${dash.toFixed(0)} ${circumference.toFixed(0)}" stroke-dashoffset="${offset.toFixed(0)}"/>`;
    offset -= dash;
  }
  const ringCircumference = 2 * Math.PI * 72;
  const ringDash = cacheHitPct / 100 * ringCircumference;
  const ringOffset = ringCircumference / 4;
  const slide01 = `<div class="slide active" id="s0">
  <div class="slide-tag"><em>01</em> &nbsp;/&nbsp; 12 &nbsp;&middot;&nbsp; Intro</div>
  <div class="eyebrow">Your year in code</div>
  <h1 class="hero">AI<br>Wrapped<br><span class="hl">&rsquo;${esc2(year.slice(2))}</span></h1>
  <div class="dt-range"><em>${formatDate2(since)}</em> &mdash; <em>${formatDate2(until)}, ${esc2(year)}</em></div>
  <div class="rule"></div>
  <div class="info">Every prompt has a price. Here&rsquo;s yours.</div>
  <div style="margin-top:10px;display:flex;align-items:center"><span class="pulse"></span><span style="font-family:'Space Mono',monospace;font-size:9px;color:var(--muted);letter-spacing:0.14em">${totalDaysInRange} DAYS OF DATA</span></div>
  <div style="margin-top:auto;padding-top:34px">${stamp}</div>
</div>`;
  const slide02 = `<div class="slide" id="s1">
  <div class="slide-tag"><em>02</em> &nbsp;/&nbsp; 12 &nbsp;&middot;&nbsp; The Big Numbers</div>
  <h2 class="title">You burned through<br><span class="hl">${esc2(formatNumber(stats.totalTokens))}</span> tokens</h2>
  <div class="g2">
    <div class="sc">
      <div class="lb">Total Cost</div>
      <div class="vl"><span class="hl">$</span>${esc2(costValue(stats.totalCost))}</div>
    </div>
    <div class="sc">
      <div class="lb">Active Days</div>
      <div class="vl">${stats.activeDays}<span class="un"> / ${stats.totalDays}</span></div>
    </div>
    <div class="sc">
      <div class="lb">Avg / Day</div>
      <div class="vl">${esc2(formatNumber(stats.averageDailyTokens))}</div>
      <div class="un">TOKENS</div>
    </div>
    <div class="sc">
      <div class="lb">Avg Cost / Day</div>
      <div class="vl"><span class="hl">$</span>${esc2(costValue(stats.averageDailyCost))}</div>
    </div>
  </div>
  <div style="margin-top:auto;padding-top:34px">${stamp}</div>
</div>`;
  const slide03 = `<div class="slide" id="s2">
  <div class="slide-tag"><em>03</em> &nbsp;/&nbsp; 12 &nbsp;&middot;&nbsp; Streak Story</div>
  <h2 class="title">Your longest streak:<br><span class="hl">${stats.longestStreak} days</span></h2>
  <div class="g2">
    <div class="sc">
      <div class="lb">Current Streak</div>
      <div class="vl">${stats.currentStreak}</div>
      <div class="un">DAYS</div>
    </div>
    <div class="sc">
      <div class="lb">Longest Streak</div>
      <div class="vl">${stats.longestStreak}</div>
      <div class="un">DAYS</div>
    </div>
  </div>
  <div class="rule"></div>
  <div class="lb" style="margin-bottom:6px">ACTIVITY MAP</div>
  <div class="sdots" id="streakDots" data-current-streak="${stats.currentStreak}" data-history='${JSON.stringify((() => {
    const end = new Date(until + "T00:00:00Z");
    const arr = [];
    for (let i = 59;i >= 0; i--) {
      const d = new Date(end.getTime() - i * 86400000);
      const ds = d.toISOString().slice(0, 10);
      arr.push(activeDates.has(ds));
    }
    return arr;
  })())}'></div>
  <div class="info">${stats.activeDays} active days out of ${totalDaysInRange} &mdash; that&rsquo;s a <span class="hi">${Math.round(stats.activeDays / Math.max(totalDaysInRange, 1) * 100)}%</span> hit rate.</div>
  <div style="margin-top:auto;padding-top:34px">${stamp}</div>
</div>`;
  const modelBars = topModels2.map((m) => {
    const prov = guessProvider(m.model);
    return `<div class="bar">
  <div class="bar-top"><div><div class="bar-name">${esc2(m.model)}</div><div class="bar-sub">${esc2(prov)}</div></div><div class="bar-pct">${m.percentage.toFixed(1)}%</div></div>
  <div class="bar-track"><div class="bar-fill" style="width:${m.percentage}%"></div></div>
</div>`;
  }).join(`
`);
  const slide04 = `<div class="slide" id="s3">
  <div class="slide-tag"><em>04</em> &nbsp;/&nbsp; 12 &nbsp;&middot;&nbsp; Top Models</div>
  <h2 class="title">Your go-to<br><span class="hl">models</span></h2>
  ${modelBars}
  <div class="rule"></div>
  <div class="info">You used <span class="hi">${stats.topModels.length} model${stats.topModels.length !== 1 ? "s" : ""}</span> total during this period.</div>
  <div style="margin-top:auto;padding-top:34px">${stamp}</div>
</div>`;
  const providerBars = providerMix.map((p) => `<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px"><div style="width:10px;height:10px;border-radius:1px;background:${p.color};flex-shrink:0"></div><span style="font-size:14px;color:var(--text);flex:1">${esc2(p.name)}</span><span class="bar-pct">${p.pct}%</span></div>`).join(`
`);
  const slide05 = `<div class="slide" id="s4">
  <div class="slide-tag"><em>05</em> &nbsp;/&nbsp; 12 &nbsp;&middot;&nbsp; Provider Mix</div>
  <h2 class="title">Where your tokens<br><span class="hl">went</span></h2>
  <div style="display:flex;align-items:center;gap:32px;margin-bottom:24px">
    <svg width="173" height="173" viewBox="0 0 150 150">${donutSegments}</svg>
    <div style="flex:1">${providerBars}</div>
  </div>
  <div class="rule"></div>
  <div class="info"><span class="hi">${esc2(formatNumber(totalProviderTokens))}</span> tokens across <span class="hi">${providers.length}</span> provider${providers.length !== 1 ? "s" : ""}.</div>
  <div style="margin-top:auto;padding-top:34px">${stamp}</div>
</div>`;
  const slide06 = `<div class="slide" id="s5">
  <div class="slide-tag"><em>06</em> &nbsp;/&nbsp; 12 &nbsp;&middot;&nbsp; Day of Week</div>
  <h2 class="title"><span class="hl">${esc2(peakDowName)}</span> is your<br>power day</h2>
  <div class="dow-row" id="dowGrid" data-dow='${JSON.stringify(dowData)}'></div>
  <div class="rule"></div>
  <div class="info">Quietest day: <span class="hi">${esc2(minDowName)}</span> at ${minDowPct}% of peak. Even your off-days have tokens flowing.</div>
  <div style="margin-top:auto;padding-top:34px">${stamp}</div>
</div>`;
  const timeSlots = [
    { ico: "\uD83C\uDF05", nm: "Morning", pct: morningPct, range: "6am \u2013 12pm" },
    { ico: "\u2600\uFE0F", nm: "Afternoon", pct: afternoonPct, range: "12pm \u2013 6pm" },
    { ico: "\uD83C\uDF07", nm: "Evening", pct: eveningPct, range: "6pm \u2013 10pm" },
    { ico: "\uD83C\uDF19", nm: "Night", pct: nightPct, range: "10pm \u2013 6am" }
  ];
  const todCells = timeSlots.map((t) => `<div class="tod-cell${t.nm === peakTimeName ? " hi" : ""}"><div class="tod-ico">${t.ico}</div><div class="tod-nm">${t.nm}</div><div class="tod-val"${t.nm === peakTimeName ? ' style="color:var(--gold)"' : ""}>${t.pct}%</div><div class="tod-sub">${t.range}</div></div>`).join(`
`);
  const slide07 = `<div class="slide" id="s6">
  <div class="slide-tag"><em>07</em> &nbsp;/&nbsp; 12 &nbsp;&middot;&nbsp; Time of Day</div>
  <h2 class="title">Peak hours:<br><span class="hl">${esc2(peakTimeName)}</span></h2>
  <div class="tod-grid">
    ${todCells}
  </div>
  <div class="rule"></div>
  <div class="info">Your <span class="hi">${esc2(peakTimeName.toLowerCase())}</span> sessions carry the heaviest token load.</div>
  <div style="margin-top:auto;padding-top:34px">${stamp}</div>
</div>`;
  const slide08 = `<div class="slide" id="s7">
  <div class="slide-tag"><em>08</em> &nbsp;/&nbsp; 12 &nbsp;&middot;&nbsp; Cache Efficiency</div>
  <h2 class="title"><span class="hl">${cacheHitPct}%</span> cache<br>hit rate</h2>
  <div class="ring-wrap">
    <svg width="200" height="200" viewBox="0 0 200 200">
      <circle cx="100" cy="100" r="72" fill="none" stroke="rgba(255,255,255,0.06)" stroke-width="14"/>
      <circle cx="100" cy="100" r="72" fill="none" stroke="var(--gold)" stroke-width="14" stroke-linecap="round" stroke-dasharray="${ringDash.toFixed(0)} ${ringCircumference.toFixed(0)}" stroke-dashoffset="${ringOffset.toFixed(0)}" transform="rotate(-90 100 100)"/>
    </svg>
    <div class="ring-center">
      <div class="ring-pct">${cacheHitPct}%</div>
      <div class="ring-lb">HIT RATE</div>
    </div>
  </div>
  <div class="g2">
    <div class="sc">
      <div class="lb">Cache Reads</div>
      <div class="vl">${esc2(formatNumber(cacheReads))}</div>
      <div class="un">TOKENS</div>
    </div>
    <div class="sc">
      <div class="lb">Cache Writes</div>
      <div class="vl">${esc2(formatNumber(cacheWrites))}</div>
      <div class="un">TOKENS</div>
    </div>
  </div>
  <div class="rule"></div>
  <div class="info">Reuse ratio: <span class="hi">${reuseRatio !== null ? reuseRatio.toFixed(1) : "0"}x</span> &mdash; every write was read back ${reuseRatio !== null ? reuseRatio.toFixed(1) : "0"} times on average.</div>
  <div style="margin-top:auto;padding-top:34px">${stamp}</div>
</div>`;
  const peakDayContent = peakDay ? `<div class="peak-box">
    <div class="peak-dt">${esc2(formatDateLong3(peakDay.date))}</div>
    <div class="peak-num">${esc2(formatNumber(peakDay.tokens))}</div>
    <div class="peak-lb">TOKENS IN ONE DAY</div>
  </div>
  <div class="rule"></div>
  <div class="g2">
    <div class="sc">
      <div class="lb">vs Daily Avg</div>
      <div class="vl">${esc2(peakMultiplier)}<span class="un">x</span></div>
    </div>
    <div class="sc">
      <div class="lb">Daily Avg</div>
      <div class="vl">${esc2(formatNumber(stats.averageDailyTokens))}</div>
      <div class="un">TOKENS</div>
    </div>
  </div>` : `<div class="info">No peak day data available for this period.</div>`;
  const slide09 = `<div class="slide" id="s8">
  <div class="slide-tag"><em>09</em> &nbsp;/&nbsp; 12 &nbsp;&middot;&nbsp; Peak Day</div>
  <h2 class="title">Your biggest<br><span class="hl">single day</span></h2>
  ${peakDayContent}
  <div style="margin-top:auto;padding-top:34px">${stamp}</div>
</div>`;
  const slide10 = `<div class="slide" id="s9">
  <div class="slide-tag"><em>10</em> &nbsp;/&nbsp; 12 &nbsp;&middot;&nbsp; Achievements</div>
  <h2 class="title"><span class="hl">${earnedCount}</span> badges<br>unlocked</h2>
  <div class="badges">
    ${badgeHtml}
  </div>
  <div class="rule"></div>
  <div class="info">${earnedCount} of ${ALL_BADGES.length} badges earned. ${earnedCount >= ALL_BADGES.length ? "You collected them all!" : `${ALL_BADGES.length - earnedCount} more to go.`}</div>
  <div style="margin-top:auto;padding-top:34px">${stamp}</div>
</div>`;
  const slide11 = `<div class="slide" id="s10">
  <div class="slide-tag"><em>11</em> &nbsp;/&nbsp; 12 &nbsp;&middot;&nbsp; Projection</div>
  <h2 class="title">Your monthly<br><span class="hl">burn rate</span></h2>
  <div style="text-align:center;margin:16px 0 8px">
    <div class="proj-fig"><span class="c">$</span>${projectedDollars}<span class="c">.${String(projectedCents).padStart(2, "0")}</span></div>
    <div class="lb" style="margin-top:10px">PROJECTED / MONTH</div>
  </div>
  <div class="rule"></div>
  <div class="g2">
    <div class="sc">
      <div class="lb">Avg Daily Cost</div>
      <div class="vl"><span class="hl">$</span>${esc2(costValue(stats.averageDailyCost))}</div>
    </div>
    <div class="sc">
      <div class="lb">Observed Days</div>
      <div class="vl">${more?.monthlyBurn?.observedDays ?? stats.activeDays}</div>
      <div class="un">OF ${more?.monthlyBurn?.calendarDays ?? totalDaysInRange}</div>
    </div>
  </div>
  <div class="rule"></div>
  <div class="info" style="font-size:19px">At <span class="hi">${esc2(avgDailyCostStr)}</span> per day, you&rsquo;re on track for <span class="hi">$${projectedDollars}.${String(projectedCents).padStart(2, "0")}</span> this month.</div>
  <div style="margin-top:auto;padding-top:34px">${stamp}</div>
</div>`;
  const generatedAt = new Date().toISOString();
  const slide12 = `<div class="slide" id="s11">
  <div class="slide-tag"><em>12</em> &nbsp;/&nbsp; 12 &nbsp;&middot;&nbsp; Fin</div>
  <div class="foot-body">
    <h2 class="title" style="text-align:center">That&rsquo;s a wrap,<br><span class="hl">&rsquo;${esc2(year.slice(2))}</span></h2>
    <div class="g2" style="width:100%">
      <div class="sc">
        <div class="lb">Total Tokens</div>
        <div class="vl">${esc2(formatNumber(stats.totalTokens))}</div>
      </div>
      <div class="sc">
        <div class="lb">Total Cost</div>
        <div class="vl"><span class="hl">$</span>${esc2(costValue(stats.totalCost))}</div>
      </div>
      <div class="sc">
        <div class="lb">Active Days</div>
        <div class="vl">${stats.activeDays}</div>
      </div>
      <div class="sc">
        <div class="lb">Models Used</div>
        <div class="vl">${stats.topModels.length}</div>
      </div>
    </div>
    <div class="rule" style="width:100%"></div>
    <div class="info" style="text-align:center">${esc2(formatDate2(since))} &mdash; ${esc2(formatDate2(until))}, ${esc2(year)}</div>
    <div style="margin-top:12px">${stamp}</div>
    <div style="font-family:'Space Mono',monospace;font-size:9px;color:var(--muted2);letter-spacing:0.1em;margin-top:8px">GENERATED ${esc2(generatedAt)}</div>
  </div>
</div>`;
  return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>AI Wrapped \u2014 TokenLeak</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,300;12..96,400;12..96,500;12..96,600;12..96,700;12..96,800&family=Space+Grotesk:wght@300;400;500;600;700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
<style>
:root {
  --bg: #09090b;
  --surface: #111114;
  --surface2: #16161a;
  --border: rgba(255,255,255,0.07);
  --border-hi: rgba(212,175,95,0.24);
  --gold: #d4af5f;
  --gold-dim: #a08040;
  --gold-pale: rgba(212,175,95,0.1);
  --ivory: #f0ead6;
  --ivory-dim: rgba(240,234,214,0.52);
  --text: #e8e2cc;
  --muted: rgba(232,226,204,0.38);
  --muted2: rgba(232,226,204,0.18);
}
* { margin:0; padding:0; box-sizing:border-box; }
html, body { width:100%; height:100%; background:var(--bg); font-family:'Space Grotesk',sans-serif; color:var(--text); overflow:hidden; }

/* Background layers */
.bg-layer { position:fixed; inset:0; z-index:0; background: radial-gradient(ellipse 60% 50% at 10% 10%, rgba(44,70,120,0.07) 0%, transparent 60%), radial-gradient(ellipse 50% 50% at 90% 90%, rgba(155,60,75,0.06) 0%, transparent 60%); }
.noise { position:fixed; inset:0; z-index:0; opacity:0.06; pointer-events:none; background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.78' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); background-size:180px; }

/* Stage */
#stage { position:fixed; inset:0; z-index:10; display:flex; align-items:center; justify-content:center; }

/* Slide card */
.slide { position:absolute; width:min(706px,95vw); min-height:min(964px,92vh); max-height:94vh; overflow-y:auto; scrollbar-width:none; background:var(--surface); border:1px solid var(--border); border-radius:3px; padding:67px 60px 55px; display:flex; flex-direction:column; font-size:115%; opacity:0; transform:translateY(32px) scale(0.988); transition:opacity 0.6s cubic-bezier(.22,1,.36,1), transform 0.6s cubic-bezier(.22,1,.36,1); pointer-events:none; box-shadow:0 1px 0 rgba(212,175,95,0.18) inset, 0 0 0 1px rgba(0,0,0,0.6), 0 40px 80px rgba(0,0,0,0.75); }
.slide::-webkit-scrollbar { display:none; }
.slide.active { opacity:1; transform:translateY(0) scale(1); pointer-events:all; }
.slide.exit-up { opacity:0; transform:translateY(-32px) scale(0.988); transition:opacity 0.36s ease, transform 0.36s ease; }
.slide::before { content:''; position:absolute; top:0; left:0; right:0; height:1px; background:var(--gold); opacity:0.5; border-radius:3px 3px 0 0; }

/* Typography */
.slide-tag { font-family:'Space Mono',monospace; font-size:14px; letter-spacing:0.22em; color:var(--muted); text-transform:uppercase; margin-bottom:41px; }
.slide-tag em { font-style:normal; color:var(--gold); }
h1.hero { font-family:'Bricolage Grotesque',sans-serif; font-size:clamp(67px,14vw,101px); font-weight:800; line-height:0.91; letter-spacing:-0.045em; color:var(--ivory); }
h2.title { font-family:'Bricolage Grotesque',sans-serif; font-size:clamp(36px,7.5vw,53px); font-weight:700; line-height:1.06; letter-spacing:-0.03em; color:var(--ivory); margin-bottom:37px; }
.hl { color:var(--gold); }
.rule { height:1px; background:var(--border); margin:32px 0; }
.rule-hi { height:1px; background:var(--border-hi); margin:25px 0; }

/* Stat card */
.sc { background:var(--surface2); border:1px solid var(--border); border-radius:2px; padding:25px 28px; display:flex; flex-direction:column; gap:6px; }
.lb { font-family:'Space Mono',monospace; font-size:13px; letter-spacing:0.18em; color:var(--muted); text-transform:uppercase; }
.vl { font-family:'Bricolage Grotesque',sans-serif; font-size:clamp(35px,7.5vw,53px); font-weight:800; color:var(--ivory); line-height:1; letter-spacing:-0.035em; }
.un { font-family:'Space Mono',monospace; font-size:13px; color:var(--gold); letter-spacing:0.12em; text-transform:uppercase; }
.g2 { display:grid; grid-template-columns:1fr 1fr; gap:13px; }

/* Bars */
.bar { display:flex; flex-direction:column; gap:10px; margin-bottom:23px; }
.bar:last-child { margin-bottom:0; }
.bar-top { display:flex; justify-content:space-between; align-items:baseline; }
.bar-name { font-size:18px; font-weight:500; color:var(--text); }
.bar-sub { font-size:14px; color:var(--muted); margin-top:1px; }
.bar-pct { font-family:'Space Mono',monospace; font-size:15px; color:var(--gold); }
.bar-track { height:1px; background:rgba(255,255,255,0.09); }
.bar-fill { height:100%; background:var(--gold); transition:width 1.1s cubic-bezier(.4,0,.2,1); }

/* Streak dots */
.sdots { display:flex; flex-wrap:wrap; gap:6px; margin:18px 0; }
.sd { width:13px; height:13px; border-radius:2px; background:var(--surface2); border:1px solid rgba(255,255,255,0.07); }
.sd.hit { background:var(--gold-dim); border-color:var(--gold-dim); }
.sd.now { background:var(--gold); border-color:var(--gold); }

/* Day of week */
.dow-row { display:grid; grid-template-columns:repeat(7,1fr); gap:6px; margin-top:16px; }
.dow-col { display:flex; flex-direction:column; align-items:center; gap:6px; }
.dow-bg { width:100%; display:flex; align-items:flex-end; justify-content:center; height:99px; }
.dow-b { width:100%; background:var(--gold); min-height:3px; border-radius:1px 1px 0 0; }
.dow-l { font-family:'Space Mono',monospace; font-size:10px; color:var(--muted); text-transform:uppercase; letter-spacing:0.06em; }

/* Time of day */
.tod-grid { display:grid; grid-template-columns:1fr 1fr; gap:9px; margin-top:8px; }
.tod-cell { background:var(--surface2); border:1px solid var(--border); border-radius:2px; padding:21px 18px; display:flex; flex-direction:column; gap:6px; }
.tod-cell.hi { border-color:var(--border-hi); }
.tod-ico { font-size:25px; line-height:1; }
.tod-nm { font-family:'Space Mono',monospace; font-size:12px; color:var(--muted); text-transform:uppercase; letter-spacing:0.12em; }
.tod-val { font-family:'Bricolage Grotesque',sans-serif; font-size:30px; font-weight:800; letter-spacing:-0.025em; color:var(--ivory); }
.tod-sub { font-size:14px; color:var(--muted); }

/* Cache ring */
.ring-wrap { position:relative; display:flex; align-items:center; justify-content:center; margin:10px 0 16px; }
.ring-center { position:absolute; text-align:center; top:50%; left:50%; transform:translate(-50%,-50%); }
.ring-pct { font-family:'Bricolage Grotesque',sans-serif; font-size:46px; font-weight:800; color:var(--gold); letter-spacing:-0.04em; line-height:1; }
.ring-lb { font-family:'Space Mono',monospace; font-size:12px; color:var(--muted); letter-spacing:0.14em; margin-top:3px; }

/* Peak box */
.peak-box { border:1px solid var(--border-hi); background:var(--surface2); border-radius:2px; padding:37px 32px; text-align:center; margin-top:9px; }
.peak-dt { font-family:'Space Mono',monospace; font-size:14px; color:var(--muted); letter-spacing:0.2em; margin-bottom:16px; text-transform:uppercase; }
.peak-num { font-family:'Bricolage Grotesque',sans-serif; font-size:81px; font-weight:800; color:var(--gold); line-height:1; letter-spacing:-0.04em; }
.peak-lb { font-family:'Space Mono',monospace; font-size:12px; color:var(--muted); letter-spacing:0.16em; margin-top:12px; text-transform:uppercase; }

/* Projection */
.proj-fig { font-family:'Bricolage Grotesque',sans-serif; font-size:94px; font-weight:800; line-height:1; letter-spacing:-0.045em; color:var(--ivory); }
.proj-fig .c { color:var(--gold); }

/* Badges */
.badges { display:flex; flex-wrap:wrap; gap:10px; }
.badge { display:flex; align-items:center; gap:10px; background:var(--surface2); border:1px solid var(--border); border-radius:2px; padding:12px 17px; }
.badge.on { border-color:var(--border-hi); }
.badge.off { opacity:0.25; filter:grayscale(1); }
.ico { font-size:21px; }
.b-name { font-size:15px; font-weight:600; color:var(--ivory); }
.b-sub { font-family:'Space Mono',monospace; font-size:12px; color:var(--muted); margin-top:1px; }

/* Info text */
.info { font-size:16px; color:var(--muted); line-height:1.6; }
.info .hi { color:var(--gold); }

/* Stamp */
.stamp { display:inline-flex; align-items:center; gap:14px; border:1px solid var(--border-hi); border-radius:2px; padding:9px 18px; }
.stamp-name { font-family:'Bricolage Grotesque',sans-serif; font-weight:800; font-size:18px; color:var(--gold); letter-spacing:-0.025em; }
.stamp-sep { width:1px; height:18px; background:var(--border-hi); }
.stamp-tag { font-family:'Space Mono',monospace; font-size:12px; color:var(--muted); letter-spacing:0.12em; text-transform:uppercase; }

/* Nav */
#nav { position:fixed; bottom:28px; left:50%; transform:translateX(-50%); z-index:100; display:flex; align-items:center; gap:16px; }
#nav button { width:44px; height:44px; border-radius:2px; background:var(--surface2); border:1px solid var(--border); color:var(--muted); font-size:15px; cursor:pointer; transition:border-color .2s, color .2s; display:flex; align-items:center; justify-content:center; }
#nav button:hover:not(:disabled) { border-color:var(--gold); color:var(--gold); }
#nav button:disabled { opacity:.18; cursor:not-allowed; }
.ctr { font-family:'Space Mono',monospace; font-size:13px; color:var(--muted); letter-spacing:0.14em; }

/* Progress dots */
#dots { position:fixed; top:24px; left:50%; transform:translateX(-50%); z-index:100; display:flex; gap:6px; align-items:center; }
.dot { width:5px; height:5px; border-radius:50%; background:rgba(255,255,255,0.1); transition:all .3s ease; cursor:pointer; }
.dot.active { background:var(--gold); width:16px; border-radius:1px; }

/* Title slide */
.eyebrow { font-family:'Space Mono',monospace; font-size:14px; letter-spacing:0.22em; color:var(--muted); text-transform:uppercase; margin-bottom:25px; }
.dt-range { font-family:'Space Mono',monospace; font-size:16px; color:var(--muted); margin-top:28px; }
.dt-range em { font-style:normal; color:var(--gold); }
@keyframes pulse { 0%,100%{opacity:1;} 50%{opacity:0.25;} }
.pulse { display:inline-block; width:6px; height:6px; border-radius:50%; background:var(--gold); animation:pulse 2.6s ease infinite; vertical-align:middle; margin-right:8px; }

/* Footer layout */
.foot-body { flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:16px; text-align:center; }
</style>
</head>
<body>
<div class="bg-layer"></div>
<div class="noise"></div>
<div id="dots"></div>
<div id="stage">
  ${slide01}
  ${slide02}
  ${slide03}
  ${slide04}
  ${slide05}
  ${slide06}
  ${slide07}
  ${slide08}
  ${slide09}
  ${slide10}
  ${slide11}
  ${slide12}
</div>
<div id="nav">
  <button id="btnPrev" disabled>&#x2190;</button>
  <span class="ctr" id="counter">01 / 12</span>
  <button id="btnNext">&#x2192;</button>
</div>
<script>
(function(){
  var slides = document.querySelectorAll('.slide');
  var dotsEl = document.getElementById('dots');
  var cur = 0;

  for (var i = 0; i < slides.length; i++) {
    var d = document.createElement('div');
    d.className = 'dot' + (i === 0 ? ' active' : '');
    d.setAttribute('data-idx', String(i));
    d.onclick = function() { goTo(parseInt(this.getAttribute('data-idx'), 10)); };
    dotsEl.appendChild(d);
  }

  // Streak dots
  var sc = document.getElementById('streakDots');
  var currentStreak = parseInt(sc ? sc.dataset.currentStreak || '0' : '0', 10);
  var history = [];
  try { history = JSON.parse(sc ? sc.dataset.history || '[]' : '[]'); } catch(e) {}
  if (sc) {
    for (var i = 0; i < 60; i++) {
      var d = document.createElement('div');
      if (i >= 60 - currentStreak) d.className = 'sd now';
      else if (history[i]) d.className = 'sd hit';
      else d.className = 'sd';
      sc.appendChild(d);
    }
  }

  // Day of week bars
  var dg = document.getElementById('dowGrid');
  var dowData = [];
  try { dowData = JSON.parse(dg ? dg.dataset.dow || '[]' : '[]'); } catch(e) {}
  if (dg) {
    for (var i = 0; i < dowData.length; i++) {
      var col = document.createElement('div');
      col.className = 'dow-col';
      var p = dowData[i].p;
      var opacity = p < 35 ? '0.35' : p < 55 ? '0.6' : '1';
      col.innerHTML = '<div class="dow-bg"><div class="dow-b" style="height:' + (p * 0.84) + 'px;opacity:' + opacity + ';"></div></div><div class="dow-l">' + dowData[i].d + '</div>';
      dg.appendChild(col);
    }
  }

  function goTo(n) {
    if (n < 0 || n >= slides.length) return;
    slides[cur].classList.remove('active');
    slides[cur].classList.add('exit-up');
    var prev = cur;
    setTimeout(function() { slides[prev].classList.remove('exit-up'); }, 380);
    cur = n;
    slides[cur].classList.add('active');
    document.getElementById('counter').textContent = String(cur + 1).padStart(2, '0') + ' / ' + String(slides.length).padStart(2, '0');
    document.getElementById('btnPrev').disabled = cur === 0;
    document.getElementById('btnNext').disabled = cur === slides.length - 1;
    var dots = document.querySelectorAll('#dots .dot');
    for (var i = 0; i < dots.length; i++) {
      if (i === cur) dots[i].classList.add('active');
      else dots[i].classList.remove('active');
    }
  }

  document.getElementById('btnNext').onclick = function() { goTo(cur + 1); };
  document.getElementById('btnPrev').onclick = function() { goTo(cur - 1); };
  document.addEventListener('keydown', function(e) {
    if (e.key === 'ArrowRight' || e.key === 'ArrowDown') goTo(cur + 1);
    if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') goTo(cur - 1);
  });
  var tx = null;
  document.addEventListener('touchstart', function(e) { tx = e.touches[0].clientX; });
  document.addEventListener('touchend', function(e) {
    if (tx === null) return;
    var dx = tx - e.changedTouches[0].clientX;
    if (Math.abs(dx) > 44) { dx > 0 ? goTo(cur + 1) : goTo(cur - 1); }
    tx = null;
  });
})();
</script>
</body>
</html>`;
}
var MONTH_NAMES4, MONTH_SHORT, DAY_NAMES_MON_FIRST, PROVIDER_COLORS2;
var init_wrapped_live_template = __esm(() => {
  init_wrapped_slides();
  MONTH_NAMES4 = [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December"
  ];
  MONTH_SHORT = [
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec"
  ];
  DAY_NAMES_MON_FIRST = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
  PROVIDER_COLORS2 = {
    anthropic: "#d4af5f",
    "claude-code": "#d4af5f",
    openai: "#3a5070",
    codex: "#3a5070",
    google: "#6a2535",
    pi: "#5a4a70"
  };
});

// packages/renderers/dist/live/wrapped-live-server.js
function tryServe2(html, port) {
  try {
    const server = Bun.serve({
      port,
      fetch(_req) {
        return new Response(html, {
          headers: { "Content-Type": "text/html; charset=utf-8" }
        });
      }
    });
    return { server, error: null };
  } catch (err) {
    return { server: null, error: err };
  }
}
function isAddrInUse2(err) {
  if (err && typeof err === "object") {
    const obj = err;
    if (obj["code"] === "EADDRINUSE")
      return true;
  }
  if (err instanceof Error) {
    const msg = err.message;
    if (msg.includes("EADDRINUSE") || msg.includes("address already in use"))
      return true;
  }
  return false;
}
async function startWrappedLiveServer(output, options = {}) {
  const html = generateWrappedLiveHtml(output);
  const startPort = options.port ?? 3456;
  const maxAttempts = 20;
  let port = startPort;
  for (let attempt = 0;attempt < maxAttempts; attempt++) {
    const result = tryServe2(html, port);
    if (result.server) {
      const actualPort = result.server.port ?? port;
      process.stderr.write(`AI Wrapped live at http://localhost:${String(actualPort)}
`);
      return { port: actualPort, stop: () => result.server.stop(true) };
    }
    if (isAddrInUse2(result.error)) {
      port++;
      continue;
    }
    throw result.error;
  }
  throw new Error(`Could not find a free port after ${maxAttempts} attempts starting from ${startPort}`);
}
var init_wrapped_live_server = __esm(() => {
  init_wrapped_live_template();
});

// packages/renderers/dist/index.js
var exports_dist = {};
__export(exports_dist, {
  startWrappedLiveServer: () => startWrappedLiveServer,
  startLiveServer: () => startLiveServer,
  renderWrappedSlidesSvg: () => renderWrappedSlidesSvg,
  renderWrappedSinglePageSvg: () => renderWrappedSinglePageSvg,
  renderWrappedPng: () => renderWrappedPng,
  renderWrappedCard: () => renderWrappedCard,
  renderTokenView: () => renderTokenView,
  renderTodView: () => renderTodView,
  renderTabBar: () => renderTabBar,
  renderSessionView: () => renderSessionView,
  renderProviderView: () => renderProviderView,
  renderOverviewView: () => renderOverviewView,
  renderModelView: () => renderModelView,
  renderDowView: () => renderDowView,
  renderCwdView: () => renderCwdView,
  renderCompareView: () => renderCompareView,
  renderBadge: () => renderBadge,
  renderAdvisorView: () => renderAdvisorView,
  dim: () => dim,
  computeAchievements: () => computeAchievements,
  colorize256: () => colorize256,
  bold256: () => bold256,
  bold: () => bold2,
  TerminalRenderer: () => TerminalRenderer,
  TIME_RANGES: () => TIME_RANGES,
  SvgRenderer: () => SvgRenderer,
  PngRenderer: () => PngRenderer,
  METRIC_TABS: () => METRIC_TABS,
  JsonRenderer: () => JsonRenderer
});
var init_dist3 = __esm(() => {
  init_json();
  init_svg();
  init_png();
  init_terminal();
  init_live_server();
  init_wrapped_live_server();
  init_terminal();
  init_terminal();
  init_terminal();
});

// packages/tui/dist/lib/theme.js
import { createTextAttributes } from "@opentui/core";
function getProviderColor3(providerName, index) {
  return PROVIDER_COLORS3[providerName] ?? CYCLE_COLORS[index % CYCLE_COLORS.length] ?? COLORS2.green;
}
var COLORS2, BOLD3, PROVIDER_COLORS3, MODEL_COLORS2, DIM3, CYCLE_COLORS;
var init_theme2 = __esm(() => {
  COLORS2 = {
    bg: "#0a0a0a",
    bgPanel: "#111111",
    green: "#00ff00",
    amber: "#ffb900",
    cyan: "#00bcd4",
    red: "#ff4444",
    white: "#e0e0e0",
    dimWhite: "#888888",
    magenta: "#ff66ff",
    blue: "#4488ff"
  };
  BOLD3 = createTextAttributes({ bold: true });
  PROVIDER_COLORS3 = {
    "claude-code": "#d97706",
    codex: "#22c55e",
    cursor: "#8b5cf6",
    pi: "#06b6d4",
    "open-code": "#ef4444"
  };
  MODEL_COLORS2 = [
    "#ffb900",
    "#00bcd4",
    "#ff66ff",
    "#4488ff",
    "#00ff00",
    "#ff4444",
    "#22c55e",
    "#8b5cf6"
  ];
  DIM3 = createTextAttributes({ dim: true });
  CYCLE_COLORS = [
    COLORS2.green,
    COLORS2.cyan,
    COLORS2.amber,
    COLORS2.magenta,
    COLORS2.blue
  ];
});

// packages/tui/dist/lib/state.js
function createInitialState() {
  return {
    selectedWindowIndex: 4,
    selectedView: "overview",
    isLoading: true,
    data: null,
    sortMode: "cost",
    modelScrollOffset: 0,
    explainDate: null,
    focusScrollOffset: 0,
    advisorScrollOffset: 0,
    compareScrollOffset: 0,
    matrixPage: 0,
    showHelp: false,
    wrappedScrollOffset: 0,
    exportStatus: null,
    showCursorSetup: false,
    cursorSetupField: "token",
    cursorSetupLabel: "",
    cursorSetupToken: "",
    cursorSetupMessage: null,
    cursorSetupSubmitting: false,
    cursorSetupStatusOverride: null,
    replayDate: null,
    replayScrollOffset: 0,
    replayExpandedBlocks: new Set,
    cachedAdvisorReport: null,
    cachedFocusReport: null,
    cachedExplainReport: null,
    cachedCompareOutput: null,
    cachedMoreStats: null,
    cachedReplayReport: null
  };
}
var WINDOW_LABELS, WINDOW_DAYS;
var init_state = __esm(() => {
  WINDOW_LABELS = ["1D", "7D", "30D", "90D", "ALL"];
  WINDOW_DAYS = [1, 7, 30, 90, 0];
});

// packages/tui/dist/lib/data.js
function todayStr() {
  const d = new Date;
  return d.toISOString().slice(0, 10);
}
function daysAgoStr(days) {
  const d = new Date;
  d.setDate(d.getDate() - days);
  return d.toISOString().slice(0, 10);
}
function createRegistry() {
  const registry = new ProviderRegistry;
  registry.register(new ClaudeCodeProvider);
  registry.register(new CodexProvider);
  registry.register(new CursorProvider);
  registry.register(new OpenCodeProvider);
  registry.register(new PiProvider);
  return registry;
}
async function loadAllData() {
  const cursorSetupStatus = await resolveCursorSetupStatus({ attemptSync: true });
  const registry = createRegistry();
  const today = todayStr();
  const allTimeRange = { since: "2020-01-01", until: today };
  const results = await registry.loadAll(allTimeRange);
  const providers = results.filter((r) => r.data !== null).map((r) => r.data);
  if (providers.length === 0) {
    const emptyDaily = mergeProviderData([]);
    const emptyStats = aggregate(emptyDaily, today);
    return {
      providers: [],
      allTimeStats: emptyStats,
      windows: [],
      dateRange: allTimeRange,
      mergedDaily: [],
      cursorSetupStatus
    };
  }
  const allMerged = mergeProviderData(providers);
  const allTimeStats = aggregate(allMerged, today);
  const windowConfigs = [
    { label: "1D", days: 1 },
    { label: "7D", days: 7 },
    { label: "30D", days: 30 },
    { label: "90D", days: 90 }
  ];
  const windows = windowConfigs.map(({ label, days }) => {
    const since = daysAgoStr(days - 1);
    const filtered = allMerged.filter((d) => d.date >= since && d.date <= today);
    const stats = aggregate(filtered, today);
    return { label, days, stats };
  });
  windows.push({ label: "ALL", days: 0, stats: allTimeStats });
  return {
    providers,
    allTimeStats,
    windows,
    dateRange: allTimeRange,
    mergedDaily: allMerged,
    cursorSetupStatus
  };
}
function getDailyForWindow(data, windowIndex) {
  const today = todayStr();
  const days = WINDOW_DAYS[windowIndex];
  if (days === undefined || days === 0) {
    return data.mergedDaily;
  }
  const since = daysAgoStr(days - 1);
  return data.mergedDaily.filter((d) => d.date >= since && d.date <= today);
}
function getScopedWindowData(state) {
  if (!state.data || state.data.windows.length === 0)
    return null;
  const days = WINDOW_DAYS[state.selectedWindowIndex];
  const today = todayStr();
  const windowRange = days && days > 0 ? { since: daysAgoStr(days - 1), until: today } : state.data.dateRange;
  const scopedProviders = state.data.providers.map((p) => {
    if (!days || !p.events)
      return p;
    const filteredEvents = p.events.filter((e) => e.date >= windowRange.since && e.date <= windowRange.until);
    const filteredDaily = p.daily?.filter((d) => d.date >= windowRange.since && d.date <= windowRange.until);
    return { ...p, events: filteredEvents, daily: filteredDaily };
  });
  return { windowRange, scopedProviders };
}
function ensureAdvisorReport(state) {
  if (!state.data || state.data.windows.length === 0)
    return null;
  if (state.cachedAdvisorReport)
    return state.cachedAdvisorReport;
  const windowStats = state.data.windows[state.selectedWindowIndex]?.stats;
  if (!windowStats)
    return null;
  const scoped = getScopedWindowData(state);
  if (!scoped)
    return null;
  const output2 = {
    schemaVersion: SCHEMA_VERSION,
    generated: new Date().toISOString(),
    dateRange: scoped.windowRange,
    providers: scoped.scopedProviders,
    aggregated: windowStats
  };
  const report = analyzeEfficiency(output2, MODEL_PRICING);
  state.cachedAdvisorReport = report;
  return report;
}
function ensureFocusReport(state) {
  if (!state.data)
    return null;
  if (state.cachedFocusReport)
    return state.cachedFocusReport;
  const allEvents = state.data.providers.flatMap((p) => p.events ?? []);
  const days = WINDOW_DAYS[state.selectedWindowIndex];
  let filtered = allEvents;
  if (days && days > 0) {
    const since = daysAgoStr(days - 1);
    const today = todayStr();
    filtered = allEvents.filter((e) => e.date >= since && e.date <= today);
  }
  const report = buildFocusReport(filtered);
  state.cachedFocusReport = report;
  return report;
}
function ensureExplainReport(state) {
  if (!state.data)
    return null;
  if (state.cachedExplainReport && state.cachedExplainReport.date === state.explainDate) {
    return state.cachedExplainReport;
  }
  if (!state.explainDate) {
    const windowStats = state.data.windows[state.selectedWindowIndex]?.stats;
    state.explainDate = windowStats?.peakDay?.date ?? todayStr();
  }
  const report = buildExplainReport(state.data.providers, state.explainDate);
  state.cachedExplainReport = report;
  return report;
}
function ensureCompareOutput(state) {
  if (!state.data)
    return null;
  if (state.cachedCompareOutput)
    return state.cachedCompareOutput;
  const days = WINDOW_DAYS[state.selectedWindowIndex] || 365;
  const today = todayStr();
  const rangeB = { since: daysAgoStr(days - 1), until: today };
  const rangeA = { since: daysAgoStr(days * 2 - 1), until: daysAgoStr(days) };
  const output2 = compareRanges(state.data.mergedDaily, rangeA, rangeB);
  state.cachedCompareOutput = output2;
  return output2;
}
function ensureMoreStats(state) {
  if (!state.data || state.data.windows.length === 0)
    return null;
  if (state.cachedMoreStats)
    return state.cachedMoreStats;
  const scoped = getScopedWindowData(state);
  if (!scoped)
    return null;
  const more = buildMoreStats(scoped.scopedProviders, scoped.windowRange);
  state.cachedMoreStats = more;
  return more;
}
function ensureReplayReport(state) {
  if (!state.data)
    return null;
  if (state.cachedReplayReport && state.cachedReplayReport.date === state.replayDate) {
    return state.cachedReplayReport;
  }
  if (!state.replayDate) {
    state.replayDate = todayStr();
  }
  const scoped = getScopedWindowData(state);
  if (!scoped)
    return null;
  const report = buildReplayReport(scoped.scopedProviders, state.replayDate);
  state.cachedReplayReport = report;
  return report;
}
function getDayOfWeekForWindow(state) {
  if (!state.data)
    return [];
  const daily = getDailyForWindow(state.data, state.selectedWindowIndex);
  return dayOfWeekBreakdown(daily);
}
var init_data = __esm(() => {
  init_dist();
  init_dist2();
  init_state();
});

// packages/tui/dist/lib/format.js
function formatTokens15(n) {
  if (n >= 1e9)
    return `${(n / 1e9).toFixed(1)}B`;
  if (n >= 1e6)
    return `${(n / 1e6).toFixed(1)}M`;
  if (n >= 1000)
    return `${(n / 1000).toFixed(1)}K`;
  return n.toLocaleString("en-US");
}
function formatCost15(n) {
  return `$${n.toFixed(2)}`;
}
function formatPercent5(n) {
  return `${(n * 100).toFixed(1)}%`;
}
function padRight(s, width) {
  return s.length >= width ? s.slice(0, width) : s + " ".repeat(width - s.length);
}
function padLeft(s, width) {
  return s.length >= width ? s.slice(0, width) : " ".repeat(width - s.length) + s;
}
function truncate3(s, maxLen) {
  if (maxLen <= 0)
    return "";
  if (maxLen === 1)
    return "\u2026";
  if (s.length <= maxLen)
    return s;
  return s.slice(0, maxLen - 1) + "\u2026";
}
function asciiBar(ratio, width) {
  const clamped = Math.max(0, Math.min(1, ratio));
  const w = Math.max(0, Math.floor(width));
  const filled = Math.round(clamped * w);
  const empty = w - filled;
  return "\u2588".repeat(filled) + "\u2591".repeat(empty);
}
function formatShortDate(dateStr) {
  const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
  const parts = dateStr.split("-");
  const monthIdx = parseInt(parts[1], 10) - 1;
  const day = parseInt(parts[2], 10);
  if (isNaN(monthIdx) || isNaN(day) || monthIdx < 0 || monthIdx > 11)
    return dateStr;
  return `${months[monthIdx]} ${day}`;
}

// packages/tui/dist/panels/header.js
import { Box, Text } from "@opentui/core";
function formatCompactTime() {
  const now = new Date;
  const month = String(now.getMonth() + 1).padStart(2, "0");
  const day = String(now.getDate()).padStart(2, "0");
  const hours = String(now.getHours()).padStart(2, "0");
  const minutes = String(now.getMinutes()).padStart(2, "0");
  return `${month}/${day} ${hours}:${minutes}`;
}
function buildHeader(state, renderer, onViewSwitch) {
  const costStr = state.data ? formatCost15(state.data.allTimeStats.totalCost) : "$...";
  const windowIdx = state.selectedWindowIndex;
  const stats = state.data?.windows[windowIdx]?.stats;
  const windowCost = stats ? formatCost15(stats.totalCost) : costStr;
  const tabParts = [];
  for (let i = 0;i < WINDOW_LABELS.length; i++) {
    const label = WINDOW_LABELS[i];
    const isSelected = i === windowIdx;
    if (isSelected) {
      tabParts.push(Text({
        content: ` ${label} `,
        fg: COLORS2.bg,
        bg: COLORS2.amber,
        attributes: BOLD3
      }));
    } else {
      tabParts.push(Text({
        content: ` ${label} `,
        fg: state.isLoading ? COLORS2.dimWhite : COLORS2.white
      }));
    }
  }
  const viewParts = [];
  for (const v of VIEWS) {
    const isActive = state.selectedView === v.mode;
    const viewMode = v.mode;
    viewParts.push(Box({
      onMouseDown: onViewSwitch ? () => {
        onViewSwitch(viewMode);
      } : undefined
    }, Text({
      content: ` ${v.label} `,
      fg: isActive ? COLORS2.bg : COLORS2.dimWhite,
      bg: isActive ? COLORS2.cyan : undefined,
      attributes: isActive ? BOLD3 : undefined
    })));
  }
  return Box({
    flexDirection: "row",
    width: "100%",
    justifyContent: "space-between",
    paddingLeft: 1,
    paddingRight: 1,
    height: 1
  }, Box({ flexDirection: "row", gap: 1 }, Text({ content: " TOKENLEAK ", fg: COLORS2.amber, attributes: BOLD3 }), ...tabParts, Text({ content: "  ", fg: COLORS2.dimWhite }), ...viewParts), Box({ flexDirection: "row", gap: 2 }, Text({ content: windowCost, fg: COLORS2.amber, attributes: BOLD3 }), Text({ content: formatCompactTime(), fg: COLORS2.green })));
}
var VIEWS;
var init_header = __esm(() => {
  init_theme2();
  init_state();
  VIEWS = [
    { key: "1", label: "Overview", mode: "overview" },
    { key: "2", label: "Matrix", mode: "matrix" },
    { key: "3", label: "Advisor", mode: "advisor" },
    { key: "4", label: "Focus", mode: "focus" },
    { key: "5", label: "Explain", mode: "explain" },
    { key: "6", label: "Compare", mode: "compare" },
    { key: "7", label: "Export", mode: "export" },
    { key: "8", label: "Wrapped", mode: "wrapped" },
    { key: "9", label: "Replay", mode: "replay" }
  ];
});

// packages/tui/dist/lib/chart.js
import { Box as Box2, Text as Text2 } from "@opentui/core";
function buildChart(daily, chartWidth, chartHeight) {
  if (daily.length === 0) {
    return Box2({ flexDirection: "column", width: "100%" }, Text2({ content: "No data for this period", fg: COLORS2.dimWhite }));
  }
  const modelTotals = new Map;
  for (const day of daily) {
    for (const m of day.models) {
      modelTotals.set(m.model, (modelTotals.get(m.model) ?? 0) + m.totalTokens);
    }
  }
  const sortedModels = [...modelTotals.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5);
  const chartModels = sortedModels.map(([name], i) => ({
    model: name,
    color: MODEL_COLORS2[i % MODEL_COLORS2.length]
  }));
  if (chartWidth < 40) {
    return buildCompactList(daily, chartModels);
  }
  const maxTokens = Math.max(...daily.map((d) => d.totalTokens), 1);
  const yAxisWidth = 8;
  const barAreaWidth = Math.max(chartWidth - yAxisWidth - 2, 10);
  const maxBars = Math.floor(barAreaWidth / 2);
  const step = daily.length > maxBars ? Math.ceil(daily.length / maxBars) : 1;
  const sampledDays = [];
  for (let i = 0;i < daily.length; i += step) {
    sampledDays.push(daily[i]);
  }
  const rows = [];
  for (let row = chartHeight - 1;row >= 0; row--) {
    const threshold = row / chartHeight * maxTokens;
    let yLabel = "";
    if (row === chartHeight - 1) {
      yLabel = formatTokens15(maxTokens);
    } else if (row === 0) {
      yLabel = "0";
    } else if (row === Math.floor(chartHeight / 2)) {
      yLabel = formatTokens15(maxTokens / 2);
    }
    const labelPadded = yLabel.padStart(yAxisWidth - 1) + "\u2502";
    let barStr = "";
    for (const day of sampledDays) {
      if (day.totalTokens > threshold) {
        barStr += "\u2588 ";
      } else {
        barStr += "  ";
      }
    }
    rows.push(Box2({ flexDirection: "row", width: "100%", height: 1 }, Text2({ content: labelPadded, fg: COLORS2.dimWhite }), Text2({ content: barStr, fg: COLORS2.green })));
  }
  const xLine = "\u2500".repeat(Math.min(sampledDays.length * 2, barAreaWidth));
  rows.push(Box2({ flexDirection: "row", width: "100%", height: 1 }, Text2({ content: " ".repeat(yAxisWidth), fg: COLORS2.dimWhite }), Text2({ content: xLine, fg: COLORS2.dimWhite })));
  const xLabels = buildXLabels(sampledDays, barAreaWidth);
  rows.push(Box2({ flexDirection: "row", width: "100%", height: 1 }, Text2({ content: " ".repeat(yAxisWidth), fg: COLORS2.dimWhite }), Text2({ content: xLabels, fg: COLORS2.dimWhite })));
  rows.push(Box2({ width: "100%", height: 1 }));
  const legendParts = [];
  for (const cm of chartModels) {
    legendParts.push(Text2({ content: `\u25CF ${truncate3(cm.model, 18)}  `, fg: cm.color }));
  }
  rows.push(Box2({ flexDirection: "row", width: "100%", height: 1 }, Text2({ content: " ".repeat(yAxisWidth), fg: COLORS2.dimWhite }), ...legendParts));
  return Box2({ flexDirection: "column", width: "100%" }, ...rows);
}
function buildXLabels(days, width) {
  if (days.length === 0)
    return "";
  const labelCount = Math.min(4, days.length);
  const positions = [];
  for (let i = 0;i < labelCount; i++) {
    positions.push(Math.floor(i / (labelCount - 1 || 1) * (days.length - 1)));
  }
  let result = "";
  let pos = 0;
  for (const idx of positions) {
    const targetPos = idx * 2;
    while (pos < targetPos && pos < width) {
      result += " ";
      pos++;
    }
    const label = formatShortDate(days[idx].date);
    result += label;
    pos += label.length;
  }
  return result.slice(0, width);
}
function buildCompactList(daily, chartModels) {
  const sorted = [...daily].sort((a, b) => b.totalTokens - a.totalTokens).slice(0, 5);
  const rows = sorted.map((d) => Box2({ flexDirection: "row", width: "100%" }, Text2({ content: `${formatShortDate(d.date)}  `, fg: COLORS2.dimWhite }), Text2({ content: formatTokens15(d.totalTokens), fg: COLORS2.green, attributes: BOLD3 })));
  const legendParts = chartModels.map((cm) => Text2({ content: `\u25CF ${cm.model}  `, fg: cm.color }));
  return Box2({ flexDirection: "column", width: "100%" }, Text2({ content: "Top 5 Days", fg: COLORS2.amber, attributes: BOLD3 }), ...rows, Box2({ flexDirection: "row", width: "100%", paddingTop: 1 }, ...legendParts));
}
var init_chart = __esm(() => {
  init_theme2();
});

// packages/tui/dist/panels/chart-panel.js
import { Box as Box3, Text as Text3 } from "@opentui/core";
function createChartPanel(state, daily) {
  if (state.isLoading) {
    return Box3({
      flexDirection: "column",
      border: true,
      borderStyle: "single",
      borderColor: COLORS2.dimWhite,
      padding: 1,
      width: "100%",
      height: 14,
      title: " Tokens per Day "
    }, Text3({ content: "Loading chart data...", fg: COLORS2.dimWhite }));
  }
  const chartContent = buildChart(daily, 70, 8);
  return Box3({
    flexDirection: "column",
    border: true,
    borderStyle: "single",
    borderColor: COLORS2.amber,
    paddingLeft: 1,
    paddingRight: 1,
    paddingTop: 1,
    paddingBottom: 2,
    width: "100%",
    height: 16,
    title: " Tokens per Day "
  }, chartContent);
}
var init_chart_panel = __esm(() => {
  init_chart();
  init_theme2();
});

// packages/tui/dist/panels/stats-row.js
import { Box as Box4, Text as Text4 } from "@opentui/core";
function statCard(label, value, valueColor) {
  return Box4({ flexDirection: "row" }, Text4({ content: `${label}  `, fg: COLORS2.dimWhite }), Text4({ content: value, fg: valueColor, attributes: BOLD3 }));
}
function sep4() {
  return Text4({ content: " \u2502 ", fg: COLORS2.dimWhite });
}
function createStatsRow(state, stats) {
  if (state.isLoading || !stats) {
    return Box4({
      flexDirection: "row",
      width: "100%",
      paddingLeft: 2,
      paddingRight: 2,
      height: 1,
      justifyContent: "flex-start",
      gap: 0
    }, statCard("Tokens", "---", COLORS2.dimWhite), sep4(), statCard("Cost", "---", COLORS2.dimWhite), sep4(), statCard("Active", "---", COLORS2.dimWhite), sep4(), statCard("Streak", "---", COLORS2.dimWhite), sep4(), statCard("Cache", "---", COLORS2.dimWhite));
  }
  return Box4({
    flexDirection: "row",
    width: "100%",
    paddingLeft: 2,
    paddingRight: 2,
    height: 1,
    justifyContent: "flex-start",
    gap: 0
  }, statCard("Tokens", formatTokens15(stats.totalTokens), COLORS2.green), sep4(), statCard("Cost", formatCost15(stats.totalCost), COLORS2.amber), sep4(), statCard("Active", `${stats.activeDays}/${stats.totalDays}d`, COLORS2.cyan), sep4(), statCard("Streak", `${stats.currentStreak}d`, COLORS2.green), sep4(), statCard("Cache", formatPercent5(stats.cacheHitRate), COLORS2.cyan));
}
var init_stats_row = __esm(() => {
  init_theme2();
});

// packages/tui/dist/panels/model-list.js
import { Box as Box5, Text as Text5 } from "@opentui/core";
function createModelList(state, stats) {
  if (state.isLoading || !stats) {
    const skeletonRows = [];
    for (let i = 0;i < 5; i++) {
      skeletonRows.push(Text5({ content: "\u2500".repeat(50), fg: COLORS2.dimWhite }));
    }
    return Box5({
      flexDirection: "column",
      border: true,
      borderStyle: "single",
      borderColor: COLORS2.dimWhite,
      padding: 1,
      width: "100%",
      flexGrow: 1,
      title: " Models by Cost "
    }, ...skeletonRows);
  }
  const models = stats.topModels;
  const sortedModels = [...models].sort((a, b) => state.sortMode === "cost" ? b.cost - a.cost : b.tokens - a.tokens);
  const totalCost = stats.totalCost;
  const children = [];
  children.push(Box5({ flexDirection: "row", width: "100%", justifyContent: "space-between" }, Text5({
    content: `Models by ${state.sortMode === "cost" ? "Cost" : "Tokens"}`,
    fg: COLORS2.amber,
    attributes: BOLD3
  }), Text5({
    content: `Total: ${formatCost15(totalCost)}`,
    fg: COLORS2.amber,
    attributes: BOLD3
  })));
  children.push(Text5({ content: "\u2500".repeat(60), fg: COLORS2.dimWhite }));
  const visibleCount = 10;
  const offset = Math.min(state.modelScrollOffset, Math.max(0, sortedModels.length - visibleCount));
  const visible = sortedModels.slice(offset, offset + visibleCount);
  if (offset > 0) {
    children.push(Text5({ content: `  \u25B2 ${offset} more above`, fg: COLORS2.dimWhite }));
  }
  for (let i = 0;i < visible.length; i++) {
    const m = visible[i];
    const colorIdx = sortedModels.indexOf(m);
    const color2 = MODEL_COLORS2[colorIdx % MODEL_COLORS2.length];
    const pct = `(${m.percentage.toFixed(1)}%)`;
    const nameStr = truncate3(m.model, 30);
    const costStr = formatCost15(m.cost);
    const tokStr = formatTokens15(m.tokens);
    children.push(Box5({ flexDirection: "row", width: "100%" }, Text5({ content: "\u25CF ", fg: color2 }), Text5({
      content: padRight(nameStr, 31),
      fg: colorIdx === 0 ? COLORS2.amber : COLORS2.white,
      attributes: colorIdx === 0 ? BOLD3 : undefined
    }), Text5({ content: padRight(pct, 9), fg: COLORS2.dimWhite }), Text5({ content: padLeft(costStr, 10), fg: COLORS2.amber }), Text5({ content: padLeft(tokStr, 10), fg: COLORS2.green })));
  }
  if (offset + visibleCount < sortedModels.length) {
    children.push(Text5({
      content: `  \u25BC ${sortedModels.length - offset - visibleCount} more below`,
      fg: COLORS2.dimWhite
    }));
  }
  return Box5({
    flexDirection: "column",
    border: true,
    borderStyle: "single",
    borderColor: COLORS2.magenta,
    padding: 1,
    width: "100%",
    flexGrow: 2,
    title: " Models by Cost "
  }, ...children);
}
var init_model_list = __esm(() => {
  init_theme2();
});

// packages/tui/dist/panels/cursor-setup.js
import { Box as Box6, InputRenderable, InputRenderableEvents, RenderableEvents, Text as Text6 } from "@opentui/core";
function getCursorStatus(state) {
  return state.cursorSetupStatusOverride ?? state.data?.cursorSetupStatus ?? null;
}
function getCursorBannerText(state) {
  const status = getCursorStatus(state);
  if (!status || status.state === "ready") {
    return null;
  }
  switch (status.state) {
    case "needs_auth":
      return "Cursor not connected. Press c to connect.";
    case "needs_reauth":
      return "Cursor session expired. Press c to update token.";
    case "sync_failed_cached":
      return "Cursor sync failed, using cached data. Press c for details.";
    case "needs_sync":
      return "Cursor needs a local usage sync. Press c to retry.";
    default:
      return null;
  }
}
function buildCursorBanner(state) {
  const text2 = getCursorBannerText(state);
  if (!text2) {
    return null;
  }
  return Box6({
    flexDirection: "row",
    width: "100%",
    paddingLeft: 1,
    paddingRight: 1,
    height: 1
  }, Text6({ content: text2, fg: COLORS2.amber, attributes: BOLD3 }));
}
function renderField(label, input2) {
  return Box6({ flexDirection: "row", width: "100%", paddingLeft: 2, paddingRight: 2 }, Text6({ content: `${label}: `, fg: COLORS2.cyan, attributes: BOLD3 }), input2);
}
function buildStatusLine(message, isError) {
  if (!message) {
    return Text6({ content: "", fg: COLORS2.dimWhite });
  }
  return Text6({
    content: `  ${message}`,
    fg: isError ? COLORS2.red : COLORS2.green,
    attributes: BOLD3
  });
}
function isErrorMessage(state) {
  const status = getCursorStatus(state);
  const statusError = status?.error ?? "";
  const message = state.cursorSetupMessage ?? statusError;
  return message.toLowerCase().includes("error") || message.toLowerCase().includes("invalid") || message.toLowerCase().includes("expired") || message.toLowerCase().includes("failed");
}
function getCursorSetupInstructions(status) {
  const lines = [
    "1. Sign in to Cursor and open https://www.cursor.com/settings",
    "2. Open browser devtools, then go to Application (or Storage) > Cookies > https://www.cursor.com",
    `3. Copy the ${CURSOR_SESSION_COOKIE_NAME} cookie value and paste it here`,
    "4. Press Enter in the token field to validate, save, and sync usage CSVs",
    `5. Tokenleak stores the token in plaintext at ${getCursorCredentialsPath()}`,
    `6. Browser labels vary, but ${CURSOR_SESSION_COOKIE_NAME} is the cookie name to look for`
  ];
  if (!status) {
    return lines;
  }
  if (status.state === "sync_failed_cached" || status.state === "needs_sync") {
    return [
      "Press Enter to retry the Cursor usage sync for the active account.",
      "If the retry still fails because the session is expired, replace the token below.",
      ...lines
    ];
  }
  if (status.state === "needs_reauth") {
    return [
      "The saved Cursor session is no longer valid.",
      ...lines
    ];
  }
  return lines;
}
function hintForField(field) {
  return field === "token" ? "Tab: label field  Enter: validate/save/sync  Esc: close" : "Tab: token field  Enter on token: validate/save/sync  Esc: close";
}
function createFieldInput(renderer, value, placeholder, field, onInput, onFieldFocus) {
  const input2 = new InputRenderable(renderer, {
    width: "100%",
    flexGrow: 1,
    value,
    placeholder,
    backgroundColor: COLORS2.bg,
    focusedBackgroundColor: COLORS2.blue,
    textColor: COLORS2.white,
    focusedTextColor: COLORS2.white,
    placeholderColor: COLORS2.dimWhite
  });
  input2.on(InputRenderableEvents.INPUT, onInput);
  input2.on(RenderableEvents.FOCUSED, () => onFieldFocus(field));
  return input2;
}
function createCursorSetupPanel(state, renderer, callbacks) {
  const status = getCursorStatus(state);
  const message = state.cursorSetupMessage ?? status?.error ?? null;
  const isError = isErrorMessage(state);
  const title = status?.state === "needs_reauth" ? " Cursor Re-authentication " : " Cursor Setup ";
  const labelInput = createFieldInput(renderer, state.cursorSetupLabel, "(optional)", "label", callbacks.onLabelInput, callbacks.onFieldFocus);
  const tokenInput = createFieldInput(renderer, state.cursorSetupToken, `(paste ${CURSOR_SESSION_COOKIE_NAME})`, "token", callbacks.onTokenInput, callbacks.onFieldFocus);
  labelInput.on(InputRenderableEvents.ENTER, () => {
    callbacks.onFieldFocus("token");
    tokenInput.focus();
  });
  tokenInput.on(InputRenderableEvents.ENTER, callbacks.onSubmit);
  return {
    labelInput,
    tokenInput,
    panel: Box6({
      flexDirection: "column",
      width: "100%",
      flexGrow: 1,
      borderStyle: "single",
      borderColor: COLORS2.amber,
      padding: 1
    }, Text6({ content: title, fg: COLORS2.amber, attributes: BOLD3 }), Text6({ content: "", fg: COLORS2.dimWhite }), ...getCursorSetupInstructions(status).map((line2) => Text6({ content: `  ${line2}`, fg: COLORS2.white })), Text6({ content: "", fg: COLORS2.dimWhite }), renderField("Label", labelInput), Text6({ content: "", fg: COLORS2.dimWhite }), renderField("Token", tokenInput), Text6({ content: "", fg: COLORS2.dimWhite }), buildStatusLine(state.cursorSetupSubmitting ? "Validating token and syncing Cursor cache..." : message, isError), Text6({ content: "", fg: COLORS2.dimWhite }), Text6({ content: `  ${hintForField(state.cursorSetupField)}`, fg: COLORS2.dimWhite }))
  };
}
var CURSOR_SESSION_COOKIE_NAME = "WorkosCursorSessionToken";
var init_cursor_setup = __esm(() => {
  init_dist2();
  init_theme2();
});

// packages/tui/dist/panels/status-bar.js
import { Box as Box7, Text as Text7 } from "@opentui/core";
function formatUpdateTime() {
  const now = new Date;
  const hours = String(now.getHours()).padStart(2, "0");
  const minutes = String(now.getMinutes()).padStart(2, "0");
  return `${hours}:${minutes}`;
}
function buildStatusBar(state) {
  if (state.isLoading) {
    return Box7({
      flexDirection: "row",
      width: "100%",
      justifyContent: "space-between",
      paddingLeft: 1,
      paddingRight: 1,
      height: 1
    }, Text7({ content: "Loading...", fg: COLORS2.amber }), Text7({ content: "", fg: COLORS2.dimWhite }));
  }
  if (state.showHelp) {
    return Box7({
      flexDirection: "row",
      width: "100%",
      justifyContent: "space-between",
      paddingLeft: 1,
      paddingRight: 1,
      height: 1
    }, Text7({ content: "?/Esc:close help  q:quit", fg: COLORS2.dimWhite }), Text7({ content: `Updated ${formatUpdateTime()}`, fg: COLORS2.dimWhite }));
  }
  if (state.showCursorSetup) {
    return Box7({
      flexDirection: "row",
      width: "100%",
      justifyContent: "space-between",
      paddingLeft: 1,
      paddingRight: 1,
      height: 1
    }, Text7({ content: "tab:field  enter:token submit  esc:close", fg: COLORS2.dimWhite }), Text7({ content: `Updated ${formatUpdateTime()}`, fg: COLORS2.dimWhite }));
  }
  const helpHint = "?:help";
  const nav = `\u2190\u2192:view  tab/\u21E7tab:period  1-9:view`;
  const cursorHint = getCursorBannerText(state) ? "  c:cursor" : "";
  let keys;
  if (state.selectedView === "overview") {
    keys = `${nav}  j/k:scroll  s:sort  r:refresh${cursorHint}  ${helpHint}  q:quit`;
  } else if (state.selectedView === "matrix") {
    keys = `${nav}  [/]:page  r:refresh${cursorHint}  ${helpHint}  q:quit`;
  } else if (state.selectedView === "explain") {
    keys = `${nav}  h/l:date  r:refresh${cursorHint}  ${helpHint}  q:quit`;
  } else if (state.selectedView === "replay") {
    keys = `${nav}  h/l:date  j/k:scroll  enter:expand  r:refresh${cursorHint}  ${helpHint}  q:quit`;
  } else if (state.selectedView === "advisor" || state.selectedView === "focus" || state.selectedView === "compare" || state.selectedView === "wrapped") {
    keys = `${nav}  j/k:scroll  r:refresh${cursorHint}  ${helpHint}  q:quit`;
  } else if (state.selectedView === "export") {
    keys = `${nav}  p:png  w:wrapped  l:live  r:refresh${cursorHint}  ${helpHint}  q:quit`;
  } else {
    keys = `${nav}  r:refresh${cursorHint}  ${helpHint}  q:quit`;
  }
  return Box7({
    flexDirection: "row",
    width: "100%",
    justifyContent: "space-between",
    paddingLeft: 1,
    paddingRight: 1,
    height: 1
  }, Text7({ content: keys, fg: COLORS2.dimWhite }), Text7({
    content: `Updated ${formatUpdateTime()}`,
    fg: COLORS2.dimWhite
  }));
}
var init_status_bar = __esm(() => {
  init_theme2();
  init_cursor_setup();
});

// packages/tui/dist/panels/time-windows.js
import { Box as Box8, Text as Text8 } from "@opentui/core";
function headerRow(labels) {
  const COL_W = 12;
  return Box8({ flexDirection: "row", width: "100%" }, Text8({ content: padRight("Metric", 18), fg: COLORS2.amber, attributes: BOLD3 }), ...labels.map((l) => Text8({ content: padLeft(l, COL_W), fg: COLORS2.amber, attributes: BOLD3 })));
}
function dataRow(label, values, highlights) {
  const COL_W = 12;
  return Box8({ flexDirection: "row", width: "100%" }, Text8({ content: padRight(label, 18), fg: COLORS2.dimWhite }), ...values.map((v, i) => Text8({
    content: padLeft(v, COL_W),
    fg: highlights[i] ? COLORS2.amber : COLORS2.green,
    attributes: highlights[i] ? BOLD3 : undefined
  })));
}
function findMaxIndex(values) {
  let maxVal = -Infinity;
  let maxIdx = -1;
  for (let i = 0;i < values.length; i++) {
    if (values[i] > maxVal) {
      maxVal = values[i];
      maxIdx = i;
    }
  }
  return values.map((_, i) => i === maxIdx && maxVal > 0);
}
function createTimeWindowsPanel(props) {
  const { windows } = props;
  const children = [];
  if (windows.length === 0) {
    children.push(Text8({ content: "Loading...", fg: COLORS2.amber }));
  } else {
    const labels = windows.map((w) => w.label);
    const tokenValues = windows.map((w) => w.stats.totalTokens);
    const costValues = windows.map((w) => w.stats.totalCost);
    const avgTokenValues = windows.map((w) => w.stats.averageDailyTokens);
    const avgCostValues = windows.map((w) => w.stats.averageDailyCost);
    const activeDaysValues = windows.map((w) => w.stats.activeDays);
    children.push(headerRow(labels), Text8({ content: "\u2500".repeat(66), fg: COLORS2.dimWhite }), dataRow("Tokens", tokenValues.map(formatTokens15), findMaxIndex(tokenValues)), dataRow("Cost", costValues.map(formatCost15), findMaxIndex(costValues)), dataRow("Avg Daily Tokens", avgTokenValues.map(formatTokens15), findMaxIndex(avgTokenValues)), dataRow("Avg Daily Cost", avgCostValues.map(formatCost15), findMaxIndex(avgCostValues)), dataRow("Active Days", activeDaysValues.map((v) => v.toString()), findMaxIndex(activeDaysValues)), dataRow("Cache Hit Rate", windows.map((w) => `${(w.stats.cacheHitRate * 100).toFixed(1)}%`), findMaxIndex(windows.map((w) => w.stats.cacheHitRate))), dataRow("Current Streak", windows.map((w) => `${w.stats.currentStreak}d`), findMaxIndex(windows.map((w) => w.stats.currentStreak))));
  }
  return Box8({
    flexDirection: "column",
    border: true,
    borderStyle: "single",
    borderColor: COLORS2.cyan,
    padding: 1,
    flexGrow: 1,
    title: " TIME WINDOWS "
  }, ...children);
}
var init_time_windows = __esm(() => {
  init_theme2();
});

// packages/tui/dist/panels/matrix-activity.js
import { Box as Box9, Text as Text9 } from "@opentui/core";
function createHourOfDayPanel(hourOfDay) {
  const maxTokens = Math.max(...hourOfDay.map((h) => h.tokens), 1);
  const children = [];
  for (const entry of hourOfDay) {
    const ratio = entry.tokens / maxTokens;
    const hourLabel = String(entry.hour).padStart(2, "0");
    const barColor = entry.tokens === maxTokens ? COLORS2.amber : COLORS2.green;
    children.push(Box9({ flexDirection: "row", width: "100%" }, Text9({ content: `${hourLabel} `, fg: COLORS2.dimWhite }), Text9({ content: asciiBar(ratio, 16), fg: barColor }), Text9({ content: ` ${padLeft(formatTokens15(entry.tokens), 8)}`, fg: COLORS2.green })));
  }
  return Box9({
    flexDirection: "column",
    borderStyle: "single",
    borderColor: COLORS2.cyan,
    padding: 1,
    flexGrow: 1
  }, Text9({ content: " HOUR OF DAY ", fg: COLORS2.cyan, attributes: BOLD3 }), ...children);
}
function createDayOfWeekPanel(dayOfWeek) {
  const maxTokens = Math.max(...dayOfWeek.map((d) => d.tokens), 1);
  const children = [];
  for (const entry of dayOfWeek) {
    const ratio = entry.tokens / maxTokens;
    const barColor = entry.tokens === maxTokens ? COLORS2.amber : COLORS2.green;
    children.push(Box9({ flexDirection: "row", width: "100%" }, Text9({ content: padRight(entry.label, 4), fg: COLORS2.dimWhite }), Text9({ content: asciiBar(ratio, 16), fg: barColor }), Text9({ content: ` ${padLeft(formatTokens15(entry.tokens), 8)}`, fg: COLORS2.green })));
  }
  return Box9({
    flexDirection: "column",
    borderStyle: "single",
    borderColor: COLORS2.magenta,
    padding: 1,
    flexGrow: 1
  }, Text9({ content: " DAY OF WEEK ", fg: COLORS2.magenta, attributes: BOLD3 }), ...children);
}
var init_matrix_activity = __esm(() => {
  init_theme2();
});

// packages/tui/dist/panels/matrix-io.js
import { Box as Box10, Text as Text10 } from "@opentui/core";
function statRow(label, value, valueColor = COLORS2.green) {
  return Box10({ flexDirection: "row", width: "100%" }, Text10({ content: label, fg: COLORS2.dimWhite }), Text10({ content: "  " }), Text10({ content: value, fg: valueColor, attributes: BOLD3 }));
}
function createInputOutputPanel(io, stats) {
  const total = stats.totalInputTokens + stats.totalOutputTokens;
  const inputPct = total > 0 ? (stats.totalInputTokens / total * 100).toFixed(1) : "0.0";
  const outputPct = total > 0 ? (stats.totalOutputTokens / total * 100).toFixed(1) : "0.0";
  const ioRatio = io.inputPerOutput !== null ? io.inputPerOutput.toFixed(1) : "N/A";
  return Box10({
    flexDirection: "column",
    borderStyle: "single",
    borderColor: COLORS2.cyan,
    padding: 1,
    flexGrow: 1
  }, Text10({ content: " INPUT / OUTPUT ", fg: COLORS2.cyan, attributes: BOLD3 }), statRow("Input", `${formatTokens15(stats.totalInputTokens)}  (${inputPct}%)`), statRow("Output", `${formatTokens15(stats.totalOutputTokens)}  (${outputPct}%)`), statRow("I/O Ratio", `${ioRatio}:1`), statRow("Output Share", `${(io.outputShare * 100).toFixed(1)}%`, COLORS2.amber));
}
function createMonthlyBurnPanel(burn) {
  const burnRate = burn.observedDays > 0 ? formatCost15(burn.projectedCost / (burn.calendarDays || 30)) : "$0.00";
  return Box10({
    flexDirection: "column",
    borderStyle: "single",
    borderColor: COLORS2.amber,
    padding: 1,
    flexGrow: 1
  }, Text10({ content: " MONTHLY BURN ", fg: COLORS2.amber, attributes: BOLD3 }), statRow("Projected Tokens", formatTokens15(burn.projectedTokens)), statRow("Projected Cost", formatCost15(burn.projectedCost), COLORS2.amber), statRow("Observed", `${burn.observedDays}/${burn.calendarDays} days`), statRow("Burn Rate", `${burnRate}/day`, COLORS2.red));
}
var init_matrix_io = __esm(() => {
  init_theme2();
});

// packages/tui/dist/panels/matrix-cache.js
import { Box as Box11, Text as Text11 } from "@opentui/core";
function statRow2(label, value, valueColor = COLORS2.green) {
  return Box11({ flexDirection: "row", width: "100%" }, Text11({ content: label, fg: COLORS2.dimWhite }), Text11({ content: "  " }), Text11({ content: value, fg: valueColor, attributes: BOLD3 }));
}
function createCacheEconomicsPanel(cache) {
  const reuseStr = cache.reuseRatio !== null ? `${cache.reuseRatio.toFixed(1)}x` : "N/A";
  return Box11({
    flexDirection: "column",
    borderStyle: "single",
    borderColor: COLORS2.cyan,
    padding: 1,
    flexGrow: 1
  }, Text11({ content: " CACHE ECONOMICS ", fg: COLORS2.cyan, attributes: BOLD3 }), statRow2("Read Tokens", formatTokens15(cache.readTokens)), statRow2("Write Tokens", formatTokens15(cache.writeTokens)), statRow2("Read Coverage", `${(cache.readCoverage * 100).toFixed(1)}%`, COLORS2.amber), statRow2("Reuse Ratio", reuseStr));
}
function createCacheRoiPanel(roi) {
  if (!roi) {
    return Box11({
      flexDirection: "column",
      borderStyle: "single",
      borderColor: COLORS2.green,
      padding: 1,
      flexGrow: 1
    }, Text11({ content: " CACHE ROI ", fg: COLORS2.green, attributes: BOLD3 }), Text11({ content: "Insufficient data for ROI calculation", fg: COLORS2.dimWhite }));
  }
  const { summary } = roi;
  const paybackStr = summary.paybackRatio !== null ? `${summary.paybackRatio.toFixed(1)}x` : "N/A";
  return Box11({
    flexDirection: "column",
    borderStyle: "single",
    borderColor: COLORS2.green,
    padding: 1,
    flexGrow: 1
  }, Text11({ content: " CACHE ROI ", fg: COLORS2.green, attributes: BOLD3 }), statRow2("Read Savings", formatCost15(summary.readSavings), COLORS2.green), statRow2("Write Cost", formatCost15(summary.writeCost), COLORS2.red), statRow2("Net Savings", formatCost15(summary.netSavings), summary.netSavings >= 0 ? COLORS2.green : COLORS2.red), statRow2("Payback Ratio", paybackStr, COLORS2.amber));
}
var init_matrix_cache = __esm(() => {
  init_theme2();
});

// packages/tui/dist/panels/matrix-sessions.js
import { Box as Box12, Text as Text12 } from "@opentui/core";
function statRow3(label, value, valueColor = COLORS2.green) {
  return Box12({ flexDirection: "row", width: "100%" }, Text12({ content: label, fg: COLORS2.dimWhite }), Text12({ content: "  " }), Text12({ content: value, fg: valueColor, attributes: BOLD3 }));
}
function formatDuration5(ms) {
  if (ms === null || ms <= 0)
    return "N/A";
  const totalMinutes = Math.floor(ms / 60000);
  if (totalMinutes < 60)
    return `${totalMinutes}m`;
  const hours = Math.floor(totalMinutes / 60);
  const minutes = totalMinutes % 60;
  return `${hours}h ${minutes}m`;
}
function createSessionsPanel(sessions) {
  const longestDuration = sessions.longestSession ? formatDuration5(sessions.longestSession.durationMs) : "N/A";
  return Box12({
    flexDirection: "column",
    borderStyle: "single",
    borderColor: COLORS2.cyan,
    padding: 1,
    flexGrow: 1
  }, Text12({ content: " SESSIONS ", fg: COLORS2.cyan, attributes: BOLD3 }), statRow3("Total", `${sessions.totalSessions} sessions`), statRow3("Avg Tokens", `${formatTokens15(sessions.averageTokens)}/sess`), statRow3("Avg Cost", `${formatCost15(sessions.averageCost)}/sess`), statRow3("Longest", longestDuration), statRow3("Projects", `${sessions.projectCount}`));
}
function createTopProjectsPanel(projects) {
  const children = [];
  if (projects.length === 0) {
    children.push(Text12({ content: "No project data available", fg: COLORS2.dimWhite }));
  } else {
    const top8 = projects.slice(0, 8);
    for (let i = 0;i < top8.length; i++) {
      const p = top8[i];
      const rank = `${i + 1}.`;
      const name = truncate3(p.directory ?? p.projectId, 20);
      const isTop = i === 0;
      children.push(Box12({ flexDirection: "row", width: "100%" }, Text12({ content: padRight(rank, 3), fg: COLORS2.dimWhite }), Text12({
        content: padRight(name, 21),
        fg: isTop ? COLORS2.amber : COLORS2.green,
        attributes: isTop ? BOLD3 : undefined
      }), Text12({ content: padLeft(formatTokens15(p.totalTokens), 8), fg: COLORS2.green }), Text12({ content: padLeft(formatCost15(p.cost), 10), fg: COLORS2.amber })));
    }
  }
  return Box12({
    flexDirection: "column",
    borderStyle: "single",
    borderColor: COLORS2.magenta,
    padding: 1,
    flexGrow: 1
  }, Text12({ content: " TOP PROJECTS ", fg: COLORS2.magenta, attributes: BOLD3 }), ...children);
}
var init_matrix_sessions = __esm(() => {
  init_theme2();
});

// packages/tui/dist/panels/matrix-efficiency.js
import { Box as Box13, Text as Text13 } from "@opentui/core";
function createModelEfficiencyPanel(efficiency) {
  const children = [];
  if (!efficiency || efficiency.rankings.length === 0) {
    children.push(Text13({ content: "Insufficient data for efficiency ranking", fg: COLORS2.dimWhite }));
  } else {
    children.push(Box13({ flexDirection: "row", width: "100%" }, Text13({ content: padRight("#", 3), fg: COLORS2.amber, attributes: BOLD3 }), Text13({ content: padRight("Model", 22), fg: COLORS2.amber, attributes: BOLD3 }), Text13({ content: padLeft("Score", 7), fg: COLORS2.amber, attributes: BOLD3 }), Text13({ content: padLeft("$/M", 8), fg: COLORS2.amber, attributes: BOLD3 }), Text13({ content: padLeft("O/I", 6), fg: COLORS2.amber, attributes: BOLD3 }), Text13({ content: padLeft("Cache", 7), fg: COLORS2.amber, attributes: BOLD3 })));
    children.push(Text13({ content: "\u2500".repeat(53), fg: COLORS2.dimWhite }));
    const top8 = efficiency.rankings.slice(0, 8);
    for (let i = 0;i < top8.length; i++) {
      const r = top8[i];
      const isTop = i === 0;
      const costPerM = `$${r.costPer1MTotal.toFixed(1)}`;
      const oi = r.outputInputRatio.toFixed(2);
      const cache = `${(r.cacheCoverage * 100).toFixed(0)}%`;
      children.push(Box13({ flexDirection: "row", width: "100%" }, Text13({ content: padRight(`${i + 1}.`, 3), fg: COLORS2.dimWhite }), Text13({
        content: padRight(truncate3(r.model, 21), 22),
        fg: isTop ? COLORS2.amber : COLORS2.green,
        attributes: isTop ? BOLD3 : undefined
      }), Text13({ content: padLeft(r.score.toFixed(2), 7), fg: COLORS2.cyan, attributes: BOLD3 }), Text13({ content: padLeft(costPerM, 8), fg: COLORS2.amber }), Text13({ content: padLeft(oi, 6), fg: COLORS2.green }), Text13({ content: padLeft(cache, 7), fg: COLORS2.magenta })));
    }
  }
  return Box13({
    flexDirection: "column",
    borderStyle: "single",
    borderColor: COLORS2.cyan,
    padding: 1,
    flexGrow: 1
  }, Text13({ content: " MODEL EFFICIENCY ", fg: COLORS2.cyan, attributes: BOLD3 }), ...children);
}
function createAttributionPanel(attribution) {
  const children = [];
  if (!attribution || attribution.length === 0) {
    children.push(Text13({ content: "No attribution data available", fg: COLORS2.dimWhite }));
  } else {
    children.push(Box13({ flexDirection: "row", width: "100%" }, Text13({ content: padRight("Cluster", 16), fg: COLORS2.amber, attributes: BOLD3 }), Text13({ content: padRight("Style", 10), fg: COLORS2.amber, attributes: BOLD3 }), Text13({ content: padLeft("Tokens", 10), fg: COLORS2.amber, attributes: BOLD3 }), Text13({ content: padLeft("Sessions", 10), fg: COLORS2.amber, attributes: BOLD3 })));
    children.push(Text13({ content: "\u2500".repeat(46), fg: COLORS2.dimWhite }));
    const top8 = attribution.slice(0, 8);
    for (let i = 0;i < top8.length; i++) {
      const c = top8[i];
      const isTop = i === 0;
      children.push(Box13({ flexDirection: "row", width: "100%" }, Text13({
        content: padRight(truncate3(c.label, 15), 16),
        fg: isTop ? COLORS2.amber : COLORS2.green,
        attributes: isTop ? BOLD3 : undefined
      }), Text13({ content: padRight(c.taskStyle, 10), fg: COLORS2.cyan }), Text13({ content: padLeft(formatTokens15(c.tokens), 10), fg: COLORS2.green }), Text13({ content: padLeft(String(c.sessionCount), 10), fg: COLORS2.white })));
    }
  }
  return Box13({
    flexDirection: "column",
    borderStyle: "single",
    borderColor: COLORS2.magenta,
    padding: 1,
    flexGrow: 1
  }, Text13({ content: " ATTRIBUTION ", fg: COLORS2.magenta, attributes: BOLD3 }), ...children);
}
function formatDuration6(ms) {
  if (ms === null || ms <= 0)
    return "-";
  const hours = Math.floor(ms / 3600000);
  const mins = Math.floor(ms % 3600000 / 60000);
  if (hours > 0)
    return `${hours}h ${mins}m`;
  return `${mins}m`;
}
function createTopSessionsPanel(sessions) {
  const children = [];
  if (!sessions || sessions.length === 0) {
    children.push(Text13({ content: "No session data available", fg: COLORS2.dimWhite }));
  } else {
    children.push(Box13({ flexDirection: "row", width: "100%" }, Text13({ content: padRight("#", 3), fg: COLORS2.amber, attributes: BOLD3 }), Text13({ content: padRight("Session", 20), fg: COLORS2.amber, attributes: BOLD3 }), Text13({ content: padLeft("Tokens", 9), fg: COLORS2.amber, attributes: BOLD3 }), Text13({ content: padLeft("Cost", 9), fg: COLORS2.amber, attributes: BOLD3 }), Text13({ content: padLeft("Dur", 9), fg: COLORS2.amber, attributes: BOLD3 })));
    children.push(Text13({ content: "\u2500".repeat(50), fg: COLORS2.dimWhite }));
    const sorted = [...sessions].sort((a, b) => b.totalTokens - a.totalTokens).slice(0, 6);
    for (let i = 0;i < sorted.length; i++) {
      const s = sorted[i];
      const name = s.directory ?? s.label;
      const isTop = i === 0;
      children.push(Box13({ flexDirection: "row", width: "100%" }, Text13({ content: padRight(`${i + 1}.`, 3), fg: COLORS2.dimWhite }), Text13({
        content: padRight(truncate3(name, 18), 20),
        fg: isTop ? COLORS2.amber : COLORS2.green,
        attributes: isTop ? BOLD3 : undefined
      }), Text13({ content: padLeft(formatTokens15(s.totalTokens), 9), fg: COLORS2.green }), Text13({ content: padLeft(formatCost15(s.cost), 9), fg: COLORS2.amber }), Text13({ content: padLeft(formatDuration6(s.durationMs), 9), fg: COLORS2.cyan })));
    }
  }
  return Box13({
    flexDirection: "column",
    borderStyle: "single",
    borderColor: COLORS2.green,
    padding: 1,
    flexGrow: 1
  }, Text13({ content: " TOP SESSIONS ", fg: COLORS2.green, attributes: BOLD3 }), ...children);
}
function createCacheRoiByModelPanel(cacheRoi) {
  const children = [];
  if (!cacheRoi || cacheRoi.byModel.length === 0) {
    children.push(Text13({ content: "No cache ROI data", fg: COLORS2.dimWhite }));
  } else {
    children.push(Box13({ flexDirection: "row", width: "100%" }, Text13({ content: padRight("Model", 20), fg: COLORS2.amber, attributes: BOLD3 }), Text13({ content: padLeft("Net$", 10), fg: COLORS2.amber, attributes: BOLD3 }), Text13({ content: padLeft("Payback", 10), fg: COLORS2.amber, attributes: BOLD3 })));
    children.push(Text13({ content: "\u2500".repeat(40), fg: COLORS2.dimWhite }));
    const sorted = [...cacheRoi.byModel].sort((a, b) => b.netSavings - a.netSavings).slice(0, 6);
    for (let i = 0;i < sorted.length; i++) {
      const m = sorted[i];
      const isTop = i === 0;
      const payback = m.paybackRatio !== null ? `${m.paybackRatio.toFixed(1)}x` : "-";
      children.push(Box13({ flexDirection: "row", width: "100%" }, Text13({
        content: padRight(truncate3(m.label, 18), 20),
        fg: isTop ? COLORS2.amber : COLORS2.green,
        attributes: isTop ? BOLD3 : undefined
      }), Text13({ content: padLeft(formatCost15(m.netSavings), 10), fg: COLORS2.green }), Text13({ content: padLeft(payback, 10), fg: COLORS2.cyan })));
    }
  }
  return Box13({
    flexDirection: "column",
    borderStyle: "single",
    borderColor: COLORS2.cyan,
    padding: 1,
    flexGrow: 1
  }, Text13({ content: " CACHE ROI BY MODEL ", fg: COLORS2.cyan, attributes: BOLD3 }), ...children);
}
var init_matrix_efficiency = __esm(() => {
  init_theme2();
});

// packages/tui/dist/panels/bloomberg.js
import { Box as Box14, Text as Text14 } from "@opentui/core";
function statRow4(label, value, valueColor = COLORS2.green) {
  return Box14({ flexDirection: "row", width: "100%" }, Text14({ content: label, fg: COLORS2.dimWhite }), Text14({ content: "  " }), Text14({ content: value, fg: valueColor, attributes: BOLD3 }));
}
function createOverviewPanel(state) {
  const stats = state.data?.windows[state.selectedWindowIndex]?.stats ?? null;
  const providers = state.data?.providers ?? [];
  const children = [];
  if (!stats || stats.totalTokens === 0 && stats.totalCost === 0) {
    children.push(Text14({ content: "No usage data for this period", fg: COLORS2.dimWhite }));
  } else {
    children.push(statRow4("Total Tokens", formatTokens15(stats.totalTokens)), statRow4("Total Cost", formatCost15(stats.totalCost), COLORS2.amber), statRow4("Active / Total Days", `${stats.activeDays} / ${stats.totalDays}`), statRow4("Current Streak", `${stats.currentStreak}d`), statRow4("Longest Streak", `${stats.longestStreak}d`), statRow4("Cache Hit Rate", formatPercent5(stats.cacheHitRate), COLORS2.cyan), statRow4("Avg Daily Tokens", formatTokens15(stats.averageDailyTokens)), statRow4("Avg Daily Cost", formatCost15(stats.averageDailyCost), COLORS2.amber), statRow4("Providers", `${providers.length} active`), statRow4("Peak Day", stats.peakDay ? `${stats.peakDay.date} (${formatTokens15(stats.peakDay.tokens)})` : "N/A"), statRow4("Input Tokens", formatTokens15(stats.totalInputTokens)), statRow4("Output Tokens", formatTokens15(stats.totalOutputTokens)));
  }
  return Box14({
    flexDirection: "column",
    borderStyle: "single",
    borderColor: COLORS2.amber,
    padding: 1,
    flexGrow: 1
  }, Text14({ content: " OVERVIEW ", fg: COLORS2.amber, attributes: BOLD3 }), ...children);
}
function createProvidersPanel(state) {
  const stats = state.data?.windows[state.selectedWindowIndex]?.stats ?? null;
  const providers = state.data?.providers ?? [];
  const totalTokens = stats?.totalTokens ?? 0;
  const children = [];
  if (providers.length === 0 || totalTokens === 0) {
    children.push(Text14({ content: "No provider data for this period", fg: COLORS2.dimWhite }));
  } else {
    children.push(Box14({ flexDirection: "row", width: "100%" }, Text14({ content: padRight("Provider", 14), fg: COLORS2.amber, attributes: BOLD3 }), Text14({ content: padLeft("Tokens", 10), fg: COLORS2.amber, attributes: BOLD3 }), Text14({ content: padLeft("Cost", 10), fg: COLORS2.amber, attributes: BOLD3 }), Text14({ content: padLeft("Share", 8), fg: COLORS2.amber, attributes: BOLD3 }), Text14({ content: "  " }), Text14({ content: "Bar", fg: COLORS2.amber, attributes: BOLD3 })));
    children.push(Text14({ content: "\u2500".repeat(58), fg: COLORS2.dimWhite }));
    const days = WINDOW_DAYS[state.selectedWindowIndex];
    const providerTotals = providers.map((p) => {
      let provTokens = p.totalTokens;
      let provCost = p.totalCost;
      if (days && days > 0 && p.daily) {
        const now = new Date;
        const since = new Date(now);
        since.setDate(since.getDate() - days);
        const sinceStr = since.toISOString().slice(0, 10);
        const todayStr2 = now.toISOString().slice(0, 10);
        const filtered = p.daily.filter((d) => d.date >= sinceStr && d.date <= todayStr2);
        provTokens = filtered.reduce((s, d) => s + d.totalTokens, 0);
        provCost = filtered.reduce((s, d) => s + d.cost, 0);
      }
      return { ...p, windowTokens: provTokens, windowCost: provCost };
    });
    const sorted = providerTotals.filter((p) => p.windowTokens > 0).sort((a, b) => b.windowTokens - a.windowTokens);
    if (sorted.length === 0) {
      children.push(Text14({ content: "No provider data for this period", fg: COLORS2.dimWhite }));
    } else {
      for (let i = 0;i < sorted.length; i++) {
        const p = sorted[i];
        const share = totalTokens > 0 ? p.windowTokens / totalTokens : 0;
        const color2 = getProviderColor3(p.provider, i);
        children.push(Box14({ flexDirection: "row", width: "100%" }, Text14({ content: padRight(p.displayName, 14), fg: color2, attributes: BOLD3 }), Text14({ content: padLeft(formatTokens15(p.windowTokens), 10), fg: COLORS2.green }), Text14({ content: padLeft(formatCost15(p.windowCost), 10), fg: COLORS2.amber }), Text14({
          content: padLeft(`${(share * 100).toFixed(1)}%`, 8),
          fg: COLORS2.white
        }), Text14({ content: " " }), Text14({ content: asciiBar(share, 10), fg: color2 })));
      }
    }
  }
  return Box14({
    flexDirection: "column",
    borderStyle: "single",
    borderColor: COLORS2.green,
    padding: 1,
    flexGrow: 1
  }, Text14({ content: " PROVIDERS ", fg: COLORS2.green, attributes: BOLD3 }), ...children);
}
function createTopModelsPanel(state) {
  const stats = state.data?.windows[state.selectedWindowIndex]?.stats ?? null;
  const models = stats?.topModels ?? [];
  const children = [];
  if (models.length === 0) {
    children.push(Text14({ content: "No model data for this period", fg: COLORS2.dimWhite }));
  } else {
    children.push(Box14({ flexDirection: "row", width: "100%" }, Text14({ content: padRight("#", 3), fg: COLORS2.amber, attributes: BOLD3 }), Text14({ content: padRight("Model", 28), fg: COLORS2.amber, attributes: BOLD3 }), Text14({ content: padLeft("Tokens", 10), fg: COLORS2.amber, attributes: BOLD3 }), Text14({ content: padLeft("Cost", 10), fg: COLORS2.amber, attributes: BOLD3 }), Text14({ content: padLeft("Share", 8), fg: COLORS2.amber, attributes: BOLD3 })));
    children.push(Text14({ content: "\u2500".repeat(59), fg: COLORS2.dimWhite }));
    const top10 = models.slice(0, 10);
    for (let i = 0;i < top10.length; i++) {
      const m = top10[i];
      const isTop = i === 0;
      const nameColor = isTop ? COLORS2.amber : COLORS2.green;
      children.push(Box14({ flexDirection: "row", width: "100%" }, Text14({ content: padRight(`${i + 1}.`, 3), fg: COLORS2.dimWhite }), Text14({
        content: padRight(truncate3(m.model, 27), 28),
        fg: nameColor,
        attributes: isTop ? BOLD3 : undefined
      }), Text14({ content: padLeft(formatTokens15(m.tokens), 10), fg: COLORS2.green }), Text14({ content: padLeft(formatCost15(m.cost), 10), fg: COLORS2.amber }), Text14({
        content: padLeft(`${m.percentage.toFixed(1)}%`, 8),
        fg: COLORS2.white
      })));
    }
  }
  return Box14({
    flexDirection: "column",
    borderStyle: "single",
    borderColor: COLORS2.magenta,
    padding: 1,
    flexGrow: 1
  }, Text14({ content: " TOP MODELS ", fg: COLORS2.magenta, attributes: BOLD3 }), ...children);
}
function createPageIndicator(page) {
  const dots = Array.from({ length: MATRIX_PAGE_COUNT }, (_, i) => i === page ? "\u25CF" : "\u25CB").join(" ");
  return Box14({ flexDirection: "row", width: "100%", justifyContent: "center", height: 1 }, Text14({ content: `Page ${page + 1}/${MATRIX_PAGE_COUNT}  ${dots}  `, fg: COLORS2.dimWhite }), Text14({ content: "[", fg: COLORS2.amber }), Text14({ content: ":prev  ", fg: COLORS2.dimWhite }), Text14({ content: "]", fg: COLORS2.amber }), Text14({ content: ":next", fg: COLORS2.dimWhite }));
}
function createPage0(state) {
  const windows = state.data?.windows ?? [];
  return Box14({ flexDirection: "column", width: "100%", flexGrow: 1 }, Box14({ flexDirection: "row", flexGrow: 1, width: "100%", height: "50%" }, createOverviewPanel(state), createTimeWindowsPanel({ windows })), Box14({ flexDirection: "row", flexGrow: 1, width: "100%", height: "50%" }, createProvidersPanel(state), createTopModelsPanel(state)));
}
function createPage1(state) {
  const more = ensureMoreStats(state);
  const dowData = getDayOfWeekForWindow(state);
  if (!more) {
    return Box14({ flexDirection: "column", width: "100%", flexGrow: 1, padding: 2 }, Text14({ content: "No extended stats available for this period", fg: COLORS2.dimWhite }));
  }
  const stats = state.data?.windows[state.selectedWindowIndex]?.stats;
  return Box14({ flexDirection: "column", width: "100%", flexGrow: 1 }, Box14({ flexDirection: "row", flexGrow: 1, width: "100%", height: "50%" }, createHourOfDayPanel(more.hourOfDay), createDayOfWeekPanel(dowData)), Box14({ flexDirection: "row", flexGrow: 1, width: "100%", height: "50%" }, createInputOutputPanel(more.inputOutput, {
    totalInputTokens: stats?.totalInputTokens ?? 0,
    totalOutputTokens: stats?.totalOutputTokens ?? 0
  }), createMonthlyBurnPanel(more.monthlyBurn)));
}
function createPage2(state) {
  const more = ensureMoreStats(state);
  if (!more) {
    return Box14({ flexDirection: "column", width: "100%", flexGrow: 1, padding: 2 }, Text14({ content: "No extended stats available for this period", fg: COLORS2.dimWhite }));
  }
  return Box14({ flexDirection: "column", width: "100%", flexGrow: 1 }, Box14({ flexDirection: "row", flexGrow: 1, width: "100%", height: "50%" }, createCacheEconomicsPanel(more.cacheEconomics), createCacheRoiPanel(more.cacheRoi)), Box14({ flexDirection: "row", flexGrow: 1, width: "100%", height: "50%" }, createSessionsPanel(more.sessionMetrics), createTopProjectsPanel(more.projectDrilldown)));
}
function createPage3(state) {
  const more = ensureMoreStats(state);
  if (!more) {
    return Box14({ flexDirection: "column", width: "100%", flexGrow: 1, padding: 2 }, Text14({ content: "No extended stats available for this period", fg: COLORS2.dimWhite }));
  }
  return Box14({ flexDirection: "column", width: "100%", flexGrow: 1 }, Box14({ flexDirection: "row", flexGrow: 1, width: "100%", height: "50%" }, createModelEfficiencyPanel(more.modelEfficiency), createAttributionPanel(more.attribution)), Box14({ flexDirection: "row", flexGrow: 1, width: "100%", height: "50%" }, createTopSessionsPanel(more.sessionDrilldown), createCacheRoiByModelPanel(more.cacheRoi)));
}
function createMatrixView(state) {
  const page = state.matrixPage;
  let pageContent;
  switch (page) {
    case 0:
      pageContent = createPage0(state);
      break;
    case 1:
      pageContent = createPage1(state);
      break;
    case 2:
      pageContent = createPage2(state);
      break;
    case 3:
      pageContent = createPage3(state);
      break;
    default:
      pageContent = createPage0(state);
      break;
  }
  return Box14({ flexDirection: "column", width: "100%", height: "100%", flexGrow: 1 }, pageContent, createPageIndicator(page));
}
var MATRIX_PAGE_COUNT = 4;
var init_bloomberg = __esm(() => {
  init_state();
  init_theme2();
  init_theme2();
  init_time_windows();
  init_data();
  init_matrix_activity();
  init_matrix_io();
  init_matrix_cache();
  init_matrix_sessions();
  init_matrix_efficiency();
});

// packages/tui/dist/panels/advisor.js
import { Box as Box15, Text as Text15 } from "@opentui/core";
function confidenceColor2(c) {
  if (c === "high")
    return COLORS2.green;
  if (c === "medium")
    return COLORS2.amber;
  return COLORS2.dimWhite;
}
function confidenceLabel(c) {
  return `[${c.toUpperCase()}]`;
}
function typeLabel(type) {
  if (type === "model-downgrade")
    return "Model Downgrade";
  if (type === "cache-optimization")
    return "Cache Optimization";
  return "Usage Pattern";
}
function renderRecommendation2(rec) {
  return Box15({ flexDirection: "column", width: "100%", paddingLeft: 1, paddingRight: 1 }, Box15({ flexDirection: "row", width: "100%" }, Text15({
    content: `\u25B8 ${typeLabel(rec.type)}: ${rec.title}`,
    fg: COLORS2.white,
    attributes: BOLD3
  }), Text15({ content: "  ", fg: COLORS2.dimWhite }), Text15({
    content: confidenceLabel(rec.confidence),
    fg: confidenceColor2(rec.confidence),
    attributes: BOLD3
  })), Text15({
    content: `  ${rec.description}. Saves ${formatCost15(rec.monthlySavings)}/mo`,
    fg: COLORS2.dimWhite
  }), Text15({ content: "", fg: COLORS2.dimWhite }));
}
function createAdvisorPanel(state, report) {
  if (!report) {
    return Box15({
      flexDirection: "column",
      width: "100%",
      flexGrow: 1,
      borderStyle: "single",
      borderColor: COLORS2.dimWhite,
      paddingLeft: 1,
      paddingRight: 1
    }, Text15({ content: " Advisor ", fg: COLORS2.amber, attributes: BOLD3 }), Text15({ content: "", fg: COLORS2.dimWhite }), Text15({ content: "No event data available for analysis", fg: COLORS2.dimWhite }));
  }
  const recs = report.recommendations;
  const maxOffset = Math.max(0, recs.length - VISIBLE_ROWS);
  const offset = Math.min(state.advisorScrollOffset, maxOffset);
  const visibleRecs = recs.slice(offset, offset + VISIBLE_ROWS);
  const summaryRow = Box15({ flexDirection: "row", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text15({
    content: `Current: ${formatCost15(report.totalCurrentMonthlyCost)}/mo`,
    fg: COLORS2.white
  }), Text15({ content: "  \u2192  ", fg: COLORS2.dimWhite }), Text15({
    content: `Projected: ${formatCost15(report.totalProjectedMonthlyCost)}/mo`,
    fg: COLORS2.green
  }), Text15({ content: "  |  ", fg: COLORS2.dimWhite }), Text15({
    content: `Savings: ${formatCost15(report.totalMonthlySavings)}/mo`,
    fg: COLORS2.amber,
    attributes: BOLD3
  }));
  const recNodes = recs.length === 0 ? [Text15({ content: "  No optimization opportunities detected", fg: COLORS2.dimWhite })] : visibleRecs.map((r) => renderRecommendation2(r));
  const scrollIndicators = [];
  if (offset > 0) {
    scrollIndicators.push(Text15({ content: `  ${offset} more above`, fg: COLORS2.dimWhite }));
  }
  const below = recs.length - offset - visibleRecs.length;
  if (below > 0) {
    scrollIndicators.push(Text15({ content: `  ${below} more below`, fg: COLORS2.dimWhite }));
  }
  return Box15({
    flexDirection: "column",
    width: "100%",
    flexGrow: 1,
    borderStyle: "single",
    borderColor: COLORS2.dimWhite
  }, Text15({ content: " Advisor ", fg: COLORS2.amber, attributes: BOLD3 }), summaryRow, Text15({ content: "", fg: COLORS2.dimWhite }), ...recNodes, ...scrollIndicators);
}
var VISIBLE_ROWS = 10;
var init_advisor3 = __esm(() => {
  init_theme2();
});

// packages/tui/dist/panels/focus.js
import { Box as Box16, Text as Text16 } from "@opentui/core";
function formatHours(ms) {
  if (ms === null || ms <= 0)
    return "0.0h";
  return `${(ms / 3600000).toFixed(1)}h`;
}
function formatTokPerHour(tokPerHour) {
  return `${formatTokens15(tokPerHour)}/hr`;
}
function renderEntry(entry, rank, sessionColWidth) {
  const barWidth = 10;
  const ratio = Math.min(entry.score / 100, 1);
  const bar = asciiBar(ratio, barWidth);
  const rankStr = padLeft(`${rank}.`, 3);
  const scoreStr = padLeft(`${Math.round(entry.score)}`, 4);
  const label = truncate3(entry.label || entry.sessionId, sessionColWidth);
  const startDate = entry.start ? formatShortDate(entry.start.slice(0, 10)) : "";
  const duration = formatHours(entry.durationMs);
  const density = formatTokPerHour(entry.tokensPerHour);
  const cost = formatCost15(entry.cost);
  return Box16({ flexDirection: "column", width: "100%", paddingLeft: 1, paddingRight: 1 }, Box16({ flexDirection: "row", width: "100%" }, Text16({ content: `${rankStr} `, fg: COLORS2.dimWhite }), Text16({ content: bar, fg: COLORS2.green }), Text16({ content: ` ${scoreStr}  `, fg: COLORS2.amber, attributes: BOLD3 }), Text16({ content: padRight(label, sessionColWidth + 2), fg: COLORS2.white }), Text16({ content: padLeft(startDate, 8), fg: COLORS2.dimWhite }), Text16({ content: padLeft(duration, 7), fg: COLORS2.cyan }), Text16({ content: padLeft(density, 13), fg: COLORS2.green }), Text16({ content: padLeft(cost, 10), fg: COLORS2.amber })), Text16({
    content: `      \u2192 ${entry.rationale.join("; ")}`,
    fg: COLORS2.dimWhite
  }));
}
function createFocusPanel(state, report) {
  if (!report || report.entries.length === 0) {
    return Box16({
      flexDirection: "column",
      width: "100%",
      flexGrow: 1,
      borderStyle: "single",
      borderColor: COLORS2.dimWhite,
      paddingLeft: 1,
      paddingRight: 1
    }, Text16({ content: " Focus Sessions ", fg: COLORS2.amber, attributes: BOLD3 }), Text16({ content: "", fg: COLORS2.dimWhite }), Text16({
      content: "No session data available. Focus requires event-level provider data.",
      fg: COLORS2.dimWhite
    }));
  }
  const entries = report.entries.slice(0, MAX_ENTRIES);
  const offset = state.focusScrollOffset;
  const visible = entries.slice(offset, offset + VISIBLE_ROWS2);
  const SESSION_MIN_WIDTH = 12;
  const SESSION_MAX_WIDTH = 36;
  const rawLabels = visible.map((e) => (e.label || e.sessionId).length);
  const maxRaw = rawLabels.length > 0 ? Math.max(...rawLabels) : SESSION_MIN_WIDTH;
  const sessionColWidth = Math.min(SESSION_MAX_WIDTH, Math.max(SESSION_MIN_WIDTH, maxRaw));
  const scrollIndicators = [];
  if (offset > 0) {
    scrollIndicators.push(Text16({ content: `  ${offset} more above`, fg: COLORS2.dimWhite }));
  }
  const below = entries.length - offset - visible.length;
  if (below > 0) {
    scrollIndicators.push(Text16({ content: `  ${below} more below`, fg: COLORS2.dimWhite }));
  }
  const columnHeader = Box16({ flexDirection: "row", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text16({ content: padRight("", 4), fg: COLORS2.dimWhite }), Text16({ content: padRight("", 10), fg: COLORS2.dimWhite }), Text16({ content: padRight("Score", 6), fg: COLORS2.dimWhite }), Text16({ content: padRight("Session", sessionColWidth + 2), fg: COLORS2.dimWhite }), Text16({ content: padLeft("Date", 8), fg: COLORS2.dimWhite }), Text16({ content: padLeft("Dur", 7), fg: COLORS2.dimWhite }), Text16({ content: padLeft("Density", 13), fg: COLORS2.dimWhite }), Text16({ content: padLeft("Cost", 10), fg: COLORS2.dimWhite }));
  return Box16({
    flexDirection: "column",
    width: "100%",
    flexGrow: 1,
    borderStyle: "single",
    borderColor: COLORS2.dimWhite
  }, Text16({ content: " Focus Sessions ", fg: COLORS2.amber, attributes: BOLD3 }), Box16({ flexDirection: "row", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text16({
    content: `Scoring: ${report.method}`,
    fg: COLORS2.dimWhite
  })), Text16({ content: "", fg: COLORS2.dimWhite }), columnHeader, ...visible.map((e, i) => renderEntry(e, offset + i + 1, sessionColWidth)), ...scrollIndicators);
}
var VISIBLE_ROWS2 = 12, MAX_ENTRIES = 20;
var init_focus2 = __esm(() => {
  init_theme2();
});

// packages/tui/dist/panels/explain.js
import { Box as Box17, Text as Text17 } from "@opentui/core";
function renderEvidenceTable2(title, rows) {
  if (rows.length === 0)
    return Box17({ flexDirection: "column", width: "100%" });
  const header = Box17({ flexDirection: "row", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text17({ content: padRight(title, 22), fg: COLORS2.amber, attributes: BOLD3 }), Text17({ content: padLeft("Tokens", 12), fg: COLORS2.dimWhite }), Text17({ content: padLeft("Share", 10), fg: COLORS2.dimWhite }), Text17({ content: padLeft("Cost", 12), fg: COLORS2.dimWhite }));
  const rowNodes = rows.slice(0, 8).map((row) => Box17({ flexDirection: "row", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text17({ content: padRight(row.label, 22), fg: COLORS2.white }), Text17({ content: padLeft(formatTokens15(row.tokens), 12), fg: COLORS2.green }), Text17({ content: padLeft(formatPercent5(row.share), 10), fg: COLORS2.cyan }), Text17({ content: padLeft(formatCost15(row.cost), 12), fg: COLORS2.amber })));
  return Box17({ flexDirection: "column", width: "100%" }, header, ...rowNodes, Text17({ content: "", fg: COLORS2.dimWhite }));
}
function renderAnomalies(anomalies) {
  if (anomalies.length === 0)
    return Box17({ flexDirection: "column", width: "100%" });
  return Box17({ flexDirection: "column", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text17({ content: "Anomalies:", fg: COLORS2.amber, attributes: BOLD3 }), ...anomalies.map((a) => Text17({
    content: `\u26A0 ${a.title}: ${a.detail}`,
    fg: COLORS2.red
  })));
}
function createExplainPanel(report, explainDate) {
  const dateLabel = explainDate ? formatShortDate(explainDate) : "\u2014";
  if (!report) {
    return Box17({
      flexDirection: "column",
      width: "100%",
      flexGrow: 1,
      borderStyle: "single",
      borderColor: COLORS2.dimWhite,
      paddingLeft: 1,
      paddingRight: 1
    }, Text17({
      content: ` Explain: ${dateLabel} \u25C4 \u25BA `,
      fg: COLORS2.amber,
      attributes: BOLD3
    }), Text17({ content: "", fg: COLORS2.dimWhite }), Text17({ content: "No data available for this date", fg: COLORS2.dimWhite }));
  }
  const summaryNodes = report.summary.map((s) => Text17({ content: `\u2022 ${s}`, fg: COLORS2.white }));
  return Box17({
    flexDirection: "column",
    width: "100%",
    flexGrow: 1,
    borderStyle: "single",
    borderColor: COLORS2.dimWhite
  }, Text17({
    content: ` Explain: ${dateLabel} \u25C4 \u25BA `,
    fg: COLORS2.amber,
    attributes: BOLD3
  }), Box17({ flexDirection: "column", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text17({
    content: `"${report.headline}"`,
    fg: COLORS2.cyan,
    attributes: BOLD3
  }), Text17({ content: "", fg: COLORS2.dimWhite }), Text17({
    content: `Tokens: ${formatTokens15(report.totalTokens)}  Cost: ${formatCost15(report.totalCost)}  vs 7d avg: ${report.comparedTo7dAverage >= 0 ? "+" : ""}${(report.comparedTo7dAverage * 100).toFixed(0)}%  vs 30d avg: ${report.comparedTo30dAverage >= 0 ? "+" : ""}${(report.comparedTo30dAverage * 100).toFixed(0)}%`,
    fg: COLORS2.white
  }), Text17({ content: "", fg: COLORS2.dimWhite }), Text17({ content: "Summary:", fg: COLORS2.amber, attributes: BOLD3 }), ...summaryNodes, Text17({ content: "", fg: COLORS2.dimWhite })), renderEvidenceTable2("Top Providers", report.topProviders), renderEvidenceTable2("Top Models", report.topModels), renderAnomalies(report.anomalies));
}
var init_explain2 = __esm(() => {
  init_theme2();
});

// packages/tui/dist/panels/compare.js
import { Box as Box18, Text as Text18 } from "@opentui/core";
function deltaStr(value, isPercent) {
  const sign = value >= 0 ? "+" : "";
  if (isPercent)
    return `${sign}${(value * 100).toFixed(1)}%`;
  return `${sign}${value.toFixed(1)}`;
}
function deltaArrow(value) {
  return value >= 0 ? "\u25B2" : "\u25BC";
}
function buildMetricRows(output2) {
  const a = output2.periodB.stats;
  const b = output2.periodA.stats;
  const d = output2.deltas;
  return [
    {
      label: "Tokens",
      current: formatTokens15(a.totalTokens),
      previous: formatTokens15(b.totalTokens),
      delta: d.tokens,
      deltaLabel: `${deltaArrow(d.tokens)} ${deltaStr(d.tokens, true)}`,
      invertColor: false
    },
    {
      label: "Cost",
      current: formatCost15(a.totalCost),
      previous: formatCost15(b.totalCost),
      delta: d.cost,
      deltaLabel: `${deltaArrow(d.cost)} ${deltaStr(d.cost, true)}`,
      invertColor: true
    },
    {
      label: "Active Days",
      current: `${a.activeDays}`,
      previous: `${b.activeDays}`,
      delta: d.activeDays,
      deltaLabel: `${deltaArrow(d.activeDays)} ${d.activeDays >= 0 ? "+" : ""}${d.activeDays}`,
      invertColor: false
    },
    {
      label: "Avg Daily Tokens",
      current: formatTokens15(a.averageDailyTokens),
      previous: formatTokens15(b.averageDailyTokens),
      delta: d.averageDailyTokens,
      deltaLabel: `${deltaArrow(d.averageDailyTokens)} ${deltaStr(d.averageDailyTokens, true)}`,
      invertColor: false
    },
    {
      label: "Cache Hit Rate",
      current: formatPercent5(a.cacheHitRate),
      previous: formatPercent5(b.cacheHitRate),
      delta: d.cacheHitRate,
      deltaLabel: `${deltaArrow(d.cacheHitRate)} ${d.cacheHitRate >= 0 ? "+" : ""}${(d.cacheHitRate * 100).toFixed(1)}pp`,
      invertColor: false
    },
    {
      label: "Current Streak",
      current: `${a.currentStreak}d`,
      previous: `${b.currentStreak}d`,
      delta: d.streak,
      deltaLabel: `${deltaArrow(d.streak)} ${d.streak >= 0 ? "+" : ""}${d.streak}d`,
      invertColor: false
    }
  ];
}
function renderMetricRow(row) {
  const isPositive = row.delta >= 0;
  const deltaColor = row.invertColor ? isPositive ? COLORS2.red : COLORS2.green : isPositive ? COLORS2.green : COLORS2.red;
  return Box18({ flexDirection: "row", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text18({ content: padRight(row.label, 20), fg: COLORS2.white }), Text18({ content: padLeft(row.current, 14), fg: COLORS2.green }), Text18({ content: padLeft(row.previous, 14), fg: COLORS2.dimWhite }), Text18({ content: padLeft(row.deltaLabel, 18), fg: deltaColor }));
}
function createComparePanel(state, output2) {
  const windowLabel = WINDOW_LABELS[state.selectedWindowIndex] ?? "ALL";
  if (!output2) {
    return Box18({
      flexDirection: "column",
      width: "100%",
      flexGrow: 1,
      borderStyle: "single",
      borderColor: COLORS2.dimWhite,
      paddingLeft: 1,
      paddingRight: 1
    }, Text18({ content: ` Compare: ${windowLabel} `, fg: COLORS2.amber, attributes: BOLD3 }), Text18({ content: "", fg: COLORS2.dimWhite }), Text18({ content: "No data available for comparison", fg: COLORS2.dimWhite }));
  }
  const currentLabel = `${formatShortDate(output2.periodB.range.since)} \u2013 ${formatShortDate(output2.periodB.range.until)}`;
  const previousLabel = `${formatShortDate(output2.periodA.range.since)} \u2013 ${formatShortDate(output2.periodA.range.until)}`;
  const metricRows = buildMetricRows(output2);
  const offset = state.compareScrollOffset;
  const visible = metricRows.slice(offset);
  const headerRow2 = Box18({ flexDirection: "row", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text18({ content: padRight("Metric", 20), fg: COLORS2.dimWhite }), Text18({ content: padLeft("Current", 14), fg: COLORS2.dimWhite }), Text18({ content: padLeft("Previous", 14), fg: COLORS2.dimWhite }), Text18({ content: padLeft("Delta", 18), fg: COLORS2.dimWhite }));
  const separator = Box18({ flexDirection: "row", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text18({ content: "\u2500".repeat(66), fg: COLORS2.dimWhite }));
  return Box18({
    flexDirection: "column",
    width: "100%",
    flexGrow: 1,
    borderStyle: "single",
    borderColor: COLORS2.dimWhite
  }, Text18({ content: ` Compare: ${windowLabel} `, fg: COLORS2.amber, attributes: BOLD3 }), Box18({ flexDirection: "row", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text18({ content: `Current (${currentLabel})`, fg: COLORS2.cyan }), Text18({ content: "  vs  ", fg: COLORS2.dimWhite }), Text18({ content: `Previous (${previousLabel})`, fg: COLORS2.dimWhite })), Text18({ content: "", fg: COLORS2.dimWhite }), headerRow2, separator, ...visible.map(renderMetricRow));
}
var init_compare2 = __esm(() => {
  init_theme2();
  init_state();
});

// packages/tui/dist/panels/export.js
import { Box as Box19, Text as Text19 } from "@opentui/core";
function renderOption(opt, isDisabled) {
  return Box19({ flexDirection: "column", width: "100%", paddingLeft: 2, paddingRight: 1 }, Box19({ flexDirection: "row", width: "100%" }, Text19({
    content: `[${opt.key}]`,
    fg: isDisabled ? COLORS2.dimWhite : COLORS2.amber,
    attributes: BOLD3
  }), Text19({ content: `  ${opt.label}`, fg: isDisabled ? COLORS2.dimWhite : COLORS2.white, attributes: BOLD3 })), Text19({
    content: `    ${opt.description}`,
    fg: COLORS2.dimWhite
  }), Text19({ content: "", fg: COLORS2.dimWhite }));
}
function createExportPanel(state) {
  const hasData = !!state.data && state.data.providers.length > 0;
  const status = state.exportStatus;
  const statusNode = status ? Text19({
    content: `  ${status}`,
    fg: status.startsWith("Error") ? COLORS2.red : COLORS2.green,
    attributes: BOLD3
  }) : null;
  return Box19({
    flexDirection: "column",
    width: "100%",
    flexGrow: 1,
    borderStyle: "single",
    borderColor: COLORS2.dimWhite
  }, Text19({ content: " Export ", fg: COLORS2.amber, attributes: BOLD3 }), Text19({ content: "", fg: COLORS2.dimWhite }), Box19({ flexDirection: "column", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text19({
    content: hasData ? "Press a key to export your usage data:" : "No data loaded \u2014 load data first before exporting.",
    fg: hasData ? COLORS2.white : COLORS2.dimWhite
  })), Text19({ content: "", fg: COLORS2.dimWhite }), ...EXPORT_OPTIONS.map((opt) => renderOption(opt, !hasData)), ...statusNode ? [statusNode] : []);
}
var EXPORT_OPTIONS;
var init_export = __esm(() => {
  init_theme2();
  EXPORT_OPTIONS = [
    {
      key: "p",
      label: "Export PNG",
      description: "Render a terminal-card PNG and save to tokenleak.png"
    },
    {
      key: "w",
      label: "Wrapped PNG",
      description: "Generate the AI Wrapped infographic and save to tokenleak-wrapped.png"
    },
    {
      key: "l",
      label: "Wrapped Live",
      description: "Launch the AI Wrapped presentation in your browser"
    }
  ];
});

// packages/tui/dist/panels/wrapped.js
import { Box as Box20, Text as Text20 } from "@opentui/core";
function centerPad(s, width) {
  if (s.length >= width)
    return s.slice(0, width);
  const left = Math.floor((width - s.length) / 2);
  const right = width - s.length - left;
  return " ".repeat(left) + s + " ".repeat(right);
}
function bigStat(label, value, valueColor) {
  return Box20({ flexDirection: "column", width: STAT_COL_WIDTH, alignItems: "center" }, Text20({ content: centerPad(label, STAT_COL_WIDTH), fg: COLORS2.dimWhite }), Text20({ content: centerPad(value, STAT_COL_WIDTH), fg: valueColor, attributes: BOLD3 }));
}
function createWrappedPanel(stats, achievements, providers, scrollOffset, more) {
  if (!stats) {
    return Box20({
      flexDirection: "column",
      width: "100%",
      flexGrow: 1,
      borderStyle: "double",
      borderColor: COLORS2.amber,
      padding: 1
    }, Text20({ content: " YOUR AI WRAPPED ", fg: COLORS2.amber, attributes: BOLD3 }), Text20({ content: "No data available", fg: COLORS2.dimWhite }));
  }
  const totalDays = stats.totalDays || 1;
  const activePct = `${stats.activeDays} / ${totalDays}`;
  const contentRows = [];
  const statRow5 = (...cells) => Box20({ flexDirection: "row", width: "100%", justifyContent: "space-evenly" }, ...cells);
  contentRows.push(Text20({ content: "", fg: COLORS2.dimWhite }), statRow5(bigStat("TOTAL TOKENS", formatTokens15(stats.totalTokens), COLORS2.green), bigStat("TOTAL COST", formatCost15(stats.totalCost), COLORS2.amber), bigStat("ACTIVE DAYS", activePct, COLORS2.cyan)), Text20({ content: "", fg: COLORS2.dimWhite }), statRow5(bigStat("STREAK", `${stats.currentStreak} days`, COLORS2.green), bigStat("CACHE HIT", `${(stats.cacheHitRate * 100).toFixed(1)}%`, COLORS2.cyan), bigStat("AVG DAILY", formatTokens15(stats.averageDailyTokens) + " tok", COLORS2.green)), Text20({ content: "", fg: COLORS2.dimWhite }), statRow5(bigStat("INPUT TOKENS", formatTokens15(stats.totalInputTokens), COLORS2.green), bigStat("OUTPUT TOKENS", formatTokens15(stats.totalOutputTokens), COLORS2.amber), bigStat("PEAK DAY", stats.peakDay ? `${stats.peakDay.date}` : "N/A", COLORS2.cyan)));
  if (achievements.length > 0) {
    contentRows.push(Text20({
      content: "\u2500\u2500\u2500 ACHIEVEMENTS " + "\u2500".repeat(40),
      fg: COLORS2.amber,
      attributes: BOLD3
    }));
    for (const a of achievements) {
      const icon = ACHIEVEMENT_ICONS[a.icon] ?? "\u2605";
      contentRows.push(Box20({ flexDirection: "row", width: "100%" }, Text20({ content: `  ${icon} `, fg: COLORS2.amber }), Text20({ content: padRight(a.title, 22), fg: COLORS2.green, attributes: BOLD3 }), Text20({ content: a.subtitle, fg: COLORS2.dimWhite })));
    }
  }
  if (more) {
    contentRows.push(Text20({
      content: "\u2500\u2500\u2500 USAGE BREAKDOWN " + "\u2500".repeat(37),
      fg: COLORS2.amber,
      attributes: BOLD3
    }));
    const io = more.inputOutput;
    const ioRatio = io.inputPerOutput !== null ? `${io.inputPerOutput.toFixed(1)}:1` : "-";
    const outputShare = `${(io.outputShare * 100).toFixed(1)}%`;
    const cacheReuse = more.cacheEconomics.reuseRatio !== null ? `${more.cacheEconomics.reuseRatio.toFixed(1)}x` : "-";
    contentRows.push(Box20({ flexDirection: "row", width: "100%" }, Text20({ content: "  I/O Ratio: ", fg: COLORS2.dimWhite }), Text20({ content: padRight(ioRatio, 10), fg: COLORS2.green }), Text20({ content: "Output Share: ", fg: COLORS2.dimWhite }), Text20({ content: padRight(outputShare, 10), fg: COLORS2.green }), Text20({ content: "Cache Reuse: ", fg: COLORS2.dimWhite }), Text20({ content: cacheReuse, fg: COLORS2.cyan })));
    const burn = more.monthlyBurn;
    const projCost = formatCost15(burn.projectedCost);
    const dailyRate = burn.observedDays > 0 ? formatCost15(burn.projectedCost / (burn.calendarDays || 30)) : "-";
    contentRows.push(Box20({ flexDirection: "row", width: "100%" }, Text20({ content: "  Monthly Burn: ", fg: COLORS2.dimWhite }), Text20({ content: `${projCost} projected`, fg: COLORS2.amber }), Text20({ content: "    Burn Rate: ", fg: COLORS2.dimWhite }), Text20({ content: `${dailyRate}/day`, fg: COLORS2.amber })));
  }
  const models = stats.topModels.slice(0, 5);
  if (models.length > 0) {
    const maxTokens = Math.max(...models.map((m) => m.tokens), 1);
    contentRows.push(Text20({
      content: "\u2500\u2500\u2500 TOP MODELS " + "\u2500".repeat(42),
      fg: COLORS2.amber,
      attributes: BOLD3
    }));
    for (let i = 0;i < models.length; i++) {
      const m = models[i];
      const ratio = m.tokens / maxTokens;
      const isTop = i === 0;
      contentRows.push(Box20({ flexDirection: "row", width: "100%" }, Text20({ content: `  ${i + 1}. `, fg: COLORS2.dimWhite }), Text20({
        content: padRight(m.model, 22),
        fg: isTop ? COLORS2.amber : COLORS2.green,
        attributes: isTop ? BOLD3 : undefined
      }), Text20({ content: asciiBar(ratio, 15), fg: isTop ? COLORS2.amber : COLORS2.green }), Text20({ content: `  ${m.percentage.toFixed(1)}%`, fg: COLORS2.white }), Text20({ content: padLeft(formatCost15(m.cost), 10), fg: COLORS2.amber })));
    }
  }
  if (providers.length > 0) {
    const totalTokens = providers.reduce((s, p) => s + p.totalTokens, 0) || 1;
    contentRows.push(Text20({
      content: "\u2500\u2500\u2500 TOP PROVIDERS " + "\u2500".repeat(39),
      fg: COLORS2.amber,
      attributes: BOLD3
    }));
    for (const p of providers.slice(0, 5)) {
      const pct = (p.totalTokens / totalTokens * 100).toFixed(0);
      contentRows.push(Box20({ flexDirection: "row", width: "100%" }, Text20({ content: `  ${padRight(p.displayName, 16)}`, fg: COLORS2.green, attributes: BOLD3 }), Text20({ content: padLeft(`${formatTokens15(p.totalTokens)} tokens`, 16), fg: COLORS2.green }), Text20({ content: padLeft(formatCost15(p.totalCost), 10), fg: COLORS2.amber }), Text20({ content: padLeft(`${pct}%`, 7), fg: COLORS2.white })));
    }
  }
  const visible = contentRows.slice(scrollOffset);
  return Box20({
    flexDirection: "column",
    width: "100%",
    flexGrow: 1,
    borderStyle: "double",
    borderColor: COLORS2.amber,
    padding: 1
  }, Text20({ content: "               YOUR AI WRAPPED", fg: COLORS2.amber, attributes: BOLD3 }), ...visible);
}
var ACHIEVEMENT_ICONS, STAT_COL_WIDTH = 24;
var init_wrapped2 = __esm(() => {
  init_theme2();
  ACHIEVEMENT_ICONS = {
    fire: "\uD83D\uDD25",
    star: "\u2B50",
    circle: "\u26AA",
    diamond: "\uD83D\uDC8E",
    bolt: "\u26A1",
    trophy: "\uD83C\uDFC6",
    target: "\uD83C\uDFAF",
    mountain: "\u26F0\uFE0F",
    palette: "\uD83C\uDFA8",
    calendar: "\uD83D\uDCC5",
    moon: "\uD83C\uDF19",
    sun: "\u2600\uFE0F",
    rocket: "\uD83D\uDE80"
  };
});

// packages/tui/dist/panels/help.js
import { Box as Box21, Text as Text21 } from "@opentui/core";
function helpSection(title, items) {
  const children = [
    Text21({ content: title, fg: COLORS2.amber, attributes: BOLD3 }),
    Text21({ content: "", fg: COLORS2.dimWhite })
  ];
  for (const [key, desc] of items) {
    children.push(Box21({ flexDirection: "row", width: "100%" }, Text21({ content: `  ${key.padEnd(14)}`, fg: COLORS2.cyan, attributes: BOLD3 }), Text21({ content: desc, fg: COLORS2.white })));
  }
  children.push(Text21({ content: "", fg: COLORS2.dimWhite }));
  return children;
}
function createHelpPanel() {
  return Box21({
    flexDirection: "column",
    width: "100%",
    flexGrow: 1,
    borderStyle: "single",
    borderColor: COLORS2.amber,
    padding: 1
  }, Text21({ content: " HELP ", fg: COLORS2.amber, attributes: BOLD3 }), Text21({ content: "", fg: COLORS2.dimWhite }), Box21({ flexDirection: "row", width: "100%", flexGrow: 1 }, Box21({ flexDirection: "column", flexGrow: 1 }, ...helpSection("NAVIGATION", [
    ["\u2192", "Next view"],
    ["\u2190", "Prev view"],
    ["Tab / >", "Next time period"],
    ["Shift+Tab / <", "Prev time period"],
    ["j / \u2193", "Scroll down"],
    ["k / \u2191", "Scroll up"],
    ["[ / ]", "Matrix page (in Matrix)"]
  ]), ...helpSection("ACTIONS", [
    ["s", "Toggle sort mode"],
    ["r", "Refresh data"],
    ["c", "Open Cursor setup"],
    ["q", "Quit"]
  ]), ...helpSection("EXPORT VIEW", [
    ["p", "Save PNG"],
    ["w", "Save Wrapped PNG"],
    ["l", "Launch Live Server"]
  ])), Box21({ flexDirection: "column", flexGrow: 1 }, ...helpSection("VIEWS", [
    ["1", "Overview"],
    ["2", "Matrix"],
    ["3", "Advisor"],
    ["4", "Focus"],
    ["5", "Explain"],
    ["6", "Compare"],
    ["7", "Export"],
    ["8", "Wrapped"],
    ["?", "Help"]
  ]), ...helpSection("EXPLAIN VIEW", [
    ["h", "Previous day"],
    ["l", "Next day"]
  ]))), Text21({ content: "                  Press ? or Esc to close", fg: COLORS2.dimWhite }));
}
var init_help = __esm(() => {
  init_theme2();
});

// packages/tui/dist/panels/replay.js
import { Box as Box22, Text as Text22 } from "@opentui/core";
function formatTime2(iso) {
  const date = new Date(iso);
  return `${String(date.getUTCHours()).padStart(2, "0")}:${String(date.getUTCMinutes()).padStart(2, "0")}`;
}
function formatDuration7(ms) {
  if (ms <= 0)
    return "0s";
  const hours = Math.floor(ms / 3600000);
  const minutes = Math.floor(ms % 3600000 / 60000);
  if (hours > 0)
    return `${hours}h ${minutes}m`;
  return `${minutes}m`;
}
function renderActivityBar2(report) {
  if (report.events.length === 0) {
    return Text22({ content: "  (no events)", fg: COLORS2.dimWhite });
  }
  const slotTokens = new Array(HEATMAP_SLOTS2).fill(0);
  for (const event of report.events) {
    const date = new Date(event.timestamp);
    const slot = Math.min(date.getUTCHours() * 2 + Math.floor(date.getUTCMinutes() / 30), HEATMAP_SLOTS2 - 1);
    slotTokens[slot] += event.totalTokens;
  }
  const maxTokens = Math.max(...slotTokens);
  let bar = "";
  for (let i = 0;i < HEATMAP_SLOTS2; i++) {
    const level = maxTokens > 0 ? Math.round(slotTokens[i] / maxTokens * (HEATMAP_BLOCKS3.length - 1)) : 0;
    bar += HEATMAP_BLOCKS3[level];
  }
  const firstTime = formatTime2(report.events[0].timestamp);
  const lastTime = formatTime2(report.events[report.events.length - 1].timestamp);
  return Box22({ flexDirection: "column", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text22({ content: bar, fg: COLORS2.green }), Text22({ content: `${firstTime}${" ".repeat(Math.max(1, HEATMAP_SLOTS2 - firstTime.length - lastTime.length))}${lastTime}`, fg: COLORS2.dimWhite }));
}
function renderFlowBlockCard2(block, expanded) {
  const timeRange = `${formatTime2(block.start)}\u2013${formatTime2(block.end)}`;
  const headerText = `${timeRange}  ${block.label}  |  ${block.eventCount} events  |  ${formatTokens15(block.totalTokens)} tok  |  ${formatCost15(block.cost)}`;
  const expandIcon = expanded ? "\u25BC" : "\u25B6";
  const headerLine = Text22({
    content: `  ${expandIcon} ${headerText}`,
    fg: block.label === "Deep Flow" ? COLORS2.cyan : block.label === "Quick Lookup" ? COLORS2.dimWhite : COLORS2.white,
    attributes: BOLD3
  });
  if (!expanded) {
    return Box22({ flexDirection: "column", width: "100%" }, headerLine);
  }
  const children = [headerLine];
  children.push(Text22({
    content: `    Model: ${block.dominantModel}${block.modelSwitches > 0 ? ` (${block.modelSwitches} switch${block.modelSwitches === 1 ? "" : "es"})` : ""}`,
    fg: COLORS2.white
  }));
  for (const event of block.events) {
    const time = formatTime2(event.timestamp);
    const cacheRate = event.inputTokens + event.cacheReadTokens > 0 ? event.cacheReadTokens / (event.inputTokens + event.cacheReadTokens) : 0;
    const line2 = `    ${padRight(time, 7)} ${padRight(truncate3(event.model, 18), 19)} ${padLeft(formatTokens15(event.totalTokens), 8)}  cache:${formatPercent5(cacheRate).padStart(4)}  ${formatCost15(event.cost).padStart(8)}`;
    children.push(Text22({ content: line2, fg: COLORS2.white }));
  }
  const trend = block.cacheHitRateTrend;
  if (trend.length > 1) {
    const first = (trend[0] * 100).toFixed(0);
    const last = (trend[trend.length - 1] * 100).toFixed(0);
    if (first !== last) {
      const direction = Number(last) > Number(first) ? "\u2191" : "\u2193";
      children.push(Text22({
        content: `    Cache: ${first}% \u2192 ${last}% ${direction}`,
        fg: Number(last) > Number(first) ? COLORS2.green : COLORS2.red
      }));
    }
  }
  children.push(Text22({ content: "", fg: COLORS2.dimWhite }));
  return Box22({ flexDirection: "column", width: "100%" }, ...children);
}
function renderPulseChart2(velocity) {
  if (velocity.length === 0) {
    return Box22({ flexDirection: "column", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text22({ content: "Pulse", fg: COLORS2.amber, attributes: BOLD3 }), Text22({ content: "  (no data)", fg: COLORS2.dimWhite }));
  }
  const maxTpm = Math.max(...velocity.map((v) => v.tokensPerMinute));
  const chartWidth = Math.min(velocity.length, 60);
  const chartHeight = 5;
  const step = velocity.length / chartWidth;
  const rows = [];
  for (let row = 0;row < chartHeight; row++) {
    let line2 = "";
    for (let col = 0;col < chartWidth; col++) {
      const idx = Math.floor(col * step);
      const tpm = velocity[idx].tokensPerMinute;
      const normalizedHeight = maxTpm > 0 ? tpm / maxTpm * (chartHeight - 1) : 0;
      const threshold = chartHeight - 1 - row;
      line2 += normalizedHeight >= threshold ? "\u2588" : " ";
    }
    rows.push(line2);
  }
  const children = [
    Text22({ content: "Pulse (tok/min)", fg: COLORS2.amber, attributes: BOLD3 })
  ];
  for (let i = 0;i < rows.length; i++) {
    const label = i === 0 ? padLeft(formatTokens15(maxTpm), 7) : i === rows.length - 1 ? padLeft("0", 7) : "       ";
    children.push(Text22({ content: `${label} \u2502${rows[i]}`, fg: COLORS2.green }));
  }
  return Box22({ flexDirection: "column", width: "100%", paddingLeft: 1, paddingRight: 1 }, ...children);
}
function renderDaySummary(report) {
  const s = report.summary;
  const parts = [
    `Sessions: ${s.totalSessions}`,
    `Events: ${s.totalEvents}`,
    `Flow: ${formatDuration7(s.flowTimeMs)}`,
    `Think: ${formatDuration7(s.thinkTimeMs)}`,
    `Ratio: ${(s.flowThinkRatio * 100).toFixed(0)}%`
  ];
  if (s.peakMinute) {
    parts.push(`Peak: ${formatTokens15(s.peakMinute.tokensPerMinute)} tok/min at ${formatTime2(s.peakMinute.minute)}`);
  }
  return Box22({ flexDirection: "column", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text22({ content: parts.join("  |  "), fg: COLORS2.white }));
}
function createReplayPanel(report, replayDate, expandedBlocks, scrollOffset) {
  const dateLabel = replayDate ? formatShortDate(replayDate) : "\u2014";
  if (!report) {
    return Box22({
      flexDirection: "column",
      width: "100%",
      flexGrow: 1,
      borderStyle: "single",
      borderColor: COLORS2.dimWhite,
      paddingLeft: 1,
      paddingRight: 1
    }, Text22({
      content: ` Replay: ${dateLabel} \u25C4 \u25BA `,
      fg: COLORS2.amber,
      attributes: BOLD3
    }), Text22({ content: "", fg: COLORS2.dimWhite }), Text22({ content: "No data available for this date", fg: COLORS2.dimWhite }));
  }
  const totalCost = report.events.reduce((sum, e) => sum + e.cost, 0);
  const blockCards = report.flowBlocks.slice(scrollOffset, scrollOffset + 20).map((block) => renderFlowBlockCard2(block, expandedBlocks.has(block.blockIndex)));
  return Box22({
    flexDirection: "column",
    width: "100%",
    flexGrow: 1,
    borderStyle: "single",
    borderColor: COLORS2.dimWhite
  }, Text22({
    content: ` Replay: ${dateLabel} \u25C4 \u25BA `,
    fg: COLORS2.amber,
    attributes: BOLD3
  }), Box22({ flexDirection: "row", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text22({ content: `Total: ${formatCost15(totalCost)}`, fg: COLORS2.green })), Text22({ content: "", fg: COLORS2.dimWhite }), renderActivityBar2(report), Text22({ content: "", fg: COLORS2.dimWhite }), Box22({ flexDirection: "column", width: "100%", paddingLeft: 1, paddingRight: 1 }, Text22({
    content: `Flow Blocks (${report.flowBlocks.length})`,
    fg: COLORS2.amber,
    attributes: BOLD3
  })), ...blockCards, Text22({ content: "", fg: COLORS2.dimWhite }), renderPulseChart2(report.tokenVelocity), Text22({ content: "", fg: COLORS2.dimWhite }), renderDaySummary(report));
}
var HEATMAP_BLOCKS3, HEATMAP_SLOTS2 = 48;
var init_replay2 = __esm(() => {
  init_theme2();
  HEATMAP_BLOCKS3 = [" ", "\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
});

// packages/tui/dist/index.js
var exports_dist2 = {};
__export(exports_dist2, {
  main: () => main
});
import { Box as Box23, Text as Text23, createCliRenderer } from "@opentui/core";
function clearRoot(renderer) {
  const children = renderer.root.getChildren();
  for (const child of children) {
    renderer.root.remove(child.id);
  }
}
function buildContent(state, renderer) {
  if (state.showCursorSetup) {
    const { panel, labelInput, tokenInput } = createCursorSetupPanel(state, renderer, {
      onFieldFocus: (field) => {
        state.cursorSetupField = field;
      },
      onLabelInput: (value) => {
        state.cursorSetupLabel = value;
      },
      onTokenInput: (value) => {
        state.cursorSetupToken = value;
      },
      onSubmit: () => {
        submitCursorSetup(state, renderer);
      }
    });
    labelInput.id = CURSOR_SETUP_LABEL_INPUT_ID;
    tokenInput.id = CURSOR_SETUP_TOKEN_INPUT_ID;
    return panel;
  }
  if (state.showHelp) {
    return createHelpPanel();
  }
  const windowStats = state.data?.windows[state.selectedWindowIndex]?.stats ?? null;
  const daily = state.data ? getDailyForWindow(state.data, state.selectedWindowIndex) : [];
  switch (state.selectedView) {
    case "overview":
      return Box23({ flexDirection: "column", width: "100%", flexGrow: 1 }, createChartPanel(state, daily), createStatsRow(state, windowStats), createModelList(state, windowStats));
    case "matrix":
      return createMatrixView(state);
    case "advisor":
      return createAdvisorPanel(state, ensureAdvisorReport(state));
    case "focus":
      return createFocusPanel(state, ensureFocusReport(state));
    case "explain":
      return createExplainPanel(ensureExplainReport(state), state.explainDate);
    case "compare":
      return createComparePanel(state, ensureCompareOutput(state));
    case "export":
      return createExportPanel(state);
    case "replay":
      return createReplayPanel(ensureReplayReport(state), state.replayDate, state.replayExpandedBlocks, state.replayScrollOffset);
    case "wrapped": {
      const output2 = buildTokenleakOutput(state);
      const achievements = output2 ? computeAchievements(output2) : [];
      const providers = state.data?.providers.map((p) => ({
        displayName: p.displayName,
        totalTokens: p.totalTokens,
        totalCost: p.totalCost
      })) ?? [];
      return createWrappedPanel(windowStats, achievements, providers, state.wrappedScrollOffset, ensureMoreStats(state));
    }
    default:
      return Box23({ flexDirection: "column", width: "100%", flexGrow: 1 });
  }
}
function buildTokenleakOutput(state) {
  if (!state.data || state.data.windows.length === 0)
    return null;
  const windowStats = state.data.windows[state.selectedWindowIndex]?.stats;
  if (!windowStats)
    return null;
  const days = WINDOW_DAYS[state.selectedWindowIndex];
  const today = new Date().toISOString().slice(0, 10);
  const dateRange = days && days > 0 ? { since: (() => {
    const d = new Date;
    d.setDate(d.getDate() - (days - 1));
    return d.toISOString().slice(0, 10);
  })(), until: today } : state.data.dateRange;
  const more = ensureMoreStats(state);
  const output2 = {
    schemaVersion: SCHEMA_VERSION,
    generated: new Date().toISOString(),
    dateRange,
    providers: state.data.providers,
    aggregated: windowStats
  };
  if (more) {
    output2.more = more;
  }
  return output2;
}
function resetCursorSetupForm(state) {
  state.cursorSetupField = "token";
  state.cursorSetupLabel = "";
  state.cursorSetupToken = "";
  state.cursorSetupMessage = null;
  state.cursorSetupSubmitting = false;
}
function openCursorSetup(state) {
  state.showCursorSetup = true;
  state.showHelp = false;
  state.cursorSetupField = "token";
  state.cursorSetupMessage = null;
}
function closeCursorSetup(state) {
  state.showCursorSetup = false;
  state.cursorSetupMessage = null;
  state.cursorSetupSubmitting = false;
}
function applyLoadedData(state, freshData) {
  state.data = freshData;
  state.isLoading = false;
  state.modelScrollOffset = 0;
  state.advisorScrollOffset = 0;
  state.focusScrollOffset = 0;
  state.compareScrollOffset = 0;
  state.wrappedScrollOffset = 0;
  state.replayScrollOffset = 0;
  state.replayExpandedBlocks = new Set;
  state.replayDate = null;
  state.explainDate = null;
  state.cursorSetupStatusOverride = null;
}
async function reloadAllData(state, renderer, failurePrefix) {
  state.isLoading = true;
  invalidateAllCaches(state);
  state.exportStatus = null;
  render(state, renderer);
  try {
    const freshData = await loadAllData();
    applyLoadedData(state, freshData);
  } catch (err) {
    state.isLoading = false;
    state.exportStatus = `${failurePrefix ?? "Refresh failed"}: ${err instanceof Error ? err.message : String(err)}`;
  }
  render(state, renderer);
}
async function submitCursorSetup(state, renderer) {
  if (state.cursorSetupSubmitting) {
    return;
  }
  state.cursorSetupSubmitting = true;
  state.cursorSetupMessage = null;
  render(state, renderer);
  try {
    const token = state.cursorSetupToken.trim();
    const label = state.cursorSetupLabel.trim() || undefined;
    if (token) {
      const validation = await validateCursorSession(token);
      if (!validation.valid) {
        throw new CursorAuthError(validation.error ?? "Invalid session token", validation.reason);
      }
      saveCursorCredentials(token, label);
    }
    const status = await resolveCursorSetupStatus({ attemptSync: true });
    state.cursorSetupStatusOverride = status;
    if (status.state === "ready") {
      resetCursorSetupForm(state);
      closeCursorSetup(state);
      await reloadAllData(state, renderer, "Cursor reload failed");
      return;
    }
    if (!token && status.state === "needs_auth") {
      throw new CursorAuthError("Enter a Cursor session token to continue.");
    }
    state.cursorSetupMessage = status.error ?? "Cursor setup still needs attention.";
  } catch (err) {
    state.cursorSetupMessage = err instanceof Error ? err.message : String(err);
  } finally {
    state.cursorSetupSubmitting = false;
    render(state, renderer);
  }
}
function handleCursorSetupInput(sequence, state, renderer) {
  if (!state.showCursorSetup) {
    return false;
  }
  if (state.cursorSetupSubmitting) {
    return true;
  }
  if (sequence === "\x1B") {
    closeCursorSetup(state);
    render(state, renderer);
    return true;
  }
  if (sequence === "\t" || sequence === "\x1B[Z") {
    state.cursorSetupField = state.cursorSetupField === "token" ? "label" : "token";
    render(state, renderer);
    return true;
  }
  return false;
}
function tryOpenCursorSetup(state, renderer) {
  if (!buildCursorBanner(state)) {
    return false;
  }
  resetCursorSetupForm(state);
  openCursorSetup(state);
  render(state, renderer);
  return true;
}
function handleViewSwitch(mode) {
  if (currentState.selectedView !== mode) {
    currentState.selectedView = mode;
    currentState.modelScrollOffset = 0;
    currentState.advisorScrollOffset = 0;
    currentState.focusScrollOffset = 0;
    currentState.compareScrollOffset = 0;
    currentState.wrappedScrollOffset = 0;
    currentState.replayScrollOffset = 0;
    currentState.replayExpandedBlocks = new Set;
    if (mode === "matrix") {
      currentState.matrixPage = 0;
    }
  }
  render(currentState, currentRenderer);
}
function buildLayout(state, renderer) {
  const cursorBanner = buildCursorBanner(state);
  return Box23({
    flexDirection: "column",
    width: "100%",
    height: "100%",
    backgroundColor: COLORS2.bg
  }, buildHeader(state, renderer, handleViewSwitch), ...cursorBanner ? [cursorBanner] : [], buildContent(state, renderer), buildStatusBar(state));
}
function focusCursorSetupField(state, renderer) {
  if (!state.showCursorSetup) {
    return;
  }
  const targetId = state.cursorSetupField === "label" ? CURSOR_SETUP_LABEL_INPUT_ID : CURSOR_SETUP_TOKEN_INPUT_ID;
  const target = renderer.root.findDescendantById(targetId);
  if (target) {
    target.focus();
  }
}
function render(state, renderer) {
  clearRoot(renderer);
  renderer.root.add(buildLayout(state, renderer));
  focusCursorSetupField(state, renderer);
  renderer.requestRender();
}
function invalidateWindowCaches(state) {
  state.cachedAdvisorReport = null;
  state.cachedCompareOutput = null;
  state.cachedFocusReport = null;
  state.cachedExplainReport = null;
  state.cachedMoreStats = null;
  state.cachedReplayReport = null;
  state.explainDate = null;
  state.replayDate = null;
}
function invalidateAllCaches(state) {
  state.cachedAdvisorReport = null;
  state.cachedFocusReport = null;
  state.cachedExplainReport = null;
  state.cachedCompareOutput = null;
  state.cachedMoreStats = null;
  state.cachedReplayReport = null;
}
function shiftReplayDate(state, direction) {
  if (!state.replayDate)
    return;
  const d = new Date(state.replayDate + "T12:00:00Z");
  d.setUTCDate(d.getUTCDate() + direction);
  state.replayDate = d.toISOString().slice(0, 10);
  state.cachedReplayReport = null;
  state.replayScrollOffset = 0;
  state.replayExpandedBlocks = new Set;
}
function shiftExplainDate(state, direction) {
  if (!state.explainDate)
    return;
  const d = new Date(state.explainDate + "T12:00:00Z");
  d.setUTCDate(d.getUTCDate() + direction);
  state.explainDate = d.toISOString().slice(0, 10);
  state.cachedExplainReport = null;
}
function getScrollableItemCount(state) {
  switch (state.selectedView) {
    case "advisor":
      return ensureAdvisorReport(state)?.recommendations.length ?? 0;
    case "focus": {
      const report = ensureFocusReport(state);
      return Math.min(report?.entries.length ?? 0, 20);
    }
    case "compare":
      return 6;
    case "wrapped":
      return 30;
    case "replay":
      return ensureReplayReport(state)?.flowBlocks.length ?? 0;
    default:
      return 0;
  }
}
function getVisibleCount(view) {
  switch (view) {
    case "advisor":
      return 10;
    case "focus":
      return 12;
    case "compare":
      return 6;
    case "wrapped":
      return 20;
    case "replay":
      return 15;
    default:
      return 10;
  }
}
function getScrollOffset(state) {
  switch (state.selectedView) {
    case "advisor":
      return state.advisorScrollOffset;
    case "focus":
      return state.focusScrollOffset;
    case "compare":
      return state.compareScrollOffset;
    case "wrapped":
      return state.wrappedScrollOffset;
    case "replay":
      return state.replayScrollOffset;
    default:
      return 0;
  }
}
function setScrollOffset(state, value) {
  switch (state.selectedView) {
    case "advisor":
      state.advisorScrollOffset = value;
      break;
    case "focus":
      state.focusScrollOffset = value;
      break;
    case "compare":
      state.compareScrollOffset = value;
      break;
    case "wrapped":
      state.wrappedScrollOffset = value;
      break;
    case "replay":
      state.replayScrollOffset = value;
      break;
  }
}
async function handleExport(key, state, renderer) {
  const output2 = buildTokenleakOutput(state);
  if (!output2) {
    state.exportStatus = "Error: No data loaded";
    render(state, renderer);
    return;
  }
  try {
    if (key === "p") {
      state.exportStatus = "Rendering PNG...";
      render(state, renderer);
      const { PngRenderer: PngRenderer2 } = await Promise.resolve().then(() => (init_dist3(), exports_dist));
      const pngRenderer = new PngRenderer2;
      const buffer = await pngRenderer.render(output2, {
        format: "png",
        theme: "dark",
        width: 120,
        showInsights: true,
        noColor: false,
        output: null
      });
      const { writeFileSync: writeFileSync3 } = await import("fs");
      const outputPath = "tokenleak.png";
      writeFileSync3(outputPath, buffer);
      state.exportStatus = `Saved to ${outputPath}`;
    } else if (key === "w") {
      state.exportStatus = "Rendering Wrapped PNG...";
      render(state, renderer);
      const { renderWrappedPng: renderWrappedPng2 } = await Promise.resolve().then(() => (init_dist3(), exports_dist));
      const buffer = await renderWrappedPng2(output2, { theme: "dark" });
      const { writeFileSync: writeFileSync3 } = await import("fs");
      const outputPath = "tokenleak-wrapped.png";
      writeFileSync3(outputPath, buffer);
      state.exportStatus = `Saved to ${outputPath}`;
    } else if (key === "l") {
      state.exportStatus = "Starting live server...";
      render(state, renderer);
      const { startWrappedLiveServer: startWrappedLiveServer2 } = await Promise.resolve().then(() => (init_dist3(), exports_dist));
      const { port } = await startWrappedLiveServer2(output2);
      state.exportStatus = `Live server running at http://localhost:${port} (Ctrl+C to stop)`;
    }
  } catch (err) {
    state.exportStatus = `Error: ${err instanceof Error ? err.message : String(err)}`;
  }
  render(state, renderer);
}
async function main() {
  const renderer = await createCliRenderer({
    exitOnCtrlC: true,
    backgroundColor: COLORS2.bg,
    useMouse: true
  });
  const state = createInitialState();
  currentState = state;
  currentRenderer = renderer;
  render(state, renderer);
  try {
    const data = await loadAllData();
    applyLoadedData(state, data);
    render(state, renderer);
    renderer.addInputHandler((sequence) => {
      if (handleCursorSetupInput(sequence, state, renderer)) {
        return true;
      }
      if (sequence === "?") {
        state.showHelp = !state.showHelp;
        render(state, renderer);
        return true;
      }
      if (sequence === "\x1B" && state.showHelp) {
        state.showHelp = false;
        render(state, renderer);
        return true;
      }
      if (state.showHelp) {
        if (sequence === "q") {
          renderer.destroy();
          process.exit(0);
        }
        if (sequence === "c") {
          return tryOpenCursorSetup(state, renderer);
        }
        return false;
      }
      if (sequence === "c") {
        return tryOpenCursorSetup(state, renderer);
      }
      if (sequence === "\t" || sequence === ">") {
        state.selectedWindowIndex = (state.selectedWindowIndex + 1) % WINDOW_LABELS.length;
        state.modelScrollOffset = 0;
        invalidateWindowCaches(state);
        render(state, renderer);
        return true;
      }
      if (sequence === "\x1B[Z" || sequence === "<") {
        state.selectedWindowIndex = (state.selectedWindowIndex - 1 + WINDOW_LABELS.length) % WINDOW_LABELS.length;
        state.modelScrollOffset = 0;
        invalidateWindowCaches(state);
        render(state, renderer);
        return true;
      }
      if (sequence === "\x1B[C") {
        const idx = VIEW_ORDER.indexOf(state.selectedView);
        const next = VIEW_ORDER[(idx + 1) % VIEW_ORDER.length];
        handleViewSwitch(next);
        return true;
      }
      if (sequence === "\x1B[D") {
        const idx = VIEW_ORDER.indexOf(state.selectedView);
        const prev = VIEW_ORDER[(idx - 1 + VIEW_ORDER.length) % VIEW_ORDER.length];
        handleViewSwitch(prev);
        return true;
      }
      if ((sequence === "," || sequence === "[") && state.selectedView === "matrix") {
        state.matrixPage = Math.max(0, state.matrixPage - 1);
        render(state, renderer);
        return true;
      }
      if ((sequence === "." || sequence === "]") && state.selectedView === "matrix") {
        state.matrixPage = Math.min(3, state.matrixPage + 1);
        render(state, renderer);
        return true;
      }
      const viewMode = VIEW_KEYS[sequence];
      if (viewMode) {
        handleViewSwitch(viewMode);
        return true;
      }
      if (state.selectedView === "export" && (sequence === "p" || sequence === "w" || sequence === "l")) {
        handleExport(sequence, state, renderer);
        return true;
      }
      if (sequence === "j" || sequence === "\x1B[B") {
        if (state.selectedView === "overview") {
          const windowStats = state.data?.windows[state.selectedWindowIndex]?.stats;
          const modelCount = windowStats?.topModels.length ?? 0;
          const visibleCount = 10;
          const maxOffset = Math.max(0, modelCount - visibleCount);
          if (state.modelScrollOffset < maxOffset) {
            state.modelScrollOffset++;
            render(state, renderer);
          }
          return true;
        }
        if (SCROLLABLE_VIEWS.has(state.selectedView)) {
          const itemCount = getScrollableItemCount(state);
          const visibleCount = getVisibleCount(state.selectedView);
          const maxOffset = Math.max(0, itemCount - visibleCount);
          const current = getScrollOffset(state);
          if (current < maxOffset) {
            setScrollOffset(state, current + 1);
            render(state, renderer);
          }
          return true;
        }
        return false;
      }
      if (sequence === "k" || sequence === "\x1B[A") {
        if (state.selectedView === "overview") {
          if (state.modelScrollOffset > 0) {
            state.modelScrollOffset--;
            render(state, renderer);
          }
          return true;
        }
        if (SCROLLABLE_VIEWS.has(state.selectedView)) {
          const current = getScrollOffset(state);
          if (current > 0) {
            setScrollOffset(state, current - 1);
            render(state, renderer);
          }
          return true;
        }
        return false;
      }
      if (sequence === "h" && state.selectedView === "explain") {
        shiftExplainDate(state, -1);
        render(state, renderer);
        return true;
      }
      if (sequence === "h" && state.selectedView === "replay") {
        shiftReplayDate(state, -1);
        render(state, renderer);
        return true;
      }
      if (sequence === "l" && state.selectedView === "explain") {
        shiftExplainDate(state, 1);
        render(state, renderer);
        return true;
      }
      if (sequence === "l" && state.selectedView === "replay") {
        shiftReplayDate(state, 1);
        render(state, renderer);
        return true;
      }
      if (sequence === "\r" && state.selectedView === "replay") {
        const blockIndex = state.replayScrollOffset;
        if (state.replayExpandedBlocks.has(blockIndex)) {
          state.replayExpandedBlocks.delete(blockIndex);
        } else {
          state.replayExpandedBlocks.add(blockIndex);
        }
        render(state, renderer);
        return true;
      }
      if (sequence === "s") {
        state.sortMode = state.sortMode === "cost" ? "tokens" : "cost";
        state.modelScrollOffset = 0;
        render(state, renderer);
        return true;
      }
      if (sequence === "r") {
        reloadAllData(state, renderer);
        return true;
      }
      if (sequence === "q") {
        renderer.destroy();
        process.exit(0);
      }
      return false;
    });
  } catch (err) {
    clearRoot(renderer);
    renderer.root.add(Box23({
      flexDirection: "column",
      width: "100%",
      height: "100%",
      backgroundColor: COLORS2.bg,
      justifyContent: "center",
      alignItems: "center"
    }, Text23({
      content: "TOKENLEAK TUI",
      fg: COLORS2.amber,
      attributes: BOLD3
    }), Text23({
      content: `Error: ${err instanceof Error ? err.message : String(err)}`,
      fg: COLORS2.red
    }), Text23({
      content: "Press q to quit",
      fg: COLORS2.dimWhite
    })));
    renderer.requestRender();
    renderer.addInputHandler((sequence) => {
      if (sequence === "q") {
        renderer.destroy();
        process.exit(0);
      }
      return false;
    });
  }
}
var CURSOR_SETUP_LABEL_INPUT_ID = "cursor-setup-label-input", CURSOR_SETUP_TOKEN_INPUT_ID = "cursor-setup-token-input", currentState, currentRenderer, VIEW_KEYS, VIEW_ORDER, SCROLLABLE_VIEWS;
var init_dist4 = __esm(() => {
  init_dist();
  init_dist2();
  init_dist3();
  init_theme2();
  init_data();
  init_state();
  init_header();
  init_chart_panel();
  init_stats_row();
  init_model_list();
  init_status_bar();
  init_bloomberg();
  init_advisor3();
  init_focus2();
  init_explain2();
  init_compare2();
  init_export();
  init_wrapped2();
  init_help();
  init_replay2();
  init_cursor_setup();
  VIEW_KEYS = {
    "1": "overview",
    "2": "matrix",
    "3": "advisor",
    "4": "focus",
    "5": "explain",
    "6": "compare",
    "7": "export",
    "8": "wrapped",
    "9": "replay"
  };
  VIEW_ORDER = [
    "overview",
    "matrix",
    "advisor",
    "focus",
    "explain",
    "compare",
    "export",
    "wrapped",
    "replay"
  ];
  SCROLLABLE_VIEWS = new Set(["advisor", "focus", "compare", "wrapped", "replay"]);
});

// node_modules/citty/dist/_chunks/libs/scule.mjs
var NUMBER_CHAR_RE = /\d/;
var STR_SPLITTERS = [
  "-",
  "_",
  "/",
  "."
];
function isUppercase(char = "") {
  if (NUMBER_CHAR_RE.test(char))
    return;
  return char !== char.toLowerCase();
}
function splitByCase(str, separators) {
  const splitters = separators ?? STR_SPLITTERS;
  const parts = [];
  if (!str || typeof str !== "string")
    return parts;
  let buff = "";
  let previousUpper;
  let previousSplitter;
  for (const char of str) {
    const isSplitter = splitters.includes(char);
    if (isSplitter === true) {
      parts.push(buff);
      buff = "";
      previousUpper = undefined;
      continue;
    }
    const isUpper = isUppercase(char);
    if (previousSplitter === false) {
      if (previousUpper === false && isUpper === true) {
        parts.push(buff);
        buff = char;
        previousUpper = isUpper;
        continue;
      }
      if (previousUpper === true && isUpper === false && buff.length > 1) {
        const lastChar = buff.at(-1);
        parts.push(buff.slice(0, Math.max(0, buff.length - 1)));
        buff = lastChar + char;
        previousUpper = isUpper;
        continue;
      }
    }
    buff += char;
    previousUpper = isUpper;
    previousSplitter = isSplitter;
  }
  parts.push(buff);
  return parts;
}
function upperFirst(str) {
  return str ? str[0].toUpperCase() + str.slice(1) : "";
}
function lowerFirst(str) {
  return str ? str[0].toLowerCase() + str.slice(1) : "";
}
function pascalCase(str, opts) {
  return str ? (Array.isArray(str) ? str : splitByCase(str)).map((p) => upperFirst(opts?.normalize ? p.toLowerCase() : p)).join("") : "";
}
function camelCase(str, opts) {
  return lowerFirst(pascalCase(str || "", opts));
}
function kebabCase(str, joiner) {
  return str ? (Array.isArray(str) ? str : splitByCase(str)).map((p) => p.toLowerCase()).join(joiner ?? "-") : "";
}

// node_modules/citty/dist/index.mjs
import { parseArgs as parseArgs$1 } from "util";
function toArray(val) {
  if (Array.isArray(val))
    return val;
  return val === undefined ? [] : [val];
}
function formatLineColumns(lines, linePrefix = "") {
  const maxLength = [];
  for (const line of lines)
    for (const [i, element] of line.entries())
      maxLength[i] = Math.max(maxLength[i] || 0, element.length);
  return lines.map((l) => l.map((c, i) => linePrefix + c[i === 0 ? "padStart" : "padEnd"](maxLength[i])).join("  ")).join(`
`);
}
function resolveValue(input) {
  return typeof input === "function" ? input() : input;
}
var CLIError = class extends Error {
  code;
  constructor(message, code) {
    super(message);
    this.name = "CLIError";
    this.code = code;
  }
};
function parseRawArgs(args = [], opts = {}) {
  const booleans = new Set(opts.boolean || []);
  const strings = new Set(opts.string || []);
  const aliasMap = opts.alias || {};
  const defaults = opts.default || {};
  const aliasToMain = /* @__PURE__ */ new Map;
  const mainToAliases = /* @__PURE__ */ new Map;
  for (const [key, value] of Object.entries(aliasMap)) {
    const targets = value;
    for (const target of targets) {
      aliasToMain.set(key, target);
      if (!mainToAliases.has(target))
        mainToAliases.set(target, []);
      mainToAliases.get(target).push(key);
      aliasToMain.set(target, key);
      if (!mainToAliases.has(key))
        mainToAliases.set(key, []);
      mainToAliases.get(key).push(target);
    }
  }
  const options = {};
  function getType(name) {
    if (booleans.has(name))
      return "boolean";
    const aliases = mainToAliases.get(name) || [];
    for (const alias of aliases)
      if (booleans.has(alias))
        return "boolean";
    return "string";
  }
  const allOptions = new Set([
    ...booleans,
    ...strings,
    ...Object.keys(aliasMap),
    ...Object.values(aliasMap).flat(),
    ...Object.keys(defaults)
  ]);
  for (const name of allOptions)
    if (!options[name])
      options[name] = {
        type: getType(name),
        default: defaults[name]
      };
  for (const [alias, main] of aliasToMain.entries())
    if (alias.length === 1 && options[main] && !options[main].short)
      options[main].short = alias;
  const processedArgs = [];
  const negatedFlags = {};
  for (let i = 0;i < args.length; i++) {
    const arg = args[i];
    if (arg === "--") {
      processedArgs.push(...args.slice(i));
      break;
    }
    if (arg.startsWith("--no-")) {
      const flagName = arg.slice(5);
      negatedFlags[flagName] = true;
      continue;
    }
    processedArgs.push(arg);
  }
  let parsed;
  try {
    parsed = parseArgs$1({
      args: processedArgs,
      options: Object.keys(options).length > 0 ? options : undefined,
      allowPositionals: true,
      strict: false
    });
  } catch {
    parsed = {
      values: {},
      positionals: processedArgs
    };
  }
  const out = { _: [] };
  out._ = parsed.positionals;
  for (const [key, value] of Object.entries(parsed.values))
    out[key] = value;
  for (const [name] of Object.entries(negatedFlags)) {
    out[name] = false;
    const mainName = aliasToMain.get(name);
    if (mainName)
      out[mainName] = false;
    const aliases = mainToAliases.get(name);
    if (aliases)
      for (const alias of aliases)
        out[alias] = false;
  }
  for (const [alias, main] of aliasToMain.entries()) {
    if (out[alias] !== undefined && out[main] === undefined)
      out[main] = out[alias];
    if (out[main] !== undefined && out[alias] === undefined)
      out[alias] = out[main];
  }
  return out;
}
var noColor = /* @__PURE__ */ (() => {
  const env = globalThis.process?.env ?? {};
  return env.NO_COLOR === "1" || env.TERM === "dumb" || env.TEST || env.CI;
})();
var _c = (c, r = 39) => (t) => noColor ? t : `\x1B[${c}m${t}\x1B[${r}m`;
var bold = /* @__PURE__ */ _c(1, 22);
var cyan = /* @__PURE__ */ _c(36);
var gray = /* @__PURE__ */ _c(90);
var underline = /* @__PURE__ */ _c(4, 24);
function parseArgs(rawArgs, argsDef) {
  const parseOptions = {
    boolean: [],
    string: [],
    alias: {},
    default: {}
  };
  const args = resolveArgs(argsDef);
  for (const arg of args) {
    if (arg.type === "positional")
      continue;
    if (arg.type === "string" || arg.type === "enum")
      parseOptions.string.push(arg.name);
    else if (arg.type === "boolean")
      parseOptions.boolean.push(arg.name);
    if (arg.default !== undefined)
      parseOptions.default[arg.name] = arg.default;
    if (arg.alias)
      parseOptions.alias[arg.name] = arg.alias;
    const camelName = camelCase(arg.name);
    const kebabName = kebabCase(arg.name);
    if (camelName !== arg.name || kebabName !== arg.name) {
      const existingAliases = toArray(parseOptions.alias[arg.name] || []);
      if (camelName !== arg.name && !existingAliases.includes(camelName))
        existingAliases.push(camelName);
      if (kebabName !== arg.name && !existingAliases.includes(kebabName))
        existingAliases.push(kebabName);
      if (existingAliases.length > 0)
        parseOptions.alias[arg.name] = existingAliases;
    }
  }
  const parsed = parseRawArgs(rawArgs, parseOptions);
  const [...positionalArguments] = parsed._;
  const parsedArgsProxy = new Proxy(parsed, { get(target, prop) {
    return target[prop] ?? target[camelCase(prop)] ?? target[kebabCase(prop)];
  } });
  for (const [, arg] of args.entries())
    if (arg.type === "positional") {
      const nextPositionalArgument = positionalArguments.shift();
      if (nextPositionalArgument !== undefined)
        parsedArgsProxy[arg.name] = nextPositionalArgument;
      else if (arg.default === undefined && arg.required !== false)
        throw new CLIError(`Missing required positional argument: ${arg.name.toUpperCase()}`, "EARG");
      else
        parsedArgsProxy[arg.name] = arg.default;
    } else if (arg.type === "enum") {
      const argument = parsedArgsProxy[arg.name];
      const options = arg.options || [];
      if (argument !== undefined && options.length > 0 && !options.includes(argument))
        throw new CLIError(`Invalid value for argument: ${cyan(`--${arg.name}`)} (${cyan(argument)}). Expected one of: ${options.map((o) => cyan(o)).join(", ")}.`, "EARG");
    } else if (arg.required && parsedArgsProxy[arg.name] === undefined)
      throw new CLIError(`Missing required argument: --${arg.name}`, "EARG");
  return parsedArgsProxy;
}
function resolveArgs(argsDef) {
  const args = [];
  for (const [name, argDef] of Object.entries(argsDef || {}))
    args.push({
      ...argDef,
      name,
      alias: toArray(argDef.alias)
    });
  return args;
}
function defineCommand(def) {
  return def;
}
async function runCommand(cmd, opts) {
  const cmdArgs = await resolveValue(cmd.args || {});
  const parsedArgs = parseArgs(opts.rawArgs, cmdArgs);
  const context = {
    rawArgs: opts.rawArgs,
    args: parsedArgs,
    data: opts.data,
    cmd
  };
  if (typeof cmd.setup === "function")
    await cmd.setup(context);
  let result;
  try {
    const subCommands = await resolveValue(cmd.subCommands);
    if (subCommands && Object.keys(subCommands).length > 0) {
      const subCommandArgIndex = opts.rawArgs.findIndex((arg) => !arg.startsWith("-"));
      const subCommandName = opts.rawArgs[subCommandArgIndex];
      if (subCommandName) {
        if (!subCommands[subCommandName])
          throw new CLIError(`Unknown command ${cyan(subCommandName)}`, "E_UNKNOWN_COMMAND");
        const subCommand = await resolveValue(subCommands[subCommandName]);
        if (subCommand)
          await runCommand(subCommand, { rawArgs: opts.rawArgs.slice(subCommandArgIndex + 1) });
      } else if (!cmd.run)
        throw new CLIError(`No command specified.`, "E_NO_COMMAND");
    }
    if (typeof cmd.run === "function")
      result = await cmd.run(context);
  } finally {
    if (typeof cmd.cleanup === "function")
      await cmd.cleanup(context);
  }
  return { result };
}
async function resolveSubCommand(cmd, rawArgs, parent) {
  const subCommands = await resolveValue(cmd.subCommands);
  if (subCommands && Object.keys(subCommands).length > 0) {
    const subCommandArgIndex = rawArgs.findIndex((arg) => !arg.startsWith("-"));
    const subCommandName = rawArgs[subCommandArgIndex];
    const subCommand = await resolveValue(subCommands[subCommandName]);
    if (subCommand)
      return resolveSubCommand(subCommand, rawArgs.slice(subCommandArgIndex + 1), cmd);
  }
  return [cmd, parent];
}
async function showUsage(cmd, parent) {
  try {
    console.log(await renderUsage(cmd, parent) + `
`);
  } catch (error) {
    console.error(error);
  }
}
var negativePrefixRe = /^no[-A-Z]/;
async function renderUsage(cmd, parent) {
  const cmdMeta = await resolveValue(cmd.meta || {});
  const cmdArgs = resolveArgs(await resolveValue(cmd.args || {}));
  const parentMeta = await resolveValue(parent?.meta || {});
  const commandName = `${parentMeta.name ? `${parentMeta.name} ` : ""}` + (cmdMeta.name || process.argv[1]);
  const argLines = [];
  const posLines = [];
  const commandsLines = [];
  const usageLine = [];
  for (const arg of cmdArgs)
    if (arg.type === "positional") {
      const name = arg.name.toUpperCase();
      const isRequired = arg.required !== false && arg.default === undefined;
      const defaultHint = arg.default ? `="${arg.default}"` : "";
      posLines.push([
        cyan(name + defaultHint),
        arg.description || "",
        arg.valueHint ? `<${arg.valueHint}>` : ""
      ]);
      usageLine.push(isRequired ? `<${name}>` : `[${name}]`);
    } else {
      const isRequired = arg.required === true && arg.default === undefined;
      const argStr = [...(arg.alias || []).map((a) => `-${a}`), `--${arg.name}`].join(", ") + (arg.type === "string" && (arg.valueHint || arg.default) ? `=${arg.valueHint ? `<${arg.valueHint}>` : `"${arg.default || ""}"`}` : "") + (arg.type === "enum" && arg.options ? `=<${arg.options.join("|")}>` : "");
      argLines.push([cyan(argStr + (isRequired ? " (required)" : "")), arg.description || ""]);
      if (arg.type === "boolean" && (arg.default === true || arg.negativeDescription) && !negativePrefixRe.test(arg.name)) {
        const negativeArgStr = [...(arg.alias || []).map((a) => `--no-${a}`), `--no-${arg.name}`].join(", ");
        argLines.push([cyan(negativeArgStr + (isRequired ? " (required)" : "")), arg.negativeDescription || ""]);
      }
      if (isRequired)
        usageLine.push(argStr);
    }
  if (cmd.subCommands) {
    const commandNames = [];
    const subCommands = await resolveValue(cmd.subCommands);
    for (const [name, sub] of Object.entries(subCommands)) {
      const meta = await resolveValue((await resolveValue(sub))?.meta);
      if (meta?.hidden)
        continue;
      commandsLines.push([cyan(name), meta?.description || ""]);
      commandNames.push(name);
    }
    usageLine.push(commandNames.join("|"));
  }
  const usageLines = [];
  const version = cmdMeta.version || parentMeta.version;
  usageLines.push(gray(`${cmdMeta.description} (${commandName + (version ? ` v${version}` : "")})`), "");
  const hasOptions = argLines.length > 0 || posLines.length > 0;
  usageLines.push(`${underline(bold("USAGE"))} ${cyan(`${commandName}${hasOptions ? " [OPTIONS]" : ""} ${usageLine.join(" ")}`)}`, "");
  if (posLines.length > 0) {
    usageLines.push(underline(bold("ARGUMENTS")), "");
    usageLines.push(formatLineColumns(posLines, "  "));
    usageLines.push("");
  }
  if (argLines.length > 0) {
    usageLines.push(underline(bold("OPTIONS")), "");
    usageLines.push(formatLineColumns(argLines, "  "));
    usageLines.push("");
  }
  if (commandsLines.length > 0) {
    usageLines.push(underline(bold("COMMANDS")), "");
    usageLines.push(formatLineColumns(commandsLines, "  "));
    usageLines.push("", `Use ${cyan(`${commandName} <command> --help`)} for more information about a command.`);
  }
  return usageLines.filter((l) => typeof l === "string").join(`
`);
}
async function runMain(cmd, opts = {}) {
  const rawArgs = opts.rawArgs || process.argv.slice(2);
  const showUsage$1 = opts.showUsage || showUsage;
  try {
    if (rawArgs.includes("--help") || rawArgs.includes("-h")) {
      await showUsage$1(...await resolveSubCommand(cmd, rawArgs));
      process.exit(0);
    } else if (rawArgs.length === 1 && rawArgs[0] === "--version") {
      const meta = typeof cmd.meta === "function" ? await cmd.meta() : await cmd.meta;
      if (!meta?.version)
        throw new CLIError("No version specified", "E_NO_VERSION");
      console.log(meta.version);
    } else
      await runCommand(cmd, { rawArgs });
  } catch (error) {
    if (error instanceof CLIError) {
      await showUsage$1(...await resolveSubCommand(cmd, rawArgs));
      console.error(error.message);
    } else
      console.error(error, `
`);
    process.exit(1);
  }
}

// packages/cli/src/cli.ts
init_dist();
init_dist2();
init_dist3();
import { writeFileSync as writeFileSync3 } from "fs";

// packages/cli/src/config.ts
import { readFileSync as readFileSync5 } from "fs";
import { join as join8 } from "path";
import { homedir as homedir8 } from "os";
var CONFIG_FILENAME = ".tokenleakrc";
function loadConfig() {
  try {
    const configPath = join8(homedir8(), CONFIG_FILENAME);
    const raw = readFileSync5(configPath, "utf-8");
    const parsed = JSON.parse(raw);
    if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
      return parsed;
    }
    return {};
  } catch {
    return {};
  }
}

// packages/cli/src/data-loader.ts
init_dist();

// packages/cli/src/errors.ts
class TokenleakError extends Error {
  constructor(message) {
    super(message);
    this.name = "TokenleakError";
  }
}
function handleError(error) {
  if (error instanceof TokenleakError) {
    process.stderr.write(`Error: ${error.message}
`);
  } else if (error instanceof Error) {
    process.stderr.write(`Error: ${error.message}
`);
  } else {
    process.stderr.write(`Error: ${String(error)}
`);
  }
  process.exit(1);
}

// packages/cli/src/data-loader.ts
async function loadTokenleakData(providers, range) {
  const { data: providerDataList, stats } = await loadAndAggregate(providers, range);
  return {
    schemaVersion: SCHEMA_VERSION,
    generated: new Date().toISOString(),
    dateRange: range,
    providers: providerDataList,
    aggregated: stats,
    more: buildMoreStats(providerDataList, range)
  };
}
function resolveCompareRange(compareStr, currentRange) {
  if (compareStr === "auto" || compareStr === "true" || compareStr === "") {
    return computePreviousPeriod(currentRange);
  }
  const parsed = parseCompareRange(compareStr);
  if (!parsed) {
    throw new TokenleakError(`Invalid --compare format: "${compareStr}". Use YYYY-MM-DD..YYYY-MM-DD or "auto".`);
  }
  return parsed;
}
async function loadAndAggregate(providers, range, allowEmpty = false) {
  const results = await Promise.all(providers.map(async (p) => {
    try {
      return await p.load(range);
    } catch {
      return null;
    }
  }));
  const providerDataList = results.filter((r) => r !== null);
  if (!allowEmpty && providerDataList.length === 0) {
    throw new TokenleakError("No provider data found");
  }
  const mergedDaily = mergeProviderData(providerDataList);
  const stats = aggregate(mergedDaily, range.until);
  return { data: providerDataList, stats };
}
async function loadCompareTokenleakData(providers, currentRange, compareStr) {
  const previousRange = resolveCompareRange(compareStr, currentRange);
  const [currentResult, previousResult] = await Promise.all([
    loadAndAggregate(providers, currentRange),
    loadAndAggregate(providers, previousRange, true)
  ]);
  const compareOutput = buildCompareOutput({ range: currentRange, stats: currentResult.stats }, { range: previousRange, stats: previousResult.stats });
  return {
    compareOutput,
    currentData: currentResult.data,
    previousData: previousResult.data,
    output: {
      schemaVersion: SCHEMA_VERSION,
      generated: new Date().toISOString(),
      dateRange: currentRange,
      providers: currentResult.data,
      aggregated: currentResult.stats,
      more: buildMoreStats(currentResult.data, currentRange, {
        previousRange,
        previousProviders: previousResult.data,
        previousStats: compareOutput.periodB.stats,
        deltas: compareOutput.deltas
      })
    }
  };
}

// packages/cli/src/date-range.ts
init_dist();
var DATE_FORMAT = /^\d{4}-\d{2}-\d{2}$/;
function isValidDate(dateStr) {
  if (!DATE_FORMAT.test(dateStr))
    return false;
  const d = new Date(dateStr + "T00:00:00Z");
  return !Number.isNaN(d.getTime()) && d.toISOString().slice(0, 10) === dateStr;
}
function computeDateRange(args) {
  const until = args.until ?? new Date().toISOString().slice(0, 10);
  if (args.until && !isValidDate(args.until)) {
    throw new TokenleakError(`Invalid --until date: "${args.until}". Use YYYY-MM-DD format.`);
  }
  if (args.since && !isValidDate(args.since)) {
    throw new TokenleakError(`Invalid --since date: "${args.since}". Use YYYY-MM-DD format.`);
  }
  let since;
  if (args.since) {
    since = args.since;
  } else {
    const daysBack = args.days ?? DEFAULT_DAYS;
    const d = new Date(until);
    d.setDate(d.getDate() - daysBack);
    since = d.toISOString().slice(0, 10);
  }
  if (since > until) {
    throw new TokenleakError(`--since (${since}) must not be after --until (${until}).`);
  }
  return { since, until };
}

// packages/cli/src/env.ts
var VALID_FORMATS = new Set(["json", "svg", "png", "terminal"]);
var VALID_THEMES = new Set(["dark", "light"]);
function loadEnvOverrides() {
  const overrides = {};
  const format = process.env["TOKENLEAK_FORMAT"];
  if (format && VALID_FORMATS.has(format)) {
    overrides.format = format;
  }
  const theme = process.env["TOKENLEAK_THEME"];
  if (theme && VALID_THEMES.has(theme)) {
    overrides.theme = theme;
  }
  const days = process.env["TOKENLEAK_DAYS"];
  if (days !== undefined && days !== "") {
    const parsed = Number(days);
    if (Number.isFinite(parsed) && parsed > 0) {
      overrides.days = parsed;
    }
  }
  return overrides;
}

// packages/cli/src/cursor.ts
init_dist2();
import { createInterface } from "readline/promises";
import { stdin as input, stdout as output } from "process";
async function readSecret(prompt) {
  if (!input.isTTY || !output.isTTY) {
    const rl = createInterface({ input, output });
    try {
      return (await rl.question(prompt)).trim();
    } finally {
      rl.close();
    }
  }
  output.write(prompt);
  input.resume();
  input.setEncoding("utf8");
  if (typeof input.setRawMode === "function") {
    input.setRawMode(true);
  }
  return await new Promise((resolve, reject) => {
    let value = "";
    const cleanup = () => {
      input.off("data", onData);
      if (typeof input.setRawMode === "function") {
        input.setRawMode(false);
      }
      input.pause();
      output.write(`
`);
    };
    const onData = (chunk) => {
      const text2 = String(chunk);
      for (const char of text2) {
        if (char === "\x03") {
          cleanup();
          reject(new TokenleakError("Cancelled"));
          return;
        }
        if (char === "\r" || char === `
`) {
          cleanup();
          resolve(value.trim());
          return;
        }
        if (char === "\b" || char === "\x7F") {
          value = value.slice(0, -1);
          continue;
        }
        value += char;
      }
    };
    input.on("data", onData);
  });
}
function buildCursorHelpText() {
  return [
    "tokenleak cursor",
    "Manage Cursor authentication and cache sync.",
    "",
    "Usage:",
    "  tokenleak cursor login [--name <label>]",
    "  tokenleak cursor status [--name <label>]",
    "  tokenleak cursor accounts [--json]",
    "  tokenleak cursor switch <name-or-id>",
    "  tokenleak cursor logout [--name <label> | --all] [--purge-cache]",
    "  tokenleak cursor reset",
    "",
    "Notes:",
    "  Session tokens come from https://www.cursor.com/settings",
    "  Session tokens are stored in plaintext with local-only file permissions.",
    `  Credentials: ${getCursorCredentialsPath()}`,
    `  Cache: ${getCursorCacheDir()}`,
    ""
  ].join(`
`);
}
function printCursorAccounts(json) {
  const accounts = listCursorAccounts();
  if (json) {
    process.stdout.write(`${JSON.stringify({ accounts }, null, 2)}
`);
    return;
  }
  if (accounts.length === 0) {
    process.stdout.write(`No saved Cursor accounts.
`);
    return;
  }
  process.stdout.write(`Cursor accounts:
`);
  for (const account of accounts) {
    const marker = account.isActive ? "*" : "-";
    const label = account.label ? `${account.label} (${account.id})` : account.id;
    process.stdout.write(`  ${marker} ${label}
`);
  }
}
async function runCursorLogin(name) {
  if (name && listCursorAccounts().some((account) => account.label?.toLowerCase() === name.toLowerCase())) {
    throw new TokenleakError(`Cursor account label already exists: ${name}`);
  }
  process.stdout.write(`Session tokens are stored in plaintext at ${getCursorCredentialsPath()} with local-only file permissions.
`);
  const token = await readSecret("Enter Cursor session token: ");
  if (!token) {
    throw new TokenleakError("No token provided");
  }
  process.stdout.write(`Validating session token...
`);
  const result = await validateCursorSession(token);
  if (!result.valid) {
    throw new TokenleakError(result.error ?? "Invalid session token");
  }
  const accountId = saveCursorCredentials(token, name);
  const display = name ?? accountId;
  process.stdout.write(`Saved Cursor account ${display}.
`);
}
async function runCursorStatus(name) {
  const credentials = name ? getCursorCredentialsFor(name) : getActiveCursorCredentials();
  if (!credentials) {
    throw new TokenleakError(name ? `Account not found: ${name}` : "No saved Cursor accounts");
  }
  const result = await validateCursorSession(credentials.sessionToken);
  if (!result.valid) {
    throw new TokenleakError(result.error ?? "Invalid / expired session");
  }
  process.stdout.write(`Cursor session is valid.
`);
  if (result.membershipType) {
    process.stdout.write(`Membership: ${result.membershipType}
`);
  }
}
function runCursorLogout(name, all, purgeCache) {
  if (all) {
    removeAllCursorAccounts(purgeCache);
    process.stdout.write(`Logged out from all Cursor accounts.
`);
    return;
  }
  if (name) {
    removeCursorAccount(name, purgeCache);
    process.stdout.write(`Logged out from Cursor account '${name}'.
`);
    return;
  }
  const store = loadCursorCredentialsStore();
  if (!store) {
    throw new TokenleakError("No saved Cursor accounts");
  }
  removeCursorAccount(store.activeAccountId, purgeCache);
  process.stdout.write(`Logged out from Cursor account '${store.activeAccountId}'.
`);
}
function parseNameFlag(argv, index) {
  const value = argv[index + 1];
  if (!value) {
    throw new TokenleakError(`${argv[index]} requires a value`);
  }
  return [value, index + 2];
}
function wrapCursorError(error) {
  if (error instanceof TokenleakError) {
    throw error;
  }
  if (error instanceof CursorAuthError) {
    throw new TokenleakError(error.message);
  }
  throw error;
}
async function runCursorCommand(argv) {
  const command = argv[0];
  if (!command || command === "--help" || command === "-h") {
    process.stdout.write(buildCursorHelpText());
    return;
  }
  if (command === "login") {
    let name;
    for (let index = 1;index < argv.length; ) {
      const arg = argv[index];
      if (arg === "--name") {
        [name, index] = parseNameFlag(argv, index);
      } else {
        throw new TokenleakError(`Unknown cursor flag "${arg}"`);
      }
    }
    try {
      await runCursorLogin(name);
    } catch (error) {
      wrapCursorError(error);
    }
    return;
  }
  if (command === "status") {
    let name;
    for (let index = 1;index < argv.length; ) {
      const arg = argv[index];
      if (arg === "--name") {
        [name, index] = parseNameFlag(argv, index);
      } else {
        throw new TokenleakError(`Unknown cursor flag "${arg}"`);
      }
    }
    try {
      await runCursorStatus(name);
    } catch (error) {
      wrapCursorError(error);
    }
    return;
  }
  if (command === "accounts") {
    if (argv.length > 2 || argv[1] && argv[1] !== "--json") {
      throw new TokenleakError(`Unknown cursor flag "${argv[1]}"`);
    }
    printCursorAccounts(argv.includes("--json"));
    return;
  }
  if (command === "switch") {
    const target = argv[1];
    if (!target) {
      throw new TokenleakError("tokenleak cursor switch requires a name or account id");
    }
    try {
      setActiveCursorAccount(target);
    } catch (error) {
      wrapCursorError(error);
    }
    process.stdout.write(`Active Cursor account set to ${target}.
`);
    return;
  }
  if (command === "logout") {
    let name;
    let all = false;
    let purgeCache = false;
    for (let index = 1;index < argv.length; ) {
      const arg = argv[index];
      if (arg === "--name") {
        [name, index] = parseNameFlag(argv, index);
        continue;
      }
      if (arg === "--all") {
        all = true;
        index += 1;
        continue;
      }
      if (arg === "--purge-cache") {
        purgeCache = true;
        index += 1;
        continue;
      }
      throw new TokenleakError(`Unknown cursor flag "${arg}"`);
    }
    if (all && name) {
      throw new TokenleakError("tokenleak cursor logout cannot combine --all with --name");
    }
    try {
      runCursorLogout(name, all, purgeCache);
    } catch (error) {
      wrapCursorError(error);
    }
    return;
  }
  if (command === "reset") {
    if (argv.length > 1) {
      throw new TokenleakError(`Unknown cursor flag "${argv[1]}"`);
    }
    try {
      resetCursorProviderState();
    } catch (error) {
      wrapCursorError(error);
    }
    process.stdout.write(`Cleared saved Cursor accounts and local usage cache.
`);
    return;
  }
  throw new TokenleakError(`Unknown cursor command "${command}"`);
}

// packages/cli/src/explain.ts
function formatTokens13(tokens) {
  return Math.round(tokens).toLocaleString("en-US");
}
function formatCost13(cost) {
  return `$${cost.toFixed(2)}`;
}
function formatShare(share) {
  return `${(share * 100).toFixed(0)}%`;
}
function truncate(value, width) {
  if (value.length <= width) {
    return value;
  }
  if (width <= 3) {
    return ".".repeat(Math.max(0, width));
  }
  return `${value.slice(0, width - 3)}...`;
}
function renderEvidenceTable(title, rows, width) {
  const labelWidth = Math.max(16, Math.min(42, width - 33));
  const header = `  ${"Label".padEnd(labelWidth)} ${"Tokens".padStart(12)} ${"Share".padStart(6)} ${"Cost".padStart(10)}`;
  const divider2 = `  ${"-".repeat(Math.max(12, header.length - 2))}`;
  if (rows.length === 0) {
    return [title, "  none"];
  }
  const lines = [title, header, divider2];
  for (const row of rows) {
    lines.push(`  ${truncate(row.label, labelWidth).padEnd(labelWidth)} ${formatTokens13(row.tokens).padStart(12)} ${formatShare(row.share).padStart(6)} ${formatCost13(row.cost).padStart(10)}`);
  }
  return lines;
}
function renderExplainTerminal(report, width = 80) {
  const lines = [
    `Explain ${report.date}`,
    report.headline,
    "",
    ...report.summary.map((line2) => `- ${line2}`),
    "",
    ...renderEvidenceTable("Providers", report.topProviders, width),
    "",
    ...renderEvidenceTable("Sessions", report.topSessions, width),
    "",
    ...renderEvidenceTable("Projects", report.topProjects, width),
    "",
    ...renderEvidenceTable("Models", report.topModels, width),
    "",
    "Anomalies"
  ];
  if (report.anomalies.length === 0) {
    lines.push("  none");
  } else {
    for (const anomaly of report.anomalies) {
      lines.push(`  [${anomaly.type}] ${anomaly.title}: ${anomaly.detail}`);
    }
  }
  return lines.join(`
`);
}
function buildExplainHelpText() {
  return [
    "Usage:",
    "  tokenleak explain <date> [flags]",
    "",
    "Explain Flags:",
    "  -f, --format <format>   Output format: terminal, json",
    "  -o, --output <path>     Write output to a file and infer format from extension",
    "  -w, --width <number>    Terminal render width",
    "  -p, --provider <list>   Provider filter list, comma-separated",
    "      --claude            Only include Claude Code",
    "      --codex             Only include Codex",
    "      --cursor            Only include Cursor",
    "      --pi                Only include Pi",
    "      --open-code         Only include OpenCode",
    "      --all-providers     Ignore provider filters and use every available provider",
    "      --no-color          Accepted for parity with terminal output",
    "      --help              Show explain help",
    "",
    "Examples:",
    "  tokenleak explain 2026-03-10",
    "  tokenleak explain 2026-03-10 --format json",
    "  tokenleak explain 2026-03-10 --provider pi --output explain.json",
    ""
  ].join(`
`);
}

// packages/cli/src/replay.ts
function formatTokens14(tokens) {
  if (tokens >= 1e6) {
    return `${(tokens / 1e6).toFixed(1)}M`;
  }
  if (tokens >= 1000) {
    return `${(tokens / 1000).toFixed(1)}K`;
  }
  return `${Math.round(tokens)}`;
}
function formatCost14(cost) {
  return `$${cost.toFixed(2)}`;
}
function formatDuration4(ms) {
  if (ms <= 0) {
    return "0s";
  }
  const hours = Math.floor(ms / 3600000);
  const minutes = Math.floor(ms % 3600000 / 60000);
  const seconds = Math.floor(ms % 60000 / 1000);
  if (hours > 0) {
    return `${hours}h ${minutes}m`;
  }
  if (minutes > 0) {
    return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
  }
  return `${seconds}s`;
}
function formatTime(iso) {
  const date = new Date(iso);
  return `${String(date.getUTCHours()).padStart(2, "0")}:${String(date.getUTCMinutes()).padStart(2, "0")}`;
}
function truncate2(value, width) {
  if (value.length <= width) {
    return value;
  }
  if (width <= 3) {
    return ".".repeat(Math.max(0, width));
  }
  return `${value.slice(0, width - 3)}...`;
}
var HEATMAP_SLOTS = 48;
var HEATMAP_BLOCKS2 = [" ", "\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
function renderActivityBar(report, width) {
  if (report.events.length === 0) {
    return ["Activity", "  (no events)"];
  }
  const slotTokens = new Array(HEATMAP_SLOTS).fill(0);
  for (const event of report.events) {
    const date = new Date(event.timestamp);
    const hour = date.getUTCHours();
    const minute = date.getUTCMinutes();
    const slot = Math.min(hour * 2 + Math.floor(minute / 30), HEATMAP_SLOTS - 1);
    slotTokens[slot] += event.totalTokens;
  }
  const maxTokens = Math.max(...slotTokens);
  const barWidth = Math.min(HEATMAP_SLOTS, width - 4);
  const step = HEATMAP_SLOTS / barWidth;
  let bar = "  ";
  for (let i = 0;i < barWidth; i++) {
    const slotIndex = Math.floor(i * step);
    const tokens = slotTokens[slotIndex];
    const level = maxTokens > 0 ? Math.round(tokens / maxTokens * (HEATMAP_BLOCKS2.length - 1)) : 0;
    bar += HEATMAP_BLOCKS2[level];
  }
  const firstTime = formatTime(report.events[0].timestamp);
  const lastTime = formatTime(report.events[report.events.length - 1].timestamp);
  const timeLabel = `  ${firstTime}${" ".repeat(Math.max(1, barWidth - firstTime.length - lastTime.length))}${lastTime}`;
  return ["Activity", bar, timeLabel];
}
function renderFlowBlockCard(block, width) {
  const timeRange = `${formatTime(block.start)}-${formatTime(block.end)}`;
  const header = `  [${timeRange}] ${block.label} | ${block.eventCount} events | ${formatTokens14(block.totalTokens)} tok | ${formatCost14(block.cost)}`;
  const lines = [truncate2(header, width)];
  const modelInfo = `    Model: ${block.dominantModel}${block.modelSwitches > 0 ? ` (${block.modelSwitches} switch${block.modelSwitches === 1 ? "" : "es"})` : ""}`;
  lines.push(truncate2(modelInfo, width));
  const trend = block.cacheHitRateTrend;
  if (trend.length > 0) {
    const firstRate = (trend[0] * 100).toFixed(0);
    const lastRate = (trend[trend.length - 1] * 100).toFixed(0);
    if (trend.length > 1 && firstRate !== lastRate) {
      lines.push(`    Cache: ${firstRate}% -> ${lastRate}%`);
    } else {
      lines.push(`    Cache: ${firstRate}%`);
    }
  }
  return lines;
}
function renderPulseChart(velocity, width) {
  if (velocity.length === 0) {
    return ["Pulse", "  (no data)"];
  }
  const maxTpm = Math.max(...velocity.map((v) => v.tokensPerMinute));
  const chartWidth = Math.min(velocity.length, width - 10);
  const chartHeight = 5;
  const step = velocity.length / chartWidth;
  const grid = [];
  for (let row = 0;row < chartHeight; row++) {
    grid.push(new Array(chartWidth).fill(" "));
  }
  for (let col = 0;col < chartWidth; col++) {
    const idx = Math.floor(col * step);
    const tpm = velocity[idx].tokensPerMinute;
    const height = maxTpm > 0 ? Math.round(tpm / maxTpm * (chartHeight - 1)) : 0;
    for (let row = chartHeight - 1;row >= chartHeight - 1 - height; row--) {
      if (row >= 0) {
        grid[row][col] = "\u2588";
      }
    }
  }
  const lines = ["Pulse (tokens/min)"];
  const maxLabel = formatTokens14(maxTpm);
  for (let row = 0;row < chartHeight; row++) {
    const label = row === 0 ? maxLabel.padStart(7) : row === chartHeight - 1 ? "      0" : "       ";
    lines.push(`${label} |${grid[row].join("")}`);
  }
  return lines;
}
function renderReplayTerminal(report, width = 80) {
  const lines = [
    `Session Replay: ${report.date}`,
    ""
  ];
  lines.push(...renderActivityBar(report, width));
  lines.push("");
  if (report.flowBlocks.length === 0) {
    lines.push("Flow Blocks", "  (no activity)");
  } else {
    lines.push(`Flow Blocks (${report.flowBlocks.length})`);
    for (const block of report.flowBlocks) {
      lines.push(...renderFlowBlockCard(block, width));
      lines.push("");
    }
  }
  lines.push(...renderPulseChart(report.tokenVelocity, width));
  lines.push("");
  const s = report.summary;
  const summaryParts = [
    `Sessions: ${s.totalSessions}`,
    `Events: ${s.totalEvents}`,
    `Flow: ${formatDuration4(s.flowTimeMs)}`,
    `Think: ${formatDuration4(s.thinkTimeMs)}`,
    `Ratio: ${(s.flowThinkRatio * 100).toFixed(0)}%`
  ];
  if (s.peakMinute) {
    summaryParts.push(`Peak: ${formatTokens14(s.peakMinute.tokensPerMinute)} tok/min at ${formatTime(s.peakMinute.minute)}`);
  }
  lines.push(truncate2(summaryParts.join(" | "), width));
  return lines.join(`
`);
}
function buildReplayHelpText() {
  return [
    "Usage:",
    "  tokenleak replay [date] [flags]",
    "",
    "Arguments:",
    "  date                    Date to replay in YYYY-MM-DD format (defaults to today)",
    "",
    "Replay Flags:",
    "  -f, --format <format>   Output format: terminal, json",
    "  -o, --output <path>     Write output to a file and infer format from extension",
    "  -w, --width <number>    Terminal render width",
    "  -p, --provider <list>   Provider filter list, comma-separated",
    "      --claude            Only include Claude Code",
    "      --codex             Only include Codex",
    "      --cursor            Only include Cursor",
    "      --pi                Only include Pi",
    "      --open-code         Only include OpenCode",
    "      --all-providers     Ignore provider filters and use every available provider",
    "      --no-color          Accepted for parity with terminal output",
    "      --help              Show replay help",
    "",
    "Examples:",
    "  tokenleak replay",
    "  tokenleak replay 2026-03-10",
    "  tokenleak replay 2026-03-10 --format json",
    "  tokenleak replay --provider claude --output replay.json",
    ""
  ].join(`
`);
}

// packages/cli/src/flags.ts
var CLI_FLAG_ORDER = [
  "format",
  "theme",
  "since",
  "until",
  "days",
  "output",
  "width",
  "provider",
  "compare",
  "upload",
  "claude",
  "codex",
  "cursor",
  "pi",
  "openCode",
  "allProviders",
  "listProviders",
  "more",
  "clipboard",
  "open",
  "liveServer",
  "wrappedLive",
  "noColor",
  "noInsights",
  "advisor"
];
var CLI_FLAG_NAMES = {
  format: "--format",
  theme: "--theme",
  since: "--since",
  until: "--until",
  days: "--days",
  output: "--output",
  width: "--width",
  provider: "--provider",
  compare: "--compare",
  upload: "--upload",
  claude: "--claude",
  codex: "--codex",
  cursor: "--cursor",
  pi: "--pi",
  openCode: "--open-code",
  allProviders: "--all-providers",
  listProviders: "--list-providers",
  more: "--more",
  clipboard: "--clipboard",
  open: "--open",
  liveServer: "--live-server",
  wrappedLive: "--wrapped-live",
  noColor: "--no-color",
  noInsights: "--no-insights",
  advisor: "--advisor"
};
function buildCliArgTokens(cliArgs) {
  const tokens = [];
  for (const key of CLI_FLAG_ORDER) {
    const value = cliArgs[key];
    if (value === undefined || value === false || value === null) {
      continue;
    }
    const flag = CLI_FLAG_NAMES[key];
    if (!flag)
      continue;
    tokens.push(flag);
    if (value !== true) {
      tokens.push(String(value));
    }
  }
  return tokens;
}
function buildCliPreview(cliArgs) {
  const tokens = buildCliArgTokens(cliArgs);
  return tokens.length === 0 ? "tokenleak" : `tokenleak ${tokens.join(" ")}`;
}

// packages/cli/src/interactive.ts
import { emitKeypressEvents } from "readline";
import { createInterface as createInterface2 } from "readline/promises";
var INTERACTIVE_FLAG_LINES = [
  "    explain <date>       explain one day of usage",
  "    focus                rank deep-work sessions",
  "-f, --format <format>   terminal | png | svg | json | wrapped",
  "-t, --theme <theme>     dark | light",
  "-s, --since <date>      YYYY-MM-DD start date",
  "-u, --until <date>      YYYY-MM-DD end date",
  "-d, --days <number>     trailing days window",
  "-o, --output <path>     write output to a file",
  "-w, --width <number>    terminal render width",
  "-p, --provider <list>   comma-separated providers",
  "    --claude            shortcut for Claude Code",
  "    --codex             shortcut for Codex",
  "    --cursor            shortcut for Cursor",
  "    --pi                shortcut for Pi",
  "    --open-code         shortcut for Open Code",
  "    --all-providers     ignore provider filters",
  "    --list-providers    show provider registry",
  "    --compare <range>   auto or YYYY-MM-DD..YYYY-MM-DD",
  "    --more              richer PNG/SVG stats",
  "    --clipboard         copy rendered output",
  "    --open              open generated file",
  "    --upload <target>   gist",
  "-L, --live-server       local interactive dashboard",
  "    --wrapped-live      AI Wrapped presentation in browser",
  "    --no-color          disable ANSI colors",
  "    --no-insights       hide terminal insights",
  "    --help              print help",
  "    --version           print version"
];
var TAB_RANGE_DAY_COUNTS = {
  "7d": 7,
  "30d": 30,
  "90d": 90,
  "365d": 365
};
var DAY_MS = 24 * 60 * 60 * 1000;
var ESC3 = "\x1B[";
var RESET2 = `${ESC3}0m`;
var BOLD = `${ESC3}1m`;
var DIM = `${ESC3}2m`;
var CYAN = `${ESC3}36m`;
var GREEN = `${ESC3}32m`;
var YELLOW = `${ESC3}33m`;
var RED = `${ESC3}31m`;
var WHITE = `${ESC3}97m`;
var HOME_CLEAR = "\x1B[H\x1B[J";
var HIDE_CURSOR = "\x1B[?25l";
var SHOW_CURSOR = "\x1B[?25h";
var ALT_SCREEN_ON = "\x1B[?1049h";
var ALT_SCREEN_OFF = "\x1B[?1049l";
var ALT_SCROLL_ON = "\x1B[?1007h";
var ALT_SCROLL_OFF = "\x1B[?1007l";
var LOADING_TICK_MS = 120;
function color(text2, code) {
  return `${code}${text2}${RESET2}`;
}
function stripAnsi2(text2) {
  return text2.replace(/\x1b\[[0-9;?]*[A-Za-z]/g, "");
}
function visibleLength2(text2) {
  return stripAnsi2(text2).length;
}
function padVisible2(text2, width) {
  const padding = Math.max(0, width - visibleLength2(text2));
  return text2 + " ".repeat(padding);
}
function truncateVisible2(text2, width) {
  if (width <= 0)
    return "";
  const plain = stripAnsi2(text2);
  if (plain.length <= width)
    return text2;
  const limit = width <= 3 ? width : width - 3;
  let visibleCount = 0;
  let index = 0;
  let result = "";
  let sawAnsi = false;
  while (index < text2.length && visibleCount < limit) {
    if (text2[index] === "\x1B") {
      const match = text2.slice(index).match(/^\x1b\[[0-9;?]*[A-Za-z]/);
      if (match) {
        result += match[0];
        index += match[0].length;
        sawAnsi = true;
        continue;
      }
    }
    result += text2[index];
    index += 1;
    visibleCount += 1;
  }
  if (width <= 3) {
    return sawAnsi ? `${result}${RESET2}` : result;
  }
  return sawAnsi ? `${result}...${RESET2}` : `${result}...`;
}
function joinColumns(left, right, totalWidth) {
  const gutter = 3;
  const leftWidth = Math.max(42, Math.min(58, Math.floor(totalWidth * 0.44)));
  const rightWidth = Math.max(36, totalWidth - leftWidth - gutter);
  const rows = Math.max(left.length, right.length);
  const lines = [];
  for (let index = 0;index < rows; index++) {
    const leftLine = truncateVisible2(left[index] ?? "", leftWidth);
    const rightLine = truncateVisible2(right[index] ?? "", rightWidth);
    lines.push(`${padVisible2(leftLine, leftWidth)}${" ".repeat(gutter)}${rightLine}`);
  }
  return lines;
}
function renderRule(width) {
  return color("-".repeat(width), DIM);
}
function describeRequest(args) {
  const output2 = typeof args["output"] === "string" ? args["output"] : null;
  if (args["liveServer"]) {
    return {
      title: "Live Dashboard",
      loadingTitle: "Starting live dashboard",
      loadingDetail: "Launching the local server. Press Ctrl-C in the live view to stop it, then you will return here.",
      executionMode: "inherit"
    };
  }
  if (args["wrappedLive"]) {
    return {
      title: "Wrapped Live",
      loadingTitle: "Starting wrapped live presentation",
      loadingDetail: "Loading usage data and launching the local server. Press Ctrl-C to stop it, then you will return here.",
      executionMode: "inherit"
    };
  }
  if (args["listProviders"]) {
    return {
      title: "Provider Registry",
      loadingTitle: "Loading provider registry",
      loadingDetail: "Checking registered providers and current availability.",
      executionMode: "capture"
    };
  }
  if (args["compare"]) {
    return {
      title: "Compare Report",
      loadingTitle: "Building compare report",
      loadingDetail: output2 ? `Computing period deltas and writing the report to ${output2}.` : "Computing period deltas for the current and previous windows.",
      executionMode: "capture"
    };
  }
  switch (args["format"]) {
    case "json":
      return {
        title: "JSON Export",
        loadingTitle: "Generating JSON report",
        loadingDetail: output2 ? `Collecting token usage and writing JSON to ${output2}.` : "Collecting token usage and building structured JSON output.",
        executionMode: "capture"
      };
    case "svg":
      return {
        title: "SVG Export",
        loadingTitle: "Rendering SVG",
        loadingDetail: output2 ? `Rendering a vector card and writing it to ${output2}.` : "Rendering a vector card from your usage data.",
        executionMode: "capture"
      };
    case "png":
      return {
        title: "PNG Export",
        loadingTitle: "Rendering PNG",
        loadingDetail: output2 ? `Rendering the PNG card and writing it to ${output2}. This can take a few seconds.` : "Rendering the PNG card. This can take a few seconds.",
        executionMode: "capture"
      };
    default:
      return {
        title: "Terminal Dashboard",
        loadingTitle: "Generating terminal dashboard",
        loadingDetail: "Reading provider logs and aggregating token usage.",
        executionMode: "capture"
      };
  }
}
function finalizeCliArgs(args) {
  const finalized = { ...args };
  const format = finalized["format"];
  if (finalized["compare"] && (format === "png" || format === "svg")) {
    finalized["more"] = true;
  }
  if (finalized["open"] && finalized["output"] === undefined && typeof format === "string") {
    if (format === "png" || format === "svg" || format === "json") {
      finalized["output"] = `tokenleak.${format}`;
    } else {
      delete finalized["open"];
    }
  }
  if (format === "png") {
    delete finalized["clipboard"];
    delete finalized["upload"];
  }
  return finalized;
}
function createRunCommand(args) {
  const finalizedArgs = finalizeCliArgs(args);
  return {
    type: "run",
    request: {
      args: finalizedArgs,
      preview: buildCliPreview(finalizedArgs),
      argv: buildCliArgTokens(finalizedArgs),
      ...describeRequest(finalizedArgs)
    }
  };
}
function createSubcommandRunCommand(subcommand, args, positionalArgs = [], overrides = {}) {
  const finalizedArgs = finalizeCliArgs(args);
  const argv = [subcommand, ...positionalArgs, ...buildCliArgTokens(finalizedArgs)];
  const preview = argv.length === 0 ? "tokenleak" : `tokenleak ${argv.join(" ")}`;
  return {
    type: "run",
    request: {
      args: {
        ...finalizedArgs,
        subcommand
      },
      argv,
      preview,
      ...describeRequest(finalizedArgs),
      ...overrides
    }
  };
}
function renderMenu(options, selectedIndex) {
  return options.map((option, index) => {
    const isSelected = index === selectedIndex;
    const prefix = isSelected ? color(">", GREEN) : " ";
    const number = isSelected ? color(option.shortcut, WHITE + BOLD) : color(option.shortcut, YELLOW);
    const title = isSelected ? color(option.title, WHITE + BOLD) : color(option.title, WHITE);
    const description = isSelected ? color(option.description, CYAN) : color(option.description, DIM);
    return `${prefix} [${number}] ${title} ${description}`;
  });
}
function renderFlagPanel() {
  return [
    color("All Flags", WHITE + BOLD),
    color("Every flag remains available while using the launcher.", DIM),
    "",
    ...INTERACTIVE_FLAG_LINES.map((line2) => color(line2, CYAN))
  ];
}
function sliceVisibleWindow(items, selectedIndex, maxVisible) {
  if (items.length <= maxVisible) {
    return [...items];
  }
  const visibleCount = Math.max(1, maxVisible);
  const maxStart = items.length - visibleCount;
  const start = Math.max(0, Math.min(maxStart, selectedIndex - Math.floor(visibleCount / 2)));
  return items.slice(start, start + visibleCount);
}
function renderMenuPanel(context, options, selectedIndex) {
  const selected = options[selectedIndex];
  return [
    color("Tokenleak Interactive Launcher", WHITE + BOLD),
    `${color(`v${context.version}`, YELLOW)} ${color("interactive command center", CYAN)}`,
    "",
    color("Arrow keys move. Shortcut keys jump directly. Enter runs the selected action.", DIM),
    color("Commands run inside this session, so you can keep selecting without leaving tokenleak.", DIM),
    "",
    ...renderMenu(options, selectedIndex),
    "",
    color("Preview", WHITE + BOLD),
    color(selected.preview, GREEN),
    "",
    color("Keys", WHITE + BOLD),
    `${color("Up/Down", YELLOW)} move  ${color("Enter", YELLOW)} run  ${color("H", YELLOW)} help  ${color("Q", YELLOW)} quit`,
    "",
    renderRule(44)
  ];
}
function buildCompactLauncherBody(context, options, selectedIndex, width, rows) {
  const selected = options[selectedIndex];
  const menuLines = renderMenu(options, selectedIndex);
  const compact = rows < 18;
  const header = compact ? [
    color("Tokenleak Interactive Launcher", WHITE + BOLD),
    color("Narrow pane detected. Press H for the full flag reference.", DIM)
  ] : [
    color("Tokenleak Interactive Launcher", WHITE + BOLD),
    `${color(`v${context.version}`, YELLOW)} ${color("adaptive launcher view", CYAN)}`,
    color("Narrow pane detected. Press H for the full flag reference.", DIM),
    ""
  ];
  const footer = compact ? [
    "",
    color(truncateVisible2(selected.preview, width), GREEN),
    `${color("Up/Down", YELLOW)} move  ${color("Enter", YELLOW)} run  ${color("H", YELLOW)} help  ${color("Q", YELLOW)} quit`
  ] : [
    "",
    color("Preview", WHITE + BOLD),
    color(truncateVisible2(selected.preview, width), GREEN),
    "",
    `${color("Up/Down", YELLOW)} move  ${color("Enter", YELLOW)} run  ${color("H", YELLOW)} help  ${color("Q", YELLOW)} quit`,
    renderRule(44)
  ];
  const meta = [
    color("Actions", WHITE + BOLD),
    color("Use arrow keys to move through the launcher menu.", DIM)
  ];
  const fixedLineCount = header.length + meta.length + footer.length;
  const menuViewport = Math.max(1, rows - fixedLineCount);
  const visibleMenu = sliceVisibleWindow(menuLines, selectedIndex, menuViewport);
  return [...header, ...meta, ...visibleMenu, ...footer].slice(0, Math.max(1, rows));
}
function buildLauncherBody(context, options, selectedIndex, width, rows) {
  const menuPanel = renderMenuPanel(context, options, selectedIndex);
  const flagPanel = renderFlagPanel();
  const wideBody = joinColumns(menuPanel, flagPanel, width);
  if (width >= 118 && wideBody.length <= rows) {
    return wideBody;
  }
  const stackedBody = [...menuPanel, "", ...flagPanel];
  if (stackedBody.length <= rows) {
    return stackedBody;
  }
  return buildCompactLauncherBody(context, options, selectedIndex, width, rows);
}
function renderHelpOverlay(helpText, width) {
  const rows = Math.max(6, process.stdout.rows ?? 40);
  const lines = helpText.trimEnd().split(`
`);
  const header = [
    color("Tokenleak Help", WHITE + BOLD),
    color("Press Enter, Escape, H, or Q to return to the launcher.", DIM),
    ""
  ];
  const availableHeight = Math.max(1, rows - header.length - 1);
  const visibleLines = lines.slice(0, availableHeight).map((line2) => truncateVisible2(line2, width));
  const truncatedNotice = lines.length > visibleLines.length ? [
    color("Help truncated to fit this pane. Resize taller or run `tokenleak --help` for the full output.", DIM)
  ] : [];
  return `${HOME_CLEAR}${HIDE_CURSOR}${[...header, ...visibleLines, ...truncatedNotice].join(`
`)}`;
}
function renderLauncher(context, options, selectedIndex) {
  const width = Math.max(40, process.stdout.columns ?? 120);
  const rows = Math.max(8, process.stdout.rows ?? 40);
  const body = buildLauncherBody(context, options, selectedIndex, width, rows);
  return `${HOME_CLEAR}${HIDE_CURSOR}${body.join(`
`)}`;
}
var BRAILLE_SPINNER = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
function renderProgressBar(frame, width, elapsedSeconds) {
  const spinner = BRAILLE_SPINNER[frame % BRAILLE_SPINNER.length];
  const timeStr = `${elapsedSeconds}s`;
  const prefix = `${spinner} Working... [`;
  const suffix = `] ${timeStr}`;
  const chromeWidth = prefix.length + suffix.length;
  const barWidth = Math.max(8, width - chromeWidth);
  const cycle = barWidth * 2;
  const position = frame % cycle;
  const fillCount = position <= barWidth ? position : cycle - position;
  const filled = "\u2588".repeat(fillCount);
  const empty = "\u2591".repeat(barWidth - fillCount);
  const coloredFilled = color(filled, GREEN);
  const coloredEmpty = color(empty, DIM);
  return `${color(spinner, GREEN)} Working... [${coloredFilled}${coloredEmpty}] ${color(timeStr, DIM)}`;
}
function renderLoading(request, frame = 0, startedAt = Date.now()) {
  const elapsedSeconds = Math.max(0, Math.floor((Date.now() - startedAt) / 1000));
  const termWidth = Math.max(40, (process.stdout.columns ?? 80) - 2);
  const progressBar = renderProgressBar(frame, termWidth, elapsedSeconds);
  const lines = [
    color(request.loadingTitle, WHITE + BOLD),
    color(request.preview, CYAN),
    "",
    color(request.loadingDetail, DIM),
    "",
    progressBar,
    "",
    renderRule(44)
  ];
  return `${HOME_CLEAR}${HIDE_CURSOR}${lines.join(`
`)}`;
}
function clampScrollOffset(offset, totalLines, viewportHeight) {
  const maxOffset = Math.max(0, totalLines - Math.max(1, viewportHeight));
  return Math.min(Math.max(0, offset), maxOffset);
}
function buildOutputSectionLines(title, content, width) {
  const normalized = content.trimEnd();
  if (!normalized)
    return [];
  const lines = normalized.split(`
`).map((line2) => truncateVisible2(line2, width));
  return [color(title, WHITE + BOLD), ...lines, ""];
}
function renderResult(request, result, scrollOffset = 0) {
  const width = Math.max(60, (process.stdout.columns ?? 120) - 1);
  const rows = process.stdout.rows ?? 40;
  const statusColor = result.ok ? GREEN : RED;
  const statusLabel = result.ok ? "Completed" : "Failed";
  const header = [
    color(request.title, WHITE + BOLD),
    color(request.preview, CYAN),
    "",
    `${color("Status", WHITE + BOLD)} ${color(statusLabel, statusColor)}`,
    color(result.summary, DIM),
    ""
  ];
  const contentLines = [
    ...buildOutputSectionLines("Output", result.stdout, width),
    ...buildOutputSectionLines("Messages", result.stderr, width)
  ];
  const body = contentLines.length > 0 ? contentLines : [color("No captured output for this command.", DIM), ""];
  const footer = [
    renderRule(44),
    `${color("Up/Down", YELLOW)} scroll  ${color("PgUp/PgDn", YELLOW)} page  ${color("Enter", YELLOW)} launcher  ${color("Q", YELLOW)} quit`
  ];
  const viewportHeight = Math.max(4, rows - header.length - footer.length - 1);
  const effectiveOffset = clampScrollOffset(scrollOffset, body.length, viewportHeight);
  const visibleBody = body.slice(effectiveOffset, effectiveOffset + viewportHeight);
  const padding = Array.from({ length: Math.max(0, viewportHeight - visibleBody.length) }, () => "");
  const scrollStatus = body.length > viewportHeight ? color(`Lines ${effectiveOffset + 1}-${Math.min(body.length, effectiveOffset + viewportHeight)} of ${body.length}`, DIM) : color("All command output is visible.", DIM);
  const lines = [...header, ...visibleBody, ...padding, scrollStatus, ...footer];
  return `${HOME_CLEAR}${HIDE_CURSOR}${lines.join(`
`)}`;
}
function enterAltScreen() {
  process.stdout.write(`${ALT_SCREEN_ON}${ALT_SCROLL_ON}${HOME_CLEAR}${HIDE_CURSOR}`);
}
function leaveAltScreen() {
  process.stdout.write(`${SHOW_CURSOR}${ALT_SCROLL_OFF}${ALT_SCREEN_OFF}`);
}
function paint(content) {
  process.stdout.write(content);
}
function suspendRawMode() {
  if (process.stdin.isTTY) {
    process.stdin.setRawMode(false);
  }
  process.stdin.pause();
  process.stdout.write(SHOW_CURSOR);
}
function resumeRawMode() {
  if (process.stdin.isTTY) {
    process.stdin.setRawMode(true);
  }
  process.stdin.resume();
  process.stdout.write(HIDE_CURSOR);
}

class InteractiveExitError extends Error {
  constructor() {
    super("Interactive session cancelled");
    this.name = "InteractiveExitError";
  }
}
var PROVIDER_CHOICES = [
  { value: "claude-code", label: "Claude Code", description: "Anthropic project logs" },
  { value: "codex", label: "Codex", description: "OpenAI session logs" },
  { value: "cursor", label: "Cursor", description: "Cursor API cache exports" },
  { value: "pi", label: "Pi", description: "pi-mono local session logs" },
  { value: "open-code", label: "Open Code", description: "Open Code storage and database" }
];
function isInteractiveExitError(error) {
  return error instanceof InteractiveExitError;
}
function parsePositiveInteger(value) {
  const trimmed = value.trim();
  if (trimmed === "")
    return null;
  const parsed = Number(trimmed);
  if (!Number.isInteger(parsed) || parsed <= 0) {
    throw new Error(`Expected a positive whole number, received "${value}".`);
  }
  return parsed;
}
function renderChoiceScreen(title, description, options, selectedIndex, selectedValues, footer = `${color("Up/Down", YELLOW)} move  ${color("Space", YELLOW)} toggle  ${color("Enter", YELLOW)} confirm  ${color("Ctrl-C", YELLOW)} exit`) {
  const optionLines = options.map((option, index) => {
    const isSelected = index === selectedIndex;
    const isChecked = selectedValues ? selectedValues.has(option.value) : isSelected;
    const pointer = isSelected ? color(">", GREEN) : " ";
    const checkbox = selectedValues ? isChecked ? color("[x]", GREEN) : color("[ ]", DIM) : isSelected ? color("[\u2022]", GREEN) : color("[ ]", DIM);
    const titleColor = isSelected ? WHITE + BOLD : WHITE;
    const descriptionColor = isSelected ? CYAN : DIM;
    return `${pointer} ${checkbox} ${color(option.label, titleColor)} ${color(option.description, descriptionColor)}`;
  });
  const lines = [
    color(title, WHITE + BOLD),
    color(description, DIM),
    "",
    ...optionLines,
    "",
    renderRule(44),
    footer
  ];
  return `${HOME_CLEAR}${HIDE_CURSOR}${lines.join(`
`)}`;
}
async function ask(prompt, initialValue = "") {
  const readline = createInterface2({
    input: process.stdin,
    output: process.stdout
  });
  let settled = false;
  return new Promise((resolve, reject) => {
    const finish = (fn) => {
      if (settled)
        return;
      settled = true;
      readline.off("SIGINT", onSigint);
      readline.close();
      fn();
    };
    const onSigint = () => {
      finish(() => reject(new InteractiveExitError));
    };
    readline.on("SIGINT", onSigint);
    const suffix = initialValue ? ` (${initialValue})` : "";
    readline.question(`${prompt}${suffix}: `).then((value) => {
      finish(() => resolve(value.trim() || initialValue));
    }).catch((error) => {
      finish(() => reject(error));
    });
  });
}
async function askYesNo(prompt, defaultValue = false) {
  const hint = defaultValue ? "Y/n" : "y/N";
  const value = (await ask(`${prompt} [${hint}]`)).toLowerCase();
  if (value === "")
    return defaultValue;
  return value === "y" || value === "yes";
}
async function promptSingleChoice(title, description, options, initialIndex = 0) {
  return new Promise((resolve, reject) => {
    let selectedIndex = Math.max(0, Math.min(initialIndex, options.length - 1));
    const onKeypress = (_input, key) => {
      if (key.ctrl && key.name === "c") {
        cleanup();
        reject(new InteractiveExitError);
        return;
      }
      if (key.name === "up") {
        selectedIndex = (selectedIndex - 1 + options.length) % options.length;
        render();
        return;
      }
      if (key.name === "down") {
        selectedIndex = (selectedIndex + 1) % options.length;
        render();
        return;
      }
      const digit = key.sequence?.match(/^[1-9]$/)?.[0];
      if (digit) {
        const index = Number(digit) - 1;
        if (index < options.length) {
          selectedIndex = index;
          cleanup();
          resolve(options[selectedIndex].value);
        }
        return;
      }
      if (key.name === "return" || key.name === "enter") {
        cleanup();
        resolve(options[selectedIndex].value);
      }
    };
    function render() {
      paint(renderChoiceScreen(title, description, options, selectedIndex, undefined, `${color("Up/Down", YELLOW)} move  ${color("1-9", YELLOW)} pick  ${color("Enter", YELLOW)} confirm  ${color("Ctrl-C", YELLOW)} exit`));
    }
    function cleanup() {
      process.stdin.off("keypress", onKeypress);
      suspendRawMode();
    }
    render();
    resumeRawMode();
    process.stdin.on("keypress", onKeypress);
  });
}
async function promptMultiChoice(title, description, options, initialValues = []) {
  return new Promise((resolve, reject) => {
    let selectedIndex = 0;
    const selectedValues = new Set(initialValues);
    const onKeypress = (_input, key) => {
      if (key.ctrl && key.name === "c") {
        cleanup();
        reject(new InteractiveExitError);
        return;
      }
      if (key.name === "up") {
        selectedIndex = (selectedIndex - 1 + options.length) % options.length;
        render();
        return;
      }
      if (key.name === "down") {
        selectedIndex = (selectedIndex + 1) % options.length;
        render();
        return;
      }
      if (key.name === "space") {
        toggleSelected(selectedIndex);
        render();
        return;
      }
      const digit = key.sequence?.match(/^[1-9]$/)?.[0];
      if (digit) {
        const index = Number(digit) - 1;
        if (index < options.length) {
          selectedIndex = index;
          toggleSelected(selectedIndex);
          render();
        }
        return;
      }
      if (key.name === "return" || key.name === "enter") {
        cleanup();
        resolve(Array.from(selectedValues));
      }
    };
    function toggleSelected(index) {
      const value = options[index].value;
      if (selectedValues.has(value)) {
        selectedValues.delete(value);
      } else {
        selectedValues.add(value);
      }
    }
    function render() {
      paint(renderChoiceScreen(title, description, options, selectedIndex, selectedValues));
    }
    function cleanup() {
      process.stdin.off("keypress", onKeypress);
      suspendRawMode();
    }
    render();
    resumeRawMode();
    process.stdin.on("keypress", onKeypress);
  });
}
function applySelectedProviders(args, providers) {
  if (providers.length === 0)
    return;
  args["provider"] = providers.join(",");
}
async function promptTheme(defaultTheme = "dark") {
  const theme = await promptSingleChoice("Theme", "Pick the rendering theme.", [
    { value: "dark", label: "Dark", description: "High-contrast dark canvas" },
    { value: "light", label: "Light", description: "Bright export with light background" }
  ], defaultTheme === "light" ? 1 : 0);
  return theme;
}
async function promptDateWindow() {
  const choice = await promptSingleChoice("Date Window", "Choose how much history to include.", [
    { value: "7", label: "Last 7 days", description: "Quick recent snapshot" },
    { value: "30", label: "Last 30 days", description: "Short-term trend window" },
    { value: "90", label: "Last 90 days", description: "Default overview" },
    { value: "365", label: "Last 365 days", description: "Long-range usage pattern" },
    { value: "custom", label: "Custom range", description: "Enter exact dates manually" }
  ], 2);
  if (choice !== "custom") {
    return { days: Number(choice) };
  }
  const since = await ask("Since date YYYY-MM-DD");
  const until = await ask("Until date YYYY-MM-DD (blank for today)");
  const args = { since };
  if (until)
    args["until"] = until;
  return args;
}
async function promptProviderSelection(title = "Provider Filter") {
  return promptMultiChoice(title, "Toggle one or more providers. Leave everything unchecked to use auto-detection.", PROVIDER_CHOICES);
}
async function promptOutputPath(defaultPath) {
  return ask("Output file", defaultPath);
}
async function promptWidth() {
  const choice = await promptSingleChoice("Terminal Width", "Choose the dashboard width.", [
    { value: "80", label: "80 columns", description: "Standard terminal width" },
    { value: "100", label: "100 columns", description: "Balanced dashboard layout" },
    { value: "120", label: "120 columns", description: "Wide dashboard layout" },
    { value: "custom", label: "Custom width", description: "Enter an exact width" }
  ], 1);
  if (choice !== "custom") {
    return Number(choice);
  }
  while (true) {
    try {
      const parsed = parsePositiveInteger(await ask("Custom width"));
      if (parsed !== null) {
        return parsed;
      }
      paint(`${HOME_CLEAR}${SHOW_CURSOR}${color("Width required", RED)}
${color("Enter a positive whole number to continue.", DIM)}

Press Enter to try again.`);
      await ask("");
    } catch (error) {
      paint(`${HOME_CLEAR}${SHOW_CURSOR}${color("Invalid width", RED)}
${color(error instanceof Error ? error.message : String(error), DIM)}

Press Enter to try again.`);
      await ask("");
    }
  }
}
async function promptCompareSetting() {
  const choice = await promptSingleChoice("Compare Mode", "Optionally compare the current range against an earlier period.", [
    { value: "off", label: "No compare", description: "Render a standard single-period report" },
    {
      value: "auto",
      label: "Auto compare",
      description: "Split the selected window automatically"
    },
    {
      value: "custom",
      label: "Custom compare range",
      description: "Provide an explicit YYYY-MM-DD..YYYY-MM-DD range"
    }
  ]);
  if (choice === "off")
    return null;
  if (choice === "auto")
    return "auto";
  return ask("Previous range YYYY-MM-DD..YYYY-MM-DD");
}
function inferDashboardTimeRange(rangeArgs) {
  const days = typeof rangeArgs["days"] === "number" ? rangeArgs["days"] : null;
  if (days !== null) {
    if (days <= 7)
      return "7d";
    if (days <= 30)
      return "30d";
    if (days <= 90)
      return "90d";
    return "365d";
  }
  const since = typeof rangeArgs["since"] === "string" ? rangeArgs["since"].trim() : "";
  if (!since)
    return "30d";
  const rawUntil = typeof rangeArgs["until"] === "string" ? rangeArgs["until"].trim() : "";
  const until = rawUntil || new Date().toISOString().slice(0, 10);
  const sinceMs = Date.parse(`${since}T00:00:00.000Z`);
  const untilMs = Date.parse(`${until}T00:00:00.000Z`);
  if (!Number.isFinite(sinceMs) || !Number.isFinite(untilMs) || sinceMs > untilMs) {
    return "30d";
  }
  const spanDays = Math.max(1, Math.ceil((untilMs - sinceMs) / DAY_MS));
  if (spanDays <= 7)
    return "7d";
  if (spanDays <= 30)
    return "30d";
  if (spanDays <= 90)
    return "90d";
  return "365d";
}
function buildTabbedDashboardOptions(rangeArgs, providers, width, noInsights, noColor2, compare = "auto") {
  const options = {
    initialTimeRange: inferDashboardTimeRange(rangeArgs),
    noColor: noColor2,
    noInsights
  };
  const rawSince = typeof rangeArgs["since"] === "string" ? rangeArgs["since"].trim() : "";
  const rawUntil = typeof rangeArgs["until"] === "string" ? rangeArgs["until"].trim() : "";
  const since = rawSince || undefined;
  const until = rawUntil || undefined;
  if (since) {
    options.initialRange = computeDateRange({ since, until });
    options.until = options.initialRange.until;
  } else if (until) {
    options.until = computeDateRange({ until }).until;
  }
  if (providers.length > 0) {
    options.providerNames = [...providers];
  }
  if (width !== null) {
    options.width = width;
  }
  if (compare) {
    options.compare = compare;
  }
  return options;
}
function createTabbedDashboardRequest(options) {
  const args = {};
  const initialDays = options.initialTimeRange ? TAB_RANGE_DAY_COUNTS[options.initialTimeRange] : undefined;
  if (options.initialRange) {
    args["since"] = options.initialRange.since;
    args["until"] = options.initialRange.until;
  } else {
    if (initialDays !== undefined)
      args["days"] = initialDays;
    if (options.until)
      args["until"] = options.until;
  }
  if (options.providerNames && options.providerNames.length > 0) {
    args["provider"] = options.providerNames.join(",");
  }
  if (options.compare)
    args["compare"] = options.compare;
  if (options.width !== undefined)
    args["width"] = options.width;
  if (options.noInsights)
    args["noInsights"] = true;
  if (options.noColor)
    args["noColor"] = true;
  return {
    args,
    preview: buildCliPreview(args),
    title: "Launch Dashboard",
    loadingTitle: "Starting dashboard",
    loadingDetail: "Launching the interactive terminal dashboard",
    executionMode: "inherit"
  };
}
async function buildDashboardPreset() {
  const rangeArgs = await promptDateWindow();
  const providers = await promptProviderSelection();
  const width = await promptWidth();
  const noInsights = await askYesNo("Hide insights panel", false);
  const noColor2 = await askYesNo("Disable ANSI colors", false);
  return {
    type: "tabbed-dashboard",
    options: buildTabbedDashboardOptions(rangeArgs, providers, width, noInsights, noColor2)
  };
}
async function buildJsonPreset() {
  const rangeArgs = await promptDateWindow();
  const providers = await promptProviderSelection();
  const compare = await promptCompareSetting();
  const saveToFile = await askYesNo("Write JSON to a file", false);
  const clipboard = !saveToFile && await askYesNo("Copy JSON to clipboard after render", false);
  const args = {
    format: "json",
    ...rangeArgs
  };
  applySelectedProviders(args, providers);
  if (compare)
    args["compare"] = compare;
  if (saveToFile) {
    args["output"] = await promptOutputPath(compare ? "tokenleak-compare.json" : "tokenleak.json");
  }
  if (clipboard)
    args["clipboard"] = true;
  return createRunCommand(args);
}
async function buildImagePreset(format) {
  const theme = await promptTheme();
  const rangeArgs = await promptDateWindow();
  const providers = await promptProviderSelection("Provider Filter");
  const compare = await promptCompareSetting();
  const output2 = await promptOutputPath(`tokenleak.${format}`);
  const shouldOpen = await askYesNo("Open the file when done", true);
  const more = compare ? true : await askYesNo("Enable --more stats", format === "png");
  const args = {
    format,
    theme,
    output: output2,
    open: shouldOpen,
    more,
    ...rangeArgs
  };
  applySelectedProviders(args, providers);
  if (compare)
    args["compare"] = compare;
  return createRunCommand(args);
}
async function buildWrappedPreset() {
  const theme = await promptTheme();
  const rangeArgs = await promptDateWindow();
  const providers = await promptProviderSelection("Provider Filter");
  const output2 = await promptOutputPath("tokenleak-wrapped.png");
  const shouldOpen = await askYesNo("Open the image when done", true);
  const args = {
    format: "wrapped",
    theme,
    output: output2,
    open: shouldOpen,
    ...rangeArgs
  };
  applySelectedProviders(args, providers);
  return createRunCommand(args);
}
async function buildComparePreset() {
  const rangeArgs = await promptDateWindow();
  const providers = await promptProviderSelection();
  const compareMode = await promptSingleChoice("Reference Period", "Choose how the earlier comparison period should be defined.", [
    {
      value: "auto",
      label: "Auto compare",
      description: "Split the chosen window automatically"
    },
    {
      value: "custom",
      label: "Custom compare range",
      description: "Enter an explicit prior range manually"
    }
  ]);
  const compare = compareMode === "custom" ? await ask("Previous range YYYY-MM-DD..YYYY-MM-DD") : "auto";
  const saveToFile = await askYesNo("Write compare output to a file", false);
  const args = {
    format: "json",
    compare,
    ...rangeArgs
  };
  applySelectedProviders(args, providers);
  if (saveToFile) {
    args["output"] = await promptOutputPath("tokenleak-compare.json");
  }
  return createRunCommand(args);
}
async function buildExplainPreset() {
  const date = await ask("Date to explain (YYYY-MM-DD)");
  const format = await promptSingleChoice("Explain Format", "Choose how the explain report should be rendered.", [
    {
      value: "terminal",
      label: "Terminal",
      description: "Narrative report in the current terminal"
    },
    { value: "json", label: "JSON", description: "Structured explain payload" }
  ]);
  const providers = await promptProviderSelection();
  const width = format === "terminal" ? await promptWidth() : null;
  const output2 = await ask("Output file (blank keeps stdout)");
  const noColor2 = format === "terminal" ? await askYesNo("Disable ANSI colors", false) : false;
  const args = {
    format
  };
  if (width)
    args["width"] = width;
  if (output2)
    args["output"] = output2;
  if (noColor2)
    args["noColor"] = true;
  applySelectedProviders(args, providers);
  return createSubcommandRunCommand("explain", args, [date], {
    title: "Explain Day",
    loadingTitle: "Building explain report",
    loadingDetail: `Analyzing what drove usage on ${date}.`
  });
}
async function buildFocusPreset() {
  const format = await promptSingleChoice("Focus Format", "Choose how the focus report should be rendered.", [
    {
      value: "terminal",
      label: "Terminal",
      description: "Ranked session report in the current terminal"
    },
    { value: "json", label: "JSON", description: "Structured focus payload" }
  ]);
  const rangeArgs = await promptDateWindow();
  const providers = await promptProviderSelection();
  const width = format === "terminal" ? await promptWidth() : null;
  const output2 = await ask("Output file (blank keeps stdout)");
  const noColor2 = format === "terminal" ? await askYesNo("Disable ANSI colors", false) : false;
  const args = {
    format,
    ...rangeArgs
  };
  if (width)
    args["width"] = width;
  if (output2)
    args["output"] = output2;
  if (noColor2)
    args["noColor"] = true;
  applySelectedProviders(args, providers);
  return createSubcommandRunCommand("focus", args, [], {
    title: "Focus Sessions",
    loadingTitle: "Ranking focus sessions",
    loadingDetail: "Finding the deepest work sessions for the selected range."
  });
}
async function buildAdvisorPreset() {
  const format = await promptSingleChoice("Advisor Format", "Choose how the advisor report should be rendered.", [
    {
      value: "terminal",
      label: "Terminal",
      description: "Efficiency recommendations in the current terminal"
    },
    { value: "json", label: "JSON", description: "Structured advisor payload" }
  ]);
  const rangeArgs = await promptDateWindow();
  const providers = await promptProviderSelection();
  const output2 = await ask("Output file (blank keeps stdout)");
  const noColor2 = format === "terminal" ? await askYesNo("Disable ANSI colors", false) : false;
  const args = {
    format,
    advisor: true,
    ...rangeArgs
  };
  if (output2)
    args["output"] = output2;
  if (noColor2)
    args["noColor"] = true;
  applySelectedProviders(args, providers);
  return createRunCommand(args);
}
async function buildLivePreset() {
  const theme = await promptTheme();
  const rangeArgs = await promptDateWindow();
  const providers = await promptProviderSelection();
  const more = await askYesNo("Enable --more stats", true);
  const args = {
    liveServer: true,
    theme,
    more,
    ...rangeArgs
  };
  applySelectedProviders(args, providers);
  return createRunCommand(args);
}
async function buildWrappedLivePreset() {
  const rangeArgs = await promptDateWindow();
  const providers = await promptProviderSelection("Provider Filter");
  const args = {
    wrappedLive: true,
    ...rangeArgs
  };
  applySelectedProviders(args, providers);
  return createRunCommand(args);
}
async function buildExportPreset() {
  const format = await promptSingleChoice("Export Format", "Choose the export format.", [
    { value: "png", label: "PNG", description: "Raster export for social and docs" },
    { value: "svg", label: "SVG", description: "Shareable vector card" },
    { value: "json", label: "JSON", description: "Structured machine-readable output" }
  ]);
  if (format === "json") {
    return buildJsonPreset();
  }
  return buildImagePreset(format);
}
async function askFormatChoice() {
  return promptSingleChoice("Output Format", "Choose the primary renderer for this command.", [
    { value: "terminal", label: "Terminal", description: "Dashboard in the current terminal" },
    { value: "json", label: "JSON", description: "Structured machine-readable output" },
    { value: "svg", label: "SVG", description: "Shareable vector export" },
    { value: "png", label: "PNG", description: "Raster export for social and docs" },
    {
      value: "wrapped",
      label: "\uD83C\uDF89 Wrapped",
      description: "Your AI coding story card (PNG)"
    }
  ]);
}
async function buildCustomCommand() {
  const mode = await promptSingleChoice("Command Type", "Choose the command family you want to configure.", [
    {
      value: "run",
      label: "Standard command",
      description: "Render terminal, JSON, SVG, or PNG output"
    },
    {
      value: "live-server",
      label: "Live server",
      description: "Launch the browser dashboard locally"
    },
    {
      value: "list-providers",
      label: "List providers",
      description: "Inspect registered provider backends"
    }
  ]);
  if (mode === "live-server") {
    return buildLivePreset();
  }
  if (mode === "list-providers") {
    return createRunCommand({ listProviders: true });
  }
  const format = await askFormatChoice();
  const theme = format === "terminal" ? null : await promptTheme();
  const rangeArgs = await promptDateWindow();
  const providers = await promptProviderSelection();
  const compare = await promptCompareSetting();
  const width = format === "terminal" ? await promptWidth() : null;
  const output2 = format === "terminal" ? await ask("Output file (blank keeps stdout)") : format === "json" ? await ask("Output file (blank keeps stdout)") : await ask("Output file", `tokenleak.${format}`);
  const noColor2 = await askYesNo("Disable ANSI colors", false);
  const noInsights = format === "terminal" ? await askYesNo("Hide insights", false) : false;
  const more = await askYesNo("Enable --more stats", format === "png" || format === "svg");
  const clipboard = format !== "png" ? await askYesNo("Copy output to clipboard", false) : false;
  const open = format !== "terminal" ? await askYesNo("Open generated file", false) : false;
  const upload = format !== "png" ? await ask("Upload target [blank/gist]") : "";
  const args = {
    format,
    ...rangeArgs
  };
  if (theme)
    args["theme"] = theme;
  if (compare)
    args["compare"] = compare;
  if (width)
    args["width"] = width;
  if (output2)
    args["output"] = output2;
  if (noColor2)
    args["noColor"] = true;
  if (noInsights)
    args["noInsights"] = true;
  if (more)
    args["more"] = true;
  if (clipboard)
    args["clipboard"] = true;
  if (open)
    args["open"] = true;
  if (upload)
    args["upload"] = upload;
  applySelectedProviders(args, providers);
  return createRunCommand(args);
}
function createMenuOptions() {
  return [
    {
      shortcut: "1",
      title: "Launch Dashboard",
      description: "guided terminal view",
      preview: "tokenleak --days 90",
      select: buildDashboardPreset
    },
    {
      shortcut: "2",
      title: "Export",
      description: "JSON, SVG, or PNG (PNG default)",
      preview: "tokenleak --format png --output tokenleak.png",
      select: buildExportPreset
    },
    {
      shortcut: "3",
      title: "\uD83C\uDF89 AI Wrapped",
      description: "your personal AI coding story card",
      preview: "tokenleak --format wrapped --output tokenleak-wrapped.png --open",
      select: buildWrappedPreset
    },
    {
      shortcut: "4",
      title: "\u2728 Wrapped Live",
      description: "interactive AI Wrapped in a browser",
      preview: "tokenleak --wrapped-live --days 365",
      select: buildWrappedLivePreset
    },
    {
      shortcut: "5",
      title: "Compare Periods",
      description: "diff current vs previous usage",
      preview: "tokenleak --compare auto --format json",
      select: buildComparePreset
    },
    {
      shortcut: "6",
      title: "\uD83D\uDCA1 Advisor",
      description: "model efficiency recommendations",
      preview: "tokenleak --advisor",
      select: buildAdvisorPreset
    },
    {
      shortcut: "7",
      title: "Start Live Server",
      description: "browser dashboard on localhost",
      preview: "tokenleak --live-server --theme dark",
      select: buildLivePreset
    },
    {
      shortcut: "8",
      title: "Explain Day",
      description: "diagnose one day of usage",
      preview: "tokenleak explain 2026-03-10",
      select: buildExplainPreset
    },
    {
      shortcut: "9",
      title: "Focus Sessions",
      description: "rank deep-work sessions",
      preview: "tokenleak focus --days 30",
      select: buildFocusPreset
    },
    {
      shortcut: "0",
      title: "Build Custom Command",
      description: "configure flags interactively",
      preview: "tokenleak --format terminal --days 90",
      select: buildCustomCommand
    }
  ];
}
async function promptForMenuCommand(context, options, state) {
  let showHelp = false;
  let resolving = false;
  return new Promise((resolve, reject) => {
    const onKeypress = async (_input, key) => {
      if (resolving) {
        return;
      }
      if (key.ctrl && key.name === "c") {
        cleanup();
        resolve({ type: "exit" });
        return;
      }
      if (showHelp) {
        if (key.name === "escape" || key.name === "return" || key.name === "enter" || key.name === "q" || key.name === "h") {
          showHelp = false;
          paint(renderLauncher(context, options, state.selectedIndex));
        }
        return;
      }
      if (key.name === "up") {
        state.selectedIndex = (state.selectedIndex - 1 + options.length) % options.length;
        paint(renderLauncher(context, options, state.selectedIndex));
        return;
      }
      if (key.name === "down") {
        state.selectedIndex = (state.selectedIndex + 1) % options.length;
        paint(renderLauncher(context, options, state.selectedIndex));
        return;
      }
      if (key.name === "h") {
        showHelp = true;
        paint(renderHelpOverlay(context.helpText, Math.max(60, (process.stdout.columns ?? 120) - 1)));
        return;
      }
      if (key.name === "q" || key.name === "escape") {
        cleanup();
        resolve({ type: "exit" });
        return;
      }
      const digit = key.sequence?.match(/^[0-9]$/)?.[0];
      if (digit) {
        const nextIndex = options.findIndex((option) => option.shortcut === digit);
        if (nextIndex >= 0) {
          state.selectedIndex = nextIndex;
          resolving = true;
          cleanup();
          try {
            const command = await options[nextIndex].select();
            resolve(command);
          } catch (error) {
            if (isInteractiveExitError(error)) {
              resolve({ type: "exit" });
              return;
            }
            reject(error);
          }
        }
        return;
      }
      if (key.name === "return" || key.name === "enter") {
        resolving = true;
        cleanup();
        try {
          const command = await options[state.selectedIndex].select();
          resolve(command);
        } catch (error) {
          if (isInteractiveExitError(error)) {
            resolve({ type: "exit" });
            return;
          }
          reject(error);
        }
      }
    };
    function cleanup() {
      process.stdin.off("keypress", onKeypress);
      suspendRawMode();
    }
    paint(renderLauncher(context, options, state.selectedIndex));
    resumeRawMode();
    process.stdin.on("keypress", onKeypress);
  });
}
async function showExecutionResult(request, result) {
  const body = [
    ...buildOutputSectionLines("Output", result.stdout, Math.max(60, (process.stdout.columns ?? 120) - 1)),
    ...buildOutputSectionLines("Messages", result.stderr, Math.max(60, (process.stdout.columns ?? 120) - 1))
  ];
  let scrollOffset = 0;
  return new Promise((resolve) => {
    const viewportHeight = () => {
      const rows = process.stdout.rows ?? 40;
      const headerLines = 6;
      const footerLines = 3;
      return Math.max(4, rows - headerLines - footerLines);
    };
    const render = () => {
      paint(renderResult(request, result, scrollOffset));
    };
    const onKeypress = (_input, key) => {
      if (key.ctrl && key.name === "c") {
        cleanup();
        resolve("exit");
        return;
      }
      if (key.name === "q" || key.name === "escape") {
        cleanup();
        resolve("exit");
        return;
      }
      if (key.name === "return" || key.name === "enter") {
        cleanup();
        resolve("menu");
        return;
      }
      const page = viewportHeight();
      if (key.name === "up") {
        scrollOffset = clampScrollOffset(scrollOffset - 1, body.length, page);
        render();
        return;
      }
      if (key.name === "down") {
        scrollOffset = clampScrollOffset(scrollOffset + 1, body.length, page);
        render();
        return;
      }
      if (key.name === "pageup") {
        scrollOffset = clampScrollOffset(scrollOffset - page, body.length, page);
        render();
        return;
      }
      if (key.name === "pagedown") {
        scrollOffset = clampScrollOffset(scrollOffset + page, body.length, page);
        render();
        return;
      }
      if (key.name === "home") {
        scrollOffset = 0;
        render();
        return;
      }
      if (key.name === "end") {
        scrollOffset = clampScrollOffset(Number.MAX_SAFE_INTEGER, body.length, page);
        render();
      }
    };
    const cleanup = () => {
      process.stdin.off("keypress", onKeypress);
      suspendRawMode();
    };
    render();
    resumeRawMode();
    process.stdin.on("keypress", onKeypress);
  });
}
function shouldStartInteractiveCli(argv, stdinIsTTY, stdoutIsTTY) {
  return argv.length === 0 && stdinIsTTY && stdoutIsTTY;
}
async function startInteractiveCli(context, execute, launchTabbedDashboard) {
  const options = createMenuOptions();
  const state = { selectedIndex: 0 };
  let interrupted = false;
  let ignoreSigint = false;
  const onSigint = () => {
    if (!ignoreSigint) {
      interrupted = true;
    }
  };
  emitKeypressEvents(process.stdin);
  enterAltScreen();
  process.on("SIGINT", onSigint);
  try {
    while (true) {
      if (interrupted) {
        return;
      }
      const command = await promptForMenuCommand(context, options, state);
      if (command.type === "exit") {
        return;
      }
      if (command.type === "show-help") {
        continue;
      }
      if (command.type === "tabbed-dashboard") {
        if (launchTabbedDashboard) {
          const request = createTabbedDashboardRequest(command.options);
          let dashboardError = null;
          leaveAltScreen();
          try {
            ignoreSigint = true;
            await launchTabbedDashboard(command.options);
          } catch (error) {
            dashboardError = error;
          } finally {
            ignoreSigint = false;
            enterAltScreen();
          }
          if (dashboardError) {
            const message = dashboardError instanceof Error ? dashboardError.message : String(dashboardError);
            const next2 = await showExecutionResult(request, {
              ok: false,
              summary: message,
              stdout: "",
              stderr: message
            });
            if (next2 === "exit") {
              return;
            }
          }
        }
        continue;
      }
      const startedAt = Date.now();
      let loadingFrame = 0;
      paint(renderLoading(command.request, loadingFrame, startedAt));
      const loadingTicker = setInterval(() => {
        loadingFrame += 1;
        paint(renderLoading(command.request, loadingFrame, startedAt));
      }, LOADING_TICK_MS);
      let result;
      try {
        if (command.request.executionMode === "inherit") {
          clearInterval(loadingTicker);
          leaveAltScreen();
          try {
            ignoreSigint = true;
            result = await execute(command.request);
          } finally {
            ignoreSigint = false;
            enterAltScreen();
          }
        } else {
          result = await execute(command.request);
        }
      } finally {
        clearInterval(loadingTicker);
      }
      if (interrupted) {
        return;
      }
      const next = await showExecutionResult(command.request, result);
      if (next === "exit") {
        return;
      }
    }
  } finally {
    process.off("SIGINT", onSigint);
    suspendRawMode();
    leaveAltScreen();
  }
}

// packages/cli/src/sharing/clipboard.ts
var PLATFORM_COMMANDS = {
  darwin: ["pbcopy"],
  linux: ["xclip", "-selection", "clipboard"],
  win32: ["clip"]
};
function getClipboardCommand(platform = process.platform) {
  const command = PLATFORM_COMMANDS[platform];
  if (!command) {
    throw new Error(`Clipboard is not supported on platform "${platform}". Supported: macOS, Linux, Windows.`);
  }
  return command;
}
async function copyToClipboard(content, platform = process.platform) {
  const [cmd, ...args] = getClipboardCommand(platform);
  const proc = Bun.spawn([cmd, ...args], {
    stdin: "pipe",
    stdout: "ignore",
    stderr: "pipe"
  });
  proc.stdin.write(content);
  proc.stdin.end();
  const exitCode = await proc.exited;
  if (exitCode !== 0) {
    const stderr = await new Response(proc.stderr).text();
    throw new Error(`Clipboard command "${cmd}" failed with exit code ${exitCode}: ${stderr.trim()}`);
  }
}
// packages/cli/src/sharing/open.ts
var PLATFORM_COMMANDS2 = {
  darwin: "open",
  linux: "xdg-open",
  win32: "start"
};
function getOpenCommand(platform = process.platform) {
  const command = PLATFORM_COMMANDS2[platform];
  if (!command) {
    throw new Error(`Opening files is not supported on platform "${platform}". Supported: macOS, Linux, Windows.`);
  }
  return command;
}
async function openFile(filePath, platform = process.platform) {
  const cmd = getOpenCommand(platform);
  const spawnArgs = platform === "win32" ? ["cmd", "/c", "start", "", filePath] : [cmd, filePath];
  const proc = Bun.spawn(spawnArgs, {
    stdout: "ignore",
    stderr: "pipe"
  });
  const exitCode = await proc.exited;
  if (exitCode !== 0) {
    const stderr = await new Response(proc.stderr).text();
    throw new Error(`Failed to open "${filePath}" with "${cmd}": exit code ${exitCode}: ${stderr.trim()}`);
  }
}
// packages/cli/src/sharing/gist.ts
async function isGhAvailable() {
  try {
    const proc = Bun.spawn(["gh", "auth", "status"], {
      stdout: "ignore",
      stderr: "ignore"
    });
    const exitCode = await proc.exited;
    return exitCode === 0;
  } catch {
    return false;
  }
}
async function uploadToGist(content, filename, description) {
  const available = await isGhAvailable();
  if (!available) {
    throw new Error("GitHub CLI (gh) is not installed or not authenticated. " + "Install it from https://cli.github.com and run `gh auth login`.");
  }
  const { join: join9 } = await import("path");
  const { tmpdir: tmpdir2 } = await import("os");
  const { writeFileSync: writeFileSync3, unlinkSync: unlinkSync2 } = await import("fs");
  const tmpPath = join9(tmpdir2(), `tokenleak-gist-${Date.now()}-${filename}`);
  writeFileSync3(tmpPath, content, "utf-8");
  try {
    const proc = Bun.spawn(["gh", "gist", "create", tmpPath, "--desc", description, "--public"], {
      stdout: "pipe",
      stderr: "pipe"
    });
    const exitCode = await proc.exited;
    const stdout = (await new Response(proc.stdout).text()).trim();
    const stderr = (await new Response(proc.stderr).text()).trim();
    if (exitCode !== 0) {
      throw new Error(`Failed to create gist: ${stderr || "unknown error"} (exit code ${exitCode})`);
    }
    if (!stdout.startsWith("http")) {
      throw new Error(`Unexpected gh output: ${stdout}`);
    }
    return stdout;
  } finally {
    try {
      unlinkSync2(tmpPath);
    } catch {}
  }
}
// packages/cli/src/tabbed-dashboard.ts
init_dist3();
var HOME_CLEAR2 = "\x1B[H\x1B[J";
var HIDE_CURSOR2 = "\x1B[?25l";
var SHOW_CURSOR2 = "\x1B[?25h";
var ALT_SCREEN_ON2 = "\x1B[?1049h";
var ALT_SCREEN_OFF2 = "\x1B[?1049l";
var ALT_SCROLL_ON2 = "\x1B[?1007h";
var ALT_SCROLL_OFF2 = "\x1B[?1007l";
var DIM2 = "\x1B[2m";
var RESET3 = "\x1B[0m";
var BOLD2 = "\x1B[1m";
var YELLOW2 = "\x1B[33m";
function timeRangeToDays(range) {
  switch (range) {
    case "7d":
      return 7;
    case "30d":
      return 30;
    case "90d":
      return 90;
    case "365d":
      return 365;
    default:
      return 30;
  }
}
function computeRange(range, baseUntil) {
  const until = baseUntil;
  const d = new Date(until);
  d.setDate(d.getDate() - timeRangeToDays(range));
  const since = d.toISOString().slice(0, 10);
  return { since, until };
}
function resolveRange(state, timeRange) {
  if (state.initialRange && timeRange === state.initialTimeRange) {
    return state.initialRange;
  }
  return computeRange(timeRange, state.baseUntil);
}
async function loadForRange(state, providers, timeRange) {
  const cached = state.dataCache.get(timeRange);
  if (cached)
    return cached;
  const inflight = state.inflightLoads.get(timeRange);
  if (inflight)
    return inflight;
  const range = resolveRange(state, timeRange);
  const loadPromise = (state.compare ? loadCompareTokenleakData(providers, range, state.compare).then((result) => result.output) : loadTokenleakData(providers, range)).then((output2) => {
    state.dataCache.set(timeRange, output2);
    return output2;
  }).finally(() => {
    state.inflightLoads.delete(timeRange);
  });
  state.inflightLoads.set(timeRange, loadPromise);
  return loadPromise;
}
function getRenderWidth(state) {
  const terminalWidth = Math.max(40, (process.stdout.columns ?? 80) - 1);
  if (state.width === null) {
    return terminalWidth;
  }
  return Math.max(40, Math.min(terminalWidth, state.width));
}
function getViewportHeight(state, width, rows) {
  const headerLines = renderTabBar(state.timeRange, state.metricTab, width, state.noColor).split(`
`).length + 2;
  const footerLines = 1;
  return Math.max(4, rows - headerLines - footerLines - 1);
}
function renderActiveView(output2, tab, width, noColor2, noInsights) {
  const options = {
    format: "terminal",
    theme: "dark",
    width,
    showInsights: !noInsights,
    noColor: noColor2,
    output: null,
    more: true
  };
  switch (tab) {
    case "overview":
      return renderOverviewView(output2, options);
    case "delta":
      return renderCompareView(output2, width, noColor2);
    case "provider":
      return renderProviderView(output2, width, noColor2);
    case "sess":
      return renderSessionView(output2, width, noColor2);
    case "tok":
      return renderTokenView(output2, width, noColor2);
    case "model":
      return renderModelView(output2, width, noColor2);
    case "cwd":
      return renderCwdView(output2, width, noColor2);
    case "dow":
      return renderDowView(output2, width, noColor2);
    case "tod":
      return renderTodView(output2, width, noColor2);
    default:
      return renderOverviewView(output2, options);
  }
}
function renderScreen(output2, state) {
  const width = getRenderWidth(state);
  const rows = process.stdout.rows ?? 40;
  const tabBar = renderTabBar(state.timeRange, state.metricTab, width, state.noColor);
  const tabBarLines = tabBar.split(`
`);
  const rangeLabel = state.noColor ? `  ${output2.dateRange.since} \u2192 ${output2.dateRange.until}` : `  ${DIM2}${output2.dateRange.since} \u2192 ${output2.dateRange.until}${RESET3}`;
  const headerLines = [...tabBarLines, rangeLabel, ""];
  const footerLines = [""];
  const viewportHeight = getViewportHeight(state, width, rows);
  const viewContent = renderActiveView(output2, state.metricTab, width, state.noColor, state.noInsights);
  const contentLines = viewContent.split(`
`);
  const effectiveOffset = clampScrollOffset(state.scrollOffset, contentLines.length, viewportHeight);
  state.scrollOffset = effectiveOffset;
  const visibleContent = contentLines.slice(effectiveOffset, effectiveOffset + viewportHeight);
  const padding = Array.from({ length: Math.max(0, viewportHeight - visibleContent.length) }, () => "");
  const scrollInfo = contentLines.length > viewportHeight ? state.noColor ? `  Lines ${effectiveOffset + 1}-${Math.min(contentLines.length, effectiveOffset + viewportHeight)} of ${contentLines.length}` : `  ${DIM2}Lines ${effectiveOffset + 1}-${Math.min(contentLines.length, effectiveOffset + viewportHeight)} of ${contentLines.length}${RESET3}` : "";
  return `${HOME_CLEAR2}${HIDE_CURSOR2}${[
    ...headerLines,
    ...visibleContent,
    ...padding,
    scrollInfo,
    ...footerLines
  ].join(`
`)}`;
}
function renderLoading2(state) {
  const width = getRenderWidth(state);
  const tabBar = renderTabBar(state.timeRange, state.metricTab, width, state.noColor);
  const loading = state.noColor ? "  Loading data..." : `  ${YELLOW2}${BOLD2}Loading data...${RESET3}`;
  return `${HOME_CLEAR2}${HIDE_CURSOR2}${tabBar}

${loading}`;
}
function enterAltScreen2() {
  process.stdout.write(`${ALT_SCREEN_ON2}${ALT_SCROLL_ON2}${HOME_CLEAR2}${HIDE_CURSOR2}`);
}
function leaveAltScreen2() {
  process.stdout.write(`${SHOW_CURSOR2}${ALT_SCROLL_OFF2}${ALT_SCREEN_OFF2}`);
}
function paint2(content) {
  process.stdout.write(content);
}
function suspendRawMode2() {
  if (process.stdin.isTTY) {
    process.stdin.setRawMode(false);
  }
  process.stdin.pause();
  process.stdout.write(SHOW_CURSOR2);
}
function resumeRawMode2() {
  if (process.stdin.isTTY) {
    process.stdin.setRawMode(true);
  }
  process.stdin.resume();
  process.stdout.write(HIDE_CURSOR2);
}
async function startTabbedDashboard(providers, options) {
  const state = {
    timeRange: options.initialTimeRange ?? "30d",
    initialTimeRange: options.initialTimeRange ?? "30d",
    metricTab: "overview",
    scrollOffset: 0,
    dataCache: new Map,
    inflightLoads: new Map,
    noColor: options.noColor,
    noInsights: options.noInsights ?? false,
    compare: options.compare ?? "auto",
    baseUntil: options.until ?? new Date().toISOString().slice(0, 10),
    initialRange: options.initialRange ?? null,
    width: options.width ?? null
  };
  enterAltScreen2();
  let currentOutput = null;
  let activeLoadId = 0;
  let shouldClose = false;
  const loadAndRender = async (timeRange) => {
    const loadId = ++activeLoadId;
    paint2(renderLoading2(state));
    let output2;
    try {
      output2 = await loadForRange(state, providers, timeRange);
    } catch (error) {
      if (shouldClose || loadId !== activeLoadId || state.timeRange !== timeRange) {
        return;
      }
      throw error;
    }
    if (shouldClose || loadId !== activeLoadId || state.timeRange !== timeRange) {
      return;
    }
    currentOutput = output2;
    paint2(renderScreen(currentOutput, state));
  };
  const rerender = () => {
    if (currentOutput) {
      paint2(renderScreen(currentOutput, state));
    }
  };
  const onResize = () => {
    rerender();
  };
  process.stdout.on("resize", onResize);
  try {
    await loadAndRender(state.timeRange);
    let fatalError = null;
    await new Promise((resolve) => {
      const settleFailure = (error) => {
        fatalError = error;
        cleanup();
        resolve();
      };
      const runAsyncAction = (action) => {
        action().catch((error) => {
          settleFailure(error);
        });
      };
      const onKeypress = (_input, key) => {
        if (key.ctrl && key.name === "c") {
          cleanup();
          resolve();
          return;
        }
        if (key.name === "q" || key.name === "escape") {
          cleanup();
          resolve();
          return;
        }
        if (key.name === "left") {
          const idx = TIME_RANGES.indexOf(state.timeRange);
          const newIdx = (idx - 1 + TIME_RANGES.length) % TIME_RANGES.length;
          state.timeRange = TIME_RANGES[newIdx];
          state.scrollOffset = 0;
          runAsyncAction(() => loadAndRender(state.timeRange));
          return;
        }
        if (key.name === "right") {
          const idx = TIME_RANGES.indexOf(state.timeRange);
          const newIdx = (idx + 1) % TIME_RANGES.length;
          state.timeRange = TIME_RANGES[newIdx];
          state.scrollOffset = 0;
          runAsyncAction(() => loadAndRender(state.timeRange));
          return;
        }
        if (key.name === "tab") {
          const idx = METRIC_TABS.indexOf(state.metricTab);
          const newIdx = key.shift ? (idx - 1 + METRIC_TABS.length) % METRIC_TABS.length : (idx + 1) % METRIC_TABS.length;
          state.metricTab = METRIC_TABS[newIdx];
          state.scrollOffset = 0;
          rerender();
          return;
        }
        const digit = key.sequence?.match(/^[1-9]$/)?.[0];
        if (digit) {
          const tabIdx = Number(digit) - 1;
          if (tabIdx < METRIC_TABS.length) {
            state.metricTab = METRIC_TABS[tabIdx];
            state.scrollOffset = 0;
            rerender();
          }
          return;
        }
        const rows = process.stdout.rows ?? 40;
        const viewportHeight = getViewportHeight(state, getRenderWidth(state), rows);
        if (key.name === "up") {
          state.scrollOffset = Math.max(0, state.scrollOffset - 1);
          rerender();
          return;
        }
        if (key.name === "down") {
          state.scrollOffset += 1;
          rerender();
          return;
        }
        if (key.name === "pageup") {
          state.scrollOffset = Math.max(0, state.scrollOffset - viewportHeight);
          rerender();
          return;
        }
        if (key.name === "pagedown") {
          state.scrollOffset += viewportHeight;
          rerender();
          return;
        }
        if (key.name === "home") {
          state.scrollOffset = 0;
          rerender();
          return;
        }
        if (key.name === "end") {
          state.scrollOffset = Number.MAX_SAFE_INTEGER;
          rerender();
          return;
        }
      };
      function cleanup() {
        shouldClose = true;
        process.stdin.off("keypress", onKeypress);
        suspendRawMode2();
      }
      resumeRawMode2();
      process.stdin.on("keypress", onKeypress);
    });
    if (fatalError) {
      throw fatalError;
    }
  } finally {
    process.stdout.off("resize", onResize);
    leaveAltScreen2();
  }
}

// packages/cli/src/cli.ts
var FORMAT_VALUES = ["json", "svg", "png", "terminal", "wrapped"];
var FOCUS_FORMAT_VALUES = ["json", "terminal"];
var THEME_VALUES = ["dark", "light"];
var PROVIDER_SHORTCUTS = {
  claude: "claude-code",
  codex: "codex",
  cursor: "cursor",
  pi: "pi",
  openCode: "open-code"
};
var PROVIDER_ALIASES = {
  anthropic: "claude-code",
  claude: "claude-code",
  "claude-code": "claude-code",
  claudecode: "claude-code",
  codex: "codex",
  cursor: "cursor",
  "cursor-ide": "cursor",
  cursoride: "cursor",
  openai: "codex",
  pi: "pi",
  "pi-mono": "pi",
  "open-code": "open-code",
  open_code: "open-code",
  opencode: "open-code"
};
var PROVIDER_ALIAS_GROUPS = {
  "claude-code": ["anthropic", "claude", "claudecode"],
  codex: ["openai"],
  cursor: ["cursor-ide", "cursoride"],
  pi: ["pi-mono"],
  "open-code": ["opencode", "open_code"]
};
function normalizeProviderToken(token) {
  const normalized = token.trim().toLowerCase().replace(/\s+/g, "-");
  return PROVIDER_ALIASES[normalized] ?? normalized;
}
function getRequestedProviders(config) {
  const requested = new Set;
  if (config.provider) {
    for (const token of config.provider.split(",")) {
      const normalized = normalizeProviderToken(token);
      if (normalized) {
        requested.add(normalized);
      }
    }
  }
  if (config.claude)
    requested.add(PROVIDER_SHORTCUTS.claude);
  if (config.codex)
    requested.add(PROVIDER_SHORTCUTS.codex);
  if (config.cursor)
    requested.add(PROVIDER_SHORTCUTS.cursor);
  if (config.pi)
    requested.add(PROVIDER_SHORTCUTS.pi);
  if (config.openCode)
    requested.add(PROVIDER_SHORTCUTS.openCode);
  return requested;
}
function providerMatchesFilter(provider, requested) {
  if (requested.size === 0)
    return true;
  const candidates = [
    normalizeProviderToken(provider.name),
    normalizeProviderToken(provider.displayName)
  ];
  return candidates.some((candidate) => requested.has(candidate));
}
function buildHelpText() {
  return [
    `tokenleak ${VERSION}`,
    "Visualize AI coding assistant token usage across providers.",
    "Running `tokenleak` with no flags opens the TUI dashboard in a TTY.",
    "",
    "Usage:",
    "  tokenleak [flags]",
    "  tokenleak explain <date> [flags]",
    "  tokenleak focus [flags]",
    "  tokenleak replay [date] [flags]",
    "  tokenleak cursor <command>",
    "",
    "Subcommands:",
    "  explain <date>         Explain what drove usage on one day",
    "  focus                  Rank sessions by deep-work score",
    "  replay [date]          Replay a day's session timeline (defaults to today)",
    "  cursor                 Manage Cursor auth and cache sync",
    "",
    "Provider Shortcuts:",
    "  --claude                Only include Claude Code",
    "  --codex                 Only include Codex",
    "  --cursor                Only include Cursor",
    "  --pi                    Only include Pi",
    "  --open-code             Only include OpenCode",
    "  --all-providers         Ignore provider filters and use every available provider",
    "  --list-providers        Show registered providers and aliases",
    "",
    "Flags:",
    "  -f, --format <format>   Output format: terminal, png, svg, json, wrapped",
    "  -t, --theme <theme>     Theme for png/svg/live output: dark, light",
    "  -s, --since <date>      Start date in YYYY-MM-DD format",
    "  -u, --until <date>      End date in YYYY-MM-DD format",
    `  -d, --days <number>     Number of trailing days to include (default: ${DEFAULT_DAYS})`,
    "  -o, --output <path>     Write output to a file and infer format from extension",
    "  -w, --width <number>    Terminal render width",
    "  -p, --provider <list>   Provider filter list, comma-separated",
    "      --compare <range>   Compare against YYYY-MM-DD..YYYY-MM-DD or auto",
    "      --more             Add expanded PNG/SVG stats and unlock compare cards",
    "      --advisor           Analyze usage and suggest cost-saving model switches",
    "      --clipboard         Copy rendered output to the clipboard",
    "      --open              Open the generated output file",
    "      --upload <target>   Upload rendered output, currently: gist",
    "  -L, --live-server       Start the interactive local dashboard",
    "      --wrapped-live      Start the AI Wrapped presentation in a browser",
    "      --legacy            Open the classic interactive launcher instead of TUI",
    "      --no-color          Disable ANSI colors",
    "      --no-insights       Hide insights in terminal mode",
    "      --help              Show this help",
    "      --version           Show version information",
    "",
    "Examples:",
    "  tokenleak",
    "  tokenleak --claude --days 30",
    "  tokenleak --codex --format png --output codex.png",
    "  tokenleak --pi --days 30",
    "  tokenleak --open-code --since 2026-01-01 --until 2026-03-01",
    "  tokenleak --provider claude,codex,pi --format svg --output usage.svg",
    "  tokenleak --provider anthropic,openai,pi-mono",
    "  tokenleak --list-providers",
    "  tokenleak --compare auto --format terminal",
    "  tokenleak --live-server --theme light",
    "  tokenleak --wrapped-live --days 365",
    "  tokenleak explain 2026-03-10",
    "  tokenleak explain 2026-03-10 --format json",
    "  tokenleak focus --provider codex --days 30",
    "  tokenleak replay",
    "  tokenleak replay 2026-03-10 --format json",
    "",
    "Version:",
    `  CLI ${VERSION}`,
    `  Schema ${SCHEMA_VERSION}`,
    ""
  ].join(`
`);
}
function buildFocusHelpText() {
  return [
    `tokenleak focus ${VERSION}`,
    "Rank sessions by a deep-work score built from duration, token density, and project streaks.",
    "",
    "Usage:",
    "  tokenleak focus [flags]",
    "",
    "Flags:",
    "  -f, --format <format>   Output format: terminal, json",
    "  -s, --since <date>      Start date in YYYY-MM-DD format",
    "  -u, --until <date>      End date in YYYY-MM-DD format",
    `  -d, --days <number>     Number of trailing days to include (default: ${DEFAULT_DAYS})`,
    "  -o, --output <path>     Write output to a file and infer format from extension",
    "  -w, --width <number>    Terminal render width",
    "  -p, --provider <list>   Provider filter list, comma-separated",
    "      --claude            Only include Claude Code",
    "      --codex             Only include Codex",
    "      --cursor           Only include Cursor",
    "      --pi                Only include Pi",
    "      --open-code         Only include OpenCode",
    "      --all-providers     Ignore provider filters and use every available provider",
    "      --list-providers    Show registered providers and aliases",
    "      --no-color          Disable ANSI colors in terminal output",
    "      --help              Show this help",
    "      --version           Show version information",
    "",
    "Examples:",
    "  tokenleak focus",
    "  tokenleak focus --provider claude,codex --days 30",
    "  tokenleak focus --format json --output focus.json",
    ""
  ].join(`
`);
}
function buildVersionText() {
  return `tokenleak ${VERSION}
schema ${SCHEMA_VERSION}
`;
}
function normalizeCliArg(arg) {
  const flagMap = {
    "--all-providers": "--allProviders",
    "--list-providers": "--listProviders",
    "--open-code": "--openCode",
    "--live-server": "--liveServer",
    "--wrapped-live": "--wrappedLive",
    "--no-color": "--noColor",
    "--no-insights": "--noInsights"
  };
  return flagMap[arg] ?? arg;
}
function buildInteractiveSummary(cliArgs, ok, exitCode) {
  if (!ok) {
    return `Command exited with code ${exitCode}.`;
  }
  if (typeof cliArgs["output"] === "string") {
    const outputPath = cliArgs["output"];
    const format2 = String(cliArgs["format"] ?? inferFormatFromPath(outputPath) ?? "output").toUpperCase();
    return `${format2} written to ${outputPath}.`;
  }
  if (cliArgs["subcommand"] === "explain") {
    return "Explain report generated.";
  }
  if (cliArgs["subcommand"] === "focus") {
    return "Focus report generated.";
  }
  if (cliArgs["subcommand"] === "cursor") {
    return "Cursor command completed.";
  }
  if (cliArgs["listProviders"]) {
    return "Provider registry loaded.";
  }
  if (cliArgs["liveServer"]) {
    return "Live dashboard stopped.";
  }
  if (cliArgs["wrappedLive"]) {
    return "Wrapped live presentation stopped.";
  }
  if (cliArgs["compare"]) {
    return "Compare report generated.";
  }
  const format = String(cliArgs["format"] ?? "terminal");
  if (format === "terminal") {
    return "Terminal dashboard generated.";
  }
  return `${format.toUpperCase()} command finished successfully.`;
}
async function executeInteractiveCommand(request) {
  try {
    const cliPath = process.argv[1];
    if (!cliPath) {
      return {
        ok: false,
        summary: "Could not resolve the current tokenleak entrypoint.",
        stdout: "",
        stderr: "Error: process.argv[1] is missing."
      };
    }
    const command = [process.execPath, cliPath, ...request.argv ?? buildCliArgTokens(request.args)];
    if (request.executionMode === "inherit") {
      const proc2 = Bun.spawn(command, {
        stdin: "inherit",
        stdout: "inherit",
        stderr: "inherit"
      });
      const exitCode2 = await proc2.exited;
      return {
        ok: exitCode2 === 0,
        summary: buildInteractiveSummary(request.args, exitCode2 === 0, exitCode2),
        stdout: "",
        stderr: ""
      };
    }
    const proc = Bun.spawn(command, {
      stdin: "ignore",
      stdout: "pipe",
      stderr: "pipe"
    });
    const [exitCode, stdout, stderr] = await Promise.all([
      proc.exited,
      new Response(proc.stdout).text(),
      new Response(proc.stderr).text()
    ]);
    return {
      ok: exitCode === 0,
      summary: buildInteractiveSummary(request.args, exitCode === 0, exitCode),
      stdout,
      stderr
    };
  } catch (error) {
    return {
      ok: false,
      summary: "Interactive command failed before it could finish.",
      stdout: "",
      stderr: error instanceof Error ? `Error: ${error.message}` : `Error: ${String(error)}`
    };
  }
}
function normalizeCliArgv(argv) {
  const normalized = argv.map(normalizeCliArg);
  const result = [];
  for (let i = 0;i < normalized.length; i++) {
    const arg = normalized[i];
    if (arg === "--provider" || arg === "-p") {
      result.push(arg);
      const providerParts = [];
      let j = i + 1;
      while (j < normalized.length) {
        const next = normalized[j];
        if (next.startsWith("-"))
          break;
        providerParts.push(next);
        j++;
      }
      if (providerParts.length > 0) {
        result.push(providerParts.join(" "));
        i = j - 1;
      }
      continue;
    }
    result.push(arg);
  }
  return result;
}
function registerBuiltInProviders(registry) {
  registry.register(new ClaudeCodeProvider);
  registry.register(new CodexProvider);
  registry.register(new CursorProvider);
  registry.register(new PiProvider);
  registry.register(new OpenCodeProvider);
}
function buildProviderList(providers, availability) {
  const lines = ["Registered providers:", ""];
  for (const provider of providers) {
    const aliases = PROVIDER_ALIAS_GROUPS[provider.name] ?? [];
    const status = availability.get(provider.name) ? "available" : "unavailable";
    lines.push(`- ${provider.name} (${provider.displayName}) [${status}]`);
    if (aliases.length > 0) {
      lines.push(`  aliases: ${aliases.join(", ")}`);
    }
  }
  lines.push("");
  return lines.join(`
`);
}
function createRegistry2() {
  const registry = new ProviderRegistry;
  registerBuiltInProviders(registry);
  return registry;
}
function validateProviderSelection(config) {
  if (config.allProviders && (config.provider || config.claude || config.codex || config.cursor || config.pi || config.openCode)) {
    throw new TokenleakError("--all-providers cannot be combined with provider filters");
  }
}
async function selectAvailableProviders(config) {
  validateProviderSelection(config);
  const requestedProviders = getRequestedProviders(config);
  const requestedCursor = requestedProviders.has(PROVIDER_SHORTCUTS.cursor);
  if (requestedCursor && !isCursorLoggedIn() && !hasCursorUsageCache()) {
    throw new TokenleakError("Cursor is selected but not authenticated. Run `tokenleak cursor login` first.");
  }
  const cursorSync = await shouldSyncCursorForRun(config);
  if (cursorSync.attempted && cursorSync.error) {
    if (hasCursorUsageCache()) {
      process.stderr.write(`Cursor sync failed, using cached data: ${cursorSync.error}
`);
    } else if (requestedCursor) {
      throw new TokenleakError(cursorSync.error);
    } else {
      process.stderr.write(`Cursor sync skipped: ${cursorSync.error}
`);
    }
  }
  const registry = createRegistry2();
  let available = await registry.getAvailable();
  if (!config.allProviders && requestedProviders.size > 0) {
    if (config.provider && (config.claude || config.codex || config.cursor || config.pi || config.openCode)) {
      process.stderr.write(`Combining provider filters: ${Array.from(requestedProviders).join(", ")}
`);
    }
    available = available.filter((provider) => providerMatchesFilter(provider, requestedProviders));
  }
  return available;
}
function resolveTabbedDashboardProviderConfig(opts) {
  return {
    provider: opts.providerNames && opts.providerNames.length > 0 ? opts.providerNames.join(",") : undefined,
    claude: false,
    codex: false,
    cursor: false,
    pi: false,
    openCode: false,
    allProviders: false
  };
}
async function resolveTabbedDashboardProviders(opts) {
  return selectAvailableProviders(resolveTabbedDashboardProviderConfig(opts));
}
async function loadProviderData(config) {
  const dateRange = computeDateRange({
    since: config.since,
    until: config.until,
    days: config.days
  });
  return loadProviderDataForRange(config, dateRange);
}
async function loadProviderDataForRange(config, dateRange, available = null) {
  const resolvedProviders = available ?? await selectAvailableProviders(config);
  const availableProviders = resolvedProviders;
  if (availableProviders.length === 0) {
    throw new TokenleakError("No provider data found");
  }
  const results = await Promise.all(availableProviders.map(async (provider) => {
    try {
      return await provider.load(dateRange);
    } catch {
      return null;
    }
  }));
  const providerDataList = results.filter((result) => result !== null);
  if (providerDataList.length === 0) {
    throw new TokenleakError("No provider data found");
  }
  return { dateRange, providerDataList };
}
function inferFormatFromPath(filePath) {
  const ext = filePath.split(".").pop()?.toLowerCase();
  switch (ext) {
    case "json":
      return "json";
    case "svg":
      return "svg";
    case "png":
      return "png";
    default:
      return null;
  }
}
function resolveConfig(cliArgs) {
  const fileConfig = loadConfig();
  const envConfig = loadEnvOverrides();
  const merged = {
    format: "terminal",
    theme: "dark",
    days: DEFAULT_DAYS,
    output: null,
    width: 80,
    noColor: false,
    noInsights: false,
    more: false,
    claude: false,
    codex: false,
    cursor: false,
    pi: false,
    openCode: false,
    allProviders: false,
    listProviders: false,
    clipboard: false,
    open: false,
    liveServer: false,
    wrappedLive: false,
    advisor: false
  };
  if (fileConfig.format && FORMAT_VALUES.includes(fileConfig.format)) {
    merged.format = fileConfig.format;
  }
  if (fileConfig.theme && THEME_VALUES.includes(fileConfig.theme)) {
    merged.theme = fileConfig.theme;
  }
  if (fileConfig.days !== undefined)
    merged.days = fileConfig.days;
  if (fileConfig.width !== undefined)
    merged.width = fileConfig.width;
  if (fileConfig.noColor !== undefined)
    merged.noColor = fileConfig.noColor;
  if (fileConfig.noInsights !== undefined)
    merged.noInsights = fileConfig.noInsights;
  if (fileConfig.more !== undefined)
    merged.more = fileConfig.more;
  if (envConfig.format)
    merged.format = envConfig.format;
  if (envConfig.theme)
    merged.theme = envConfig.theme;
  if (envConfig.days !== undefined)
    merged.days = envConfig.days;
  const result = { ...merged };
  if (cliArgs["format"] !== undefined) {
    result.format = cliArgs["format"];
  }
  if (cliArgs["theme"] !== undefined) {
    result.theme = cliArgs["theme"];
  }
  if (cliArgs["since"] !== undefined) {
    result.since = cliArgs["since"];
  }
  if (cliArgs["until"] !== undefined) {
    result.until = cliArgs["until"];
  }
  if (cliArgs["days"] !== undefined) {
    result.days = cliArgs["days"];
  }
  if (cliArgs["output"] !== undefined) {
    const outputPath = cliArgs["output"];
    result.output = outputPath;
    if (cliArgs["format"] === undefined) {
      const inferred = inferFormatFromPath(outputPath);
      if (inferred) {
        result.format = inferred;
      }
    }
  }
  if (cliArgs["width"] !== undefined) {
    result.width = cliArgs["width"];
  }
  if (cliArgs["noColor"] !== undefined) {
    result.noColor = cliArgs["noColor"];
  }
  if (cliArgs["noInsights"] !== undefined) {
    result.noInsights = cliArgs["noInsights"];
  }
  if (cliArgs["more"] !== undefined) {
    result.more = cliArgs["more"];
  }
  if (cliArgs["compare"] !== undefined) {
    result.compare = cliArgs["compare"];
  }
  if (cliArgs["provider"] !== undefined) {
    result.provider = cliArgs["provider"];
  }
  if (cliArgs["claude"] !== undefined) {
    result.claude = cliArgs["claude"];
  }
  if (cliArgs["codex"] !== undefined) {
    result.codex = cliArgs["codex"];
  }
  if (cliArgs["cursor"] !== undefined) {
    result.cursor = cliArgs["cursor"];
  }
  if (cliArgs["pi"] !== undefined) {
    result.pi = cliArgs["pi"];
  }
  if (cliArgs["openCode"] !== undefined) {
    result.openCode = cliArgs["openCode"];
  }
  if (cliArgs["allProviders"] !== undefined) {
    result.allProviders = cliArgs["allProviders"];
  }
  if (cliArgs["listProviders"] !== undefined) {
    result.listProviders = cliArgs["listProviders"];
  }
  if (cliArgs["clipboard"] !== undefined) {
    result.clipboard = cliArgs["clipboard"];
  }
  if (cliArgs["open"] !== undefined) {
    result.open = cliArgs["open"];
  }
  if (cliArgs["upload"] !== undefined) {
    result.upload = cliArgs["upload"];
  }
  if (cliArgs["liveServer"] !== undefined) {
    result.liveServer = cliArgs["liveServer"];
  }
  if (cliArgs["wrappedLive"] !== undefined) {
    result.wrappedLive = cliArgs["wrappedLive"];
  }
  if (cliArgs["advisor"] !== undefined) {
    result.advisor = cliArgs["advisor"];
  }
  return result;
}
function resolveFocusConfig(cliArgs) {
  const fileConfig = loadConfig();
  const envConfig = loadEnvOverrides();
  const merged = {
    format: "terminal",
    since: undefined,
    until: undefined,
    days: DEFAULT_DAYS,
    output: null,
    width: 80,
    noColor: false,
    provider: undefined,
    claude: false,
    codex: false,
    cursor: false,
    pi: false,
    openCode: false,
    allProviders: false,
    listProviders: false
  };
  if (fileConfig.format && FOCUS_FORMAT_VALUES.includes(fileConfig.format)) {
    merged.format = fileConfig.format;
  }
  if (fileConfig.days !== undefined)
    merged.days = fileConfig.days;
  if (fileConfig.width !== undefined)
    merged.width = fileConfig.width;
  if (fileConfig.noColor !== undefined)
    merged.noColor = fileConfig.noColor;
  if (envConfig.format && FOCUS_FORMAT_VALUES.includes(envConfig.format)) {
    merged.format = envConfig.format;
  }
  if (envConfig.days !== undefined)
    merged.days = envConfig.days;
  const result = { ...merged };
  if (cliArgs["format"] !== undefined) {
    const format = cliArgs["format"];
    if (!FOCUS_FORMAT_VALUES.includes(format)) {
      throw new TokenleakError(`Unsupported focus format: "${format}". Available: ${FOCUS_FORMAT_VALUES.join(", ")}`);
    }
    result.format = format;
  }
  if (cliArgs["since"] !== undefined) {
    result.since = cliArgs["since"];
  }
  if (cliArgs["until"] !== undefined) {
    result.until = cliArgs["until"];
  }
  if (cliArgs["days"] !== undefined) {
    result.days = cliArgs["days"];
  }
  if (cliArgs["output"] !== undefined) {
    const outputPath = cliArgs["output"];
    result.output = outputPath;
    if (cliArgs["format"] === undefined) {
      const inferred = inferFormatFromPath(outputPath);
      if (inferred === "json") {
        result.format = "json";
      }
    }
  }
  if (cliArgs["width"] !== undefined) {
    result.width = cliArgs["width"];
  }
  if (cliArgs["noColor"] !== undefined) {
    result.noColor = cliArgs["noColor"];
  }
  if (cliArgs["provider"] !== undefined) {
    result.provider = cliArgs["provider"];
  }
  if (cliArgs["claude"] !== undefined) {
    result.claude = cliArgs["claude"];
  }
  if (cliArgs["codex"] !== undefined) {
    result.codex = cliArgs["codex"];
  }
  if (cliArgs["cursor"] !== undefined) {
    result.cursor = cliArgs["cursor"];
  }
  if (cliArgs["pi"] !== undefined) {
    result.pi = cliArgs["pi"];
  }
  if (cliArgs["openCode"] !== undefined) {
    result.openCode = cliArgs["openCode"];
  }
  if (cliArgs["allProviders"] !== undefined) {
    result.allProviders = cliArgs["allProviders"];
  }
  if (cliArgs["listProviders"] !== undefined) {
    result.listProviders = cliArgs["listProviders"];
  }
  return result;
}
function getRenderer(format) {
  switch (format) {
    case "json":
      return new JsonRenderer;
    case "svg":
      return new SvgRenderer;
    case "terminal":
      return new TerminalRenderer;
    case "png":
      return new PngRenderer;
    default:
      throw new TokenleakError(`Format "${format}" is not supported. Available formats: json, svg, png, terminal, wrapped`);
  }
}
function formatFocusDuration(durationMs) {
  if (!durationMs || durationMs <= 0) {
    return "-";
  }
  const minutes = Math.round(durationMs / 60000);
  const hours = Math.floor(minutes / 60);
  const remainder = minutes % 60;
  if (hours === 0) {
    return `${remainder}m`;
  }
  if (remainder === 0) {
    return `${hours}h`;
  }
  return `${hours}h${String(remainder).padStart(2, "0")}m`;
}
function formatFocusDensity(tokensPerHour) {
  return `${Math.round(tokensPerHour).toLocaleString("en-US")}/h`;
}
var PROVIDER_COLORS4 = {
  "claude-code": 179,
  codex: 71,
  cursor: 78,
  pi: 73,
  "open-code": 68
};
function colorScore(value, text2, noColor2) {
  if (value >= 8)
    return colorize256(text2, 71, noColor2);
  if (value >= 5)
    return colorize256(text2, 179, noColor2);
  if (value >= 3)
    return colorize256(text2, 73, noColor2);
  return dim(text2, noColor2);
}
function colorDuration(durationMs, text2, noColor2) {
  if (durationMs && durationMs > 3600000)
    return bold256(text2, 255, noColor2);
  return text2;
}
function colorDensity(tokensPerHour, text2, noColor2) {
  if (tokensPerHour > 30000)
    return colorize256(text2, 71, noColor2);
  if (tokensPerHour > 15000)
    return colorize256(text2, 179, noColor2);
  return dim(text2, noColor2);
}
function colorProvider(provider, text2, noColor2) {
  const code = PROVIDER_COLORS4[provider] ?? 246;
  return colorize256(text2, code, noColor2);
}
function colorStreak(streak, text2, noColor2) {
  if (streak >= 3)
    return colorize256(text2, 208, noColor2);
  return text2;
}
function truncateFocus(value, maxWidth) {
  if (value.length <= maxWidth)
    return value;
  if (maxWidth <= 1)
    return value.slice(0, maxWidth);
  return `${value.slice(0, maxWidth - 1)}\u2026`;
}
function renderFocusReport(report, width, noColor2) {
  const termWidth = Math.max(60, width || 80);
  const lines = [
    bold2("Tokenleak Focus", noColor2),
    report.method,
    "",
    `${report.entries.length} sessions ranked by deep-work score.`
  ];
  if (report.entries.length === 0) {
    lines.push("", "No session data available.");
    return lines.join(`
`);
  }
  const headers = ["Score", "Dur", "Density", "Stk", "Provider", "Label"];
  const rows = report.entries.map((entry) => [
    entry.score.toFixed(1),
    formatFocusDuration(entry.durationMs),
    formatFocusDensity(entry.tokensPerHour),
    `${entry.streak}d`,
    entry.provider,
    entry.label
  ]);
  const colCount = headers.length;
  const naturalWidths = headers.map((h) => h.length);
  for (const row of rows) {
    for (let c = 0;c < colCount; c++) {
      naturalWidths[c] = Math.max(naturalWidths[c], row[c].length);
    }
  }
  const colWidths = naturalWidths.map((w) => w + 2);
  const chrome = 2 + (colCount - 1);
  const maxContentWidth = termWidth - chrome;
  let totalContent = colWidths.reduce((sum, w) => sum + w, 0);
  if (totalContent > maxContentWidth) {
    const surplus = totalContent - maxContentWidth;
    const labelIdx = colCount - 1;
    const minLabelWidth = headers[labelIdx].length + 2;
    const labelShrink = Math.min(surplus, colWidths[labelIdx] - minLabelWidth);
    colWidths[labelIdx] -= labelShrink;
    totalContent -= labelShrink;
    if (totalContent > maxContentWidth) {
      for (let c = colCount - 2;c >= 0 && totalContent > maxContentWidth; c--) {
        const minW = headers[c].length + 2;
        const shrink = Math.min(totalContent - maxContentWidth, colWidths[c] - minW);
        colWidths[c] -= shrink;
        totalContent -= shrink;
      }
    }
  }
  const border = (ch) => colorize256(ch, 245, noColor2);
  function hLine(left, mid, right) {
    return border(left) + colWidths.map((w) => border("\u2500".repeat(w))).join(border(mid)) + border(right);
  }
  function tableRow(cells) {
    const padded = cells.map((cell, c) => {
      const w = colWidths[c];
      const inner = w - 2;
      const truncated = truncateFocus(cell, inner);
      return ` ${truncated.padEnd(inner)} `;
    });
    return border("\u2502") + padded.join(border("\u2502")) + border("\u2502");
  }
  function coloredDataRow(entry, cells) {
    const padded = cells.map((cell, c) => {
      const w = colWidths[c];
      const inner = w - 2;
      const truncated = truncateFocus(cell, inner);
      const paddedText = truncated.padEnd(inner);
      switch (c) {
        case 0:
          return ` ${colorScore(entry.score, paddedText, noColor2)} `;
        case 1:
          return ` ${colorDuration(entry.durationMs, paddedText, noColor2)} `;
        case 2:
          return ` ${colorDensity(entry.tokensPerHour, paddedText, noColor2)} `;
        case 3:
          return ` ${colorStreak(entry.streak, paddedText, noColor2)} `;
        case 4:
          return ` ${colorProvider(entry.provider, paddedText, noColor2)} `;
        default:
          return ` ${paddedText} `;
      }
    });
    return border("\u2502") + padded.join(border("\u2502")) + border("\u2502");
  }
  lines.push("");
  lines.push(hLine("\u250C", "\u252C", "\u2510"));
  const headerCells = headers.map((h, c) => {
    const inner = colWidths[c] - 2;
    const padded = truncateFocus(h, inner).padEnd(inner);
    return ` ${bold2(padded, noColor2)} `;
  });
  lines.push(border("\u2502") + headerCells.join(border("\u2502")) + border("\u2502"));
  lines.push(hLine("\u251C", "\u253C", "\u2524"));
  for (let i = 0;i < report.entries.length; i++) {
    const entry = report.entries[i];
    if (i > 0) {
      lines.push(hLine("\u251C", "\u253C", "\u2524"));
    }
    lines.push(coloredDataRow(entry, rows[i]));
  }
  lines.push(hLine("\u2514", "\u2534", "\u2518"));
  lines.push("");
  lines.push(dim("Stk = project streak (consecutive days)  Density = tokens per hour", noColor2));
  return lines.join(`
`);
}
async function runFocus(cliArgs) {
  const config = resolveFocusConfig(cliArgs);
  if (!FOCUS_FORMAT_VALUES.includes(config.format)) {
    throw new TokenleakError(`Format "${config.format}" is not supported for focus. Available formats: json, terminal`);
  }
  if (config.listProviders) {
    const registry = createRegistry2();
    const providers = registry.getAll();
    const availabilityResults = await Promise.all(providers.map(async (provider) => [provider.name, await provider.isAvailable()]));
    process.stdout.write(buildProviderList(providers, new Map(availabilityResults)));
    return;
  }
  const { providerDataList } = await loadProviderData(config);
  const events = providerDataList.flatMap((provider) => provider.events ?? []);
  if (events.length === 0) {
    const emptyMsg = config.format === "json" ? JSON.stringify({ method: "No event data", entries: [] }, null, 2) : renderFocusReport({ method: "No event-level data found for focus analysis.", entries: [] }, config.width, config.noColor);
    if (config.output) {
      writeFileSync3(config.output, emptyMsg);
    } else {
      process.stdout.write(`${emptyMsg}
`);
    }
    return;
  }
  const report = buildFocusReport(events);
  const rendered = config.format === "json" ? JSON.stringify(report, null, 2) : renderFocusReport(report, config.width, config.noColor);
  if (config.output) {
    writeFileSync3(config.output, rendered);
  } else {
    process.stdout.write(`${rendered}
`);
  }
}
async function run(cliArgs) {
  const config = resolveConfig(cliArgs);
  validateProviderSelection(config);
  const registry = createRegistry2();
  if (config.listProviders) {
    const providers = registry.getAll();
    const availabilityResults = await Promise.all(providers.map(async (provider) => [provider.name, await provider.isAvailable()]));
    process.stdout.write(buildProviderList(providers, new Map(availabilityResults)));
    return;
  }
  const dateRange = computeDateRange({
    since: config.since,
    until: config.until,
    days: config.days
  });
  if (config.wrappedLive) {
    process.stderr.write(`Detecting available providers...
`);
  }
  const available = await selectAvailableProviders(config);
  if (available.length === 0) {
    throw new TokenleakError("No provider data found");
  }
  if (config.wrappedLive) {
    process.stderr.write(`Found ${available.length} provider${available.length > 1 ? "s" : ""}: ${available.map((p) => p.name).join(", ")}
`);
  }
  if (config.compare) {
    const compareResult = await loadCompareTokenleakData(available, dateRange, config.compare);
    if (config.more && (config.format === "png" || config.format === "svg")) {
      const renderer2 = getRenderer(config.format);
      const renderOptions2 = {
        format: config.format,
        theme: config.theme,
        width: config.width,
        showInsights: !config.noInsights,
        noColor: config.noColor,
        output: config.output,
        more: true
      };
      const rendered3 = await renderer2.render(compareResult.output, renderOptions2);
      if (config.output) {
        const data = typeof rendered3 === "string" ? rendered3 : Buffer.from(rendered3);
        writeFileSync3(config.output, data);
      } else {
        const text2 = typeof rendered3 === "string" ? rendered3 : rendered3.toString("utf-8");
        process.stdout.write(text2 + `
`);
      }
      return;
    }
    if (config.format === "terminal") {
      const renderer2 = getRenderer("terminal");
      const renderOptions2 = {
        format: "terminal",
        theme: config.theme,
        width: config.width,
        showInsights: !config.noInsights,
        noColor: config.noColor,
        output: config.output,
        more: true
      };
      const rendered3 = await renderer2.render(compareResult.output, renderOptions2);
      if (config.output) {
        writeFileSync3(config.output, rendered3);
      } else {
        process.stdout.write(`${rendered3}
`);
      }
      return;
    }
    if (config.format !== "json") {
      process.stderr.write(`Warning: --compare only supports JSON output. Ignoring --format ${config.format}.
`);
    }
    const rendered2 = JSON.stringify(compareResult.compareOutput, null, 2);
    if (config.output) {
      writeFileSync3(config.output, rendered2);
    } else {
      process.stdout.write(rendered2 + `
`);
    }
    return;
  }
  if (config.wrappedLive) {
    process.stderr.write(`Loading usage data (${dateRange.since} to ${dateRange.until})...
`);
  }
  const { providerDataList } = await loadProviderDataForRange(config, dateRange, available);
  if (config.wrappedLive) {
    const totalEvents = providerDataList.reduce((s, p) => s + (p.events?.length ?? 0), 0);
    const totalDays = providerDataList.reduce((s, p) => s + p.daily.length, 0);
    process.stderr.write(`Loaded ${totalDays} day-records, ${totalEvents} events
`);
    process.stderr.write(`Aggregating stats...
`);
  }
  const mergedDaily = mergeProviderData(providerDataList);
  const stats = aggregate(mergedDaily, dateRange.until);
  const needsMore = config.more || config.format === "wrapped" || config.wrappedLive || config.advisor;
  if (config.wrappedLive && needsMore) {
    process.stderr.write(`Computing extended analytics (hourOfDay, sessions, cache, projections)...
`);
  }
  const output2 = {
    schemaVersion: SCHEMA_VERSION,
    generated: new Date().toISOString(),
    dateRange,
    providers: providerDataList,
    aggregated: stats,
    more: needsMore ? buildMoreStats(providerDataList, dateRange) : null
  };
  if (config.advisor) {
    if (config.format !== "terminal" && config.format !== "json") {
      throw new TokenleakError(`--advisor only supports terminal and json formats, got "${config.format}".`);
    }
    const advisorReport = analyzeEfficiency(output2, MODEL_PRICING);
    if (config.format === "json") {
      const rendered3 = JSON.stringify(advisorReport, null, 2);
      if (config.output) {
        writeFileSync3(config.output, rendered3);
      } else {
        process.stdout.write(rendered3 + `
`);
      }
      return;
    }
    const rendered2 = renderAdvisorView(advisorReport, {
      width: config.width,
      noColor: config.noColor
    });
    if (config.output) {
      writeFileSync3(config.output, rendered2);
    } else {
      process.stdout.write(rendered2 + `
`);
    }
    return;
  }
  if (config.format === "wrapped") {
    const outputPath = config.output ?? "tokenleak-wrapped.png";
    const wrappedBuffer = await renderWrappedPng(output2, { theme: config.theme });
    writeFileSync3(outputPath, wrappedBuffer);
    process.stderr.write(`Wrapped PNG written to ${outputPath}
`);
    if (config.clipboard) {
      process.stderr.write(`Clipboard is not supported for binary PNG output. Use --output to save the file.
`);
    }
    if (config.open) {
      await openFile(outputPath);
      process.stderr.write(`Opened ${outputPath} in default application.
`);
    }
    if (config.upload === "gist") {
      const base64Content = wrappedBuffer.toString("base64");
      const filename = "tokenleak-wrapped.base64.txt";
      const description = `Tokenleak Wrapped (${dateRange.since} to ${dateRange.until}) \u2014 base64-encoded PNG, decode with: base64 -d tokenleak-wrapped.base64.txt > wrapped.png`;
      const url = await uploadToGist(base64Content, filename, description);
      process.stderr.write(`Uploaded to gist: ${url}
`);
    } else if (config.upload !== undefined) {
      throw new TokenleakError(`Unknown upload target "${config.upload}". Supported: gist`);
    }
    return;
  }
  if (config.liveServer) {
    const ignoredFlags = [];
    if (config.output)
      ignoredFlags.push("--output");
    if (config.clipboard)
      ignoredFlags.push("--clipboard");
    if (config.open)
      ignoredFlags.push("--open");
    if (config.upload)
      ignoredFlags.push("--upload");
    if (ignoredFlags.length > 0) {
      process.stderr.write(`Warning: ${ignoredFlags.join(", ")} ignored in --live-server mode.
`);
    }
    const renderOptions2 = {
      format: config.format,
      theme: config.theme,
      width: config.width,
      showInsights: !config.noInsights,
      noColor: config.noColor,
      output: config.output,
      more: config.more
    };
    const { port } = await startLiveServer(output2, renderOptions2);
    await new Promise((resolve) => {
      process.on("SIGINT", () => {
        process.stderr.write(`
Shutting down server...
`);
        resolve();
      });
      process.on("SIGTERM", () => {
        resolve();
      });
    });
    return;
  }
  if (config.wrappedLive) {
    const ignoredWrappedFlags = [];
    if (config.output)
      ignoredWrappedFlags.push("--output");
    if (config.clipboard)
      ignoredWrappedFlags.push("--clipboard");
    if (config.open)
      ignoredWrappedFlags.push("--open");
    if (config.upload)
      ignoredWrappedFlags.push("--upload");
    if (ignoredWrappedFlags.length > 0) {
      process.stderr.write(`Warning: ${ignoredWrappedFlags.join(", ")} ignored in --wrapped-live mode.
`);
    }
    process.stderr.write(`Generating wrapped presentation...
`);
    const { stop } = await startWrappedLiveServer(output2);
    process.stderr.write(`Press Ctrl+C to stop the server.
`);
    await new Promise((resolve) => {
      process.on("SIGINT", () => {
        process.stderr.write(`
Shutting down wrapped live server...
`);
        stop();
        resolve();
      });
      process.on("SIGTERM", () => {
        stop();
        resolve();
      });
    });
    process.exit(0);
    return;
  }
  const renderer = getRenderer(config.format);
  const renderOptions = {
    format: config.format,
    theme: config.theme,
    width: config.width,
    showInsights: !config.noInsights,
    noColor: config.noColor,
    output: config.output,
    more: config.more
  };
  const rendered = await renderer.render(output2, renderOptions);
  if (config.output) {
    const data = typeof rendered === "string" ? rendered : Buffer.from(rendered);
    writeFileSync3(config.output, data);
  } else {
    const text2 = typeof rendered === "string" ? rendered : rendered.toString("utf-8");
    process.stdout.write(text2 + `
`);
  }
  if (config.clipboard) {
    const text2 = typeof rendered === "string" ? rendered : rendered.toString("utf-8");
    await copyToClipboard(text2);
    process.stderr.write(`Copied output to clipboard.
`);
  }
  if (config.open) {
    if (!config.output) {
      throw new TokenleakError("--open requires --output to specify a file path");
    }
    await openFile(config.output);
    process.stderr.write(`Opened ${config.output} in default application.
`);
  }
  if (config.upload === "gist") {
    const text2 = typeof rendered === "string" ? rendered : rendered.toString("utf-8");
    const ext = config.format === "json" ? "json" : config.format === "svg" ? "svg" : "txt";
    const filename = `tokenleak.${ext}`;
    const description = `Tokenleak report (${dateRange.since} to ${dateRange.until})`;
    const url = await uploadToGist(text2, filename, description);
    process.stderr.write(`Uploaded to gist: ${url}
`);
  } else if (config.upload !== undefined) {
    throw new TokenleakError(`Unknown upload target "${config.upload}". Supported: gist`);
  }
}
function isValidDateArgument(date) {
  if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
    return false;
  }
  const parsed = new Date(`${date}T00:00:00Z`);
  return !Number.isNaN(parsed.getTime()) && parsed.toISOString().slice(0, 10) === date;
}
function parseExplainArgs(argv) {
  if (argv.length === 0 || argv[0]?.startsWith("-")) {
    throw new TokenleakError("tokenleak explain requires a <date> argument in YYYY-MM-DD format");
  }
  const date = argv[0];
  if (!isValidDateArgument(date)) {
    throw new TokenleakError("tokenleak explain requires a <date> argument in YYYY-MM-DD format");
  }
  const cliArgs = {};
  let index = 1;
  while (index < argv.length) {
    const arg = argv[index];
    switch (arg) {
      case "--help":
      case "-h":
        cliArgs["help"] = true;
        index += 1;
        break;
      case "--version":
      case "-v":
        cliArgs["version"] = true;
        index += 1;
        break;
      case "--format":
      case "-f":
        if (argv[index + 1] === undefined) {
          throw new TokenleakError(`${arg} requires a value`);
        }
        cliArgs["format"] = argv[index + 1];
        index += 2;
        break;
      case "--output":
      case "-o":
        if (argv[index + 1] === undefined) {
          throw new TokenleakError(`${arg} requires a value`);
        }
        cliArgs["output"] = argv[index + 1];
        index += 2;
        break;
      case "--width":
      case "-w":
        if (argv[index + 1] === undefined) {
          throw new TokenleakError(`${arg} requires a value`);
        }
        cliArgs["width"] = Number(argv[index + 1]);
        index += 2;
        break;
      case "--provider":
      case "-p":
        if (argv[index + 1] === undefined) {
          throw new TokenleakError(`${arg} requires a value`);
        }
        cliArgs["provider"] = argv[index + 1];
        index += 2;
        break;
      case "--claude":
        cliArgs["claude"] = true;
        index += 1;
        break;
      case "--codex":
        cliArgs["codex"] = true;
        index += 1;
        break;
      case "--cursor":
        cliArgs["cursor"] = true;
        index += 1;
        break;
      case "--pi":
        cliArgs["pi"] = true;
        index += 1;
        break;
      case "--openCode":
      case "--open-code":
        cliArgs["openCode"] = true;
        index += 1;
        break;
      case "--allProviders":
      case "--all-providers":
        cliArgs["allProviders"] = true;
        index += 1;
        break;
      case "--noColor":
      case "--no-color":
        cliArgs["noColor"] = true;
        index += 1;
        break;
      default:
        throw new TokenleakError(`Unknown explain flag "${arg}"`);
    }
  }
  return { date, cliArgs };
}
function parseReplayArgs(argv) {
  let date = null;
  if (argv.length > 0 && !argv[0].startsWith("-")) {
    date = argv[0];
    if (!isValidDateArgument(date)) {
      throw new TokenleakError("tokenleak replay date must be in YYYY-MM-DD format");
    }
  }
  if (date === null) {
    date = new Date().toISOString().slice(0, 10);
  }
  const cliArgs = {};
  let index = argv[0]?.startsWith("-") ? 0 : 1;
  while (index < argv.length) {
    const arg = argv[index];
    switch (arg) {
      case "--help":
      case "-h":
        cliArgs["help"] = true;
        index += 1;
        break;
      case "--version":
      case "-v":
        cliArgs["version"] = true;
        index += 1;
        break;
      case "--format":
      case "-f":
        if (argv[index + 1] === undefined) {
          throw new TokenleakError(`${arg} requires a value`);
        }
        cliArgs["format"] = argv[index + 1];
        index += 2;
        break;
      case "--output":
      case "-o":
        if (argv[index + 1] === undefined) {
          throw new TokenleakError(`${arg} requires a value`);
        }
        cliArgs["output"] = argv[index + 1];
        index += 2;
        break;
      case "--width":
      case "-w":
        if (argv[index + 1] === undefined) {
          throw new TokenleakError(`${arg} requires a value`);
        }
        cliArgs["width"] = Number(argv[index + 1]);
        index += 2;
        break;
      case "--provider":
      case "-p":
        if (argv[index + 1] === undefined) {
          throw new TokenleakError(`${arg} requires a value`);
        }
        cliArgs["provider"] = argv[index + 1];
        index += 2;
        break;
      case "--claude":
        cliArgs["claude"] = true;
        index += 1;
        break;
      case "--codex":
        cliArgs["codex"] = true;
        index += 1;
        break;
      case "--cursor":
        cliArgs["cursor"] = true;
        index += 1;
        break;
      case "--pi":
        cliArgs["pi"] = true;
        index += 1;
        break;
      case "--openCode":
      case "--open-code":
        cliArgs["openCode"] = true;
        index += 1;
        break;
      case "--allProviders":
      case "--all-providers":
        cliArgs["allProviders"] = true;
        index += 1;
        break;
      case "--noColor":
      case "--no-color":
        cliArgs["noColor"] = true;
        index += 1;
        break;
      default:
        throw new TokenleakError(`Unknown replay flag "${arg}"`);
    }
  }
  return { date, cliArgs };
}
function resolveReplayFormat(cliArgs) {
  if (typeof cliArgs["format"] === "string") {
    const format = cliArgs["format"];
    if (format === "json" || format === "terminal") {
      return format;
    }
    throw new TokenleakError("tokenleak replay only supports --format terminal or --format json");
  }
  if (typeof cliArgs["output"] === "string") {
    const inferred = inferFormatFromPath(cliArgs["output"]);
    if (inferred === "json") {
      return "json";
    }
  }
  return "terminal";
}
async function runReplay(date, cliArgs) {
  const config = resolveConfig(cliArgs);
  const format = resolveReplayFormat(cliArgs);
  if (config.allProviders && (config.provider || config.claude || config.codex || config.cursor || config.pi || config.openCode)) {
    throw new TokenleakError("--all-providers cannot be combined with provider filters");
  }
  const replayRange = computeDateRange({ since: date, until: date });
  const available = await selectAvailableProviders(config);
  if (available.length === 0) {
    throw new TokenleakError("No provider data found");
  }
  const replayOutput = await loadTokenleakData(available, replayRange);
  const report = buildReplayReport(replayOutput.providers, date);
  const rendered = format === "json" ? JSON.stringify(report, null, 2) : renderReplayTerminal(report, config.width);
  if (config.output) {
    writeFileSync3(config.output, rendered);
  } else {
    process.stdout.write(rendered + `
`);
  }
}
function resolveExplainFormat(cliArgs) {
  if (typeof cliArgs["format"] === "string") {
    const format = cliArgs["format"];
    if (format === "json" || format === "terminal") {
      return format;
    }
    throw new TokenleakError("tokenleak explain only supports --format terminal or --format json");
  }
  if (typeof cliArgs["output"] === "string") {
    const inferred = inferFormatFromPath(cliArgs["output"]);
    if (inferred === "json") {
      return "json";
    }
  }
  return "terminal";
}
async function runExplain(date, cliArgs) {
  const config = resolveConfig(cliArgs);
  const format = resolveExplainFormat(cliArgs);
  if (config.allProviders && (config.provider || config.claude || config.codex || config.cursor || config.pi || config.openCode)) {
    throw new TokenleakError("--all-providers cannot be combined with provider filters");
  }
  const explainRange = computeDateRange({ until: date, days: 30 });
  const available = await selectAvailableProviders(config);
  if (available.length === 0) {
    throw new TokenleakError("No provider data found");
  }
  const explainOutput = await loadTokenleakData(available, explainRange);
  const report = buildExplainReport(explainOutput.providers, date);
  const rendered = format === "json" ? JSON.stringify(report, null, 2) : renderExplainTerminal(report, config.width);
  if (config.output) {
    writeFileSync3(config.output, rendered);
  } else {
    process.stdout.write(rendered + `
`);
  }
}
var main2 = defineCommand({
  meta: {
    name: "tokenleak",
    version: VERSION,
    description: "Visualise your AI coding-assistant token usage across providers"
  },
  args: {
    format: {
      type: "string",
      alias: "f",
      description: "Output format: json, svg, png, terminal, wrapped"
    },
    theme: {
      type: "string",
      alias: "t",
      description: "Color theme: dark, light"
    },
    since: {
      type: "string",
      alias: "s",
      description: "Start date (YYYY-MM-DD)"
    },
    until: {
      type: "string",
      alias: "u",
      description: "End date (YYYY-MM-DD), defaults to today"
    },
    days: {
      type: "string",
      alias: "d",
      description: `Number of days to look back (default: ${DEFAULT_DAYS}, overridden by --since)`
    },
    output: {
      type: "string",
      alias: "o",
      description: "Output file path"
    },
    width: {
      type: "string",
      alias: "w",
      description: "Terminal width (default: 80)"
    },
    noColor: {
      type: "boolean",
      description: "Disable ANSI colors",
      default: false
    },
    noInsights: {
      type: "boolean",
      description: "Hide insights panel",
      default: false
    },
    more: {
      type: "boolean",
      description: "Add expanded PNG/SVG stats and compare cards",
      default: false
    },
    compare: {
      type: "string",
      description: "Compare two date ranges (YYYY-MM-DD..YYYY-MM-DD)"
    },
    provider: {
      type: "string",
      alias: "p",
      description: "Filter to specific provider(s), comma-separated"
    },
    claude: {
      type: "boolean",
      description: "Shortcut for --provider claude-code",
      default: false
    },
    codex: {
      type: "boolean",
      description: "Shortcut for --provider codex",
      default: false
    },
    cursor: {
      type: "boolean",
      description: "Shortcut for --provider cursor",
      default: false
    },
    pi: {
      type: "boolean",
      description: "Shortcut for --provider pi",
      default: false
    },
    openCode: {
      type: "boolean",
      description: "Shortcut for --provider open-code",
      default: false
    },
    allProviders: {
      type: "boolean",
      description: "Ignore provider filters and use every available provider",
      default: false
    },
    listProviders: {
      type: "boolean",
      description: "List registered providers and aliases",
      default: false
    },
    clipboard: {
      type: "boolean",
      description: "Copy output to clipboard after rendering",
      default: false
    },
    open: {
      type: "boolean",
      description: "Open output file in default application (requires --output)",
      default: false
    },
    upload: {
      type: "string",
      description: "Upload output to a service (supported: gist)"
    },
    liveServer: {
      type: "boolean",
      alias: "L",
      description: "Start a local server with an interactive dashboard",
      default: false
    },
    wrappedLive: {
      type: "boolean",
      description: "Start the AI Wrapped presentation in a browser",
      default: false
    },
    advisor: {
      type: "boolean",
      description: "Analyze usage and suggest cost-saving model switches",
      default: false
    },
    legacy: {
      type: "boolean",
      description: "Open the classic interactive launcher instead of TUI",
      default: false
    }
  },
  async run({ args }) {
    try {
      const cliArgs = {};
      if (args.format !== undefined)
        cliArgs["format"] = args.format;
      if (args.theme !== undefined)
        cliArgs["theme"] = args.theme;
      if (args.since !== undefined)
        cliArgs["since"] = args.since;
      if (args.until !== undefined)
        cliArgs["until"] = args.until;
      if (args.days !== undefined)
        cliArgs["days"] = Number(args.days);
      if (args.output !== undefined)
        cliArgs["output"] = args.output;
      if (args.width !== undefined)
        cliArgs["width"] = Number(args.width);
      if (args.noColor)
        cliArgs["noColor"] = true;
      if (args.noInsights)
        cliArgs["noInsights"] = true;
      if (args.more)
        cliArgs["more"] = true;
      if (args.compare !== undefined)
        cliArgs["compare"] = args.compare;
      if (args.provider !== undefined)
        cliArgs["provider"] = args.provider;
      if (args.claude)
        cliArgs["claude"] = true;
      if (args.codex)
        cliArgs["codex"] = true;
      if (args.cursor)
        cliArgs["cursor"] = true;
      if (args.pi)
        cliArgs["pi"] = true;
      if (args.openCode)
        cliArgs["openCode"] = true;
      if (args.allProviders)
        cliArgs["allProviders"] = true;
      if (args.listProviders)
        cliArgs["listProviders"] = true;
      if (args.clipboard)
        cliArgs["clipboard"] = true;
      if (args.open)
        cliArgs["open"] = true;
      if (args.upload !== undefined)
        cliArgs["upload"] = args.upload;
      if (args.liveServer)
        cliArgs["liveServer"] = true;
      if (args.wrappedLive)
        cliArgs["wrappedLive"] = true;
      if (args.advisor)
        cliArgs["advisor"] = true;
      await run(cliArgs);
    } catch (error) {
      handleError(error);
    }
  }
});
var focusMain = defineCommand({
  meta: {
    name: "focus",
    version: VERSION,
    description: "Rank sessions by deep-work score"
  },
  args: {
    format: {
      type: "string",
      alias: "f",
      description: "Output format: terminal, json"
    },
    since: {
      type: "string",
      alias: "s",
      description: "Start date (YYYY-MM-DD)"
    },
    until: {
      type: "string",
      alias: "u",
      description: "End date (YYYY-MM-DD), defaults to today"
    },
    days: {
      type: "string",
      alias: "d",
      description: `Number of days to look back (default: ${DEFAULT_DAYS}, overridden by --since)`
    },
    output: {
      type: "string",
      alias: "o",
      description: "Output file path"
    },
    width: {
      type: "string",
      alias: "w",
      description: "Terminal width (default: 80)"
    },
    noColor: {
      type: "boolean",
      description: "Disable ANSI colors",
      default: false
    },
    provider: {
      type: "string",
      alias: "p",
      description: "Filter to specific provider(s), comma-separated"
    },
    claude: {
      type: "boolean",
      description: "Shortcut for --provider claude-code",
      default: false
    },
    codex: {
      type: "boolean",
      description: "Shortcut for --provider codex",
      default: false
    },
    cursor: {
      type: "boolean",
      description: "Shortcut for --provider cursor",
      default: false
    },
    pi: {
      type: "boolean",
      description: "Shortcut for --provider pi",
      default: false
    },
    openCode: {
      type: "boolean",
      description: "Shortcut for --provider open-code",
      default: false
    },
    allProviders: {
      type: "boolean",
      description: "Ignore provider filters and use every available provider",
      default: false
    },
    listProviders: {
      type: "boolean",
      description: "List registered providers and aliases",
      default: false
    }
  },
  async run({ args }) {
    try {
      const cliArgs = {};
      if (args.format !== undefined)
        cliArgs["format"] = args.format;
      if (args.since !== undefined)
        cliArgs["since"] = args.since;
      if (args.until !== undefined)
        cliArgs["until"] = args.until;
      if (args.days !== undefined)
        cliArgs["days"] = Number(args.days);
      if (args.output !== undefined)
        cliArgs["output"] = args.output;
      if (args.width !== undefined)
        cliArgs["width"] = Number(args.width);
      if (args.noColor)
        cliArgs["noColor"] = true;
      if (args.provider !== undefined)
        cliArgs["provider"] = args.provider;
      if (args.claude)
        cliArgs["claude"] = true;
      if (args.codex)
        cliArgs["codex"] = true;
      if (args.cursor)
        cliArgs["cursor"] = true;
      if (args.pi)
        cliArgs["pi"] = true;
      if (args.openCode)
        cliArgs["openCode"] = true;
      if (args.allProviders)
        cliArgs["allProviders"] = true;
      if (args.listProviders)
        cliArgs["listProviders"] = true;
      await runFocus(cliArgs);
    } catch (error) {
      handleError(error);
    }
  }
});
var isDirectExecution = typeof Bun !== "undefined" ? Bun.main === import.meta.path : process.argv[1] !== undefined && import.meta.url.endsWith(process.argv[1].replace(/\\/g, "/"));
if (isDirectExecution) {
  await initPricing();
  const normalizedArgv = normalizeCliArgv(process.argv.slice(2));
  const argv = normalizedArgv;
  if (argv[0] === "explain") {
    try {
      const { date, cliArgs } = parseExplainArgs(argv.slice(1));
      if (cliArgs["help"]) {
        process.stdout.write(buildExplainHelpText());
        process.exit(0);
      }
      if (cliArgs["version"]) {
        process.stdout.write(buildVersionText());
        process.exit(0);
      }
      await runExplain(date, cliArgs);
      process.exit(0);
    } catch (error) {
      handleError(error);
    }
  }
  if (argv[0] === "replay") {
    try {
      const { date, cliArgs } = parseReplayArgs(argv.slice(1));
      if (cliArgs["help"]) {
        process.stdout.write(buildReplayHelpText());
        process.exit(0);
      }
      if (cliArgs["version"]) {
        process.stdout.write(buildVersionText());
        process.exit(0);
      }
      await runReplay(date, cliArgs);
      process.exit(0);
    } catch (error) {
      handleError(error);
    }
  }
  if (argv[0] === "focus") {
    const focusArgv = argv.slice(1);
    process.argv = [...process.argv.slice(0, 2), ...focusArgv];
    if (focusArgv.includes("--help") || focusArgv.includes("-h")) {
      process.stdout.write(buildFocusHelpText());
      process.exit(0);
    }
    if (focusArgv.includes("--version") || focusArgv.includes("-v")) {
      process.stdout.write(buildVersionText());
      process.exit(0);
    }
    await runMain(focusMain);
    process.exit(0);
  }
  if (argv[0] === "cursor") {
    try {
      if (argv[1] === "--help" || argv[1] === "-h" || argv.length === 1) {
        process.stdout.write(buildCursorHelpText());
        process.exit(0);
      }
      if (argv[1] === "--version" || argv[1] === "-v") {
        process.stdout.write(buildVersionText());
        process.exit(0);
      }
      await runCursorCommand(argv.slice(1));
      process.exit(0);
    } catch (error) {
      handleError(error);
    }
  }
  process.argv = [...process.argv.slice(0, 2), ...normalizedArgv];
  if (argv.includes("--help") || argv.includes("-h")) {
    process.stdout.write(buildHelpText());
    process.exit(0);
  }
  if (argv.includes("--version") || argv.includes("-v")) {
    process.stdout.write(buildVersionText());
    process.exit(0);
  }
  if (argv.includes("--legacy") && shouldStartInteractiveCli(argv.filter((a) => a !== "--legacy"), Boolean(process.stdin.isTTY), Boolean(process.stdout.isTTY))) {
    const launchTabbed = async (opts) => {
      const scopedProviders = await resolveTabbedDashboardProviders(opts);
      if (scopedProviders.length === 0) {
        throw new TokenleakError("No provider data found");
      }
      await startTabbedDashboard(scopedProviders, opts);
    };
    await startInteractiveCli({
      version: VERSION,
      helpText: buildHelpText()
    }, executeInteractiveCommand, launchTabbed);
  } else if (shouldStartInteractiveCli(argv, Boolean(process.stdin.isTTY), Boolean(process.stdout.isTTY))) {
    try {
      const { main: startTui } = await Promise.resolve().then(() => (init_dist4(), exports_dist2));
      await startTui();
    } catch (error) {
      handleError(error);
    }
  } else {
    await runMain(main2);
  }
}
export {
  runFocus,
  run,
  resolveTabbedDashboardProviders,
  resolveTabbedDashboardProviderConfig,
  resolveFocusConfig,
  resolveConfig,
  renderFocusReport,
  normalizeCliArgv,
  inferFormatFromPath,
  computeDateRange,
  colorStreak,
  colorScore,
  colorProvider,
  colorDuration,
  colorDensity,
  buildInteractiveSummary
};
