#!/usr/bin/env node

// src/cli.ts
import { Command } from "commander";

// src/export.ts
import { writeFile } from "fs/promises";
import { resolve } from "path";

// src/types.ts
var CATEGORY_LABELS = {
  coding: "Coding",
  debugging: "Debugging",
  feature: "Feature Dev",
  refactoring: "Refactoring",
  testing: "Testing",
  exploration: "Exploration",
  planning: "Planning",
  delegation: "Delegation",
  git: "Git Ops",
  "build/deploy": "Build/Deploy",
  conversation: "Conversation",
  brainstorming: "Brainstorming",
  general: "General"
};

// src/export.ts
function escCsv(s) {
  if (s.includes(",") || s.includes('"') || s.includes("\n")) {
    return `"${s.replace(/"/g, '""')}"`;
  }
  return s;
}
function buildDailyRows(projects) {
  const daily = {};
  for (const project of projects) {
    for (const session of project.sessions) {
      for (const turn of session.turns) {
        if (!turn.timestamp) continue;
        const day = turn.timestamp.slice(0, 10);
        if (!daily[day]) daily[day] = { cost: 0, calls: 0, input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
        for (const call of turn.assistantCalls) {
          daily[day].cost += call.costUSD;
          daily[day].calls++;
          daily[day].input += call.usage.inputTokens;
          daily[day].output += call.usage.outputTokens;
          daily[day].cacheRead += call.usage.cacheReadInputTokens;
          daily[day].cacheWrite += call.usage.cacheCreationInputTokens;
        }
      }
    }
  }
  return Object.entries(daily).sort().map(([date, d]) => ({
    Date: date,
    "Cost (USD)": Math.round(d.cost * 100) / 100,
    "API Calls": d.calls,
    "Input Tokens": d.input,
    "Output Tokens": d.output,
    "Cache Read Tokens": d.cacheRead,
    "Cache Write Tokens": d.cacheWrite
  }));
}
function buildActivityRows(projects) {
  const catTotals = {};
  for (const project of projects) {
    for (const session of project.sessions) {
      for (const [cat, d] of Object.entries(session.categoryBreakdown)) {
        if (!catTotals[cat]) catTotals[cat] = { turns: 0, cost: 0 };
        catTotals[cat].turns += d.turns;
        catTotals[cat].cost += d.costUSD;
      }
    }
  }
  return Object.entries(catTotals).sort(([, a], [, b]) => b.cost - a.cost).map(([cat, d]) => ({
    Activity: CATEGORY_LABELS[cat] ?? cat,
    "Cost (USD)": Math.round(d.cost * 100) / 100,
    Turns: d.turns
  }));
}
function buildModelRows(projects) {
  const modelTotals = {};
  for (const project of projects) {
    for (const session of project.sessions) {
      for (const [model, d] of Object.entries(session.modelBreakdown)) {
        if (!modelTotals[model]) modelTotals[model] = { calls: 0, cost: 0, input: 0, output: 0 };
        modelTotals[model].calls += d.calls;
        modelTotals[model].cost += d.costUSD;
        modelTotals[model].input += d.tokens.inputTokens;
        modelTotals[model].output += d.tokens.outputTokens;
      }
    }
  }
  return Object.entries(modelTotals).sort(([, a], [, b]) => b.cost - a.cost).map(([model, d]) => ({
    Model: model,
    "Cost (USD)": Math.round(d.cost * 100) / 100,
    "API Calls": d.calls,
    "Input Tokens": d.input,
    "Output Tokens": d.output
  }));
}
function buildToolRows(projects) {
  const toolTotals = {};
  for (const project of projects) {
    for (const session of project.sessions) {
      for (const [tool, d] of Object.entries(session.toolBreakdown)) {
        toolTotals[tool] = (toolTotals[tool] ?? 0) + d.calls;
      }
    }
  }
  return Object.entries(toolTotals).sort(([, a], [, b]) => b - a).map(([tool, calls]) => ({ Tool: tool, Calls: calls }));
}
function buildProjectRows(projects) {
  return projects.map((p) => ({
    Project: p.projectPath,
    "Cost (USD)": Math.round(p.totalCostUSD * 100) / 100,
    "API Calls": p.totalApiCalls,
    Sessions: p.sessions.length
  }));
}
function rowsToCsv(rows) {
  if (rows.length === 0) return "";
  const headers = Object.keys(rows[0]);
  const lines = [headers.map(escCsv).join(",")];
  for (const row of rows) {
    lines.push(headers.map((h) => escCsv(String(row[h] ?? ""))).join(","));
  }
  return lines.join("\n");
}
function buildSummaryRow(period) {
  const cost = period.projects.reduce((s, p) => s + p.totalCostUSD, 0);
  const calls = period.projects.reduce((s, p) => s + p.totalApiCalls, 0);
  const sessions = period.projects.reduce((s, p) => s + p.sessions.length, 0);
  return { Period: period.label, "Cost (USD)": Math.round(cost * 100) / 100, "API Calls": calls, Sessions: sessions };
}
async function exportCsv(periods, outputPath) {
  const allProjects = periods.find((p) => p.label === "30 Days")?.projects ?? periods[periods.length - 1].projects;
  const parts = [];
  parts.push("# Summary");
  parts.push(rowsToCsv(periods.map(buildSummaryRow)));
  parts.push("");
  for (const period of periods) {
    parts.push(`# Daily - ${period.label}`);
    parts.push(rowsToCsv(buildDailyRows(period.projects)));
    parts.push("");
    parts.push(`# Activity - ${period.label}`);
    parts.push(rowsToCsv(buildActivityRows(period.projects)));
    parts.push("");
    parts.push(`# Models - ${period.label}`);
    parts.push(rowsToCsv(buildModelRows(period.projects)));
    parts.push("");
  }
  parts.push("# Tools - All");
  parts.push(rowsToCsv(buildToolRows(allProjects)));
  parts.push("");
  parts.push("# Projects - All");
  parts.push(rowsToCsv(buildProjectRows(allProjects)));
  parts.push("");
  const fullPath = resolve(outputPath);
  await writeFile(fullPath, parts.join("\n"), "utf-8");
  return fullPath;
}
async function exportJson(periods, outputPath) {
  const allProjects = periods.find((p) => p.label === "30 Days")?.projects ?? periods[periods.length - 1].projects;
  const periodData = {};
  for (const period of periods) {
    periodData[period.label] = {
      summary: buildSummaryRow(period),
      daily: buildDailyRows(period.projects),
      activity: buildActivityRows(period.projects),
      models: buildModelRows(period.projects)
    };
  }
  const data = {
    generated: (/* @__PURE__ */ new Date()).toISOString(),
    periods: periodData,
    tools: buildToolRows(allProjects),
    projects: buildProjectRows(allProjects)
  };
  const fullPath = resolve(outputPath);
  await writeFile(fullPath, JSON.stringify(data, null, 2), "utf-8");
  return fullPath;
}

// src/models.ts
import { readFile, writeFile as writeFile2, mkdir } from "fs/promises";
import { join } from "path";
import { homedir } from "os";
var LITELLM_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
var WEB_SEARCH_COST = 0.01;
var FALLBACK_PRICING = {
  "claude-opus-4-6": { inputCostPerToken: 5e-6, outputCostPerToken: 25e-6, cacheWriteCostPerToken: 625e-8, cacheReadCostPerToken: 5e-7, webSearchCostPerRequest: WEB_SEARCH_COST, fastMultiplier: 6 },
  "claude-opus-4-5": { inputCostPerToken: 5e-6, outputCostPerToken: 25e-6, cacheWriteCostPerToken: 625e-8, cacheReadCostPerToken: 5e-7, webSearchCostPerRequest: WEB_SEARCH_COST, fastMultiplier: 1 },
  "claude-opus-4-1": { inputCostPerToken: 15e-6, outputCostPerToken: 75e-6, cacheWriteCostPerToken: 1875e-8, cacheReadCostPerToken: 15e-7, webSearchCostPerRequest: WEB_SEARCH_COST, fastMultiplier: 1 },
  "claude-opus-4": { inputCostPerToken: 15e-6, outputCostPerToken: 75e-6, cacheWriteCostPerToken: 1875e-8, cacheReadCostPerToken: 15e-7, webSearchCostPerRequest: WEB_SEARCH_COST, fastMultiplier: 1 },
  "claude-sonnet-4-6": { inputCostPerToken: 3e-6, outputCostPerToken: 15e-6, cacheWriteCostPerToken: 375e-8, cacheReadCostPerToken: 3e-7, webSearchCostPerRequest: WEB_SEARCH_COST, fastMultiplier: 1 },
  "claude-sonnet-4-5": { inputCostPerToken: 3e-6, outputCostPerToken: 15e-6, cacheWriteCostPerToken: 375e-8, cacheReadCostPerToken: 3e-7, webSearchCostPerRequest: WEB_SEARCH_COST, fastMultiplier: 1 },
  "claude-sonnet-4": { inputCostPerToken: 3e-6, outputCostPerToken: 15e-6, cacheWriteCostPerToken: 375e-8, cacheReadCostPerToken: 3e-7, webSearchCostPerRequest: WEB_SEARCH_COST, fastMultiplier: 1 },
  "claude-3-7-sonnet": { inputCostPerToken: 3e-6, outputCostPerToken: 15e-6, cacheWriteCostPerToken: 375e-8, cacheReadCostPerToken: 3e-7, webSearchCostPerRequest: WEB_SEARCH_COST, fastMultiplier: 1 },
  "claude-3-5-sonnet": { inputCostPerToken: 3e-6, outputCostPerToken: 15e-6, cacheWriteCostPerToken: 375e-8, cacheReadCostPerToken: 3e-7, webSearchCostPerRequest: WEB_SEARCH_COST, fastMultiplier: 1 },
  "claude-haiku-4-5": { inputCostPerToken: 1e-6, outputCostPerToken: 5e-6, cacheWriteCostPerToken: 125e-8, cacheReadCostPerToken: 1e-7, webSearchCostPerRequest: WEB_SEARCH_COST, fastMultiplier: 1 },
  "claude-3-5-haiku": { inputCostPerToken: 8e-7, outputCostPerToken: 4e-6, cacheWriteCostPerToken: 1e-6, cacheReadCostPerToken: 8e-8, webSearchCostPerRequest: WEB_SEARCH_COST, fastMultiplier: 1 },
  "gpt-4o": { inputCostPerToken: 25e-7, outputCostPerToken: 1e-5, cacheWriteCostPerToken: 25e-7, cacheReadCostPerToken: 125e-8, webSearchCostPerRequest: WEB_SEARCH_COST, fastMultiplier: 1 },
  "gpt-4o-mini": { inputCostPerToken: 15e-8, outputCostPerToken: 6e-7, cacheWriteCostPerToken: 15e-8, cacheReadCostPerToken: 75e-9, webSearchCostPerRequest: WEB_SEARCH_COST, fastMultiplier: 1 },
  "gemini-2.5-pro": { inputCostPerToken: 125e-8, outputCostPerToken: 1e-5, cacheWriteCostPerToken: 125e-8, cacheReadCostPerToken: 315e-9, webSearchCostPerRequest: WEB_SEARCH_COST, fastMultiplier: 1 }
};
var pricingCache = null;
function getCacheDir() {
  return join(homedir(), ".cache", "codeburn");
}
function getCachePath() {
  return join(getCacheDir(), "litellm-pricing.json");
}
function parseLiteLLMEntry(entry) {
  if (!entry.input_cost_per_token || !entry.output_cost_per_token) return null;
  return {
    inputCostPerToken: entry.input_cost_per_token,
    outputCostPerToken: entry.output_cost_per_token,
    cacheWriteCostPerToken: entry.cache_creation_input_token_cost ?? entry.input_cost_per_token * 1.25,
    cacheReadCostPerToken: entry.cache_read_input_token_cost ?? entry.input_cost_per_token * 0.1,
    webSearchCostPerRequest: WEB_SEARCH_COST,
    fastMultiplier: entry.provider_specific_entry?.fast ?? 1
  };
}
async function fetchAndCachePricing() {
  const response = await fetch(LITELLM_URL);
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  const data = await response.json();
  const pricing = /* @__PURE__ */ new Map();
  for (const [name, entry] of Object.entries(data)) {
    if (name.includes("/") || name.includes(".")) continue;
    const costs = parseLiteLLMEntry(entry);
    if (costs) pricing.set(name, costs);
  }
  await mkdir(getCacheDir(), { recursive: true });
  await writeFile2(getCachePath(), JSON.stringify({
    timestamp: Date.now(),
    data: Object.fromEntries(pricing)
  }));
  return pricing;
}
async function loadCachedPricing() {
  try {
    const raw = await readFile(getCachePath(), "utf-8");
    const cached = JSON.parse(raw);
    if (Date.now() - cached.timestamp > CACHE_TTL_MS) return null;
    return new Map(Object.entries(cached.data));
  } catch {
    return null;
  }
}
async function loadPricing() {
  const cached = await loadCachedPricing();
  if (cached) {
    pricingCache = cached;
    return;
  }
  try {
    pricingCache = await fetchAndCachePricing();
  } catch {
    pricingCache = new Map(Object.entries(FALLBACK_PRICING));
  }
}
function getCanonicalName(model) {
  return model.replace(/@.*$/, "").replace(/-\d{8}$/, "");
}
function getModelCosts(model) {
  const canonical = getCanonicalName(model);
  if (pricingCache?.has(canonical)) return pricingCache.get(canonical);
  for (const [key, costs] of pricingCache ?? /* @__PURE__ */ new Map()) {
    if (canonical.startsWith(key) || key.startsWith(canonical)) return costs;
  }
  for (const [key, costs] of Object.entries(FALLBACK_PRICING)) {
    if (canonical.startsWith(key)) return costs;
  }
  return null;
}
function calculateCost(model, inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens, webSearchRequests, speed = "standard") {
  const costs = getModelCosts(model);
  if (!costs) return 0;
  const multiplier = speed === "fast" ? costs.fastMultiplier : 1;
  return multiplier * (inputTokens * costs.inputCostPerToken + outputTokens * costs.outputCostPerToken + cacheCreationTokens * costs.cacheWriteCostPerToken + cacheReadTokens * costs.cacheReadCostPerToken + webSearchRequests * costs.webSearchCostPerRequest);
}
function getShortModelName(model) {
  const canonical = getCanonicalName(model);
  const shortNames = {
    "claude-opus-4-6": "Opus 4.6",
    "claude-opus-4-5": "Opus 4.5",
    "claude-opus-4-1": "Opus 4.1",
    "claude-opus-4": "Opus 4",
    "claude-sonnet-4-6": "Sonnet 4.6",
    "claude-sonnet-4-5": "Sonnet 4.5",
    "claude-sonnet-4": "Sonnet 4",
    "claude-3-7-sonnet": "Sonnet 3.7",
    "claude-3-5-sonnet": "Sonnet 3.5",
    "claude-haiku-4-5": "Haiku 4.5",
    "claude-3-5-haiku": "Haiku 3.5",
    "gpt-4o": "GPT-4o",
    "gpt-4o-mini": "GPT-4o Mini",
    "gemini-2.5-pro": "Gemini 2.5 Pro"
  };
  for (const [key, name] of Object.entries(shortNames)) {
    if (canonical.startsWith(key)) return name;
  }
  return canonical;
}

// src/parser.ts
import { readdir, readFile as readFile2, stat } from "fs/promises";
import { basename, join as join2 } from "path";
import { homedir as homedir2 } from "os";

// src/classifier.ts
var TEST_PATTERNS = /\b(test|pytest|vitest|jest|mocha|spec|coverage|npm\s+test|npx\s+vitest|npx\s+jest)\b/i;
var GIT_PATTERNS = /\bgit\s+(push|pull|commit|merge|rebase|checkout|branch|stash|log|diff|status|add|reset|cherry-pick|tag)\b/i;
var BUILD_PATTERNS = /\b(npm\s+run\s+build|npm\s+publish|pip\s+install|docker|deploy|make\s+build|npm\s+run\s+dev|npm\s+start|pm2|systemctl|brew|cargo\s+build)\b/i;
var INSTALL_PATTERNS = /\b(npm\s+install|pip\s+install|brew\s+install|apt\s+install|cargo\s+add)\b/i;
var DEBUG_KEYWORDS = /\b(fix|bug|error|broken|failing|crash|issue|debug|traceback|exception|stack\s*trace|not\s+working|wrong|unexpected)\b/i;
var FEATURE_KEYWORDS = /\b(add|create|implement|new|build|feature|introduce|set\s*up|scaffold|generate)\b/i;
var REFACTOR_KEYWORDS = /\b(refactor|clean\s*up|rename|reorganize|simplify|extract|restructure|move|migrate|split)\b/i;
var BRAINSTORM_KEYWORDS = /\b(brainstorm|idea|what\s+if|explore|think\s+about|approach|strategy|design|consider|how\s+should|what\s+would|opinion|suggest|recommend)\b/i;
var RESEARCH_KEYWORDS = /\b(research|investigate|look\s+into|find\s+out|check|search|analyze|review|understand|explain|how\s+does|what\s+is|show\s+me|list|compare)\b/i;
var EDIT_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "FileEditTool", "FileWriteTool", "NotebookEdit"]);
var READ_TOOLS = /* @__PURE__ */ new Set(["Read", "Grep", "Glob", "FileReadTool", "GrepTool", "GlobTool"]);
var BASH_TOOLS = /* @__PURE__ */ new Set(["Bash", "BashTool", "PowerShellTool"]);
var TASK_TOOLS = /* @__PURE__ */ new Set(["TaskCreate", "TaskUpdate", "TaskGet", "TaskList", "TaskOutput", "TaskStop", "TodoWrite"]);
var SEARCH_TOOLS = /* @__PURE__ */ new Set(["WebSearch", "WebFetch", "ToolSearch"]);
function hasEditTools(tools) {
  return tools.some((t) => EDIT_TOOLS.has(t));
}
function hasReadTools(tools) {
  return tools.some((t) => READ_TOOLS.has(t));
}
function hasBashTool(tools) {
  return tools.some((t) => BASH_TOOLS.has(t));
}
function hasTaskTools(tools) {
  return tools.some((t) => TASK_TOOLS.has(t));
}
function hasSearchTools(tools) {
  return tools.some((t) => SEARCH_TOOLS.has(t));
}
function hasMcpTools(tools) {
  return tools.some((t) => t.startsWith("mcp__"));
}
function hasSkillTool(tools) {
  return tools.some((t) => t === "Skill");
}
function getAllTools(turn) {
  return turn.assistantCalls.flatMap((c) => c.tools);
}
function classifyByToolPattern(turn) {
  const tools = getAllTools(turn);
  if (tools.length === 0) return null;
  if (turn.assistantCalls.some((c) => c.hasPlanMode)) return "planning";
  if (turn.assistantCalls.some((c) => c.hasAgentSpawn)) return "delegation";
  const hasEdits = hasEditTools(tools);
  const hasReads = hasReadTools(tools);
  const hasBash = hasBashTool(tools);
  const hasTasks = hasTaskTools(tools);
  const hasSearch = hasSearchTools(tools);
  const hasMcp = hasMcpTools(tools);
  const hasSkill = hasSkillTool(tools);
  if (hasBash && !hasEdits) {
    const userMsg = turn.userMessage;
    if (TEST_PATTERNS.test(userMsg)) return "testing";
    if (GIT_PATTERNS.test(userMsg)) return "git";
    if (BUILD_PATTERNS.test(userMsg)) return "build/deploy";
    if (INSTALL_PATTERNS.test(userMsg)) return "build/deploy";
  }
  if (hasEdits) return "coding";
  if (hasBash && hasReads) return "exploration";
  if (hasBash) return "coding";
  if (hasSearch || hasMcp) return "exploration";
  if (hasReads && !hasEdits) return "exploration";
  if (hasTasks && !hasEdits) return "planning";
  if (hasSkill) return "general";
  return null;
}
function refineByKeywords(category, userMessage) {
  if (category === "coding") {
    if (DEBUG_KEYWORDS.test(userMessage)) return "debugging";
    if (REFACTOR_KEYWORDS.test(userMessage)) return "refactoring";
    if (FEATURE_KEYWORDS.test(userMessage)) return "feature";
    return "coding";
  }
  if (category === "exploration") {
    if (RESEARCH_KEYWORDS.test(userMessage)) return "exploration";
    if (DEBUG_KEYWORDS.test(userMessage)) return "debugging";
    return "exploration";
  }
  return category;
}
function classifyConversation(userMessage) {
  if (BRAINSTORM_KEYWORDS.test(userMessage)) return "brainstorming";
  if (RESEARCH_KEYWORDS.test(userMessage)) return "exploration";
  if (DEBUG_KEYWORDS.test(userMessage)) return "debugging";
  if (FEATURE_KEYWORDS.test(userMessage)) return "feature";
  return "conversation";
}
function classifyTurn(turn) {
  const tools = getAllTools(turn);
  let category;
  if (tools.length === 0) {
    category = classifyConversation(turn.userMessage);
  } else {
    const toolCategory = classifyByToolPattern(turn);
    if (toolCategory) {
      category = refineByKeywords(toolCategory, turn.userMessage);
    } else {
      category = classifyConversation(turn.userMessage);
    }
  }
  return { ...turn, category };
}

