agentix-cli 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/README.md +75 -27
  2. package/dist/{agent-RDVGL2TW.js → agent-57MG4LBM.js} +2 -2
  3. package/dist/{audit-Z47AQFFD.js → audit-JU3HWISB.js} +2 -2
  4. package/dist/{board-dashboard-KX2CNOSY.js → board-dashboard-HXDOYGIG.js} +2237 -69
  5. package/dist/board-dashboard-HXDOYGIG.js.map +1 -0
  6. package/dist/chunk-23AUU4S2.js +102 -0
  7. package/dist/chunk-23AUU4S2.js.map +1 -0
  8. package/dist/chunk-4MREHZP5.js +111 -0
  9. package/dist/chunk-4MREHZP5.js.map +1 -0
  10. package/dist/chunk-4YCH6IZV.js +2 -0
  11. package/dist/chunk-6B74TO2J.js +743 -0
  12. package/dist/chunk-6B74TO2J.js.map +1 -0
  13. package/dist/chunk-7P5QRX5W.js +108 -0
  14. package/dist/chunk-7P5QRX5W.js.map +1 -0
  15. package/dist/chunk-A6BKSZQA.js +3 -0
  16. package/dist/chunk-A6BKSZQA.js.map +1 -0
  17. package/dist/{chunk-6PPIFDOQ.js → chunk-CNNLREHD.js} +67 -22
  18. package/dist/{chunk-6PPIFDOQ.js.map → chunk-CNNLREHD.js.map} +1 -1
  19. package/dist/{chunk-J4WKMKTP.js → chunk-DLVOHCTA.js} +2 -2
  20. package/dist/chunk-E4ZZILAK.js +15 -0
  21. package/dist/chunk-E4ZZILAK.js.map +1 -0
  22. package/dist/{chunk-TRQSP67X.js → chunk-IKBHHTIT.js} +2 -2
  23. package/dist/chunk-JTJIPNXY.js +2 -0
  24. package/dist/chunk-JTJIPNXY.js.map +1 -0
  25. package/dist/chunk-MBOLXKA2.js +6 -0
  26. package/dist/chunk-MBOLXKA2.js.map +1 -0
  27. package/dist/{inbox-O5UB3YQN.js → chunk-MTRWXRFF.js} +69 -4
  28. package/dist/chunk-MTRWXRFF.js.map +1 -0
  29. package/dist/{processes-7W27G3J3.js → chunk-NOF4HSGK.js} +3 -3
  30. package/dist/{processes-7W27G3J3.js.map → chunk-NOF4HSGK.js.map} +1 -1
  31. package/dist/chunk-QW2OYR3N.js +7 -0
  32. package/dist/chunk-QW2OYR3N.js.map +1 -0
  33. package/dist/chunk-SV3I4CI7.js +440 -0
  34. package/dist/chunk-SV3I4CI7.js.map +1 -0
  35. package/dist/{chunk-JXEPJ3YD.js → chunk-TC3BSUP7.js} +5 -5
  36. package/dist/chunk-VWTBHLMX.js +1 -0
  37. package/dist/chunk-WFHIIVLL.js +719 -0
  38. package/dist/chunk-WFHIIVLL.js.map +1 -0
  39. package/dist/chunk-WPPUOTY6.js +6 -0
  40. package/dist/chunk-WPPUOTY6.js.map +1 -0
  41. package/dist/cli.js +1 -1
  42. package/dist/cli.js.map +1 -1
  43. package/dist/{compaction-S5H6DTOR.js → compaction-BTUJJ3LJ.js} +4 -4
  44. package/dist/config-QXWKEQON.js +2 -0
  45. package/dist/config-mutator-53XGR2NT.js +2 -0
  46. package/dist/conflict-detector-D7VIYPDI.js +2 -0
  47. package/dist/conflict-detector-D7VIYPDI.js.map +1 -0
  48. package/dist/{context-planner-2RGHJHSO.js → context-planner-I7ID7XF3.js} +3 -3
  49. package/dist/debug-N3B5NVJU.js +2 -0
  50. package/dist/{discover-OATU7SHI.js → discover-XJXQXXIO.js} +2 -2
  51. package/dist/doctor-SEOUFHSL.js +2 -0
  52. package/dist/{editor-chat-FUBQLMAQ.js → editor-chat-RVLCKKB7.js} +2 -2
  53. package/dist/{heal-YP7QI7D3.js → heal-YEQYWX2L.js} +2 -2
  54. package/dist/inbox-BIN2S5XN.js +2 -0
  55. package/dist/index.d.ts +830 -100
  56. package/dist/index.js +2 -2
  57. package/dist/index.js.map +1 -1
  58. package/dist/{ingest-whatsapp-C3O5UPBX.js → ingest-whatsapp-LZE62INA.js} +2 -2
  59. package/dist/loader-5CA3O5GM.js +2 -0
  60. package/dist/loader-6IHUCPVO.js +2 -0
  61. package/dist/memory-extract-KRCHD3OP.js +2 -0
  62. package/dist/migrate-v2-QO7SLKIM.js +4 -0
  63. package/dist/migrate-v2-QO7SLKIM.js.map +1 -0
  64. package/dist/processes-RJ6RDP32.js +2 -0
  65. package/dist/program-SASDC2GV.js +2 -0
  66. package/dist/{providers-WCQSKTNP.js → providers-WVCMIW67.js} +2 -2
  67. package/dist/query-HZYYRCLU.js +2 -0
  68. package/dist/recipes-EPLE2SNT.js +2 -0
  69. package/dist/registry-HM4ELSXS.js +2 -0
  70. package/dist/rotation-memo-GMTZPMNE.js +13 -0
  71. package/dist/rotation-memo-GMTZPMNE.js.map +1 -0
  72. package/dist/scheduler-XVFIK4XH.js +2 -0
  73. package/dist/{slack-D27BE37Q.js → slack-6P7ZJ32Y.js} +2 -2
  74. package/dist/store-BAPDZHXE.js +2 -0
  75. package/dist/{subagent-EPOT3QDM.js → subagent-WV7QKQ3L.js} +2 -2
  76. package/dist/{task-store-3NUWLYRY.js → task-store-RHISEU6V.js} +2 -2
  77. package/dist/{telegram-UWV67KWG.js → telegram-PIYDRM46.js} +2 -2
  78. package/dist/timers-5LPZN55J.js +2 -0
  79. package/dist/types-VECTMYTO.js +2 -0
  80. package/dist/types-VECTMYTO.js.map +1 -0
  81. package/dist/types-ZRLHHCGB.js +2 -0
  82. package/dist/types-ZRLHHCGB.js.map +1 -0
  83. package/dist/web/activity-graph.global.js +654 -0
  84. package/dist/web/activity-graph.global.js.map +1 -0
  85. package/dist/web/workflow-editor.global.js +1 -1
  86. package/dist/web/workflow-editor.global.js.map +1 -1
  87. package/dist/{whatsapp-KJ2NRKKQ.js → whatsapp-PFRDMUMT.js} +2 -2
  88. package/dist/{whatsapp-state-3ZVQ6MQD.js → whatsapp-state-XMTCSRXU.js} +2 -2
  89. package/dist/wiki-53W5NLZV.js +2 -0
  90. package/dist/wiki-53W5NLZV.js.map +1 -0
  91. package/dist/workspace-setup-FPGN5VNY.js +2 -0
  92. package/dist/workspace-setup-FPGN5VNY.js.map +1 -0
  93. package/package.json +3 -2
  94. package/dist/board-dashboard-KX2CNOSY.js.map +0 -1
  95. package/dist/chunk-34NG7UDX.js +0 -11
  96. package/dist/chunk-34NG7UDX.js.map +0 -1
  97. package/dist/chunk-ASSJ4Z6Z.js +0 -164
  98. package/dist/chunk-ASSJ4Z6Z.js.map +0 -1
  99. package/dist/chunk-BLUXL6HR.js +0 -854
  100. package/dist/chunk-BLUXL6HR.js.map +0 -1
  101. package/dist/chunk-BTAEYL3P.js +0 -72
  102. package/dist/chunk-BTAEYL3P.js.map +0 -1
  103. package/dist/chunk-DSCMCVTV.js +0 -7
  104. package/dist/chunk-DSCMCVTV.js.map +0 -1
  105. package/dist/chunk-HPDHNIA3.js +0 -2
  106. package/dist/chunk-IM376SD6.js +0 -13
  107. package/dist/chunk-IM376SD6.js.map +0 -1
  108. package/dist/chunk-LEIYC3BF.js +0 -104
  109. package/dist/chunk-LEIYC3BF.js.map +0 -1
  110. package/dist/chunk-LY7JGDV7.js +0 -6
  111. package/dist/chunk-LY7JGDV7.js.map +0 -1
  112. package/dist/chunk-U364GNQX.js +0 -719
  113. package/dist/chunk-U364GNQX.js.map +0 -1
  114. package/dist/chunk-WZEYII2S.js +0 -6
  115. package/dist/chunk-WZEYII2S.js.map +0 -1
  116. package/dist/config-UOHEG4BW.js +0 -2
  117. package/dist/config-mutator-KSEBWKJH.js +0 -2
  118. package/dist/debug-TGAP7E7W.js +0 -2
  119. package/dist/inbox-O5UB3YQN.js.map +0 -1
  120. package/dist/loader-BGWA7IRY.js +0 -2
  121. package/dist/loader-LBHKSXBK.js +0 -2
  122. package/dist/memory-extract-KKPKAOPH.js +0 -2
  123. package/dist/program-2MDELQLX.js +0 -2
  124. package/dist/query-FZAL7AQD.js +0 -2
  125. package/dist/recipes-LZ56TA3X.js +0 -2
  126. package/dist/registry-ONJSILH4.js +0 -2
  127. package/dist/scheduler-XRM2RJIV.js +0 -2
  128. package/dist/store-4UCO56K2.js +0 -2
  129. package/dist/timers-QB4KYNAE.js +0 -2
  130. package/dist/types-ECMEC5BZ.js +0 -2
  131. package/dist/types-TTB6DJUE.js +0 -2
  132. package/dist/usage-dashboard-FQGPPABD.js +0 -803
  133. package/dist/usage-dashboard-FQGPPABD.js.map +0 -1
  134. package/dist/wiki-OUYKM7MB.js +0 -2
  135. package/dist/workspace-setup-6GDBEORT.js +0 -2
  136. /package/dist/{agent-RDVGL2TW.js.map → agent-57MG4LBM.js.map} +0 -0
  137. /package/dist/{audit-Z47AQFFD.js.map → audit-JU3HWISB.js.map} +0 -0
  138. /package/dist/{chunk-HPDHNIA3.js.map → chunk-4YCH6IZV.js.map} +0 -0
  139. /package/dist/{chunk-J4WKMKTP.js.map → chunk-DLVOHCTA.js.map} +0 -0
  140. /package/dist/{chunk-TRQSP67X.js.map → chunk-IKBHHTIT.js.map} +0 -0
  141. /package/dist/{chunk-JXEPJ3YD.js.map → chunk-TC3BSUP7.js.map} +0 -0
  142. /package/dist/{config-UOHEG4BW.js.map → chunk-VWTBHLMX.js.map} +0 -0
  143. /package/dist/{compaction-S5H6DTOR.js.map → compaction-BTUJJ3LJ.js.map} +0 -0
  144. /package/dist/{config-mutator-KSEBWKJH.js.map → config-QXWKEQON.js.map} +0 -0
  145. /package/dist/{debug-TGAP7E7W.js.map → config-mutator-53XGR2NT.js.map} +0 -0
  146. /package/dist/{context-planner-2RGHJHSO.js.map → context-planner-I7ID7XF3.js.map} +0 -0
  147. /package/dist/{heal-YP7QI7D3.js.map → debug-N3B5NVJU.js.map} +0 -0
  148. /package/dist/{discover-OATU7SHI.js.map → discover-XJXQXXIO.js.map} +0 -0
  149. /package/dist/{loader-BGWA7IRY.js.map → doctor-SEOUFHSL.js.map} +0 -0
  150. /package/dist/{editor-chat-FUBQLMAQ.js.map → editor-chat-RVLCKKB7.js.map} +0 -0
  151. /package/dist/{loader-LBHKSXBK.js.map → heal-YEQYWX2L.js.map} +0 -0
  152. /package/dist/{memory-extract-KKPKAOPH.js.map → inbox-BIN2S5XN.js.map} +0 -0
  153. /package/dist/{ingest-whatsapp-C3O5UPBX.js.map → ingest-whatsapp-LZE62INA.js.map} +0 -0
  154. /package/dist/{program-2MDELQLX.js.map → loader-5CA3O5GM.js.map} +0 -0
  155. /package/dist/{providers-WCQSKTNP.js.map → loader-6IHUCPVO.js.map} +0 -0
  156. /package/dist/{query-FZAL7AQD.js.map → memory-extract-KRCHD3OP.js.map} +0 -0
  157. /package/dist/{recipes-LZ56TA3X.js.map → processes-RJ6RDP32.js.map} +0 -0
  158. /package/dist/{registry-ONJSILH4.js.map → program-SASDC2GV.js.map} +0 -0
  159. /package/dist/{scheduler-XRM2RJIV.js.map → providers-WVCMIW67.js.map} +0 -0
  160. /package/dist/{store-4UCO56K2.js.map → query-HZYYRCLU.js.map} +0 -0
  161. /package/dist/{task-store-3NUWLYRY.js.map → recipes-EPLE2SNT.js.map} +0 -0
  162. /package/dist/{timers-QB4KYNAE.js.map → registry-HM4ELSXS.js.map} +0 -0
  163. /package/dist/{types-ECMEC5BZ.js.map → scheduler-XVFIK4XH.js.map} +0 -0
  164. /package/dist/{slack-D27BE37Q.js.map → slack-6P7ZJ32Y.js.map} +0 -0
  165. /package/dist/{types-TTB6DJUE.js.map → store-BAPDZHXE.js.map} +0 -0
  166. /package/dist/{subagent-EPOT3QDM.js.map → subagent-WV7QKQ3L.js.map} +0 -0
  167. /package/dist/{wiki-OUYKM7MB.js.map → task-store-RHISEU6V.js.map} +0 -0
  168. /package/dist/{telegram-UWV67KWG.js.map → telegram-PIYDRM46.js.map} +0 -0
  169. /package/dist/{workspace-setup-6GDBEORT.js.map → timers-5LPZN55J.js.map} +0 -0
  170. /package/dist/{whatsapp-KJ2NRKKQ.js.map → whatsapp-PFRDMUMT.js.map} +0 -0
  171. /package/dist/{whatsapp-state-3ZVQ6MQD.js.map → whatsapp-state-XMTCSRXU.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/daemon/usage-dashboard.ts"],"sourcesContent":["import { createServer } from \"http\"\nimport { readdirSync } from \"fs\"\nimport { TokenTracker, type DailyUsage, type AgentUsage, type DailyReport } from \"./token-tracker\"\n\n// --- Usage Dashboard: zero-dep web UI for token cost tracking ---\n\nexport function startUsageDashboard(port: number = 4201): void {\n const tracker = new TokenTracker()\n\n const server = createServer(async (req, res) => {\n const url = new URL(req.url || \"/\", `http://localhost:${port}`)\n const path = url.pathname\n\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\")\n\n if (path === \"/api/usage\") {\n const from = url.searchParams.get(\"from\") || \"\"\n const to = url.searchParams.get(\"to\") || \"\"\n const data = loadUsageRange(tracker, from, to)\n res.writeHead(200, { \"Content-Type\": \"application/json\" })\n res.end(JSON.stringify(data))\n return\n }\n\n if (path === \"/api/usage.csv\") {\n const from = url.searchParams.get(\"from\") || \"\"\n const to = url.searchParams.get(\"to\") || \"\"\n const rows = loadUsageRange(tracker, from, to)\n const header = \"date,tasks,input,output,cache_read,cache_create,cost_usd,top_agent\"\n const body = rows.map((d) => {\n const top = Object.entries(d.agents).sort(([, a], [, b]) => b.cost - a.cost)[0]\n return [d.date, d.tasks, d.input, d.output, d.cacheRead, d.cacheCreate, d.cost.toFixed(6), top ? top[0] : \"\"].join(\",\")\n }).join(\"\\n\")\n res.writeHead(200, {\n \"Content-Type\": \"text/csv; charset=utf-8\",\n \"Content-Disposition\": `attachment; filename=\"agentx-usage-${Date.now()}.csv\"`,\n })\n res.end(header + \"\\n\" + body + \"\\n\")\n return\n }\n\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" })\n res.end(renderDashboard())\n })\n\n server.listen(port, () => {\n console.log(`\\n Usage dashboard: http://localhost:${port}\\n`)\n })\n}\n\n// --- Data loading ---\n\ninterface UsageDay {\n date: string\n tasks: number\n input: number\n output: number\n cacheRead: number\n cacheCreate: number\n cost: number\n agents: Record<string, { tasks: number; cost: number; input: number; output: number; cacheRead: number; cacheCreate: number; model?: string }>\n}\n\nfunction loadUsageRange(tracker: TokenTracker, from: string, to: string): UsageDay[] {\n const dir = tracker[\"dir\"] // access private dir for file listing\n const files: string[] = []\n\n try {\n for (const f of readdirSync(dir)) {\n if (!f.endsWith(\".json\")) continue\n const date = f.replace(\".json\", \"\")\n if (from && date < from) continue\n if (to && date > to) continue\n files.push(date)\n }\n } catch {\n return []\n }\n\n files.sort()\n\n return files.map((date) => {\n const usage = tracker.getDate(date)\n if (!usage) return null\n\n let tasks = 0, input = 0, output = 0, cacheRead = 0, cacheCreate = 0, cost = 0\n const agents: UsageDay[\"agents\"] = {}\n\n for (const [id, agent] of Object.entries(usage.agents)) {\n const agentCost = TokenTracker.calculateCost(agent)\n // Token displays sum tier1 + tier2 so operators see the REAL volume\n // they paid for. Tier2 tokens (from requests >200K input) are billed\n // at 1.5×, but they're still tokens processed — hiding them made\n // low-display/high-cost days look inconsistent on the dashboard.\n const aInput = (agent.inputTokens || 0) + (agent.tier2InputTokens || 0)\n const aOutput = (agent.outputTokens || 0) + (agent.tier2OutputTokens || 0)\n const aCacheRead = (agent.cacheReadTokens || 0) + (agent.tier2CacheReadTokens || 0)\n const aCacheCreate = (agent.cacheCreateTokens || 0) + (agent.tier2CacheCreateTokens || 0)\n tasks += agent.tasks\n input += aInput\n output += aOutput\n cacheRead += aCacheRead\n cacheCreate += aCacheCreate\n cost += agentCost\n agents[id] = {\n tasks: agent.tasks,\n cost: agentCost,\n input: aInput,\n output: aOutput,\n cacheRead: aCacheRead,\n cacheCreate: aCacheCreate,\n model: agent.model,\n }\n }\n\n return { date, tasks, input, output, cacheRead, cacheCreate, cost, agents }\n }).filter((d): d is UsageDay => d !== null && d.tasks > 0)\n}\n\n// --- HTML rendering ---\n\nfunction renderDashboard(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\" data-theme=\"dark\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Usage · AgentX</title>\n<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n<link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap\" rel=\"stylesheet\">\n<style>${CSS}</style>\n</head>\n<body>\n\n<header class=\"topbar\">\n <div class=\"brand\">\n <div class=\"brand-mark\">§</div>\n <div class=\"brand-path\"><b>agentx</b><span class=\"slash\">/</span><b>observability</b><span class=\"slash\">/</span>usage</div>\n </div>\n <div class=\"env-badge\" id=\"envBadge\">local</div>\n <div class=\"topbar-right\">\n <a class=\"backlink\" href=\"/\" id=\"backToMain\" title=\"Back to dashboard\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M19 12H5M12 19l-7-7 7-7\"/></svg>\n <span>Dashboard</span>\n </a>\n <div class=\"theme-switch\" role=\"tablist\" aria-label=\"Theme\">\n <button data-t=\"dark\" class=\"active\">Dark</button>\n <button data-t=\"midnight\">Midnight</button>\n </div>\n </div>\n</header>\n\n<div class=\"page\">\n <div class=\"page-header\">\n <div class=\"page-title\">\n <h1>Token usage &amp; cost</h1>\n <p><span class=\"live-dot\"></span>Live telemetry across all agents. Last ingest <span id=\"lastIngest\" class=\"mono\">—</span>.</p>\n </div>\n <div class=\"controls\">\n <div class=\"segmented\" id=\"rangeSeg\">\n <button data-range=\"7\">7d</button>\n <button data-range=\"14\">14d</button>\n <button data-range=\"30\" class=\"active\">30d</button>\n <button data-range=\"90\">90d</button>\n <button data-range=\"0\">All</button>\n </div>\n <div class=\"date-picker\" title=\"Range\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\"/><path d=\"M16 2v4M8 2v4M3 10h18\"/></svg>\n <span id=\"rangeLabel\">—</span>\n </div>\n <a class=\"btn-ghost\" id=\"exportBtn\" href=\"#\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/><polyline points=\"7 10 12 15 17 10\"/><line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\"/></svg>\n Export CSV\n </a>\n </div>\n </div>\n\n <div class=\"kpi-row\" id=\"kpis\"></div>\n\n <div class=\"hero-grid\">\n <div class=\"card\">\n <div class=\"card-head\">\n <div>\n <div class=\"card-title\">Cost over time</div>\n <div class=\"card-sub\">Daily spend, stacked by token category</div>\n </div>\n <div class=\"card-meta\">\n <div class=\"legend\">\n <span class=\"legend-item\"><span class=\"legend-swatch\" style=\"background:var(--input-c)\"></span>Input</span>\n <span class=\"legend-item\"><span class=\"legend-swatch\" style=\"background:var(--output-c)\"></span>Output</span>\n <span class=\"legend-item\"><span class=\"legend-swatch\" style=\"background:var(--cache-r-c)\"></span>Cache read</span>\n <span class=\"legend-item\"><span class=\"legend-swatch\" style=\"background:var(--cache-w-c)\"></span>Cache write</span>\n </div>\n </div>\n </div>\n <div class=\"card-body hero-chart-wrap\">\n <div class=\"hero-overlay\">\n <div class=\"hero-stat\"><div class=\"v mono\" id=\"heroTotalCost\">$0</div><div class=\"l\">Total · range</div></div>\n <div class=\"hero-stat\"><div class=\"v mono\" id=\"heroPeak\">$0</div><div class=\"l\">Peak day</div></div>\n <div class=\"hero-stat\"><div class=\"v mono\" id=\"heroAvg\">$0</div><div class=\"l\">Daily avg</div></div>\n </div>\n <canvas id=\"heroChart\" class=\"hero-canvas\"></canvas>\n </div>\n </div>\n\n <div class=\"card dist-card\">\n <div class=\"card-head\" style=\"padding:0 0 10px\">\n <div>\n <div class=\"card-title\">Token mix</div>\n <div class=\"card-sub\">Volume by category · range</div>\n </div>\n </div>\n <div id=\"distList\"></div>\n <div class=\"saved-chip\">\n <div class=\"l\">Estimated savings from cache</div>\n <div class=\"v mono\" id=\"savedChip\">$0</div>\n </div>\n </div>\n </div>\n\n <div class=\"two-col\">\n <div class=\"card\">\n <div class=\"card-head\">\n <div>\n <div class=\"card-title\">Top agents by spend</div>\n <div class=\"card-sub\">Ranked across the selected range</div>\n </div>\n </div>\n <div class=\"agent-list\" id=\"agentList\"></div>\n </div>\n\n <div class=\"card\">\n <div class=\"card-head\">\n <div>\n <div class=\"card-title\">Cache efficiency</div>\n <div class=\"card-sub\">Hit rate and avoided input cost</div>\n </div>\n <span class=\"env-badge\" id=\"cacheHealth\" style=\"border-color:color-mix(in oklch,var(--accent) 40%,var(--border))\">\n <span style=\"color:var(--accent);font-weight:600\">—</span>\n </span>\n </div>\n <div class=\"card-body\">\n <div class=\"gauge\">\n <div class=\"gauge-dial\">\n <svg width=\"140\" height=\"140\" viewBox=\"0 0 140 140\">\n <circle cx=\"70\" cy=\"70\" r=\"58\" stroke=\"var(--surface-2)\" stroke-width=\"12\" fill=\"none\"/>\n <circle id=\"gaugeArc\" cx=\"70\" cy=\"70\" r=\"58\" stroke=\"var(--accent)\" stroke-width=\"12\" fill=\"none\" stroke-linecap=\"round\" stroke-dasharray=\"364\" stroke-dashoffset=\"364\" transform=\"rotate(-90 70 70)\"/>\n </svg>\n <div class=\"gauge-readout\">\n <div class=\"num mono\" id=\"gaugeNum\">0%</div>\n <div class=\"lbl\">Hit rate</div>\n </div>\n </div>\n <div class=\"cache-stats\">\n <div class=\"cache-stat\"><div class=\"lbl\">Cache reads</div><div class=\"val mono\" id=\"cacheReads\">0 <span class=\"sub\">tok</span></div></div>\n <div class=\"cache-stat\"><div class=\"lbl\">Cache writes</div><div class=\"val mono\" id=\"cacheWrites\">0 <span class=\"sub\">tok</span></div></div>\n <div class=\"cache-stat\"><div class=\"lbl\">Reuse multiplier</div><div class=\"val mono\" id=\"reuseMult\">0×</div></div>\n <div class=\"cache-stat\"><div class=\"lbl\">Avoided input</div><div class=\"val mono\" id=\"avoidedInput\">0</div></div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"card table-card\">\n <div class=\"table-head\">\n <div>\n <div class=\"card-title\">Daily detail</div>\n <div class=\"card-sub\">Per-day breakdown with agent attribution</div>\n </div>\n <div class=\"table-filters\">\n <button class=\"filter-chip active\" data-filter=\"all\">All days</button>\n <button class=\"filter-chip\" data-filter=\"weekdays\">Weekdays</button>\n <button class=\"filter-chip\" data-filter=\"over10\">&gt; $10</button>\n </div>\n </div>\n <div class=\"table-scroll\">\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Date</th>\n <th class=\"num\">Tasks</th>\n <th>Mix</th>\n <th class=\"num\">Input</th>\n <th class=\"num\">Output</th>\n <th class=\"num\">Cache R</th>\n <th class=\"num\">Cache W</th>\n <th class=\"num\">Cost</th>\n <th>Top agents</th>\n </tr>\n </thead>\n <tbody id=\"dailyTbody\"></tbody>\n </table>\n </div>\n </div>\n</div>\n\n<script>${JS}</script>\n</body>\n</html>`\n}\n\n// --- Embedded CSS (mockup: cool-neutral dark + electric-lime accent) ---\n\nconst CSS = `\n:root {\n --bg: oklch(0.16 0.01 250);\n --bg-elev: oklch(0.19 0.012 250);\n --surface: oklch(0.21 0.013 250);\n --surface-2: oklch(0.24 0.014 250);\n --border: oklch(0.28 0.015 250);\n --border-soft: oklch(0.24 0.012 250);\n --text: oklch(0.96 0.005 250);\n --text-2: oklch(0.78 0.01 250);\n --text-3: oklch(0.58 0.012 250);\n --text-4: oklch(0.42 0.012 250);\n --accent: oklch(0.86 0.19 128);\n --accent-dim: oklch(0.86 0.19 128 / 0.14);\n --accent-ink: oklch(0.22 0.05 128);\n --input-c: oklch(0.75 0.12 240);\n --output-c: oklch(0.78 0.13 180);\n --cache-r-c: oklch(0.72 0.10 290);\n --cache-w-c: oklch(0.78 0.13 60);\n --pos: oklch(0.82 0.16 150);\n --neg: oklch(0.72 0.19 25);\n --radius: 10px;\n --radius-sm: 6px;\n --radius-lg: 14px;\n --shadow-sm: 0 1px 0 oklch(1 0 0 / 0.03) inset, 0 1px 2px oklch(0 0 0 / 0.3);\n}\nhtml[data-theme=\"midnight\"] { --bg: oklch(0.13 0.015 265); }\n* { margin: 0; padding: 0; box-sizing: border-box; }\nhtml, body { background: var(--bg); }\nbody { color: var(--text); font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; font-size: 13px; line-height: 1.4; -webkit-font-smoothing: antialiased; min-height: 100vh; }\n.mono { font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums; }\nbutton, a { font-family: inherit; cursor: pointer; }\na { color: inherit; text-decoration: none; }\n\n/* TOP BAR */\n.topbar { position: sticky; top: 0; z-index: 10; display: flex; align-items: center; gap: 20px; padding: 12px 24px; background: color-mix(in oklch, var(--bg) 88%, transparent); backdrop-filter: blur(12px); border-bottom: 1px solid var(--border-soft); }\n.brand { display: flex; align-items: center; gap: 10px; font-weight: 600; font-size: 13px; letter-spacing: -0.01em; }\n.brand-mark { width: 22px; height: 22px; border-radius: 6px; background: linear-gradient(135deg, var(--accent) 0%, oklch(0.78 0.14 160) 100%); display: grid; place-items: center; color: var(--accent-ink); font-weight: 800; font-size: 11px; box-shadow: 0 0 0 1px oklch(1 0 0 / 0.08), 0 2px 8px oklch(0.86 0.19 128 / 0.25); }\n.brand-path { color: var(--text-3); font-weight: 400; }\n.brand-path b { color: var(--text-2); font-weight: 500; }\n.slash { color: var(--text-4); margin: 0 4px; }\n.env-badge { display: inline-flex; align-items: center; gap: 6px; padding: 3px 8px 3px 6px; border: 1px solid var(--border); border-radius: 999px; font-size: 11px; color: var(--text-2); background: var(--surface); }\n.env-badge::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--pos); box-shadow: 0 0 0 2px oklch(0.82 0.16 150 / 0.2); }\n.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }\n.backlink { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px; font-size: 12px; color: var(--text-2); border: 1px solid var(--border); border-radius: 7px; transition: all .12s; }\n.backlink:hover { color: var(--text); border-color: var(--text-4); background: var(--surface); }\n.backlink svg { width: 13px; height: 13px; }\n.theme-switch { display: inline-flex; padding: 2px; background: var(--surface); border: 1px solid var(--border); border-radius: 7px; }\n.theme-switch button { background: transparent; border: 0; color: var(--text-3); padding: 3px 10px; font-size: 11px; font-weight: 500; border-radius: 5px; letter-spacing: 0.01em; transition: all .12s; }\n.theme-switch button.active { background: var(--surface-2); color: var(--text); }\n\n/* PAGE */\n.page { max-width: 1440px; margin: 0 auto; padding: 24px 24px 80px; }\n.page-header { display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; flex-wrap: wrap; margin-bottom: 24px; }\n.page-title h1 { font-size: 22px; font-weight: 600; letter-spacing: -0.015em; margin-bottom: 6px; }\n.page-title p { font-size: 13px; color: var(--text-3); max-width: 540px; }\n.page-title .live-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); margin-right: 6px; vertical-align: middle; animation: pulse 2s ease-in-out infinite; }\n@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }\n\n.controls { display: flex; gap: 8px; align-items: center; }\n.segmented { display: inline-flex; padding: 2px; background: var(--surface); border: 1px solid var(--border); border-radius: 8px; }\n.segmented button { background: transparent; border: 0; color: var(--text-3); padding: 5px 10px; font-size: 12px; font-weight: 500; border-radius: 6px; transition: all .12s; }\n.segmented button.active { background: var(--surface-2); color: var(--text); box-shadow: 0 1px 0 oklch(1 0 0 / 0.04) inset, 0 1px 2px oklch(0 0 0 / 0.2); }\n.segmented button:hover:not(.active) { color: var(--text); }\n.date-picker { display: inline-flex; align-items: center; gap: 8px; background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 5px 10px; font-size: 12px; color: var(--text-2); }\n.date-picker svg { width: 13px; height: 13px; color: var(--text-3); }\n.btn-ghost { background: var(--surface); color: var(--text-2); border: 1px solid var(--border); padding: 5px 12px; font-size: 12px; font-weight: 500; border-radius: 8px; display: inline-flex; align-items: center; gap: 6px; }\n.btn-ghost:hover { border-color: var(--text-4); color: var(--text); }\n.btn-ghost svg { width: 13px; height: 13px; }\n\n/* KPI ROW */\n.kpi-row { display: grid; grid-template-columns: repeat(6, 1fr); gap: 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; margin-bottom: 20px; box-shadow: var(--shadow-sm); }\n.kpi { padding: 18px 20px; border-right: 1px solid var(--border-soft); display: flex; flex-direction: column; gap: 8px; position: relative; min-width: 0; }\n.kpi:last-child { border-right: 0; }\n.kpi-label { font-size: 11px; color: var(--text-3); text-transform: uppercase; letter-spacing: 0.06em; font-weight: 500; }\n.kpi-value { font-size: 26px; font-weight: 600; letter-spacing: -0.02em; line-height: 1.1; display: flex; align-items: baseline; gap: 4px; }\n.kpi-value .unit { font-size: 13px; color: var(--text-3); font-weight: 500; }\n.kpi-accent .kpi-value { color: var(--accent); }\n.kpi-delta { font-size: 11px; display: inline-flex; align-items: center; gap: 3px; color: var(--text-3); font-weight: 500; }\n.kpi-delta.up { color: var(--neg); }\n.kpi-delta.down { color: var(--pos); }\n.kpi-delta svg { width: 10px; height: 10px; }\n.kpi-spark { height: 22px; margin-top: auto; display: flex; align-items: flex-end; gap: 1.5px; }\n.kpi-spark .bar { flex: 1; background: var(--text-4); border-radius: 1px; min-height: 2px; opacity: 0.5; }\n.kpi-accent .kpi-spark .bar { background: var(--accent); opacity: 0.7; }\n.kpi-spark .bar:last-child { opacity: 1; background: var(--accent); }\n\n/* CARD */\n.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); display: flex; flex-direction: column; min-width: 0; }\n.card-head { padding: 14px 20px 10px; display: flex; align-items: center; justify-content: space-between; gap: 12px; }\n.card-title { font-size: 13px; font-weight: 600; letter-spacing: -0.005em; }\n.card-sub { font-size: 12px; color: var(--text-3); margin-top: 2px; }\n.card-head .card-meta { display: flex; align-items: center; gap: 10px; }\n.card-body { padding: 4px 20px 18px; flex: 1; min-width: 0; }\n.legend { display: flex; gap: 12px; flex-wrap: wrap; }\n.legend-item { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; color: var(--text-2); font-weight: 500; }\n.legend-swatch { width: 8px; height: 8px; border-radius: 2px; }\n\n/* HERO GRID */\n.hero-grid { display: grid; grid-template-columns: 1fr 320px; gap: 16px; margin-bottom: 16px; }\n@media (max-width: 1200px) { .hero-grid { grid-template-columns: 1fr; } }\n.hero-chart-wrap { position: relative; }\n.hero-canvas { width: 100%; height: 300px; display: block; }\n.hero-overlay { position: absolute; top: 14px; left: 20px; display: flex; gap: 22px; pointer-events: none; }\n.hero-stat .v { font-size: 22px; font-weight: 600; letter-spacing: -0.02em; color: var(--text); }\n.hero-stat .l { font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-3); font-weight: 500; margin-top: 2px; }\n\n/* DIST */\n.dist-card { padding: 14px 18px 18px; }\n.dist-row { display: grid; grid-template-columns: 80px 1fr 92px; align-items: center; gap: 10px; padding: 9px 0; border-bottom: 1px dashed var(--border-soft); }\n.dist-row:last-child { border-bottom: 0; }\n.dist-label { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--text-2); font-weight: 500; }\n.dist-dot { width: 8px; height: 8px; border-radius: 2px; }\n.dist-bar { position: relative; height: 6px; background: var(--surface-2); border-radius: 3px; overflow: hidden; }\n.dist-bar-fill { height: 100%; border-radius: 3px; transition: width .6s cubic-bezier(0.22,1,0.36,1); }\n.dist-val { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--text-2); text-align: right; font-weight: 500; }\n.saved-chip { margin-top: 16px; padding: 10px 12px; background: var(--accent-dim); border: 1px solid color-mix(in oklch, var(--accent) 35%, transparent); border-radius: 8px; display: flex; align-items: center; justify-content: space-between; }\n.saved-chip .l { font-size: 11px; color: var(--text-2); }\n.saved-chip .v { font-size: 14px; font-weight: 600; color: var(--accent); }\n\n/* TWO COL */\n.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; }\n@media (max-width: 1100px) { .two-col { grid-template-columns: 1fr; } }\n\n/* AGENT LEADERBOARD */\n.agent-list { display: flex; flex-direction: column; }\n.agent-row { display: grid; grid-template-columns: 22px 1fr 60px 90px 90px; align-items: center; gap: 12px; padding: 10px 20px; border-top: 1px solid var(--border-soft); transition: background .12s; }\n.agent-row:hover { background: var(--bg-elev); }\n.agent-rank { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--text-4); font-weight: 500; }\n.agent-name-wrap { display: flex; align-items: center; gap: 10px; min-width: 0; }\n.agent-ico { width: 24px; height: 24px; border-radius: 6px; display: grid; place-items: center; font-size: 11px; font-weight: 700; flex-shrink: 0; }\n.agent-name { font-size: 12.5px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.agent-model { font-size: 10.5px; color: var(--text-3); margin-top: 1px; }\n.agent-tasks { font-family: 'JetBrains Mono', monospace; font-size: 11.5px; color: var(--text-2); text-align: right; }\n.agent-bar-wrap { position: relative; height: 5px; background: var(--surface-2); border-radius: 2px; overflow: hidden; }\n.agent-bar-fill { height: 100%; border-radius: 2px; transition: width .7s cubic-bezier(0.22,1,0.36,1); }\n.agent-cost { font-family: 'JetBrains Mono', monospace; font-size: 12.5px; font-weight: 600; text-align: right; color: var(--text); }\n.agent-cost .sub { display: block; font-size: 10px; color: var(--text-3); font-weight: 400; margin-top: 1px; }\n\n/* GAUGE */\n.gauge { display: grid; grid-template-columns: 140px 1fr; gap: 24px; align-items: center; padding: 6px 0 4px; }\n.gauge-dial { position: relative; width: 140px; height: 140px; }\n.gauge-readout { position: absolute; inset: 0; display: grid; place-items: center; text-align: center; }\n.gauge-readout .num { font-size: 26px; font-weight: 600; letter-spacing: -0.02em; }\n.gauge-readout .lbl { font-size: 10px; color: var(--text-3); letter-spacing: 0.06em; text-transform: uppercase; margin-top: 2px; }\n.cache-stats { display: flex; flex-direction: column; gap: 10px; }\n.cache-stat { display: flex; justify-content: space-between; align-items: baseline; border-bottom: 1px dashed var(--border-soft); padding-bottom: 8px; }\n.cache-stat:last-child { border-bottom: 0; }\n.cache-stat .lbl { font-size: 11px; color: var(--text-3); text-transform: uppercase; letter-spacing: 0.05em; }\n.cache-stat .val { font-size: 14px; font-weight: 600; }\n.cache-stat .val .sub { font-size: 10px; color: var(--text-3); margin-left: 4px; font-weight: 400; }\n\n/* TABLE */\n.table-card { margin-top: 16px; }\n.table-head { display: flex; align-items: center; justify-content: space-between; padding: 14px 20px 12px; }\n.table-filters { display: flex; gap: 6px; }\n.filter-chip { background: transparent; border: 1px solid var(--border); color: var(--text-3); font-size: 11px; padding: 3px 10px; border-radius: 999px; transition: all .12s; }\n.filter-chip:hover, .filter-chip.active { color: var(--text); background: var(--surface-2); border-color: var(--text-4); }\n.table-scroll { overflow-x: auto; }\n.data-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }\n.data-table thead th { text-align: left; padding: 8px 20px; background: var(--bg-elev); border-top: 1px solid var(--border-soft); border-bottom: 1px solid var(--border-soft); font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-3); font-weight: 500; white-space: nowrap; }\n.data-table thead th.num, .data-table tbody td.num { text-align: right; font-family: 'JetBrains Mono', monospace; }\n.data-table tbody td { padding: 10px 20px; border-bottom: 1px solid var(--border-soft); color: var(--text-2); vertical-align: middle; white-space: nowrap; }\n.data-table tbody tr:hover td { background: var(--bg-elev); color: var(--text); }\n.data-table tbody tr:last-child td { border-bottom: 0; }\n.row-date { color: var(--text); font-weight: 500; }\n.row-date .day { color: var(--text-3); font-weight: 400; margin-left: 6px; font-size: 11px; }\n.row-cost { color: var(--accent); font-weight: 600; }\n.minibar { display: inline-flex; gap: 1px; height: 12px; width: 80px; align-items: flex-end; }\n.minibar span { flex: 1; border-radius: 1px; min-height: 1px; display: block; height: 100%; }\n.agent-chips { display: inline-flex; gap: 4px; flex-wrap: wrap; }\n.agent-chip { display: inline-flex; align-items: center; gap: 5px; padding: 2px 7px 2px 5px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 999px; font-size: 10.5px; color: var(--text-2); }\n.agent-chip .d { width: 6px; height: 6px; border-radius: 50%; }\n.empty { padding: 40px 20px; text-align: center; color: var(--text-3); font-size: 13px; }\n\n@media (max-width: 1024px) {\n .kpi-row { grid-template-columns: repeat(3, 1fr); }\n .kpi:nth-child(3) { border-right: 0; }\n .kpi { border-bottom: 1px solid var(--border-soft); }\n .kpi:nth-last-child(-n+3) { border-bottom: 0; }\n}\n@media (max-width: 680px) {\n .kpi-row { grid-template-columns: repeat(2, 1fr); }\n .kpi { border-right: 1px solid var(--border-soft); border-bottom: 1px solid var(--border-soft); }\n .kpi:nth-child(2n) { border-right: 0; }\n}\n`\n\n// --- Embedded JavaScript ---\n\nconst JS = `\n/* ---- state ---- */\nlet data = [];\nlet currentRange = 30;\nlet tableFilter = 'all';\n\n/* ---- formatters ---- */\nfunction fmtTok(n) {\n if (n >= 1e9) return (n/1e9).toFixed(2) + 'B';\n if (n >= 1e6) return (n/1e6).toFixed(2) + 'M';\n if (n >= 1e3) return (n/1e3).toFixed(1) + 'K';\n return String(Math.round(n));\n}\nfunction fmtCost(n, digits) {\n if (digits === undefined) digits = 2;\n if (!isFinite(n)) n = 0;\n if (n >= 10000) return '$' + (n/1000).toFixed(1) + 'K';\n if (n === 0) return '$0';\n if (n < 0.01) return '$' + n.toFixed(4);\n return '$' + n.toFixed(digits);\n}\nfunction fmtDate(iso) {\n const d = new Date(iso + 'T00:00:00');\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n}\nfunction fmtDay(iso) {\n const d = new Date(iso + 'T00:00:00');\n return d.toLocaleDateString(undefined, { weekday: 'short' });\n}\nfunction isWeekday(iso) {\n const d = new Date(iso + 'T00:00:00');\n const day = d.getDay();\n return day !== 0 && day !== 6;\n}\n\n/* deterministic color per agent id — hashed hue around the cool palette */\nconst AGENT_COLOR_CACHE = {};\nfunction agentColor(id) {\n if (AGENT_COLOR_CACHE[id]) return AGENT_COLOR_CACHE[id];\n let h = 0;\n for (let i = 0; i < id.length; i++) h = ((h << 5) - h + id.charCodeAt(i)) | 0;\n const hue = Math.abs(h) % 360;\n const c = 'oklch(0.74 0.13 ' + hue + ')';\n AGENT_COLOR_CACHE[id] = c;\n return c;\n}\n\nfunction getCss(name) {\n return getComputedStyle(document.documentElement).getPropertyValue(name).trim();\n}\n\n/* ---- theme ---- */\n(function initTheme() {\n try {\n const saved = localStorage.getItem('ax-usage-theme');\n if (saved) document.documentElement.setAttribute('data-theme', saved);\n } catch (e) {}\n})();\ndocument.querySelectorAll('.theme-switch button').forEach(b => {\n b.addEventListener('click', () => {\n const t = b.dataset.t;\n document.documentElement.setAttribute('data-theme', t);\n try { localStorage.setItem('ax-usage-theme', t); } catch (e) {}\n document.querySelectorAll('.theme-switch button').forEach(x => x.classList.toggle('active', x === b));\n });\n const cur = document.documentElement.getAttribute('data-theme') || 'dark';\n b.classList.toggle('active', b.dataset.t === cur);\n});\n\n/* back-to-dashboard: link to the same host at the main-dashboard port */\n(function wireBack() {\n const a = document.getElementById('backToMain');\n if (a) a.href = window.location.protocol + '//' + window.location.hostname + ':4202/';\n})();\n\n/* ---- fetch ---- */\nfunction rangeToParams() {\n const params = new URLSearchParams();\n if (currentRange > 0) {\n const to = new Date();\n const from = new Date(Date.now() - currentRange * 86400000);\n params.set('from', from.toISOString().slice(0,10));\n params.set('to', to.toISOString().slice(0,10));\n }\n return params;\n}\nasync function load() {\n const params = rangeToParams();\n try {\n const res = await fetch('/api/usage?' + params);\n data = await res.json();\n } catch (e) { data = []; }\n render();\n}\n\n/* ---- range segmented + export ---- */\ndocument.querySelectorAll('#rangeSeg button').forEach(b => {\n b.addEventListener('click', () => {\n document.querySelectorAll('#rangeSeg button').forEach(x => x.classList.remove('active'));\n b.classList.add('active');\n currentRange = parseInt(b.dataset.range, 10);\n load();\n });\n});\ndocument.querySelectorAll('.filter-chip').forEach(c => {\n c.addEventListener('click', () => {\n document.querySelectorAll('.filter-chip').forEach(x => x.classList.remove('active'));\n c.classList.add('active');\n tableFilter = c.dataset.filter;\n renderTable();\n });\n});\ndocument.getElementById('exportBtn').addEventListener('click', (e) => {\n e.preventDefault();\n const params = rangeToParams();\n window.location.href = '/api/usage.csv?' + params;\n});\n\n/* ---- KPIs ---- */\nfunction renderKPIs() {\n const totalCost = data.reduce((s,d) => s + d.cost, 0);\n const totalTasks = data.reduce((s,d) => s + d.tasks, 0);\n const totalInput = data.reduce((s,d) => s + d.input, 0);\n const totalOutput = data.reduce((s,d) => s + d.output, 0);\n const totalCacheR = data.reduce((s,d) => s + d.cacheRead, 0);\n const totalCacheW = data.reduce((s,d) => s + d.cacheCreate, 0);\n const avgDaily = data.length ? totalCost / data.length : 0;\n const hitRate = (totalCacheR + totalInput) > 0 ? (totalCacheR / (totalCacheR + totalInput) * 100) : 0;\n const costPerTask = totalTasks > 0 ? totalCost / totalTasks : 0;\n\n const L = data.length;\n const last7 = data.slice(Math.max(0, L-7)).reduce((s,d)=>s+d.cost,0);\n const prev7 = data.slice(Math.max(0, L-14), Math.max(0, L-7)).reduce((s,d)=>s+d.cost,0);\n const wow = prev7 > 0 ? ((last7 - prev7) / prev7 * 100) : 0;\n const taskLast = data.slice(Math.max(0, L-7)).reduce((s,d)=>s+d.tasks,0);\n const taskPrev = data.slice(Math.max(0, L-14), Math.max(0, L-7)).reduce((s,d)=>s+d.tasks,0);\n const taskDelta = taskPrev > 0 ? ((taskLast-taskPrev)/taskPrev*100) : 0;\n\n const kpis = [\n { label: 'Total spend', value: fmtCost(totalCost), delta: wow, deltaLabel: 'vs prev 7d', sparks: data.map(d=>d.cost), accent: true },\n { label: 'Daily average', value: fmtCost(avgDaily), sub: '/ day', sparks: data.map(d=>d.cost) },\n { label: 'Tasks run', value: totalTasks.toLocaleString(), delta: taskDelta, deltaLabel: 'vs prev 7d', sparks: data.map(d=>d.tasks) },\n { label: 'Tokens processed', value: fmtTok(totalInput + totalOutput + totalCacheR + totalCacheW), sub: 'tok', sparks: data.map(d => d.input + d.output + d.cacheRead + d.cacheCreate) },\n { label: 'Cache hit rate', value: hitRate.toFixed(0) + '%', sparks: data.map(d => d.cacheRead / Math.max(1, d.cacheRead + d.input) * 100) },\n { label: 'Cost / task', value: fmtCost(costPerTask, 3), sparks: data.map(d => d.cost / Math.max(1, d.tasks)) },\n ];\n\n document.getElementById('kpis').innerHTML = kpis.map(k => {\n const max = Math.max.apply(null, k.sparks.concat([0.0001]));\n const bars = k.sparks.map(v => '<div class=\"bar\" style=\"height:' + Math.max(2, (v/max)*100) + '%\"></div>').join('');\n let deltaHtml = '';\n if (k.delta !== undefined) {\n const up = k.delta > 0;\n const cls = up ? 'up' : 'down';\n const arrow = up\n ? '<svg viewBox=\"0 0 10 10\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\"><path d=\"M2 7l3-3 3 3M5 4v5\"/></svg>'\n : '<svg viewBox=\"0 0 10 10\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\"><path d=\"M2 3l3 3 3-3M5 6V1\"/></svg>';\n deltaHtml = '<div class=\"kpi-delta ' + cls + '\">' + arrow + Math.abs(k.delta).toFixed(1) + '% ' + k.deltaLabel + '</div>';\n }\n const sub = k.sub ? '<span class=\"unit\">' + k.sub + '</span>' : '';\n return '<div class=\"kpi ' + (k.accent ? 'kpi-accent' : '') + '\">' +\n '<div class=\"kpi-label\">' + k.label + '</div>' +\n '<div class=\"kpi-value mono\">' + k.value + sub + '</div>' +\n deltaHtml +\n '<div class=\"kpi-spark\">' + bars + '</div>' +\n '</div>';\n }).join('');\n}\n\n/* ---- Hero stacked bar chart ---- */\nfunction setupCanvas(id, hOverride) {\n const canvas = document.getElementById(id);\n const dpr = window.devicePixelRatio || 1;\n const wrap = canvas.parentElement;\n const rect = wrap.getBoundingClientRect();\n const w = rect.width;\n const h = hOverride || canvas.clientHeight || 260;\n canvas.width = Math.max(1, Math.round(w * dpr));\n canvas.height = Math.max(1, Math.round(h * dpr));\n canvas.style.width = w + 'px';\n canvas.style.height = h + 'px';\n const ctx = canvas.getContext('2d');\n ctx.scale(dpr, dpr);\n ctx.clearRect(0, 0, w, h);\n return { ctx, w, h };\n}\nfunction roundRect(ctx, x, y, w, h, r) {\n if (w <= 0 || h <= 0) return;\n r = Math.min(r, w/2, h/2);\n ctx.beginPath();\n ctx.moveTo(x+r, y); ctx.lineTo(x+w-r, y);\n ctx.quadraticCurveTo(x+w, y, x+w, y+r);\n ctx.lineTo(x+w, y+h); ctx.lineTo(x, y+h);\n ctx.lineTo(x, y+r);\n ctx.quadraticCurveTo(x, y, x+r, y);\n ctx.closePath();\n}\nfunction renderHero() {\n const { ctx, w, h } = setupCanvas('heroChart', 300);\n if (!data.length) {\n ctx.fillStyle = getCss('--text-3');\n ctx.font = '12px Inter';\n ctx.textAlign = 'center';\n ctx.fillText('No usage data in this range', w/2, h/2);\n document.getElementById('heroTotalCost').textContent = '$0';\n document.getElementById('heroPeak').textContent = '$0';\n document.getElementById('heroAvg').textContent = '$0';\n return;\n }\n const pad = { t: 70, r: 16, b: 28, l: 48 };\n const cw = w - pad.l - pad.r;\n const ch = h - pad.t - pad.b;\n\n const series = data.map(d => {\n const tot = d.input + d.output + d.cacheRead + d.cacheCreate;\n if (!tot) return { input:0, output:0, cacheR:0, cacheW:0, total: d.cost };\n return {\n input: d.cost * (d.input / tot),\n output: d.cost * (d.output / tot),\n cacheR: d.cost * (d.cacheRead / tot),\n cacheW: d.cost * (d.cacheCreate / tot),\n total: d.cost,\n };\n });\n const maxTot = Math.max.apply(null, series.map(s=>s.total).concat([0.001]));\n\n ctx.font = '10.5px JetBrains Mono, monospace';\n ctx.textAlign = 'right';\n ctx.textBaseline = 'middle';\n for (let i = 0; i <= 4; i++) {\n const v = (maxTot / 4) * i;\n const y = pad.t + ch - (i / 4) * ch;\n ctx.strokeStyle = getCss('--border-soft');\n ctx.lineWidth = 1;\n ctx.beginPath(); ctx.moveTo(pad.l, y + 0.5); ctx.lineTo(pad.l + cw, y + 0.5); ctx.stroke();\n ctx.fillStyle = getCss('--text-4');\n ctx.fillText(fmtCost(v, 0), pad.l - 8, y);\n }\n\n ctx.fillStyle = getCss('--text-3');\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n ctx.font = '10.5px Inter';\n const nLabels = Math.min(7, data.length);\n for (let i = 0; i < nLabels; i++) {\n const idx = Math.round((i / (nLabels - 1 || 1)) * (data.length - 1));\n const x = pad.l + (idx / Math.max(1, data.length - 1)) * cw;\n ctx.fillText(fmtDate(data[idx].date), x, pad.t + ch + 10);\n }\n\n const catOrder = [\n { k: 'input', color: getCss('--input-c') },\n { k: 'output', color: getCss('--output-c') },\n { k: 'cacheR', color: getCss('--cache-r-c') },\n { k: 'cacheW', color: getCss('--cache-w-c') },\n ];\n const barW = Math.max(2, (cw / data.length) * 0.7);\n const gap = cw / data.length;\n\n data.forEach((d, i) => {\n const s = series[i];\n const x = pad.l + i * gap + (gap - barW) / 2;\n let yOff = 0;\n catOrder.forEach((c, ci) => {\n const v = s[c.k];\n const barH = (v / maxTot) * ch;\n const y = pad.t + ch - yOff - barH;\n ctx.fillStyle = c.color;\n const radius = ci === catOrder.length - 1 ? 2 : 0;\n roundRect(ctx, x, y, barW, barH + 0.5, radius);\n ctx.fill();\n yOff += barH;\n });\n });\n\n const total = series.reduce((s, p) => s + p.total, 0);\n const peak = Math.max.apply(null, series.map(p => p.total));\n const avg = total / Math.max(1, series.length);\n document.getElementById('heroTotalCost').textContent = fmtCost(total);\n document.getElementById('heroPeak').textContent = fmtCost(peak);\n document.getElementById('heroAvg').textContent = fmtCost(avg);\n}\n\n/* ---- Distribution + savings chip ---- */\nfunction renderDistribution() {\n const tot = { input:0, output:0, cacheRead:0, cacheCreate:0 };\n data.forEach(d => { tot.input += d.input; tot.output += d.output; tot.cacheRead += d.cacheRead; tot.cacheCreate += d.cacheCreate; });\n const grand = tot.input + tot.output + tot.cacheRead + tot.cacheCreate;\n const items = [\n { lbl: 'Input', v: tot.input, c: 'var(--input-c)' },\n { lbl: 'Output', v: tot.output, c: 'var(--output-c)' },\n { lbl: 'Cache read', v: tot.cacheRead, c: 'var(--cache-r-c)' },\n { lbl: 'Cache write', v: tot.cacheCreate, c: 'var(--cache-w-c)' },\n ];\n const max = Math.max.apply(null, items.map(i => i.v).concat([1]));\n document.getElementById('distList').innerHTML = items.map(it => {\n const pct = grand > 0 ? (it.v / grand * 100) : 0;\n const barPct = (it.v / max) * 100;\n return '<div class=\"dist-row\">' +\n '<div class=\"dist-label\"><span class=\"dist-dot\" style=\"background:' + it.c + '\"></span>' + it.lbl + '</div>' +\n '<div class=\"dist-bar\"><div class=\"dist-bar-fill\" style=\"width:' + barPct + '%;background:' + it.c + '\"></div></div>' +\n '<div class=\"dist-val\">' + fmtTok(it.v) + ' · ' + pct.toFixed(0) + '%</div>' +\n '</div>';\n }).join('');\n // rough savings: cache-read tokens priced at ~10% of input. Matches mockup formula.\n const savedCost = (tot.cacheRead * 0.9) / 1e6 * 3;\n document.getElementById('savedChip').textContent = fmtCost(savedCost);\n}\n\n/* ---- Agent leaderboard ---- */\nfunction renderAgents() {\n const totals = {};\n data.forEach(d => {\n for (const id in d.agents) {\n const a = d.agents[id];\n if (!totals[id]) totals[id] = { cost:0, tasks:0, input:0, output:0, cacheR:0, cacheW:0, model: a.model || '' };\n totals[id].cost += a.cost; totals[id].tasks += a.tasks;\n totals[id].input += a.input; totals[id].output += a.output;\n totals[id].cacheR += a.cacheRead; totals[id].cacheW += a.cacheCreate;\n if (a.model) totals[id].model = a.model;\n }\n });\n const items = Object.keys(totals).map(id => [id, totals[id]]).sort((a,b) => b[1].cost - a[1].cost).slice(0, 12);\n const max = items[0] ? items[0][1].cost : 1;\n const container = document.getElementById('agentList');\n if (!items.length) { container.innerHTML = '<div class=\"empty\">No agent activity</div>'; return; }\n container.innerHTML = items.map((pair, i) => {\n const id = pair[0], a = pair[1];\n const c = agentColor(id);\n const initials = id.split('-').map(s => s[0]).join('').slice(0,2).toUpperCase();\n const iconBg = 'color-mix(in oklch, ' + c + ' 22%, var(--surface-2))';\n const barPct = (a.cost / max) * 100;\n return '<div class=\"agent-row\">' +\n '<div class=\"agent-rank\">' + String(i+1).padStart(2,'0') + '</div>' +\n '<div class=\"agent-name-wrap\">' +\n '<div class=\"agent-ico\" style=\"background:' + iconBg + ';color:' + c + '\">' + initials + '</div>' +\n '<div style=\"min-width:0\">' +\n '<div class=\"agent-name\">' + id + '</div>' +\n (a.model ? '<div class=\"agent-model\">' + a.model + '</div>' : '') +\n '</div>' +\n '</div>' +\n '<div class=\"agent-tasks\">' + a.tasks.toLocaleString() + '</div>' +\n '<div class=\"agent-bar-wrap\"><div class=\"agent-bar-fill\" style=\"width:' + barPct + '%;background:' + c + '\"></div></div>' +\n '<div class=\"agent-cost\">' + fmtCost(a.cost) + '<span class=\"sub\">' + fmtTok(a.input + a.output + a.cacheR + a.cacheW) + ' tok</span></div>' +\n '</div>';\n }).join('');\n}\n\n/* ---- Cache gauge ---- */\nfunction renderCache() {\n const tot = data.reduce((s,d) => ({ r: s.r + d.cacheRead, w: s.w + d.cacheCreate, i: s.i + d.input }), { r:0, w:0, i:0 });\n const hit = (tot.r + tot.i) > 0 ? tot.r / (tot.r + tot.i) * 100 : 0;\n const circ = 2 * Math.PI * 58;\n const offset = circ - (hit / 100) * circ;\n const arc = document.getElementById('gaugeArc');\n arc.style.strokeDasharray = circ.toFixed(1);\n arc.style.strokeDashoffset = circ.toFixed(1);\n requestAnimationFrame(() => {\n arc.style.transition = 'stroke-dashoffset 1s cubic-bezier(0.22,1,0.36,1)';\n arc.style.strokeDashoffset = offset.toFixed(1);\n });\n document.getElementById('gaugeNum').textContent = hit.toFixed(0) + '%';\n document.getElementById('cacheReads').innerHTML = fmtTok(tot.r) + ' <span class=\"sub\">tok</span>';\n document.getElementById('cacheWrites').innerHTML = fmtTok(tot.w) + ' <span class=\"sub\">tok</span>';\n const mult = tot.w > 0 ? (tot.r / tot.w) : 0;\n document.getElementById('reuseMult').textContent = mult.toFixed(1) + '×';\n document.getElementById('avoidedInput').textContent = fmtTok(tot.r);\n const healthLabel = hit >= 60 ? 'Healthy' : hit >= 30 ? 'Warming up' : 'Cold';\n document.getElementById('cacheHealth').innerHTML = '<span style=\"color:var(--accent);font-weight:600\">' + healthLabel + '</span>';\n}\n\n/* ---- Daily table ---- */\nfunction renderTable() {\n const tbody = document.getElementById('dailyTbody');\n let rows = data.slice().reverse();\n if (tableFilter === 'weekdays') rows = rows.filter(r => isWeekday(r.date));\n else if (tableFilter === 'over10') rows = rows.filter(r => r.cost > 10);\n if (!rows.length) { tbody.innerHTML = '<tr><td colspan=\"9\" class=\"empty\">No rows match this filter.</td></tr>'; return; }\n tbody.innerHTML = rows.map(d => {\n const tot = d.input + d.output + d.cacheRead + d.cacheCreate || 1;\n const mix = [\n { v: d.input, c: 'var(--input-c)' },\n { v: d.output, c: 'var(--output-c)' },\n { v: d.cacheRead, c: 'var(--cache-r-c)' },\n { v: d.cacheCreate, c: 'var(--cache-w-c)' },\n ];\n const mixHtml = mix.map(m => '<span style=\"flex:' + (m.v/tot) + ';background:' + m.c + '\"></span>').join('');\n const topAgents = Object.keys(d.agents).map(id => [id, d.agents[id]]).sort((a,b) => b[1].cost - a[1].cost).slice(0, 3);\n const chips = topAgents.map(pair => {\n const id = pair[0];\n return '<span class=\"agent-chip\"><span class=\"d\" style=\"background:' + agentColor(id) + '\"></span>' + id + '</span>';\n }).join('');\n return '<tr>' +\n '<td class=\"row-date\">' + fmtDate(d.date) + '<span class=\"day\">' + fmtDay(d.date) + '</span></td>' +\n '<td class=\"num\">' + d.tasks.toLocaleString() + '</td>' +\n '<td><div class=\"minibar\">' + mixHtml + '</div></td>' +\n '<td class=\"num\">' + fmtTok(d.input) + '</td>' +\n '<td class=\"num\">' + fmtTok(d.output) + '</td>' +\n '<td class=\"num\">' + fmtTok(d.cacheRead) + '</td>' +\n '<td class=\"num\">' + fmtTok(d.cacheCreate) + '</td>' +\n '<td class=\"num row-cost\">' + fmtCost(d.cost) + '</td>' +\n '<td>' + chips + '</td>' +\n '</tr>';\n }).join('');\n}\n\n/* ---- meta chrome ---- */\nfunction updateRangeLabel() {\n const el = document.getElementById('rangeLabel');\n const li = document.getElementById('lastIngest');\n const badge = document.getElementById('envBadge');\n if (badge) badge.textContent = window.location.hostname;\n if (!data.length) { el.textContent = 'No data'; if (li) li.textContent = '—'; return; }\n el.textContent = fmtDate(data[0].date) + ' – ' + fmtDate(data[data.length - 1].date);\n if (li) li.textContent = data[data.length - 1].date;\n}\n\n/* ---- main render ---- */\nfunction render() {\n updateRangeLabel();\n renderKPIs();\n renderHero();\n renderDistribution();\n renderAgents();\n renderCache();\n renderTable();\n}\n\nwindow.addEventListener('resize', () => { renderHero(); });\n\n/* initial */\nload();\n`\n\nexport default startUsageDashboard\n"],"mappings":"oEAAA,OAAS,gBAAAA,MAAoB,OAC7B,OAAS,eAAAC,MAAmB,KAKrB,SAASC,EAAoBC,EAAe,KAAY,CAC7D,IAAMC,EAAU,IAAIC,EAELC,EAAa,MAAOC,EAAKC,IAAQ,CAC9C,IAAMC,EAAM,IAAI,IAAIF,EAAI,KAAO,IAAK,oBAAoBJ,GAAM,EACxDO,EAAOD,EAAI,SAIjB,GAFAD,EAAI,UAAU,8BAA+B,GAAG,EAE5CE,IAAS,aAAc,CACzB,IAAMC,EAAOF,EAAI,aAAa,IAAI,MAAM,GAAK,GACvCG,EAAKH,EAAI,aAAa,IAAI,IAAI,GAAK,GACnCI,EAAOC,EAAeV,EAASO,EAAMC,CAAE,EAC7CJ,EAAI,UAAU,IAAK,CAAE,eAAgB,kBAAmB,CAAC,EACzDA,EAAI,IAAI,KAAK,UAAUK,CAAI,CAAC,EAC5B,OAGF,GAAIH,IAAS,iBAAkB,CAC7B,IAAMC,EAAOF,EAAI,aAAa,IAAI,MAAM,GAAK,GACvCG,EAAKH,EAAI,aAAa,IAAI,IAAI,GAAK,GACnCM,EAAOD,EAAeV,EAASO,EAAMC,CAAE,EACvCI,EAAS,qEACTC,EAAOF,EAAK,IAAKG,GAAM,CAC3B,IAAMC,EAAM,OAAO,QAAQD,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAEE,CAAC,EAAG,CAAC,CAAEC,CAAC,IAAMA,EAAE,KAAOD,EAAE,IAAI,EAAE,CAAC,EAC9E,MAAO,CAACF,EAAE,KAAMA,EAAE,MAAOA,EAAE,MAAOA,EAAE,OAAQA,EAAE,UAAWA,EAAE,YAAaA,EAAE,KAAK,QAAQ,CAAC,EAAGC,EAAMA,EAAI,CAAC,EAAI,EAAE,EAAE,KAAK,GAAG,CACxH,CAAC,EAAE,KAAK;AAAA,CAAI,EACZX,EAAI,UAAU,IAAK,CACjB,eAAgB,0BAChB,sBAAuB,sCAAsC,KAAK,IAAI,QACxE,CAAC,EACDA,EAAI,IAAIQ,EAAS;AAAA,EAAOC,EAAO;AAAA,CAAI,EACnC,OAGFT,EAAI,UAAU,IAAK,CAAE,eAAgB,0BAA2B,CAAC,EACjEA,EAAI,IAAIc,EAAgB,CAAC,CAC3B,CAAC,EAEM,OAAOnB,EAAM,IAAM,CACxB,QAAQ,IAAI;AAAA,sCAAyCA;AAAA,CAAQ,CAC/D,CAAC,CACH,CAeA,SAASW,EAAeV,EAAuBO,EAAcC,EAAwB,CACnF,IAAMW,EAAMnB,EAAQ,IACdoB,EAAkB,CAAC,EAEzB,GAAI,CACF,QAAWC,KAAKC,EAAYH,CAAG,EAAG,CAChC,GAAI,CAACE,EAAE,SAAS,OAAO,EAAG,SAC1B,IAAME,EAAOF,EAAE,QAAQ,QAAS,EAAE,EAC9Bd,GAAQgB,EAAOhB,GACfC,GAAMe,EAAOf,GACjBY,EAAM,KAAKG,CAAI,EAEnB,MAAE,CACA,MAAO,CAAC,CACV,CAEA,OAAAH,EAAM,KAAK,EAEJA,EAAM,IAAKG,GAAS,CACzB,IAAMC,EAAQxB,EAAQ,QAAQuB,CAAI,EAClC,GAAI,CAACC,EAAO,OAAO,KAEnB,IAAIC,EAAQ,EAAGC,EAAQ,EAAGC,EAAS,EAAGC,EAAY,EAAGC,EAAc,EAAGC,EAAO,EACvEC,EAA6B,CAAC,EAEpC,OAAW,CAACC,EAAIC,CAAK,IAAK,OAAO,QAAQT,EAAM,MAAM,EAAG,CACtD,IAAMU,EAAYjC,EAAa,cAAcgC,CAAK,EAK5CE,GAAUF,EAAM,aAAe,IAAMA,EAAM,kBAAoB,GAC/DG,GAAWH,EAAM,cAAgB,IAAMA,EAAM,mBAAqB,GAClEI,GAAcJ,EAAM,iBAAmB,IAAMA,EAAM,sBAAwB,GAC3EK,GAAgBL,EAAM,mBAAqB,IAAMA,EAAM,wBAA0B,GACvFR,GAASQ,EAAM,MACfP,GAASS,EACTR,GAAUS,EACVR,GAAaS,EACbR,GAAeS,EACfR,GAAQI,EACRH,EAAOC,CAAE,EAAI,CACX,MAAOC,EAAM,MACb,KAAMC,EACN,MAAOC,EACP,OAAQC,EACR,UAAWC,EACX,YAAaC,EACb,MAAOL,EAAM,KACf,EAGF,MAAO,CAAE,KAAAV,EAAM,MAAAE,EAAO,MAAAC,EAAO,OAAAC,EAAQ,UAAAC,EAAW,YAAAC,EAAa,KAAAC,EAAM,OAAAC,CAAO,CAC5E,CAAC,EAAE,OAAQjB,GAAqBA,IAAM,MAAQA,EAAE,MAAQ,CAAC,CAC3D,CAIA,SAASI,GAA0B,CACjC,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SASAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAuKCC;AAAA;AAAA,QAGV,CAIA,IAAMD,EAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8LNC,EAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkbJC,EAAQ3C","names":["createServer","readdirSync","startUsageDashboard","port","tracker","TokenTracker","createServer","req","res","url","path","from","to","data","loadUsageRange","rows","header","body","d","top","a","b","renderDashboard","dir","files","f","readdirSync","date","usage","tasks","input","output","cacheRead","cacheCreate","cost","agents","id","agent","agentCost","aInput","aOutput","aCacheRead","aCacheCreate","CSS","JS","usage_dashboard_default"]}
@@ -1,2 +0,0 @@
1
- import{a,b}from"./chunk-LEIYC3BF.js";import"./chunk-WZEYII2S.js";import"./chunk-64P4QHSZ.js";import{a as c}from"./chunk-BFZUG66X.js";import"./chunk-QOYAX2FT.js";import"./chunk-HPDHNIA3.js";export{b as WikiHub,a as WikiStore,c as agenticQuery};
2
- //# sourceMappingURL=wiki-OUYKM7MB.js.map
@@ -1,2 +0,0 @@
1
- import{a,b}from"./chunk-ZE2YFX4K.js";import"./chunk-WJXU5F4Z.js";import"./chunk-HPDHNIA3.js";export{b as setupAllWorkspaces,a as setupWorkspace};
2
- //# sourceMappingURL=workspace-setup-6GDBEORT.js.map