{"version":3,"file":"usage-command.mjs","names":[],"sources":["../../../src/commands/usage-command.ts"],"sourcesContent":["/**\n * /usage — LLM usage and cost reporting.\n *\n * Provider-aware: shows real data for Bankr, directs to dashboard for others.\n * Replaces the Bankr-only /llmcost with a unified command.\n *\n * Subcommands:\n *   /usage          — usage summary for active provider\n *   /usage pricing  — show model pricing reference\n *   /usage 7        — Bankr usage for past N days (default 30)\n */\n\nimport { getActiveProvider, PROVIDERS } from '../services/keychain-secrets.js';\nimport {\n  fetchBankrUsage,\n  PROVIDER_DASHBOARDS,\n  PRICING,\n  type ModelPricing,\n} from '../services/usage-tracker.js';\n\nexport const usageNewCommand = {\n  name: 'usage',\n  description: 'LLM usage, costs, and provider dashboard links',\n  acceptsArgs: true,\n  requireAuth: true,\n\n  handler: async (ctx: any) => {\n    const args = (ctx?.args ?? '').trim();\n\n    // ── /usage pricing ─────────────────────────────────────────────\n    if (args === 'pricing' || args === 'prices' || args === 'cost') {\n      return { text: formatPricing() };\n    }\n\n    const provider = getActiveProvider();\n    const providerConfig = (PROVIDERS as Record<string, any>)[provider];\n    const label = providerConfig?.label ?? provider;\n    const dashboard = PROVIDER_DASHBOARDS[provider] ?? null;\n    const hasKey = !!process.env[providerConfig?.envVar ?? ''];\n\n    // ── Bankr: show real usage data ────────────────────────────────\n    if (provider === 'bankr' || process.env.BANKR_LLM_KEY) {\n      const daysArg = parseInt(args, 10);\n      const days = (daysArg > 0 && daysArg <= 90) ? daysArg : 30;\n\n      const data = await fetchBankrUsage(days);\n      if (!data) {\n        return { text: `Could not fetch Bankr usage. Check BANKR_LLM_KEY.\\n\\nDashboard: ${PROVIDER_DASHBOARDS.bankr}` };\n      }\n\n      const t = data.totals;\n      const lines = [\n        `**LLM Usage — ${label} (${days} days)**`,\n        '',\n      ];\n\n      // Show credit balance if available\n      if (data.credits) {\n        lines.push(`**Balance:** $${data.credits.balance.toFixed(2)}`);\n        lines.push('');\n      }\n\n      lines.push(\n        '**Totals:**',\n        `  Requests: ${t.totalRequests.toLocaleString()}`,\n        `  Input tokens: ${t.totalInputTokens.toLocaleString()}`,\n        `  Output tokens: ${t.totalOutputTokens.toLocaleString()}`,\n        `  Cache reads: ${t.totalCacheReadInputTokens.toLocaleString()}`,\n        `  Total cost: $${t.totalCost.toFixed(2)}`,\n      );\n\n      if (data.byModel.length > 0) {\n        lines.push('', '**By model:**');\n        const sorted = [...data.byModel].sort((a, b) => b.totalCost - a.totalCost);\n        for (const m of sorted) {\n          lines.push(`  ${m.model}: ${m.requests.toLocaleString()} reqs, $${m.totalCost.toFixed(2)}`);\n        }\n      }\n\n      lines.push('', `Dashboard: ${PROVIDER_DASHBOARDS.bankr}`);\n\n      // If active provider is NOT bankr but BANKR_LLM_KEY exists, note it\n      if (provider !== 'bankr') {\n        lines.unshift(`*Active provider: ${label} — showing Bankr data (has API key)*\\n`);\n      }\n\n      return { text: lines.join('\\n') };\n    }\n\n    // ── Other providers: show config + dashboard link ──────────────\n    const lines = [\n      `**LLM Usage — ${label}**`,\n      '',\n      `Active provider: **${label}**`,\n      `API key: ${hasKey ? 'configured' : 'not set'}`,\n    ];\n\n    if (dashboard) {\n      lines.push('', `Usage data is available at your provider's dashboard:`, dashboard);\n    }\n\n    // Show pricing for reference\n    lines.push('', '**Model pricing (per 1M tokens):**');\n    const relevantModels = getRelevantModels(provider);\n    for (const [model, pricing] of relevantModels) {\n      lines.push(`  ${model}: $${pricing.inputPer1M} input / $${pricing.outputPer1M} output`);\n    }\n\n    lines.push('', '*Tip: Run `/usage pricing` to see all model prices.*');\n    \n    // If BANKR_LLM_KEY is set but not active, mention it\n    if (process.env.BANKR_LLM_KEY) {\n      lines.push('', `*Bankr key detected — run \\`/usage\\` after \\`/api use bankr\\` for detailed stats.*`);\n    }\n\n    return { text: lines.join('\\n') };\n  },\n};\n\n// ─── Helpers ─────────────────────────────────────────────────────────────\n\nfunction getRelevantModels(provider: string): Array<[string, ModelPricing]> {\n  const entries = Object.entries(PRICING);\n  switch (provider) {\n    case 'anthropic':\n    case 'bankr':\n      return entries.filter(([k]) => k.startsWith('claude'));\n    case 'openai':\n      return entries.filter(([k]) => k.startsWith('gpt') || k.startsWith('o'));\n    case 'openrouter':\n      return entries; // OpenRouter has all models\n    default:\n      return entries;\n  }\n}\n\nfunction formatPricing(): string {\n  const lines = ['**Model Pricing Reference (per 1M tokens)**', ''];\n\n  lines.push('**Anthropic:**');\n  for (const [model, p] of Object.entries(PRICING)) {\n    if (model.startsWith('claude')) {\n      const cache = p.cachePer1M ? ` / $${p.cachePer1M} cache` : '';\n      lines.push(`  ${model}: $${p.inputPer1M} in / $${p.outputPer1M} out${cache}`);\n    }\n  }\n\n  lines.push('', '**OpenAI:**');\n  for (const [model, p] of Object.entries(PRICING)) {\n    if (model.startsWith('gpt') || model.startsWith('o')) {\n      lines.push(`  ${model}: $${p.inputPer1M} in / $${p.outputPer1M} out`);\n    }\n  }\n\n  lines.push('', '*Prices as of March 2026. Check provider dashboards for current rates.*');\n  return lines.join('\\n');\n}\n"],"mappings":"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"}