// src/parser.ts
function getClaudeDir() {
  return join2(homedir2(), ".claude");
}
function getProjectsDir() {
  return join2(getClaudeDir(), "projects");
}
function unsanitizePath(dirName) {
  return dirName.replace(/-/g, "/");
}
function parseJsonlLine(line) {
  try {
    return JSON.parse(line);
  } catch {
    return null;
  }
}
function extractToolNames(content) {
  return content.filter((b) => b.type === "tool_use").map((b) => b.name);
}
function extractMcpTools(tools) {
  return tools.filter((t) => t.startsWith("mcp__"));
}
function extractCoreTools(tools) {
  return tools.filter((t) => !t.startsWith("mcp__"));
}
function getUserMessageText(entry) {
  if (!entry.message || entry.message.role !== "user") return "";
  const content = entry.message.content;
  if (typeof content === "string") return content;
  if (Array.isArray(content)) {
    return content.filter((b) => b.type === "text").map((b) => b.text).join(" ");
  }
  return "";
}
function getMessageId(entry) {
  if (entry.type !== "assistant") return null;
  const msg = entry.message;
  return msg?.id ?? null;
}
function parseApiCall(entry) {
  if (entry.type !== "assistant") return null;
  const msg = entry.message;
  if (!msg?.usage || !msg?.model) return null;
  const usage = msg.usage;
  const tokens = {
    inputTokens: usage.input_tokens ?? 0,
    outputTokens: usage.output_tokens ?? 0,
    cacheCreationInputTokens: usage.cache_creation_input_tokens ?? 0,
    cacheReadInputTokens: usage.cache_read_input_tokens ?? 0,
    webSearchRequests: usage.server_tool_use?.web_search_requests ?? 0
  };
  const tools = extractToolNames(msg.content ?? []);
  const costUSD = calculateCost(
    msg.model,
    tokens.inputTokens,
    tokens.outputTokens,
    tokens.cacheCreationInputTokens,
    tokens.cacheReadInputTokens,
    tokens.webSearchRequests,
    usage.speed ?? "standard"
  );
  return {
    model: msg.model,
    usage: tokens,
    costUSD,
    tools,
    mcpTools: extractMcpTools(tools),
    hasAgentSpawn: tools.includes("Agent"),
    hasPlanMode: tools.includes("EnterPlanMode"),
    speed: usage.speed ?? "standard",
    timestamp: entry.timestamp ?? ""
  };
}
function groupIntoTurns(entries, seenMsgIds) {
  const turns = [];
  let currentUserMessage = "";
  let currentCalls = [];
  let currentTimestamp = "";
  let currentSessionId = "";
  for (const entry of entries) {
    if (entry.type === "user") {
      if (currentCalls.length > 0) {
        turns.push({
          userMessage: currentUserMessage,
          assistantCalls: currentCalls,
          timestamp: currentTimestamp,
          sessionId: currentSessionId
        });
      }
      currentUserMessage = getUserMessageText(entry);
      currentCalls = [];
      currentTimestamp = entry.timestamp ?? "";
      currentSessionId = entry.sessionId ?? "";
    } else if (entry.type === "assistant") {
      const msgId = getMessageId(entry);
      if (msgId && seenMsgIds.has(msgId)) continue;
      if (msgId) seenMsgIds.add(msgId);
      const call = parseApiCall(entry);
      if (call) currentCalls.push(call);
    }
  }
  if (currentCalls.length > 0) {
    turns.push({
      userMessage: currentUserMessage,
      assistantCalls: currentCalls,
      timestamp: currentTimestamp,
      sessionId: currentSessionId
    });
  }
  return turns;
}
function buildSessionSummary(sessionId, project, turns) {
  const modelBreakdown = {};
  const toolBreakdown = {};
  const mcpBreakdown = {};
  const categoryBreakdown = {};
  let totalCost = 0;
  let totalInput = 0;
  let totalOutput = 0;
  let totalCacheRead = 0;
  let totalCacheWrite = 0;
  let apiCalls = 0;
  let firstTs = "";
  let lastTs = "";
  for (const turn of turns) {
    const turnCost = turn.assistantCalls.reduce((s, c) => s + c.costUSD, 0);
    if (!categoryBreakdown[turn.category]) {
      categoryBreakdown[turn.category] = { turns: 0, costUSD: 0 };
    }
    categoryBreakdown[turn.category].turns++;
    categoryBreakdown[turn.category].costUSD += turnCost;
    for (const call of turn.assistantCalls) {
      totalCost += call.costUSD;
      totalInput += call.usage.inputTokens;
      totalOutput += call.usage.outputTokens;
      totalCacheRead += call.usage.cacheReadInputTokens;
      totalCacheWrite += call.usage.cacheCreationInputTokens;
      apiCalls++;
      const modelKey = getShortModelName(call.model);
      if (!modelBreakdown[modelKey]) {
        modelBreakdown[modelKey] = {
          calls: 0,
          costUSD: 0,
          tokens: { inputTokens: 0, outputTokens: 0, cacheCreationInputTokens: 0, cacheReadInputTokens: 0, webSearchRequests: 0 }
        };
      }
      modelBreakdown[modelKey].calls++;
      modelBreakdown[modelKey].costUSD += call.costUSD;
      modelBreakdown[modelKey].tokens.inputTokens += call.usage.inputTokens;
      modelBreakdown[modelKey].tokens.outputTokens += call.usage.outputTokens;
      modelBreakdown[modelKey].tokens.cacheReadInputTokens += call.usage.cacheReadInputTokens;
      modelBreakdown[modelKey].tokens.cacheCreationInputTokens += call.usage.cacheCreationInputTokens;
      for (const tool of extractCoreTools(call.tools)) {
        toolBreakdown[tool] = toolBreakdown[tool] ?? { calls: 0 };
        toolBreakdown[tool].calls++;
      }
      for (const mcp of call.mcpTools) {
        const server = mcp.split("__")[1] ?? mcp;
        mcpBreakdown[server] = mcpBreakdown[server] ?? { calls: 0 };
        mcpBreakdown[server].calls++;
      }
      if (!firstTs || call.timestamp < firstTs) firstTs = call.timestamp;
      if (!lastTs || call.timestamp > lastTs) lastTs = call.timestamp;
    }
  }
  return {
    sessionId,
    project,
    firstTimestamp: firstTs || turns[0]?.timestamp || "",
    lastTimestamp: lastTs || turns[turns.length - 1]?.timestamp || "",
    totalCostUSD: totalCost,
    totalInputTokens: totalInput,
    totalOutputTokens: totalOutput,
    totalCacheReadTokens: totalCacheRead,
    totalCacheWriteTokens: totalCacheWrite,
    apiCalls,
    turns,
    modelBreakdown,
    toolBreakdown,
    mcpBreakdown,
    categoryBreakdown
  };
}
async function parseSessionFile(filePath, project, seenMsgIds, dateRange) {
  const content = await readFile2(filePath, "utf-8");
  const lines = content.split("\n").filter((l) => l.trim());
  const entries = [];
  for (const line of lines) {
    const entry = parseJsonlLine(line);
    if (entry) entries.push(entry);
  }
  if (entries.length === 0) return null;
  let filteredEntries = entries;
  if (dateRange) {
    filteredEntries = entries.filter((e) => {
      if (!e.timestamp) return e.type === "user";
      const ts = new Date(e.timestamp);
      return ts >= dateRange.start && ts <= dateRange.end;
    });
    if (filteredEntries.length === 0) return null;
  }
  const sessionId = basename(filePath, ".jsonl");
  const turns = groupIntoTurns(filteredEntries, seenMsgIds);
  const classified = turns.map(classifyTurn);
  return buildSessionSummary(sessionId, project, classified);
}
async function parseAllSessions(dateRange) {
  const projectsDir = getProjectsDir();
  const projects = [];
  const seenMsgIds = /* @__PURE__ */ new Set();
  let projectDirs;
  try {
    projectDirs = await readdir(projectsDir);
  } catch {
    return [];
  }
  for (const dirName of projectDirs) {
    const dirPath = join2(projectsDir, dirName);
    const dirStat = await stat(dirPath).catch(() => null);
    if (!dirStat?.isDirectory()) continue;
    const files = await readdir(dirPath).catch(() => []);
    const jsonlFiles = files.filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
    const sessions = [];
    for (const file of jsonlFiles) {
      const session = await parseSessionFile(join2(dirPath, file), dirName, seenMsgIds, dateRange);
      if (session && session.apiCalls > 0) {
        sessions.push(session);
      }
    }
    if (sessions.length > 0) {
      const totalCost = sessions.reduce((s, sess) => s + sess.totalCostUSD, 0);
      const totalCalls = sessions.reduce((s, sess) => s + sess.apiCalls, 0);
      projects.push({
        project: dirName,
        projectPath: unsanitizePath(dirName),
        sessions,
        totalCostUSD: totalCost,
        totalApiCalls: totalCalls
      });
    }
  }
  return projects.sort((a, b) => b.totalCostUSD - a.totalCostUSD);
}

// src/format.ts
import chalk from "chalk";
function formatCost(cost) {
  if (cost >= 1) return `$${cost.toFixed(2)}`;
  if (cost >= 0.01) return `$${cost.toFixed(3)}`;
  return `$${cost.toFixed(4)}`;
}
function formatTokens(n) {
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
  if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
  return n.toString();
}
function renderStatusBar(projects) {
  const now = /* @__PURE__ */ new Date();
  const today = now.toISOString().slice(0, 10);
  const monthStart = `${today.slice(0, 7)}-01`;
  let todayCost = 0, todayCalls = 0, monthCost = 0, monthCalls = 0;
  for (const project of projects) {
    for (const session of project.sessions) {
      for (const turn of session.turns) {
        if (!turn.timestamp) continue;
        const day = turn.timestamp.slice(0, 10);
        const turnCost = turn.assistantCalls.reduce((s, c) => s + c.costUSD, 0);
        const turnCalls = turn.assistantCalls.length;
        if (day === today) {
          todayCost += turnCost;
          todayCalls += turnCalls;
        }
        if (day >= monthStart) {
          monthCost += turnCost;
          monthCalls += turnCalls;
        }
      }
    }
  }
  const lines = [""];
  lines.push(`  ${chalk.bold("Today")}  ${chalk.yellowBright(formatCost(todayCost))}  ${chalk.dim(`${todayCalls} calls`)}    ${chalk.bold("Month")}  ${chalk.yellowBright(formatCost(monthCost))}  ${chalk.dim(`${monthCalls} calls`)}`);
  lines.push("");
  return lines.join("\n");
}

// src/menubar.ts
import { execSync } from "child_process";
import { existsSync } from "fs";
import { chmod, mkdir as mkdir2, unlink, writeFile as writeFile3 } from "fs/promises";
import { homedir as homedir3, platform } from "os";
import { join as join3 } from "path";
var PLUGIN_REFRESH = "5m";
function getSwiftBarPluginDir() {
  return join3(homedir3(), "Library", "Application Support", "SwiftBar", "plugins");
}
function getXbarPluginDir() {
  return join3(homedir3(), "Library", "Application Support", "xbar", "plugins");
}
function getCodeburnBin() {
  try {
    return execSync("which codeburn", { encoding: "utf-8" }).trim();
  } catch {
    return "npx --yes codeburn";
  }
}
function generatePlugin(bin) {
  const home = homedir3();
  return `#!/bin/bash
# <xbar.title>CodeBurn</xbar.title>
# <xbar.version>v0.1.0</xbar.version>
# <xbar.author>AgentSeal</xbar.author>
# <xbar.author.github>agentseal</xbar.author.github>
# <xbar.desc>See where your AI coding tokens burn. Tracks cost, activity, and model usage across Claude Code, Cursor, and Codex by task type, tool, MCP server, and project.</xbar.desc>
# <xbar.image>file://${home}/codeburn/assets/logo.png</xbar.image>
# <xbar.abouturl>https://github.com/agentseal/codeburn</xbar.abouturl>
# <xbar.dependencies>node</xbar.dependencies>

export PATH="/usr/local/bin:/opt/homebrew/bin:$HOME/.local/bin:$HOME/.npm-global/bin:$PATH"

${bin} status --format menubar 2>/dev/null || echo "-- | sfimage=flame.fill"
`;
}
function miniBar(value, max, width = 10) {
  if (max === 0) return "\xB7".repeat(width);
  const filled = Math.round(value / max * width);
  return "\u2588".repeat(Math.min(filled, width)) + "\xB7".repeat(Math.max(width - filled, 0));
}
function renderMenubarFormat(today, week, month) {
  const lines = [];
  lines.push(`${formatCost(today.cost)} | sfimage=flame.fill color=#FF8C42`);
  lines.push("---");
  lines.push(`CodeBurn | size=15 color=#FF8C42`);
  lines.push(`AI Coding Cost Tracker | size=11`);
  lines.push("---");
  lines.push(`Today      ${formatCost(today.cost)}      ${today.calls.toLocaleString()} calls | size=14`);
  lines.push("---");
  const maxCat = Math.max(...today.categories.map((c) => c.cost), 0.01);
  lines.push(`Activity - Today | size=12 color=#FF8C42`);
  for (const cat of today.categories.slice(0, 8)) {
    const bar = miniBar(cat.cost, maxCat);
    const name = cat.name.padEnd(14);
    lines.push(`${bar}  ${name} ${formatCost(cat.cost).padStart(8)}  ${String(cat.turns).padStart(4)} turns | font=Menlo size=11`);
  }
  lines.push("---");
  const maxModel = Math.max(...today.models.filter((m) => m.name !== "<synthetic>").map((m) => m.cost), 0.01);
  lines.push(`Models - Today | size=12 color=#FF8C42`);
  for (const model of today.models.slice(0, 5)) {
    if (model.name === "<synthetic>") continue;
    const bar = miniBar(model.cost, maxModel);
    const name = model.name.padEnd(14);
    lines.push(`${bar}  ${name} ${formatCost(model.cost).padStart(8)}  ${String(model.calls).padStart(5)} calls | font=Menlo size=11`);
  }
  const cacheHit = today.inputTokens + today.cacheReadTokens > 0 ? (today.cacheReadTokens / (today.inputTokens + today.cacheReadTokens) * 100).toFixed(0) : "0";
  lines.push(`Tokens: ${formatTokens(today.inputTokens)} in \xB7 ${formatTokens(today.outputTokens)} out \xB7 ${cacheHit}% cache hit | font=Menlo size=10`);
  lines.push("---");
  lines.push(`7 Days     ${formatCost(week.cost)}    ${week.calls.toLocaleString()} calls | size=14`);
  const weekMaxCat = Math.max(...week.categories.map((c) => c.cost), 0.01);
  const weekMaxModel = Math.max(...week.models.filter((m) => m.name !== "<synthetic>").map((m) => m.cost), 0.01);
  lines.push(`--Activity | size=12 color=#FF8C42`);
  for (const cat of week.categories.slice(0, 8)) {
    const bar = miniBar(cat.cost, weekMaxCat);
    const name = cat.name.padEnd(14);
    lines.push(`--${bar}  ${name} ${formatCost(cat.cost).padStart(8)}  ${String(cat.turns).padStart(4)} turns | font=Menlo size=11`);
  }
  lines.push(`-----`);
  lines.push(`--Models | size=12 color=#FF8C42`);
  for (const model of week.models.slice(0, 5)) {
    if (model.name === "<synthetic>") continue;
    const bar = miniBar(model.cost, weekMaxModel);
    const name = model.name.padEnd(14);
    lines.push(`--${bar}  ${name} ${formatCost(model.cost).padStart(8)}  ${String(model.calls).padStart(5)} calls | font=Menlo size=11`);
  }
  lines.push(`Month      ${formatCost(month.cost)}    ${month.calls.toLocaleString()} calls | size=14`);
  const monthMaxCat = Math.max(...month.categories.map((c) => c.cost), 0.01);
  const monthMaxModel = Math.max(...month.models.filter((m) => m.name !== "<synthetic>").map((m) => m.cost), 0.01);
  lines.push(`--Activity | size=12 color=#FF8C42`);
  for (const cat of month.categories.slice(0, 8)) {
    const bar = miniBar(cat.cost, monthMaxCat);
    const name = cat.name.padEnd(14);
    lines.push(`--${bar}  ${name} ${formatCost(cat.cost).padStart(8)}  ${String(cat.turns).padStart(4)} turns | font=Menlo size=11`);
  }
  lines.push(`-----`);
  lines.push(`--Models | size=12 color=#FF8C42`);
  for (const model of month.models.slice(0, 5)) {
    if (model.name === "<synthetic>") continue;
    const bar = miniBar(model.cost, monthMaxModel);
    const name = model.name.padEnd(14);
    lines.push(`--${bar}  ${name} ${formatCost(model.cost).padStart(8)}  ${String(model.calls).padStart(5)} calls | font=Menlo size=11`);
  }
  lines.push("---");
  const home = process.env.HOME ?? "~";
  lines.push(`Open Full Report | terminal=true shell=/bin/bash param1=-c param2="cd '${home}/codeburn' && npx tsx src/cli.ts report; echo ''; echo 'Press any key to close...'; read -n1"`);
  lines.push(`Export CSV to Desktop | terminal=false shell=/bin/bash param1=-c param2="cd '${home}/codeburn' && npx tsx src/cli.ts export -o '${home}/Desktop/codeburn-report.csv' 2>/dev/null"`);
  lines.push(`Refresh | refresh=true`);
  return lines.join("\n");
}
async function installMenubar() {
  if (platform() !== "darwin") {
    return "Menu bar integration is only available on macOS. Use `codeburn watch` or `codeburn status` instead.";
  }
  const bin = getCodeburnBin();
  const pluginContent = generatePlugin(bin);
  let pluginDir;
  let appName;
  if (existsSync(getSwiftBarPluginDir())) {
    pluginDir = getSwiftBarPluginDir();
    appName = "SwiftBar";
  } else if (existsSync(getXbarPluginDir())) {
    pluginDir = getXbarPluginDir();
    appName = "xbar";
  } else {
    pluginDir = getSwiftBarPluginDir();
    appName = "SwiftBar";
    await mkdir2(pluginDir, { recursive: true });
  }
  const pluginPath = join3(pluginDir, `codeburn.${PLUGIN_REFRESH}.sh`);
  await writeFile3(pluginPath, pluginContent, "utf-8");
  await chmod(pluginPath, 493);
  const swiftbarInstalled = existsSync("/Applications/SwiftBar.app") || existsSync(join3(homedir3(), "Applications", "SwiftBar.app"));
  const xbarInstalled = existsSync("/Applications/xbar.app") || existsSync(join3(homedir3(), "Applications", "xbar.app"));
  const lines = [];
  lines.push(`
  Plugin installed to: ${pluginPath}`);
  if (swiftbarInstalled || xbarInstalled) {
    lines.push(`  ${appName} detected - plugin should appear in your menu bar shortly.`);
    lines.push(`  If not, open ${appName} and refresh plugins.
`);
  } else {
    lines.push(`
  To see CodeBurn in your menu bar, install SwiftBar:`);
    lines.push(`    brew install --cask swiftbar`);
    lines.push(`
  Then launch SwiftBar - the plugin will load automatically.
`);
  }
  return lines.join("\n");
}
async function uninstallMenubar() {
  const paths = [
    join3(getSwiftBarPluginDir(), `codeburn.${PLUGIN_REFRESH}.sh`),
    join3(getXbarPluginDir(), `codeburn.${PLUGIN_REFRESH}.sh`)
  ];
  let removed = false;
  for (const p of paths) {
    if (existsSync(p)) {
      await unlink(p);
      removed = true;
    }
  }
  return removed ? "\n  Menu bar plugin removed.\n" : "\n  No menu bar plugin found.\n";
}

// src/dashboard.tsx
import { useState, useCallback } from "react";
import { render, Box, Text, useInput, useApp } from "ink";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
var PERIODS = ["today", "week", "month"];
var PERIOD_LABELS = {
  today: "Today",
  week: "7 Days",
  month: "This Month"
};
var MIN_WIDE = 90;
var ORANGE = "#FF8C42";
var DIM = "#555555";
var GOLD = "#FFD700";
var PANEL_COLORS = {
  overview: "#FF8C42",
  daily: "#5B9EF5",
  project: "#5BF5A0",
  model: "#E05BF5",
  activity: "#F5C85B",
  tools: "#5BF5E0",
  mcp: "#F55BE0"
};
var CATEGORY_COLORS = {
  coding: "#5B9EF5",
  debugging: "#F55B5B",
  feature: "#5BF58C",
  refactoring: "#F5E05B",
  testing: "#E05BF5",
  exploration: "#5BF5E0",
  planning: "#7B9EF5",
  delegation: "#F5C85B",
  git: "#CCCCCC",
  "build/deploy": "#5BF5A0",
  conversation: "#888888",
  brainstorming: "#F55BE0",
  general: "#666666"
};
function toHex(r, g, b) {
  return "#" + [r, g, b].map((v) => Math.round(v).toString(16).padStart(2, "0")).join("");
}
function lerp(a, b, t) {
  return a + t * (b - a);
}
function gradientColor(pct) {
  if (pct <= 0.33) {
    const t2 = pct / 0.33;
    return toHex(lerp(91, 245, t2), lerp(158, 200, t2), lerp(245, 91, t2));
  }
  if (pct <= 0.66) {
    const t2 = (pct - 0.33) / 0.33;
    return toHex(lerp(245, 255, t2), lerp(200, 140, t2), lerp(91, 66, t2));
  }
  const t = (pct - 0.66) / 0.34;
  return toHex(lerp(255, 245, t), lerp(140, 91, t), lerp(66, 91, t));
}
function getDateRange(period) {
  const now = /* @__PURE__ */ new Date();
  const end = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
  switch (period) {
    case "today":
      return { start: new Date(now.getFullYear(), now.getMonth(), now.getDate()), end };
    case "week":
      return { start: new Date(now.getFullYear(), now.getMonth(), now.getDate() - 7), end };
    case "month":
      return { start: new Date(now.getFullYear(), now.getMonth(), 1), end };
  }
}
function getLayout() {
  const termWidth = process.stdout.columns || parseInt(process.env["COLUMNS"] ?? "") || 80;
  const dashWidth = Math.min(104, termWidth);
  const wide = dashWidth >= MIN_WIDE;
  const halfWidth = wide ? Math.floor(dashWidth / 2) : dashWidth;
  const inner = halfWidth - 4;
  const barWidth = Math.max(6, Math.min(10, inner - 30));
  return { dashWidth, wide, halfWidth, barWidth };
}
function HBar({ value, max, width }) {
  if (max === 0) return /* @__PURE__ */ jsx(Text, { color: DIM, children: "\u2591".repeat(width) });
  const filled = Math.round(value / max * width);
  const fillChars = [];
  for (let i = 0; i < Math.min(filled, width); i++) {
    fillChars.push(/* @__PURE__ */ jsx(Text, { color: gradientColor(i / width), children: "\u2588" }, i));
  }
  return /* @__PURE__ */ jsxs(Text, { children: [
    fillChars,
    /* @__PURE__ */ jsx(Text, { color: "#333333", children: "\u2591".repeat(Math.max(width - filled, 0)) })
  ] });
}
function Panel({ title, color, children, width }) {
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: color, paddingX: 1, width, overflowX: "hidden", children: [
    /* @__PURE__ */ jsx(Text, { bold: true, color, children: title }),
    children
  ] });
}
function fit(s, n) {
  return s.length > n ? s.slice(0, n) : s.padEnd(n);
}
function Overview({ projects, label, width }) {
  const totalCost = projects.reduce((s, p) => s + p.totalCostUSD, 0);
  const totalCalls = projects.reduce((s, p) => s + p.totalApiCalls, 0);
  const totalSessions = projects.reduce((s, p) => s + p.sessions.length, 0);
  const allSessions = projects.flatMap((p) => p.sessions);
  const totalInput = allSessions.reduce((s, sess) => s + sess.totalInputTokens, 0);
  const totalOutput = allSessions.reduce((s, sess) => s + sess.totalOutputTokens, 0);
  const totalCacheRead = allSessions.reduce((s, sess) => s + sess.totalCacheReadTokens, 0);
  const totalCacheWrite = allSessions.reduce((s, sess) => s + sess.totalCacheWriteTokens, 0);
  const cacheHit = totalInput + totalCacheRead > 0 ? totalCacheRead / (totalInput + totalCacheRead) * 100 : 0;
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: PANEL_COLORS.overview, paddingX: 1, width, children: [
    /* @__PURE__ */ jsxs(Text, { wrap: "truncate-end", children: [
      /* @__PURE__ */ jsx(Text, { bold: true, color: ORANGE, children: "CodeBurn" }),
      /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
        "  ",
        label
      ] })
    ] }),
    /* @__PURE__ */ jsxs(Text, { wrap: "truncate-end", children: [
      /* @__PURE__ */ jsx(Text, { bold: true, color: GOLD, children: formatCost(totalCost) }),
      /* @__PURE__ */ jsx(Text, { dimColor: true, children: " cost   " }),
      /* @__PURE__ */ jsx(Text, { bold: true, children: totalCalls.toLocaleString() }),
      /* @__PURE__ */ jsx(Text, { dimColor: true, children: " calls   " }),
      /* @__PURE__ */ jsx(Text, { bold: true, children: String(totalSessions) }),
      /* @__PURE__ */ jsx(Text, { dimColor: true, children: " sessions   " }),
      /* @__PURE__ */ jsxs(Text, { bold: true, children: [
        cacheHit.toFixed(0),
        "%"
      ] }),
      /* @__PURE__ */ jsx(Text, { dimColor: true, children: " cache hit" })
    ] }),
    /* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
      formatTokens(totalInput),
      " in   ",
      formatTokens(totalOutput),
      " out   ",
      formatTokens(totalCacheRead),
      " cached   ",
      formatTokens(totalCacheWrite),
      " written"
    ] })
  ] });
}
function DailyActivity({ projects, days = 14, pw, bw }) {
  const dailyCosts = {};
  const dailyCalls = {};
  for (const project of projects) {
    for (const session of project.sessions) {
      for (const turn of session.turns) {
        if (!turn.timestamp) continue;
        const day = turn.timestamp.slice(0, 10);
        dailyCosts[day] = (dailyCosts[day] ?? 0) + turn.assistantCalls.reduce((s, c) => s + c.costUSD, 0);
        dailyCalls[day] = (dailyCalls[day] ?? 0) + turn.assistantCalls.length;
      }
    }
  }
  const sortedDays = Object.keys(dailyCosts).sort().slice(-days);
  const maxCost = Math.max(...sortedDays.map((d) => dailyCosts[d] ?? 0));
  return /* @__PURE__ */ jsxs(Panel, { title: "Daily Activity", color: PANEL_COLORS.daily, width: pw, children: [
    /* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
      "".padEnd(6 + bw),
      "cost".padStart(8),
      "calls".padStart(6)
    ] }),
    sortedDays.map((day) => /* @__PURE__ */ jsxs(Text, { wrap: "truncate-end", children: [
      /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
        day.slice(5),
        " "
      ] }),
      /* @__PURE__ */ jsx(HBar, { value: dailyCosts[day] ?? 0, max: maxCost, width: bw }),
      /* @__PURE__ */ jsx(Text, { color: GOLD, children: formatCost(dailyCosts[day] ?? 0).padStart(8) }),
      /* @__PURE__ */ jsx(Text, { children: String(dailyCalls[day] ?? 0).padStart(6) })
    ] }, day))
  ] });
}
function shortProject(project) {
  const parts = project.replace(/^-/, "").split("-").filter(Boolean);
  if (parts.length <= 2) return parts.join("/");
  return parts.slice(-2).join("/");
}
function ProjectBreakdown({ projects, pw, bw }) {
  const maxCost = Math.max(...projects.map((p) => p.totalCostUSD));
  const nw = Math.max(8, pw - bw - 23);
  return /* @__PURE__ */ jsxs(Panel, { title: "By Project", color: PANEL_COLORS.project, width: pw, children: [
    /* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
      "".padEnd(bw + 1 + nw),
      "cost".padStart(8),
      "sess".padStart(6)
    ] }),
    projects.slice(0, 8).map((project, i) => /* @__PURE__ */ jsxs(Text, { wrap: "truncate-end", children: [
      /* @__PURE__ */ jsx(HBar, { value: project.totalCostUSD, max: maxCost, width: bw }),
      /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
        " ",
        fit(shortProject(project.project), nw)
      ] }),
      /* @__PURE__ */ jsx(Text, { color: GOLD, children: formatCost(project.totalCostUSD).padStart(8) }),
      /* @__PURE__ */ jsx(Text, { children: String(project.sessions.length).padStart(6) })
    ] }, `${project.project}-${i}`))
  ] });
}
function ModelBreakdown({ projects, pw, bw }) {
  const modelTotals = {};
  for (const project of projects) {
    for (const session of project.sessions) {
      for (const [model, data] of Object.entries(session.modelBreakdown)) {
        if (!modelTotals[model]) modelTotals[model] = { calls: 0, costUSD: 0 };
        modelTotals[model].calls += data.calls;
        modelTotals[model].costUSD += data.costUSD;
      }
    }
  }
  const sorted = Object.entries(modelTotals).sort(([, a], [, b]) => b.costUSD - a.costUSD);
  const maxCost = sorted[0]?.[1]?.costUSD ?? 0;
  const nw = Math.max(6, pw - bw - 25);
  return /* @__PURE__ */ jsxs(Panel, { title: "By Model", color: PANEL_COLORS.model, width: pw, children: [
    /* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
      "".padEnd(bw + 1 + nw),
      "cost".padStart(8),
      "calls".padStart(7)
    ] }),
    sorted.map(([model, data], i) => /* @__PURE__ */ jsxs(Text, { wrap: "truncate-end", children: [
      /* @__PURE__ */ jsx(HBar, { value: data.costUSD, max: maxCost, width: bw }),
      /* @__PURE__ */ jsxs(Text, { children: [
        " ",
        fit(model, nw)
      ] }),
      /* @__PURE__ */ jsx(Text, { color: GOLD, children: formatCost(data.costUSD).padStart(8) }),
      /* @__PURE__ */ jsx(Text, { children: String(data.calls).padStart(7) })
    ] }, `${model}-${i}`))
  ] });
}
function ActivityBreakdown({ projects, pw, bw }) {
  const categoryTotals = {};
  for (const project of projects) {
    for (const session of project.sessions) {
      for (const [cat, data] of Object.entries(session.categoryBreakdown)) {
        if (!categoryTotals[cat]) categoryTotals[cat] = { turns: 0, costUSD: 0 };
        categoryTotals[cat].turns += data.turns;
        categoryTotals[cat].costUSD += data.costUSD;
      }
    }
  }
  const sorted = Object.entries(categoryTotals).sort(([, a], [, b]) => b.costUSD - a.costUSD);
  const maxCost = sorted[0]?.[1]?.costUSD ?? 0;
  return /* @__PURE__ */ jsxs(Panel, { title: "By Activity", color: PANEL_COLORS.activity, width: pw, children: [
    /* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
      "".padEnd(bw + 14),
      "cost".padStart(8),
      "turns".padStart(6)
    ] }),
    sorted.map(([cat, data]) => /* @__PURE__ */ jsxs(Text, { wrap: "truncate-end", children: [
      /* @__PURE__ */ jsx(HBar, { value: data.costUSD, max: maxCost, width: bw }),
      /* @__PURE__ */ jsxs(Text, { color: CATEGORY_COLORS[cat] ?? "#666666", children: [
        " ",
        fit(CATEGORY_LABELS[cat] ?? cat, 13)
      ] }),
      /* @__PURE__ */ jsx(Text, { color: GOLD, children: formatCost(data.costUSD).padStart(8) }),
      /* @__PURE__ */ jsx(Text, { children: String(data.turns).padStart(6) })
    ] }, cat))
  ] });
}
function ToolBreakdown({ projects, pw, bw }) {
  const toolTotals = {};
  for (const project of projects) {
    for (const session of project.sessions) {
      for (const [tool, data] of Object.entries(session.toolBreakdown)) {
        toolTotals[tool] = (toolTotals[tool] ?? 0) + data.calls;
      }
    }
  }
  const sorted = Object.entries(toolTotals).sort(([, a], [, b]) => b - a);
  const maxCalls = sorted[0]?.[1] ?? 0;
  const nw = Math.max(6, pw - bw - 15);
  return /* @__PURE__ */ jsxs(Panel, { title: "Core Tools", color: PANEL_COLORS.tools, width: pw, children: [
    /* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
      "".padEnd(bw + 1 + nw),
      "calls".padStart(7)
    ] }),
    sorted.slice(0, 10).map(([tool, calls]) => /* @__PURE__ */ jsxs(Text, { wrap: "truncate-end", children: [
      /* @__PURE__ */ jsx(HBar, { value: calls, max: maxCalls, width: bw }),
      /* @__PURE__ */ jsxs(Text, { children: [
        " ",
        fit(tool, nw)
      ] }),
      /* @__PURE__ */ jsx(Text, { children: String(calls).padStart(7) })
    ] }, tool))
  ] });
}
function McpBreakdown({ projects, pw, bw }) {
  const mcpTotals = {};
  for (const project of projects) {
    for (const session of project.sessions) {
      for (const [server, data] of Object.entries(session.mcpBreakdown)) {
        mcpTotals[server] = (mcpTotals[server] ?? 0) + data.calls;
      }
    }
  }
  const sorted = Object.entries(mcpTotals).sort(([, a], [, b]) => b - a);
  if (sorted.length === 0) {
    return /* @__PURE__ */ jsx(Panel, { title: "MCP Servers", color: PANEL_COLORS.mcp, width: pw, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No MCP usage" }) });
  }
  const maxCalls = sorted[0]?.[1] ?? 0;
  const nw = Math.max(6, pw - bw - 15);
  return /* @__PURE__ */ jsxs(Panel, { title: "MCP Servers", color: PANEL_COLORS.mcp, width: pw, children: [
    /* @__PURE__ */ jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [
      "".padEnd(bw + 1 + nw),
      "calls".padStart(6)
    ] }),
    sorted.slice(0, 8).map(([server, calls]) => /* @__PURE__ */ jsxs(Text, { wrap: "truncate-end", children: [
      /* @__PURE__ */ jsx(HBar, { value: calls, max: maxCalls, width: bw }),
      /* @__PURE__ */ jsxs(Text, { children: [
        " ",
        fit(server, nw)
      ] }),
      /* @__PURE__ */ jsx(Text, { children: String(calls).padStart(6) })
    ] }, server))
  ] });
}
function PeriodTabs({ active }) {
  return /* @__PURE__ */ jsx(Box, { gap: 1, paddingX: 1, children: PERIODS.map((p) => /* @__PURE__ */ jsx(Text, { bold: active === p, color: active === p ? ORANGE : DIM, children: active === p ? `[ ${PERIOD_LABELS[p]} ]` : `  ${PERIOD_LABELS[p]}  ` }, p)) });
}
function StatusBar({ width }) {
  return /* @__PURE__ */ jsx(Box, { borderStyle: "round", borderColor: DIM, width, justifyContent: "center", paddingX: 1, children: /* @__PURE__ */ jsxs(Text, { children: [
    /* @__PURE__ */ jsx(Text, { color: ORANGE, bold: true, children: "<" }),
    /* @__PURE__ */ jsx(Text, { color: ORANGE, children: ">" }),
    /* @__PURE__ */ jsx(Text, { dimColor: true, children: " switch   " }),
    /* @__PURE__ */ jsx(Text, { color: ORANGE, bold: true, children: "q" }),
    /* @__PURE__ */ jsx(Text, { dimColor: true, children: " quit   " }),
    /* @__PURE__ */ jsx(Text, { color: ORANGE, bold: true, children: "1" }),
    /* @__PURE__ */ jsx(Text, { dimColor: true, children: " today   " }),
    /* @__PURE__ */ jsx(Text, { color: ORANGE, bold: true, children: "2" }),
    /* @__PURE__ */ jsx(Text, { dimColor: true, children: " week   " }),
    /* @__PURE__ */ jsx(Text, { color: ORANGE, bold: true, children: "3" }),
    /* @__PURE__ */ jsx(Text, { dimColor: true, children: " month" })
  ] }) });
}
function Row({ wide, width, children }) {
  if (wide) return /* @__PURE__ */ jsx(Box, { width, children });
  return /* @__PURE__ */ jsx(Fragment, { children });
}
function DashboardContent({ projects, period }) {
  const { dashWidth, wide, halfWidth, barWidth } = getLayout();
  if (projects.length === 0) {
    return /* @__PURE__ */ jsx(Panel, { title: "CodeBurn", color: ORANGE, width: dashWidth, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
      "No usage data found for ",
      PERIOD_LABELS[period],
      "."
    ] }) });
  }
  const pw = wide ? halfWidth : dashWidth;
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: dashWidth, children: [
    /* @__PURE__ */ jsx(Overview, { projects, label: PERIOD_LABELS[period], width: dashWidth }),
    /* @__PURE__ */ jsxs(Row, { wide, width: dashWidth, children: [
      /* @__PURE__ */ jsx(DailyActivity, { projects, days: period === "month" ? 31 : 14, pw, bw: barWidth }),
      /* @__PURE__ */ jsx(ProjectBreakdown, { projects, pw, bw: barWidth })
    ] }),
    /* @__PURE__ */ jsxs(Row, { wide, width: dashWidth, children: [
      /* @__PURE__ */ jsx(ModelBreakdown, { projects, pw, bw: barWidth }),
      /* @__PURE__ */ jsx(ActivityBreakdown, { projects, pw, bw: barWidth })
    ] }),
    /* @__PURE__ */ jsxs(Row, { wide, width: dashWidth, children: [
      /* @__PURE__ */ jsx(ToolBreakdown, { projects, pw, bw: barWidth }),
      /* @__PURE__ */ jsx(McpBreakdown, { projects, pw, bw: barWidth })
    ] })
  ] });
}
function InteractiveDashboard({ initialProjects, initialPeriod }) {
  const { exit } = useApp();
  const [period, setPeriod] = useState(initialPeriod);
  const [projects, setProjects] = useState(initialProjects);
  const [loading, setLoading] = useState(false);
  const { dashWidth } = getLayout();
  const switchPeriod = useCallback(async (newPeriod) => {
    if (newPeriod === period) return;
    setLoading(true);
    setPeriod(newPeriod);
    const range = getDateRange(newPeriod);
    const data = await parseAllSessions(range);
    setProjects(data);
    setLoading(false);
  }, [period]);
  useInput((input, key) => {
    if (input === "q") {
      exit();
      return;
    }
    const idx = PERIODS.indexOf(period);
    if (key.leftArrow) {
      switchPeriod(PERIODS[(idx - 1 + PERIODS.length) % PERIODS.length]);
    } else if (key.rightArrow || key.tab) {
      switchPeriod(PERIODS[(idx + 1) % PERIODS.length]);
    } else if (input === "1") switchPeriod("today");
    else if (input === "2") switchPeriod("week");
    else if (input === "3") switchPeriod("month");
  });
  if (loading) {
    return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: dashWidth, children: [
      /* @__PURE__ */ jsx(PeriodTabs, { active: period }),
      /* @__PURE__ */ jsx(Panel, { title: "CodeBurn", color: ORANGE, width: dashWidth, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
        "Loading ",
        PERIOD_LABELS[period],
        "..."
      ] }) }),
      /* @__PURE__ */ jsx(StatusBar, { width: dashWidth })
    ] });
  }
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: dashWidth, children: [
    /* @__PURE__ */ jsx(PeriodTabs, { active: period }),
    /* @__PURE__ */ jsx(DashboardContent, { projects, period }),
    /* @__PURE__ */ jsx(StatusBar, { width: dashWidth })
  ] });
}
function StaticDashboard({ projects, period }) {
  const { dashWidth } = getLayout();
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: dashWidth, children: [
    /* @__PURE__ */ jsx(PeriodTabs, { active: period }),
    /* @__PURE__ */ jsx(DashboardContent, { projects, period })
  ] });
}
async function renderDashboard(period = "week") {
  await loadPricing();
  const range = getDateRange(period);
  const projects = await parseAllSessions(range);
  const isTTY = process.stdin.isTTY && process.stdout.isTTY;
  if (isTTY) {
    const { waitUntilExit } = render(
      /* @__PURE__ */ jsx(InteractiveDashboard, { initialProjects: projects, initialPeriod: period })
    );
    await waitUntilExit();
  } else {
    const { unmount } = render(
      /* @__PURE__ */ jsx(StaticDashboard, { projects, period }),
      { patchConsole: false }
    );
    unmount();
  }
}

// src/cli.ts
function getDateRange2(period) {
  const now = /* @__PURE__ */ new Date();
  const end = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999);
  switch (period) {
    case "today": {
      const start = new Date(now.getFullYear(), now.getMonth(), now.getDate());
      return { range: { start, end }, label: `Today (${start.toISOString().slice(0, 10)})` };
    }
    case "yesterday": {
      const start = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
      const yesterdayEnd = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1, 23, 59, 59, 999);
      return { range: { start, end: yesterdayEnd }, label: `Yesterday (${start.toISOString().slice(0, 10)})` };
    }
    case "week": {
      const start = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 7);
      return { range: { start, end }, label: "Last 7 Days" };
    }
    case "month": {
      const start = new Date(now.getFullYear(), now.getMonth(), 1);
      return { range: { start, end }, label: `${now.toLocaleString("default", { month: "long" })} ${now.getFullYear()}` };
    }
    case "all": {
      return { range: { start: /* @__PURE__ */ new Date(0), end }, label: "All Time" };
    }
    default: {
      const start = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 7);
      return { range: { start, end }, label: "Last 7 Days" };
    }
  }
}
function toPeriod(s) {
  if (s === "today") return "today";
  if (s === "month") return "month";
  return "week";
}
var program = new Command().name("codeburn").description("See where your AI coding tokens go - by task, tool, model, and project").version("0.1.0");
program.command("report", { isDefault: true }).description("Interactive usage dashboard").option("-p, --period <period>", "Starting period: today, week, month", "week").action(async (opts) => {
  await renderDashboard(toPeriod(opts.period));
});
function buildPeriodData(label, projects) {
  const sessions = projects.flatMap((p) => p.sessions);
  const catTotals = {};
  const modelTotals = {};
  let inputTokens = 0, outputTokens = 0, cacheReadTokens = 0, cacheWriteTokens = 0;
  for (const sess of sessions) {
    inputTokens += sess.totalInputTokens;
    outputTokens += sess.totalOutputTokens;
    cacheReadTokens += sess.totalCacheReadTokens;
    cacheWriteTokens += sess.totalCacheWriteTokens;
    for (const [cat, d] of Object.entries(sess.categoryBreakdown)) {
      if (!catTotals[cat]) catTotals[cat] = { turns: 0, cost: 0 };
      catTotals[cat].turns += d.turns;
      catTotals[cat].cost += d.costUSD;
    }
    for (const [model, d] of Object.entries(sess.modelBreakdown)) {
      if (!modelTotals[model]) modelTotals[model] = { calls: 0, cost: 0 };
      modelTotals[model].calls += d.calls;
      modelTotals[model].cost += d.costUSD;
    }
  }
  return {
    label,
    cost: projects.reduce((s, p) => s + p.totalCostUSD, 0),
    calls: projects.reduce((s, p) => s + p.totalApiCalls, 0),
    inputTokens,
    outputTokens,
    cacheReadTokens,
    cacheWriteTokens,
    categories: Object.entries(catTotals).sort(([, a], [, b]) => b.cost - a.cost).map(([cat, d]) => ({ name: CATEGORY_LABELS[cat] ?? cat, ...d })),
    models: Object.entries(modelTotals).sort(([, a], [, b]) => b.cost - a.cost).map(([name, d]) => ({ name, ...d }))
  };
}
program.command("status").description("Compact status output (today + week + month)").option("--format <format>", "Output format: terminal, menubar, json", "terminal").action(async (opts) => {
  await loadPricing();
  if (opts.format === "menubar") {
    const todayData = buildPeriodData("Today", await parseAllSessions(getDateRange2("today").range));
    const weekData = buildPeriodData("7 Days", await parseAllSessions(getDateRange2("week").range));
    const monthData = buildPeriodData("Month", await parseAllSessions(getDateRange2("month").range));
    console.log(renderMenubarFormat(todayData, weekData, monthData));
    return;
  }
  if (opts.format === "json") {
    const todayData = buildPeriodData("today", await parseAllSessions(getDateRange2("today").range));
    const monthData = buildPeriodData("month", await parseAllSessions(getDateRange2("month").range));
    console.log(JSON.stringify({ today: { cost: todayData.cost, calls: todayData.calls }, month: { cost: monthData.cost, calls: monthData.calls } }));
    return;
  }
  const monthProjects = await parseAllSessions(getDateRange2("month").range);
  console.log(renderStatusBar(monthProjects));
});
program.command("today").description("Today's usage dashboard").action(async () => {
  await renderDashboard("today");
});
program.command("month").description("This month's usage dashboard").action(async () => {
  await renderDashboard("month");
});
program.command("export").description("Export usage data to CSV or JSON (includes 1 day, 7 days, 30 days)").option("-f, --format <format>", "Export format: csv, json", "csv").option("-o, --output <path>", "Output file path").action(async (opts) => {
  await loadPricing();
  const periods = [
    { label: "Today", projects: await parseAllSessions(getDateRange2("today").range) },
    { label: "7 Days", projects: await parseAllSessions(getDateRange2("week").range) },
    { label: "30 Days", projects: await parseAllSessions(getDateRange2("month").range) }
  ];
  if (periods.every((p) => p.projects.length === 0)) {
    console.log("\n  No usage data found.\n");
    return;
  }
  const defaultName = `codeburn-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
  const outputPath = opts.output ?? `${defaultName}.${opts.format}`;
  let savedPath;
  if (opts.format === "json") {
    savedPath = await exportJson(periods, outputPath);
  } else {
    savedPath = await exportCsv(periods, outputPath);
  }
  console.log(`
  Exported (Today + 7 Days + 30 Days) to: ${savedPath}
`);
});
program.command("install-menubar").description("Install macOS menu bar plugin (SwiftBar/xbar)").action(async () => {
  const result = await installMenubar();
  console.log(result);
});
program.command("uninstall-menubar").description("Remove macOS menu bar plugin").action(async () => {
  const result = await uninstallMenubar();
  console.log(result);
});
program.parse();
//# sourceMappingURL=cli.js.map