agentix-cli 0.8.0 → 0.13.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 (71) hide show
  1. package/README.md +387 -116
  2. package/dist/agent-5KIMJI3F.js +2 -0
  3. package/dist/chunk-34UAFPK4.js +10 -0
  4. package/dist/chunk-34UAFPK4.js.map +1 -0
  5. package/dist/{chunk-X7UN6JAA.js → chunk-6MKAXEE5.js} +2 -2
  6. package/dist/chunk-CJ45Y2IR.js +12 -0
  7. package/dist/chunk-CJ45Y2IR.js.map +1 -0
  8. package/dist/chunk-D6EDMQRV.js +108 -0
  9. package/dist/chunk-D6EDMQRV.js.map +1 -0
  10. package/dist/chunk-DSYKYZMT.js +2 -0
  11. package/dist/chunk-DSYKYZMT.js.map +1 -0
  12. package/dist/chunk-HI24KAEY.js +54 -0
  13. package/dist/chunk-HI24KAEY.js.map +1 -0
  14. package/dist/{chunk-MGMZNJCE.js → chunk-KXZMYLHQ.js} +27 -27
  15. package/dist/chunk-KXZMYLHQ.js.map +1 -0
  16. package/dist/chunk-MCJUAE6V.js +6 -0
  17. package/dist/chunk-MCJUAE6V.js.map +1 -0
  18. package/dist/chunk-QOYAX2FT.js +2 -0
  19. package/dist/chunk-QOYAX2FT.js.map +1 -0
  20. package/dist/chunk-QZP65I2H.js +45 -0
  21. package/dist/chunk-QZP65I2H.js.map +1 -0
  22. package/dist/chunk-T25UEXVK.js +126 -0
  23. package/dist/chunk-T25UEXVK.js.map +1 -0
  24. package/dist/chunk-VH23CDHL.js +157 -0
  25. package/dist/chunk-VH23CDHL.js.map +1 -0
  26. package/dist/chunk-WJ6ZF6EZ.js +6 -0
  27. package/dist/chunk-WJ6ZF6EZ.js.map +1 -0
  28. package/dist/chunk-ZRYBSI5G.js +23 -0
  29. package/dist/chunk-ZRYBSI5G.js.map +1 -0
  30. package/dist/cli.js +277 -36
  31. package/dist/cli.js.map +1 -1
  32. package/dist/compaction-7I3E5QUO.js +28 -0
  33. package/dist/compaction-7I3E5QUO.js.map +1 -0
  34. package/dist/config-HAD5E4YX.js +2 -0
  35. package/dist/debug-N3B5NVJU.js +2 -0
  36. package/dist/heal-OTGT5HHJ.js +2 -0
  37. package/dist/index.d.ts +1849 -368
  38. package/dist/index.js +39 -35
  39. package/dist/index.js.map +1 -1
  40. package/dist/loader-YQE6XJBT.js +2 -0
  41. package/dist/loader-YQE6XJBT.js.map +1 -0
  42. package/dist/memory-extract-RGPUPMKU.js +2 -0
  43. package/dist/memory-extract-RGPUPMKU.js.map +1 -0
  44. package/dist/{providers-AVYG63KK.js → providers-G3WZ4RVJ.js} +2 -2
  45. package/dist/providers-G3WZ4RVJ.js.map +1 -0
  46. package/dist/registry-CDWY7CLL.js +2 -0
  47. package/dist/registry-CDWY7CLL.js.map +1 -0
  48. package/dist/subagent-WV7QKQ3L.js +3 -0
  49. package/dist/subagent-WV7QKQ3L.js.map +1 -0
  50. package/dist/usage-dashboard-2TJQBFSH.js +404 -0
  51. package/dist/usage-dashboard-2TJQBFSH.js.map +1 -0
  52. package/dist/workspace-setup-QQTCJY4B.js +2 -0
  53. package/dist/workspace-setup-QQTCJY4B.js.map +1 -0
  54. package/package.json +4 -1
  55. package/dist/agent-K2YOEOJ5.js +0 -2
  56. package/dist/chunk-F73GPYCO.js +0 -106
  57. package/dist/chunk-F73GPYCO.js.map +0 -1
  58. package/dist/chunk-FRFR27IN.js +0 -3
  59. package/dist/chunk-FRFR27IN.js.map +0 -1
  60. package/dist/chunk-MGMZNJCE.js.map +0 -1
  61. package/dist/chunk-NGKOM4ZZ.js +0 -137
  62. package/dist/chunk-NGKOM4ZZ.js.map +0 -1
  63. package/dist/chunk-Z4GC5D6D.js +0 -12
  64. package/dist/chunk-Z4GC5D6D.js.map +0 -1
  65. package/dist/heal-UV5A6B5T.js +0 -2
  66. package/dist/loader-6VSM6FSY.js +0 -2
  67. /package/dist/{agent-K2YOEOJ5.js.map → agent-5KIMJI3F.js.map} +0 -0
  68. /package/dist/{chunk-X7UN6JAA.js.map → chunk-6MKAXEE5.js.map} +0 -0
  69. /package/dist/{heal-UV5A6B5T.js.map → config-HAD5E4YX.js.map} +0 -0
  70. /package/dist/{loader-6VSM6FSY.js.map → debug-N3B5NVJU.js.map} +0 -0
  71. /package/dist/{providers-AVYG63KK.js.map → heal-OTGT5HHJ.js.map} +0 -0
@@ -0,0 +1,2 @@
1
+ import{a,b,c,d,e}from"./chunk-MCJUAE6V.js";import"./chunk-4YCH6IZV.js";export{e as getAutoInjectSkills,a as loadLocalSkills,d as matchSkillsToTask,c as parseSkillContent,b as parseSkillFile};
2
+ //# sourceMappingURL=loader-YQE6XJBT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,2 @@
1
+ import{a}from"./chunk-ZRYBSI5G.js";import"./chunk-4YCH6IZV.js";export{a as extractMemories};
2
+ //# sourceMappingURL=memory-extract-RGPUPMKU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,2 +1,2 @@
1
- import{e as a,f as b,g as c}from"./chunk-MGMZNJCE.js";import"./chunk-M7HKBG3V.js";import"./chunk-4YCH6IZV.js";export{b as ClaudeCodeProvider,a as ClaudeProvider,c as createProvider};
2
- //# sourceMappingURL=providers-AVYG63KK.js.map
1
+ import{e as a,f as b,g as c}from"./chunk-KXZMYLHQ.js";import"./chunk-M7HKBG3V.js";import"./chunk-4YCH6IZV.js";export{b as ClaudeCodeProvider,a as ClaudeProvider,c as createProvider};
2
+ //# sourceMappingURL=providers-G3WZ4RVJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,2 @@
1
+ import{g as a,h as b,i as c}from"./chunk-VH23CDHL.js";import"./chunk-HI24KAEY.js";import"./chunk-34UAFPK4.js";import"./chunk-ZRYBSI5G.js";import"./chunk-QOYAX2FT.js";import"./chunk-4YCH6IZV.js";export{c as AgentRegistry,b as getGlobalRegistry,a as setGlobalRegistry};
2
+ //# sourceMappingURL=registry-CDWY7CLL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,3 @@
1
+ import"./chunk-4YCH6IZV.js";var g=class{registry;activeRuns=new Map;runCounter=0;log;depthMap=new Map;constructor(t,e=console.error.bind(console,"[subagent]")){this.registry=t,this.log=e}async spawn(t){let e=this.depthMap.get(t.parentAgentId)||0;if(e>=3)return{runId:"",targetAgentId:t.targetAgentId,success:!1,content:"",error:`Sub-agent spawn depth exceeded (max: 3). Cannot spawn "${t.targetAgentId}" from "${t.parentAgentId}".`,duration:0};let n=`sub-${++this.runCounter}-${Date.now().toString(36)}`,r={request:t,runId:n,startedAt:Date.now()};this.activeRuns.set(n,r),this.depthMap.set(t.targetAgentId,e+1),this.log(`Spawning sub-agent: ${t.targetAgentId} (parent: ${t.parentAgentId}, depth: ${e+1}, blocking: ${t.blocking??!1})`);let o={message:this.buildSubAgentPrompt(t),agentId:t.targetAgentId,context:{channel:"subagent",sender:`agent:${t.parentAgentId}`,chatId:`subagent:${n}`}},i=t.timeout??3e5;try{let a=await Promise.race([this.registry.execute(o),this.timeoutPromise(i,t.targetAgentId)]),s={runId:n,targetAgentId:t.targetAgentId,success:!a.error,content:a.content,error:a.error,duration:Date.now()-r.startedAt};return this.log(`Sub-agent ${t.targetAgentId} completed in ${s.duration}ms (${s.success?"success":"error"})`),s}catch(a){return{runId:n,targetAgentId:t.targetAgentId,success:!1,content:"",error:a.message,duration:Date.now()-r.startedAt}}finally{this.activeRuns.delete(n),this.depthMap.delete(t.targetAgentId)}}async spawnParallel(t){return Promise.all(t.map(e=>this.spawn(e)))}listActive(){return Array.from(this.activeRuns.values()).map(t=>({runId:t.runId,targetAgentId:t.request.targetAgentId,parentAgentId:t.request.parentAgentId,duration:Date.now()-t.startedAt}))}buildSubAgentPrompt(t){return[`[Sub-agent task from ${t.parentAgentId}]`,"You have been spawned as a background sub-agent to handle a specific task.","Focus on completing the task below and provide a clear, actionable response.","",t.prompt].join(`
2
+ `)}timeoutPromise(t,e){return new Promise((n,r)=>{setTimeout(()=>{r(new Error(`Sub-agent "${e}" timed out after ${Math.round(t/1e3)}s`))},t)})}};export{g as SubAgentManager};
3
+ //# sourceMappingURL=subagent-WV7QKQ3L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/agents/subagent.ts"],"sourcesContent":["// --- Sub-Agent Spawning ---\n//\n// Allows agents to spawn background sub-agents from within a conversation.\n// Sub-agents run in their own session and report results back to the parent.\n//\n// Use cases:\n// - Parallel research (spawn 3 workers to investigate different aspects)\n// - Long-running background tasks (spawn worker, continue conversation)\n// - Orchestrator patterns (one agent coordinates many)\n\nimport type { AgentRegistry } from \"./registry\"\nimport type { AgentTask, AgentResponse } from \"./runtime\"\n\nexport interface SubAgentRequest {\n /** ID of the agent to spawn as sub-agent */\n targetAgentId: string\n /** Task prompt for the sub-agent */\n prompt: string\n /** ID of the parent agent that initiated the spawn */\n parentAgentId: string\n /** Channel where results should be announced */\n announceChannel?: string\n /** Chat ID where results should be announced */\n announceChatId?: string\n /** Whether to wait for completion or fire-and-forget */\n blocking?: boolean\n /** Timeout in ms (default: 5 minutes) */\n timeout?: number\n}\n\nexport interface SubAgentResult {\n /** ID assigned to this sub-agent run */\n runId: string\n /** Target agent that was spawned */\n targetAgentId: string\n /** Whether the run completed successfully */\n success: boolean\n /** Response content from the sub-agent */\n content: string\n /** Error if any */\n error?: string\n /** Duration in ms */\n duration: number\n}\n\ninterface ActiveRun {\n request: SubAgentRequest\n runId: string\n startedAt: number\n resolve?: (result: SubAgentResult) => void\n}\n\nconst DEFAULT_TIMEOUT = 5 * 60 * 1000 // 5 minutes\nconst MAX_DEPTH = 3 // Prevent infinite spawning chains\n\n/**\n * Manages sub-agent spawning and lifecycle.\n */\nexport class SubAgentManager {\n private registry: AgentRegistry\n private activeRuns: Map<string, ActiveRun> = new Map()\n private runCounter = 0\n private log: (...args: unknown[]) => void\n /** Track spawn depth to prevent infinite chains */\n private depthMap: Map<string, number> = new Map()\n\n constructor(\n registry: AgentRegistry,\n log: (...args: unknown[]) => void = console.error.bind(console, \"[subagent]\"),\n ) {\n this.registry = registry\n this.log = log\n }\n\n /**\n * Spawn a sub-agent. Returns immediately with a runId if non-blocking,\n * or waits for completion if blocking.\n */\n async spawn(request: SubAgentRequest): Promise<SubAgentResult> {\n // Check depth to prevent infinite spawning\n const parentDepth = this.depthMap.get(request.parentAgentId) || 0\n if (parentDepth >= MAX_DEPTH) {\n return {\n runId: \"\",\n targetAgentId: request.targetAgentId,\n success: false,\n content: \"\",\n error: `Sub-agent spawn depth exceeded (max: ${MAX_DEPTH}). Cannot spawn \"${request.targetAgentId}\" from \"${request.parentAgentId}\".`,\n duration: 0,\n }\n }\n\n const runId = `sub-${++this.runCounter}-${Date.now().toString(36)}`\n const run: ActiveRun = {\n request,\n runId,\n startedAt: Date.now(),\n }\n\n this.activeRuns.set(runId, run)\n this.depthMap.set(request.targetAgentId, parentDepth + 1)\n\n this.log(\n `Spawning sub-agent: ${request.targetAgentId} (parent: ${request.parentAgentId}, ` +\n `depth: ${parentDepth + 1}, blocking: ${request.blocking ?? false})`,\n )\n\n const task: AgentTask = {\n message: this.buildSubAgentPrompt(request),\n agentId: request.targetAgentId,\n context: {\n channel: \"subagent\",\n sender: `agent:${request.parentAgentId}`,\n chatId: `subagent:${runId}`,\n },\n }\n\n const timeout = request.timeout ?? DEFAULT_TIMEOUT\n\n try {\n const response = await Promise.race([\n this.registry.execute(task),\n this.timeoutPromise(timeout, request.targetAgentId),\n ])\n\n const result: SubAgentResult = {\n runId,\n targetAgentId: request.targetAgentId,\n success: !response.error,\n content: response.content,\n error: response.error,\n duration: Date.now() - run.startedAt,\n }\n\n this.log(\n `Sub-agent ${request.targetAgentId} completed in ${result.duration}ms ` +\n `(${result.success ? \"success\" : \"error\"})`,\n )\n\n return result\n } catch (error: any) {\n return {\n runId,\n targetAgentId: request.targetAgentId,\n success: false,\n content: \"\",\n error: error.message,\n duration: Date.now() - run.startedAt,\n }\n } finally {\n this.activeRuns.delete(runId)\n this.depthMap.delete(request.targetAgentId)\n }\n }\n\n /**\n * Spawn multiple sub-agents in parallel.\n */\n async spawnParallel(requests: SubAgentRequest[]): Promise<SubAgentResult[]> {\n return Promise.all(requests.map((req) => this.spawn(req)))\n }\n\n /**\n * List active sub-agent runs.\n */\n listActive(): Array<{\n runId: string\n targetAgentId: string\n parentAgentId: string\n duration: number\n }> {\n return Array.from(this.activeRuns.values()).map((run) => ({\n runId: run.runId,\n targetAgentId: run.request.targetAgentId,\n parentAgentId: run.request.parentAgentId,\n duration: Date.now() - run.startedAt,\n }))\n }\n\n private buildSubAgentPrompt(request: SubAgentRequest): string {\n return [\n `[Sub-agent task from ${request.parentAgentId}]`,\n `You have been spawned as a background sub-agent to handle a specific task.`,\n `Focus on completing the task below and provide a clear, actionable response.`,\n ``,\n request.prompt,\n ].join(\"\\n\")\n }\n\n private timeoutPromise(ms: number, agentId: string): Promise<AgentResponse> {\n return new Promise((_, reject) => {\n setTimeout(() => {\n reject(new Error(`Sub-agent \"${agentId}\" timed out after ${Math.round(ms / 1000)}s`))\n }, ms)\n })\n }\n}\n"],"mappings":"4BA0DO,IAAMA,EAAN,KAAsB,CACnB,SACA,WAAqC,IAAI,IACzC,WAAa,EACb,IAEA,SAAgC,IAAI,IAE5C,YACEC,EACAC,EAAoC,QAAQ,MAAM,KAAK,QAAS,YAAY,EAC5E,CACA,KAAK,SAAWD,EAChB,KAAK,IAAMC,CACb,CAMA,MAAM,MAAMC,EAAmD,CAE7D,IAAMC,EAAc,KAAK,SAAS,IAAID,EAAQ,aAAa,GAAK,EAChE,GAAIC,GAAe,EACjB,MAAO,CACL,MAAO,GACP,cAAeD,EAAQ,cACvB,QAAS,GACT,QAAS,GACT,MAAO,0DAAqEA,EAAQ,wBAAwBA,EAAQ,kBACpH,SAAU,CACZ,EAGF,IAAME,EAAQ,OAAO,EAAE,KAAK,cAAc,KAAK,IAAI,EAAE,SAAS,EAAE,IAC1DC,EAAiB,CACrB,QAAAH,EACA,MAAAE,EACA,UAAW,KAAK,IAAI,CACtB,EAEA,KAAK,WAAW,IAAIA,EAAOC,CAAG,EAC9B,KAAK,SAAS,IAAIH,EAAQ,cAAeC,EAAc,CAAC,EAExD,KAAK,IACH,uBAAuBD,EAAQ,0BAA0BA,EAAQ,yBACvDC,EAAc,gBAAgBD,EAAQ,UAAY,KAC9D,EAEA,IAAMI,EAAkB,CACtB,QAAS,KAAK,oBAAoBJ,CAAO,EACzC,QAASA,EAAQ,cACjB,QAAS,CACP,QAAS,WACT,OAAQ,SAASA,EAAQ,gBACzB,OAAQ,YAAYE,GACtB,CACF,EAEMG,EAAUL,EAAQ,SAAW,IAEnC,GAAI,CACF,IAAMM,EAAW,MAAM,QAAQ,KAAK,CAClC,KAAK,SAAS,QAAQF,CAAI,EAC1B,KAAK,eAAeC,EAASL,EAAQ,aAAa,CACpD,CAAC,EAEKO,EAAyB,CAC7B,MAAAL,EACA,cAAeF,EAAQ,cACvB,QAAS,CAACM,EAAS,MACnB,QAASA,EAAS,QAClB,MAAOA,EAAS,MAChB,SAAU,KAAK,IAAI,EAAIH,EAAI,SAC7B,EAEA,YAAK,IACH,aAAaH,EAAQ,8BAA8BO,EAAO,eACtDA,EAAO,QAAU,UAAY,UACnC,EAEOA,CACT,OAASC,EAAP,CACA,MAAO,CACL,MAAAN,EACA,cAAeF,EAAQ,cACvB,QAAS,GACT,QAAS,GACT,MAAOQ,EAAM,QACb,SAAU,KAAK,IAAI,EAAIL,EAAI,SAC7B,CACF,QAAE,CACA,KAAK,WAAW,OAAOD,CAAK,EAC5B,KAAK,SAAS,OAAOF,EAAQ,aAAa,CAC5C,CACF,CAKA,MAAM,cAAcS,EAAwD,CAC1E,OAAO,QAAQ,IAAIA,EAAS,IAAKC,GAAQ,KAAK,MAAMA,CAAG,CAAC,CAAC,CAC3D,CAKA,YAKG,CACD,OAAO,MAAM,KAAK,KAAK,WAAW,OAAO,CAAC,EAAE,IAAKP,IAAS,CACxD,MAAOA,EAAI,MACX,cAAeA,EAAI,QAAQ,cAC3B,cAAeA,EAAI,QAAQ,cAC3B,SAAU,KAAK,IAAI,EAAIA,EAAI,SAC7B,EAAE,CACJ,CAEQ,oBAAoBH,EAAkC,CAC5D,MAAO,CACL,wBAAwBA,EAAQ,iBAChC,6EACA,+EACA,GACAA,EAAQ,MACV,EAAE,KAAK;AAAA,CAAI,CACb,CAEQ,eAAeW,EAAYC,EAAyC,CAC1E,OAAO,IAAI,QAAQ,CAACC,EAAGC,IAAW,CAChC,WAAW,IAAM,CACfA,EAAO,IAAI,MAAM,cAAcF,sBAA4B,KAAK,MAAMD,EAAK,GAAI,IAAI,CAAC,CACtF,EAAGA,CAAE,CACP,CAAC,CACH,CACF","names":["SubAgentManager","registry","log","request","parentDepth","runId","run","task","timeout","response","result","error","requests","req","ms","agentId","_","reject"]}
@@ -0,0 +1,404 @@
1
+ import{a as p}from"./chunk-34UAFPK4.js";import"./chunk-4YCH6IZV.js";import{createServer as b}from"http";import{readdirSync as v}from"fs";function y(s=4201){let n=new p;b(async(i,e)=>{let t=new URL(i.url||"/",`http://localhost:${s}`),o=t.pathname;if(e.setHeader("Access-Control-Allow-Origin","*"),o==="/api/usage"){let c=t.searchParams.get("from")||"",r=t.searchParams.get("to")||"",l=w(n,c,r);e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify(l));return}e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(C())}).listen(s,()=>{console.log(`
2
+ Usage dashboard: http://localhost:${s}
3
+ `)})}function w(s,n,d){let i=s.dir,e=[];try{for(let t of v(i)){if(!t.endsWith(".json"))continue;let o=t.replace(".json","");n&&o<n||d&&o>d||e.push(o)}}catch{return[]}return e.sort(),e.map(t=>{let o=s.getDate(t);if(!o)return null;let c=0,r=0,l=0,h=0,u=0,f=0,x={};for(let[g,a]of Object.entries(o.agents)){let m=p.calculateCost(a);c+=a.tasks,r+=a.inputTokens||0,l+=a.outputTokens||0,h+=a.cacheReadTokens||0,u+=a.cacheCreateTokens||0,f+=m,x[g]={tasks:a.tasks,cost:m,input:a.inputTokens||0,output:a.outputTokens||0,cacheRead:a.cacheReadTokens||0,cacheCreate:a.cacheCreateTokens||0,model:a.model}}return{date:t,tasks:c,input:r,output:l,cacheRead:h,cacheCreate:u,cost:f,agents:x}}).filter(t=>t!==null&&t.tasks>0)}function C(){return`<!DOCTYPE html>
4
+ <html lang="en">
5
+ <head>
6
+ <meta charset="utf-8">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <title>AgentX Usage Dashboard</title>
9
+ <style>${k}</style>
10
+ </head>
11
+ <body>
12
+ <div class="header">
13
+ <h1>AgentX Usage Dashboard</h1>
14
+ <div class="filters">
15
+ <label>From <input type="date" id="from"></label>
16
+ <label>To <input type="date" id="to"></label>
17
+ <button onclick="load()">Apply</button>
18
+ <button onclick="setRange(7)">7d</button>
19
+ <button onclick="setRange(14)">14d</button>
20
+ <button onclick="setRange(30)">30d</button>
21
+ <button onclick="setRange(0)">All</button>
22
+ </div>
23
+ </div>
24
+
25
+ <div class="stats" id="stats"></div>
26
+
27
+ <div class="grid">
28
+ <div class="card">
29
+ <h2>Cost Over Time</h2>
30
+ <canvas id="costChart" height="260"></canvas>
31
+ </div>
32
+ <div class="card">
33
+ <h2>Tokens Over Time</h2>
34
+ <canvas id="tokenChart" height="260"></canvas>
35
+ </div>
36
+ </div>
37
+
38
+ <div class="grid">
39
+ <div class="card">
40
+ <h2>Cost Per Agent</h2>
41
+ <canvas id="agentChart" height="260"></canvas>
42
+ </div>
43
+ <div class="card">
44
+ <h2>Token Breakdown</h2>
45
+ <canvas id="breakdownChart" height="260"></canvas>
46
+ </div>
47
+ </div>
48
+
49
+ <div class="card">
50
+ <h2>Daily Detail</h2>
51
+ <table id="table">
52
+ <thead>
53
+ <tr><th>Date</th><th>Tasks</th><th>Input</th><th>Output</th><th>Cache R</th><th>Cache W</th><th>Cost</th><th>Top Agent</th></tr>
54
+ </thead>
55
+ <tbody></tbody>
56
+ </table>
57
+ </div>
58
+
59
+ <script>${T}</script>
60
+ </body>
61
+ </html>`}var k=`
62
+ :root {
63
+ --bg: #0f1117;
64
+ --card: #1a1d27;
65
+ --border: #2a2d3a;
66
+ --text: #e1e4ed;
67
+ --muted: #8b8fa3;
68
+ --accent: #6366f1;
69
+ --green: #22c55e;
70
+ --orange: #f59e0b;
71
+ --red: #ef4444;
72
+ --blue: #3b82f6;
73
+ --purple: #a855f7;
74
+ --cyan: #06b6d4;
75
+ }
76
+ * { margin: 0; padding: 0; box-sizing: border-box; }
77
+ body { background: var(--bg); color: var(--text); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; padding: 24px; }
78
+ .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; flex-wrap: wrap; gap: 12px; }
79
+ h1 { font-size: 20px; font-weight: 600; }
80
+ h2 { font-size: 14px; font-weight: 500; color: var(--muted); margin-bottom: 16px; text-transform: uppercase; letter-spacing: 0.5px; }
81
+ .filters { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
82
+ .filters label { font-size: 13px; color: var(--muted); }
83
+ .filters input { background: var(--card); border: 1px solid var(--border); color: var(--text); padding: 6px 10px; border-radius: 6px; font-size: 13px; }
84
+ .filters button { background: var(--card); border: 1px solid var(--border); color: var(--text); padding: 6px 14px; border-radius: 6px; cursor: pointer; font-size: 13px; transition: background 0.15s; }
85
+ .filters button:hover { background: var(--accent); border-color: var(--accent); }
86
+ .stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: 24px; }
87
+ .stat { background: var(--card); border: 1px solid var(--border); border-radius: 10px; padding: 16px; }
88
+ .stat .value { font-size: 24px; font-weight: 700; margin-bottom: 4px; }
89
+ .stat .label { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; }
90
+ .stat .delta { font-size: 12px; margin-top: 4px; }
91
+ .stat .delta.up { color: var(--red); }
92
+ .stat .delta.down { color: var(--green); }
93
+ .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; }
94
+ @media (max-width: 900px) { .grid { grid-template-columns: 1fr; } }
95
+ .card { background: var(--card); border: 1px solid var(--border); border-radius: 10px; padding: 20px; }
96
+ canvas { width: 100% !important; }
97
+ table { width: 100%; border-collapse: collapse; font-size: 13px; }
98
+ th { text-align: left; padding: 8px 12px; border-bottom: 1px solid var(--border); color: var(--muted); font-weight: 500; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; }
99
+ td { padding: 8px 12px; border-bottom: 1px solid var(--border); }
100
+ tr:hover td { background: rgba(99, 102, 241, 0.05); }
101
+ .cost { color: var(--accent); font-weight: 600; font-variant-numeric: tabular-nums; }
102
+ .tok { font-variant-numeric: tabular-nums; }
103
+ `,T=`
104
+ let data = [];
105
+
106
+ function fmtTok(n) {
107
+ if (n >= 1e6) return (n/1e6).toFixed(1) + 'M';
108
+ if (n >= 1e3) return (n/1e3).toFixed(0) + 'K';
109
+ return String(n);
110
+ }
111
+ function fmtCost(n) { return n < 0.01 ? '$' + n.toFixed(4) : '$' + n.toFixed(2); }
112
+
113
+ function setRange(days) {
114
+ if (days === 0) {
115
+ document.getElementById('from').value = '';
116
+ document.getElementById('to').value = '';
117
+ } else {
118
+ const to = new Date();
119
+ const from = new Date(Date.now() - days * 86400000);
120
+ document.getElementById('from').value = from.toISOString().slice(0,10);
121
+ document.getElementById('to').value = to.toISOString().slice(0,10);
122
+ }
123
+ load();
124
+ }
125
+
126
+ async function load() {
127
+ const from = document.getElementById('from').value;
128
+ const to = document.getElementById('to').value;
129
+ const params = new URLSearchParams();
130
+ if (from) params.set('from', from);
131
+ if (to) params.set('to', to);
132
+ const res = await fetch('/api/usage?' + params);
133
+ data = await res.json();
134
+ render();
135
+ }
136
+
137
+ function render() {
138
+ renderStats();
139
+ renderCostChart();
140
+ renderTokenChart();
141
+ renderAgentChart();
142
+ renderBreakdownChart();
143
+ renderTable();
144
+ }
145
+
146
+ function renderStats() {
147
+ const el = document.getElementById('stats');
148
+ const totalCost = data.reduce((s,d) => s + d.cost, 0);
149
+ const totalTasks = data.reduce((s,d) => s + d.tasks, 0);
150
+ const totalInput = data.reduce((s,d) => s + d.input, 0);
151
+ const totalOutput = data.reduce((s,d) => s + d.output, 0);
152
+ const totalCacheR = data.reduce((s,d) => s + d.cacheRead, 0);
153
+ const totalCacheW = data.reduce((s,d) => s + d.cacheCreate, 0);
154
+ const cacheRatio = (totalCacheR + totalCacheW) > 0 ? (totalCacheR / (totalCacheR + totalCacheW) * 100).toFixed(0) : '0';
155
+ const avgDaily = data.length > 0 ? totalCost / data.length : 0;
156
+
157
+ // Delta: compare last day vs previous
158
+ let delta = '';
159
+ if (data.length >= 2) {
160
+ const last = data[data.length-1].cost;
161
+ const prev = data[data.length-2].cost;
162
+ if (prev > 0) {
163
+ const pct = ((last - prev) / prev * 100).toFixed(0);
164
+ const cls = last > prev ? 'up' : 'down';
165
+ const arrow = last > prev ? '\\u2191' : '\\u2193';
166
+ delta = '<div class="delta ' + cls + '">' + arrow + ' ' + Math.abs(pct) + '% vs prev day</div>';
167
+ }
168
+ }
169
+
170
+ el.innerHTML =
171
+ stat(fmtCost(totalCost), 'Total Cost', delta) +
172
+ stat(fmtCost(avgDaily), 'Avg Daily Cost', '') +
173
+ stat(totalTasks.toLocaleString(), 'Total Tasks', '') +
174
+ stat(fmtTok(totalInput + totalOutput), 'Tokens (I/O)', '') +
175
+ stat(fmtTok(totalCacheR), 'Cache Reads', '') +
176
+ stat(cacheRatio + '%', 'Cache Hit Rate', '') +
177
+ stat(data.length.toString(), 'Days Tracked', '');
178
+ }
179
+
180
+ function stat(value, label, extra) {
181
+ return '<div class="stat"><div class="value">' + value + '</div><div class="label">' + label + '</div>' + extra + '</div>';
182
+ }
183
+
184
+ // --- Canvas chart helpers ---
185
+ function drawLine(ctx, points, w, h, color, fill) {
186
+ if (points.length < 2) return;
187
+ const max = Math.max(...points, 0.001);
188
+ const pad = { t: 10, r: 10, b: 30, l: 50 };
189
+ const cw = w - pad.l - pad.r;
190
+ const ch = h - pad.t - pad.b;
191
+
192
+ ctx.strokeStyle = color;
193
+ ctx.lineWidth = 2;
194
+ ctx.beginPath();
195
+ points.forEach((v, i) => {
196
+ const x = pad.l + (i / (points.length - 1)) * cw;
197
+ const y = pad.t + ch - (v / max) * ch;
198
+ i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
199
+ });
200
+ ctx.stroke();
201
+
202
+ if (fill) {
203
+ ctx.lineTo(pad.l + cw, pad.t + ch);
204
+ ctx.lineTo(pad.l, pad.t + ch);
205
+ ctx.closePath();
206
+ ctx.fillStyle = fill;
207
+ ctx.fill();
208
+ }
209
+
210
+ // Y axis labels
211
+ ctx.fillStyle = '#8b8fa3';
212
+ ctx.font = '11px -apple-system, sans-serif';
213
+ ctx.textAlign = 'right';
214
+ for (let i = 0; i <= 4; i++) {
215
+ const v = (max / 4) * i;
216
+ const y = pad.t + ch - (i / 4) * ch;
217
+ ctx.fillText(v >= 1000 ? fmtTok(v) : v < 0.01 ? v.toFixed(4) : v.toFixed(2), pad.l - 6, y + 4);
218
+ ctx.strokeStyle = '#2a2d3a';
219
+ ctx.lineWidth = 0.5;
220
+ ctx.beginPath(); ctx.moveTo(pad.l, y); ctx.lineTo(pad.l + cw, y); ctx.stroke();
221
+ }
222
+
223
+ // X axis labels (first, middle, last)
224
+ ctx.fillStyle = '#8b8fa3';
225
+ ctx.textAlign = 'center';
226
+ if (data.length > 0) {
227
+ const labels = [0, Math.floor(data.length/2), data.length-1];
228
+ labels.forEach(i => {
229
+ if (i < data.length) {
230
+ const x = pad.l + (i / (points.length - 1)) * cw;
231
+ ctx.fillText(data[i].date.slice(5), x, pad.t + ch + 18);
232
+ }
233
+ });
234
+ }
235
+ }
236
+
237
+ function drawBars(ctx, items, w, h, colors) {
238
+ if (items.length === 0) return;
239
+ const max = Math.max(...items.map(i => i.value), 0.001);
240
+ const pad = { t: 10, r: 10, b: 60, l: 60 };
241
+ const cw = w - pad.l - pad.r;
242
+ const ch = h - pad.t - pad.b;
243
+ const barW = Math.min(40, (cw / items.length) * 0.7);
244
+ const gap = cw / items.length;
245
+
246
+ items.forEach((item, i) => {
247
+ const barH = (item.value / max) * ch;
248
+ const x = pad.l + i * gap + (gap - barW) / 2;
249
+ const y = pad.t + ch - barH;
250
+ ctx.fillStyle = colors[i % colors.length];
251
+ ctx.beginPath();
252
+ ctx.roundRect(x, y, barW, barH, 3);
253
+ ctx.fill();
254
+
255
+ // Label
256
+ ctx.fillStyle = '#8b8fa3';
257
+ ctx.font = '11px -apple-system, sans-serif';
258
+ ctx.textAlign = 'center';
259
+ ctx.save();
260
+ ctx.translate(x + barW/2, pad.t + ch + 12);
261
+ ctx.rotate(-0.4);
262
+ ctx.fillText(item.label.length > 14 ? item.label.slice(0,12) + '..' : item.label, 0, 0);
263
+ ctx.restore();
264
+
265
+ // Value on top
266
+ ctx.fillStyle = '#e1e4ed';
267
+ ctx.textAlign = 'center';
268
+ ctx.fillText(item.fmt, x + barW/2, y - 6);
269
+ });
270
+ }
271
+
272
+ function drawStacked(ctx, series, labels, w, h, colors) {
273
+ if (labels.length === 0) return;
274
+ const pad = { t: 10, r: 10, b: 30, l: 50 };
275
+ const cw = w - pad.l - pad.r;
276
+ const ch = h - pad.t - pad.b;
277
+
278
+ // Calculate totals for max
279
+ const totals = labels.map((_, i) => series.reduce((s, sr) => s + sr.values[i], 0));
280
+ const max = Math.max(...totals, 1);
281
+
282
+ const barW = Math.min(30, (cw / labels.length) * 0.7);
283
+ const gap = cw / labels.length;
284
+
285
+ labels.forEach((_, li) => {
286
+ let yOffset = 0;
287
+ series.forEach((sr, si) => {
288
+ const val = sr.values[li];
289
+ const barH = (val / max) * ch;
290
+ const x = pad.l + li * gap + (gap - barW) / 2;
291
+ const y = pad.t + ch - yOffset - barH;
292
+ ctx.fillStyle = colors[si % colors.length];
293
+ ctx.fillRect(x, y, barW, barH);
294
+ yOffset += barH;
295
+ });
296
+ });
297
+
298
+ // Legend
299
+ ctx.font = '11px -apple-system, sans-serif';
300
+ series.forEach((sr, i) => {
301
+ const x = pad.l + i * 100;
302
+ ctx.fillStyle = colors[i % colors.length];
303
+ ctx.fillRect(x, h - 16, 10, 10);
304
+ ctx.fillStyle = '#8b8fa3';
305
+ ctx.textAlign = 'left';
306
+ ctx.fillText(sr.name, x + 14, h - 7);
307
+ });
308
+
309
+ // X axis
310
+ ctx.fillStyle = '#8b8fa3';
311
+ ctx.textAlign = 'center';
312
+ if (data.length > 0) {
313
+ [0, Math.floor(labels.length/2), labels.length-1].forEach(i => {
314
+ if (i < labels.length) {
315
+ const x = pad.l + (i / Math.max(labels.length-1,1)) * cw;
316
+ ctx.fillText(labels[i].slice(5), x, pad.t + ch + 18);
317
+ }
318
+ });
319
+ }
320
+ }
321
+
322
+ function setupCanvas(id) {
323
+ const canvas = document.getElementById(id);
324
+ const dpr = window.devicePixelRatio || 1;
325
+ const rect = canvas.parentElement.getBoundingClientRect();
326
+ const w = rect.width - 40; // account for card padding
327
+ const h = canvas.height;
328
+ canvas.width = w * dpr;
329
+ canvas.height = h * dpr;
330
+ canvas.style.width = w + 'px';
331
+ canvas.style.height = h + 'px';
332
+ const ctx = canvas.getContext('2d');
333
+ ctx.scale(dpr, dpr);
334
+ ctx.clearRect(0, 0, w, h);
335
+ return { ctx, w, h };
336
+ }
337
+
338
+ function renderCostChart() {
339
+ const { ctx, w, h } = setupCanvas('costChart');
340
+ const points = data.map(d => d.cost);
341
+ drawLine(ctx, points, w, h, '#6366f1', 'rgba(99,102,241,0.1)');
342
+ }
343
+
344
+ function renderTokenChart() {
345
+ const { ctx, w, h } = setupCanvas('tokenChart');
346
+ const labels = data.map(d => d.date);
347
+ drawStacked(ctx, [
348
+ { name: 'Input', values: data.map(d => d.input) },
349
+ { name: 'Output', values: data.map(d => d.output) },
350
+ { name: 'Cache R', values: data.map(d => d.cacheRead) },
351
+ { name: 'Cache W', values: data.map(d => d.cacheCreate) },
352
+ ], labels, w, h, ['#3b82f6', '#22c55e', '#06b6d4', '#f59e0b']);
353
+ }
354
+
355
+ function renderAgentChart() {
356
+ const { ctx, w, h } = setupCanvas('agentChart');
357
+ const agentTotals = {};
358
+ data.forEach(d => {
359
+ for (const [id, a] of Object.entries(d.agents)) {
360
+ agentTotals[id] = (agentTotals[id] || 0) + a.cost;
361
+ }
362
+ });
363
+ const items = Object.entries(agentTotals)
364
+ .sort(([,a],[,b]) => b - a)
365
+ .slice(0, 10)
366
+ .map(([id, cost]) => ({ label: id, value: cost, fmt: fmtCost(cost) }));
367
+ drawBars(ctx, items, w, h, ['#6366f1','#3b82f6','#06b6d4','#22c55e','#f59e0b','#ef4444','#a855f7','#ec4899']);
368
+ }
369
+
370
+ function renderBreakdownChart() {
371
+ const { ctx, w, h } = setupCanvas('breakdownChart');
372
+ const totals = { input: 0, output: 0, cacheRead: 0, cacheCreate: 0 };
373
+ data.forEach(d => { totals.input += d.input; totals.output += d.output; totals.cacheRead += d.cacheRead; totals.cacheCreate += d.cacheCreate; });
374
+ const items = [
375
+ { label: 'Input', value: totals.input, fmt: fmtTok(totals.input) },
376
+ { label: 'Output', value: totals.output, fmt: fmtTok(totals.output) },
377
+ { label: 'Cache Read', value: totals.cacheRead, fmt: fmtTok(totals.cacheRead) },
378
+ { label: 'Cache Write', value: totals.cacheCreate, fmt: fmtTok(totals.cacheCreate) },
379
+ ];
380
+ drawBars(ctx, items, w, h, ['#3b82f6','#22c55e','#06b6d4','#f59e0b']);
381
+ }
382
+
383
+ function renderTable() {
384
+ const tbody = document.querySelector('#table tbody');
385
+ tbody.innerHTML = data.slice().reverse().map(d => {
386
+ const top = Object.entries(d.agents).sort(([,a],[,b]) => b.cost - a.cost)[0];
387
+ const topStr = top ? top[0] + ' (' + fmtCost(top[1].cost) + ')' : '-';
388
+ return '<tr>' +
389
+ '<td>' + d.date + '</td>' +
390
+ '<td>' + d.tasks + '</td>' +
391
+ '<td class="tok">' + fmtTok(d.input) + '</td>' +
392
+ '<td class="tok">' + fmtTok(d.output) + '</td>' +
393
+ '<td class="tok">' + fmtTok(d.cacheRead) + '</td>' +
394
+ '<td class="tok">' + fmtTok(d.cacheCreate) + '</td>' +
395
+ '<td class="cost">' + fmtCost(d.cost) + '</td>' +
396
+ '<td>' + topStr + '</td>' +
397
+ '</tr>';
398
+ }).join('');
399
+ }
400
+
401
+ // Auto-load last 30 days
402
+ setRange(30);
403
+ `,O=y;export{O as default,y as startUsageDashboard};
404
+ //# sourceMappingURL=usage-dashboard-2TJQBFSH.js.map
@@ -0,0 +1 @@
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 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 tasks += agent.tasks\n input += agent.inputTokens || 0\n output += agent.outputTokens || 0\n cacheRead += agent.cacheReadTokens || 0\n cacheCreate += agent.cacheCreateTokens || 0\n cost += agentCost\n agents[id] = {\n tasks: agent.tasks,\n cost: agentCost,\n input: agent.inputTokens || 0,\n output: agent.outputTokens || 0,\n cacheRead: agent.cacheReadTokens || 0,\n cacheCreate: agent.cacheCreateTokens || 0,\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\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>AgentX Usage Dashboard</title>\n<style>${CSS}</style>\n</head>\n<body>\n<div class=\"header\">\n <h1>AgentX Usage Dashboard</h1>\n <div class=\"filters\">\n <label>From <input type=\"date\" id=\"from\"></label>\n <label>To <input type=\"date\" id=\"to\"></label>\n <button onclick=\"load()\">Apply</button>\n <button onclick=\"setRange(7)\">7d</button>\n <button onclick=\"setRange(14)\">14d</button>\n <button onclick=\"setRange(30)\">30d</button>\n <button onclick=\"setRange(0)\">All</button>\n </div>\n</div>\n\n<div class=\"stats\" id=\"stats\"></div>\n\n<div class=\"grid\">\n <div class=\"card\">\n <h2>Cost Over Time</h2>\n <canvas id=\"costChart\" height=\"260\"></canvas>\n </div>\n <div class=\"card\">\n <h2>Tokens Over Time</h2>\n <canvas id=\"tokenChart\" height=\"260\"></canvas>\n </div>\n</div>\n\n<div class=\"grid\">\n <div class=\"card\">\n <h2>Cost Per Agent</h2>\n <canvas id=\"agentChart\" height=\"260\"></canvas>\n </div>\n <div class=\"card\">\n <h2>Token Breakdown</h2>\n <canvas id=\"breakdownChart\" height=\"260\"></canvas>\n </div>\n</div>\n\n<div class=\"card\">\n <h2>Daily Detail</h2>\n <table id=\"table\">\n <thead>\n <tr><th>Date</th><th>Tasks</th><th>Input</th><th>Output</th><th>Cache R</th><th>Cache W</th><th>Cost</th><th>Top Agent</th></tr>\n </thead>\n <tbody></tbody>\n </table>\n</div>\n\n<script>${JS}</script>\n</body>\n</html>`\n}\n\n// --- Embedded CSS ---\n\nconst CSS = `\n:root {\n --bg: #0f1117;\n --card: #1a1d27;\n --border: #2a2d3a;\n --text: #e1e4ed;\n --muted: #8b8fa3;\n --accent: #6366f1;\n --green: #22c55e;\n --orange: #f59e0b;\n --red: #ef4444;\n --blue: #3b82f6;\n --purple: #a855f7;\n --cyan: #06b6d4;\n}\n* { margin: 0; padding: 0; box-sizing: border-box; }\nbody { background: var(--bg); color: var(--text); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; padding: 24px; }\n.header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; flex-wrap: wrap; gap: 12px; }\nh1 { font-size: 20px; font-weight: 600; }\nh2 { font-size: 14px; font-weight: 500; color: var(--muted); margin-bottom: 16px; text-transform: uppercase; letter-spacing: 0.5px; }\n.filters { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }\n.filters label { font-size: 13px; color: var(--muted); }\n.filters input { background: var(--card); border: 1px solid var(--border); color: var(--text); padding: 6px 10px; border-radius: 6px; font-size: 13px; }\n.filters button { background: var(--card); border: 1px solid var(--border); color: var(--text); padding: 6px 14px; border-radius: 6px; cursor: pointer; font-size: 13px; transition: background 0.15s; }\n.filters button:hover { background: var(--accent); border-color: var(--accent); }\n.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: 24px; }\n.stat { background: var(--card); border: 1px solid var(--border); border-radius: 10px; padding: 16px; }\n.stat .value { font-size: 24px; font-weight: 700; margin-bottom: 4px; }\n.stat .label { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; }\n.stat .delta { font-size: 12px; margin-top: 4px; }\n.stat .delta.up { color: var(--red); }\n.stat .delta.down { color: var(--green); }\n.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; }\n@media (max-width: 900px) { .grid { grid-template-columns: 1fr; } }\n.card { background: var(--card); border: 1px solid var(--border); border-radius: 10px; padding: 20px; }\ncanvas { width: 100% !important; }\ntable { width: 100%; border-collapse: collapse; font-size: 13px; }\nth { text-align: left; padding: 8px 12px; border-bottom: 1px solid var(--border); color: var(--muted); font-weight: 500; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; }\ntd { padding: 8px 12px; border-bottom: 1px solid var(--border); }\ntr:hover td { background: rgba(99, 102, 241, 0.05); }\n.cost { color: var(--accent); font-weight: 600; font-variant-numeric: tabular-nums; }\n.tok { font-variant-numeric: tabular-nums; }\n`\n\n// --- Embedded JavaScript ---\n\nconst JS = `\nlet data = [];\n\nfunction fmtTok(n) {\n if (n >= 1e6) return (n/1e6).toFixed(1) + 'M';\n if (n >= 1e3) return (n/1e3).toFixed(0) + 'K';\n return String(n);\n}\nfunction fmtCost(n) { return n < 0.01 ? '$' + n.toFixed(4) : '$' + n.toFixed(2); }\n\nfunction setRange(days) {\n if (days === 0) {\n document.getElementById('from').value = '';\n document.getElementById('to').value = '';\n } else {\n const to = new Date();\n const from = new Date(Date.now() - days * 86400000);\n document.getElementById('from').value = from.toISOString().slice(0,10);\n document.getElementById('to').value = to.toISOString().slice(0,10);\n }\n load();\n}\n\nasync function load() {\n const from = document.getElementById('from').value;\n const to = document.getElementById('to').value;\n const params = new URLSearchParams();\n if (from) params.set('from', from);\n if (to) params.set('to', to);\n const res = await fetch('/api/usage?' + params);\n data = await res.json();\n render();\n}\n\nfunction render() {\n renderStats();\n renderCostChart();\n renderTokenChart();\n renderAgentChart();\n renderBreakdownChart();\n renderTable();\n}\n\nfunction renderStats() {\n const el = document.getElementById('stats');\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 cacheRatio = (totalCacheR + totalCacheW) > 0 ? (totalCacheR / (totalCacheR + totalCacheW) * 100).toFixed(0) : '0';\n const avgDaily = data.length > 0 ? totalCost / data.length : 0;\n\n // Delta: compare last day vs previous\n let delta = '';\n if (data.length >= 2) {\n const last = data[data.length-1].cost;\n const prev = data[data.length-2].cost;\n if (prev > 0) {\n const pct = ((last - prev) / prev * 100).toFixed(0);\n const cls = last > prev ? 'up' : 'down';\n const arrow = last > prev ? '\\\\u2191' : '\\\\u2193';\n delta = '<div class=\"delta ' + cls + '\">' + arrow + ' ' + Math.abs(pct) + '% vs prev day</div>';\n }\n }\n\n el.innerHTML =\n stat(fmtCost(totalCost), 'Total Cost', delta) +\n stat(fmtCost(avgDaily), 'Avg Daily Cost', '') +\n stat(totalTasks.toLocaleString(), 'Total Tasks', '') +\n stat(fmtTok(totalInput + totalOutput), 'Tokens (I/O)', '') +\n stat(fmtTok(totalCacheR), 'Cache Reads', '') +\n stat(cacheRatio + '%', 'Cache Hit Rate', '') +\n stat(data.length.toString(), 'Days Tracked', '');\n}\n\nfunction stat(value, label, extra) {\n return '<div class=\"stat\"><div class=\"value\">' + value + '</div><div class=\"label\">' + label + '</div>' + extra + '</div>';\n}\n\n// --- Canvas chart helpers ---\nfunction drawLine(ctx, points, w, h, color, fill) {\n if (points.length < 2) return;\n const max = Math.max(...points, 0.001);\n const pad = { t: 10, r: 10, b: 30, l: 50 };\n const cw = w - pad.l - pad.r;\n const ch = h - pad.t - pad.b;\n\n ctx.strokeStyle = color;\n ctx.lineWidth = 2;\n ctx.beginPath();\n points.forEach((v, i) => {\n const x = pad.l + (i / (points.length - 1)) * cw;\n const y = pad.t + ch - (v / max) * ch;\n i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);\n });\n ctx.stroke();\n\n if (fill) {\n ctx.lineTo(pad.l + cw, pad.t + ch);\n ctx.lineTo(pad.l, pad.t + ch);\n ctx.closePath();\n ctx.fillStyle = fill;\n ctx.fill();\n }\n\n // Y axis labels\n ctx.fillStyle = '#8b8fa3';\n ctx.font = '11px -apple-system, sans-serif';\n ctx.textAlign = 'right';\n for (let i = 0; i <= 4; i++) {\n const v = (max / 4) * i;\n const y = pad.t + ch - (i / 4) * ch;\n ctx.fillText(v >= 1000 ? fmtTok(v) : v < 0.01 ? v.toFixed(4) : v.toFixed(2), pad.l - 6, y + 4);\n ctx.strokeStyle = '#2a2d3a';\n ctx.lineWidth = 0.5;\n ctx.beginPath(); ctx.moveTo(pad.l, y); ctx.lineTo(pad.l + cw, y); ctx.stroke();\n }\n\n // X axis labels (first, middle, last)\n ctx.fillStyle = '#8b8fa3';\n ctx.textAlign = 'center';\n if (data.length > 0) {\n const labels = [0, Math.floor(data.length/2), data.length-1];\n labels.forEach(i => {\n if (i < data.length) {\n const x = pad.l + (i / (points.length - 1)) * cw;\n ctx.fillText(data[i].date.slice(5), x, pad.t + ch + 18);\n }\n });\n }\n}\n\nfunction drawBars(ctx, items, w, h, colors) {\n if (items.length === 0) return;\n const max = Math.max(...items.map(i => i.value), 0.001);\n const pad = { t: 10, r: 10, b: 60, l: 60 };\n const cw = w - pad.l - pad.r;\n const ch = h - pad.t - pad.b;\n const barW = Math.min(40, (cw / items.length) * 0.7);\n const gap = cw / items.length;\n\n items.forEach((item, i) => {\n const barH = (item.value / max) * ch;\n const x = pad.l + i * gap + (gap - barW) / 2;\n const y = pad.t + ch - barH;\n ctx.fillStyle = colors[i % colors.length];\n ctx.beginPath();\n ctx.roundRect(x, y, barW, barH, 3);\n ctx.fill();\n\n // Label\n ctx.fillStyle = '#8b8fa3';\n ctx.font = '11px -apple-system, sans-serif';\n ctx.textAlign = 'center';\n ctx.save();\n ctx.translate(x + barW/2, pad.t + ch + 12);\n ctx.rotate(-0.4);\n ctx.fillText(item.label.length > 14 ? item.label.slice(0,12) + '..' : item.label, 0, 0);\n ctx.restore();\n\n // Value on top\n ctx.fillStyle = '#e1e4ed';\n ctx.textAlign = 'center';\n ctx.fillText(item.fmt, x + barW/2, y - 6);\n });\n}\n\nfunction drawStacked(ctx, series, labels, w, h, colors) {\n if (labels.length === 0) return;\n const pad = { t: 10, r: 10, b: 30, l: 50 };\n const cw = w - pad.l - pad.r;\n const ch = h - pad.t - pad.b;\n\n // Calculate totals for max\n const totals = labels.map((_, i) => series.reduce((s, sr) => s + sr.values[i], 0));\n const max = Math.max(...totals, 1);\n\n const barW = Math.min(30, (cw / labels.length) * 0.7);\n const gap = cw / labels.length;\n\n labels.forEach((_, li) => {\n let yOffset = 0;\n series.forEach((sr, si) => {\n const val = sr.values[li];\n const barH = (val / max) * ch;\n const x = pad.l + li * gap + (gap - barW) / 2;\n const y = pad.t + ch - yOffset - barH;\n ctx.fillStyle = colors[si % colors.length];\n ctx.fillRect(x, y, barW, barH);\n yOffset += barH;\n });\n });\n\n // Legend\n ctx.font = '11px -apple-system, sans-serif';\n series.forEach((sr, i) => {\n const x = pad.l + i * 100;\n ctx.fillStyle = colors[i % colors.length];\n ctx.fillRect(x, h - 16, 10, 10);\n ctx.fillStyle = '#8b8fa3';\n ctx.textAlign = 'left';\n ctx.fillText(sr.name, x + 14, h - 7);\n });\n\n // X axis\n ctx.fillStyle = '#8b8fa3';\n ctx.textAlign = 'center';\n if (data.length > 0) {\n [0, Math.floor(labels.length/2), labels.length-1].forEach(i => {\n if (i < labels.length) {\n const x = pad.l + (i / Math.max(labels.length-1,1)) * cw;\n ctx.fillText(labels[i].slice(5), x, pad.t + ch + 18);\n }\n });\n }\n}\n\nfunction setupCanvas(id) {\n const canvas = document.getElementById(id);\n const dpr = window.devicePixelRatio || 1;\n const rect = canvas.parentElement.getBoundingClientRect();\n const w = rect.width - 40; // account for card padding\n const h = canvas.height;\n canvas.width = w * dpr;\n canvas.height = 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}\n\nfunction renderCostChart() {\n const { ctx, w, h } = setupCanvas('costChart');\n const points = data.map(d => d.cost);\n drawLine(ctx, points, w, h, '#6366f1', 'rgba(99,102,241,0.1)');\n}\n\nfunction renderTokenChart() {\n const { ctx, w, h } = setupCanvas('tokenChart');\n const labels = data.map(d => d.date);\n drawStacked(ctx, [\n { name: 'Input', values: data.map(d => d.input) },\n { name: 'Output', values: data.map(d => d.output) },\n { name: 'Cache R', values: data.map(d => d.cacheRead) },\n { name: 'Cache W', values: data.map(d => d.cacheCreate) },\n ], labels, w, h, ['#3b82f6', '#22c55e', '#06b6d4', '#f59e0b']);\n}\n\nfunction renderAgentChart() {\n const { ctx, w, h } = setupCanvas('agentChart');\n const agentTotals = {};\n data.forEach(d => {\n for (const [id, a] of Object.entries(d.agents)) {\n agentTotals[id] = (agentTotals[id] || 0) + a.cost;\n }\n });\n const items = Object.entries(agentTotals)\n .sort(([,a],[,b]) => b - a)\n .slice(0, 10)\n .map(([id, cost]) => ({ label: id, value: cost, fmt: fmtCost(cost) }));\n drawBars(ctx, items, w, h, ['#6366f1','#3b82f6','#06b6d4','#22c55e','#f59e0b','#ef4444','#a855f7','#ec4899']);\n}\n\nfunction renderBreakdownChart() {\n const { ctx, w, h } = setupCanvas('breakdownChart');\n const totals = { input: 0, output: 0, cacheRead: 0, cacheCreate: 0 };\n data.forEach(d => { totals.input += d.input; totals.output += d.output; totals.cacheRead += d.cacheRead; totals.cacheCreate += d.cacheCreate; });\n const items = [\n { label: 'Input', value: totals.input, fmt: fmtTok(totals.input) },\n { label: 'Output', value: totals.output, fmt: fmtTok(totals.output) },\n { label: 'Cache Read', value: totals.cacheRead, fmt: fmtTok(totals.cacheRead) },\n { label: 'Cache Write', value: totals.cacheCreate, fmt: fmtTok(totals.cacheCreate) },\n ];\n drawBars(ctx, items, w, h, ['#3b82f6','#22c55e','#06b6d4','#f59e0b']);\n}\n\nfunction renderTable() {\n const tbody = document.querySelector('#table tbody');\n tbody.innerHTML = data.slice().reverse().map(d => {\n const top = Object.entries(d.agents).sort(([,a],[,b]) => b.cost - a.cost)[0];\n const topStr = top ? top[0] + ' (' + fmtCost(top[1].cost) + ')' : '-';\n return '<tr>' +\n '<td>' + d.date + '</td>' +\n '<td>' + d.tasks + '</td>' +\n '<td class=\"tok\">' + fmtTok(d.input) + '</td>' +\n '<td class=\"tok\">' + fmtTok(d.output) + '</td>' +\n '<td class=\"tok\">' + fmtTok(d.cacheRead) + '</td>' +\n '<td class=\"tok\">' + fmtTok(d.cacheCreate) + '</td>' +\n '<td class=\"cost\">' + fmtCost(d.cost) + '</td>' +\n '<td>' + topStr + '</td>' +\n '</tr>';\n }).join('');\n}\n\n// Auto-load last 30 days\nsetRange(30);\n`\n\nexport default startUsageDashboard\n"],"mappings":"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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8SJC,EAAQjC","names":["createServer","readdirSync","startUsageDashboard","port","tracker","TokenTracker","createServer","req","res","url","path","from","to","data","loadUsageRange","renderDashboard","dir","files","f","readdirSync","date","usage","tasks","input","output","cacheRead","cacheCreate","cost","agents","id","agent","agentCost","d","CSS","JS","usage_dashboard_default"]}
@@ -0,0 +1,2 @@
1
+ import{a,b}from"./chunk-QZP65I2H.js";import"./chunk-HI24KAEY.js";import"./chunk-4YCH6IZV.js";export{b as setupAllWorkspaces,a as setupWorkspace};
2
+ //# sourceMappingURL=workspace-setup-QQTCJY4B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentix-cli",
3
- "version": "0.8.0",
3
+ "version": "0.13.0",
4
4
  "description": "Self-hosted multi-agent orchestrator — routes Telegram, WhatsApp, crons, and A2A mesh tasks to Claude Code, OpenAI, or any LLM provider",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -52,6 +52,9 @@
52
52
  "clean": "rimraf dist",
53
53
  "format:write": "prettier --write \"src/**/*.{ts,tsx,mdx}\" --cache",
54
54
  "format:check": "prettier --check \"src/**/*.{ts,tsx,mdx}\" --cache",
55
+ "eval": "vitest run test/eval/",
56
+ "eval:track": "TRACK_SCORES=1 vitest run test/eval/real-data-eval.test.ts",
57
+ "usage:track": "tsx src/scripts/track-usage.ts",
55
58
  "prepublishOnly": "npm run build"
56
59
  },
57
60
  "dependencies": {
@@ -1,2 +0,0 @@
1
- import{s as a,t as b,u as c}from"./chunk-F73GPYCO.js";import"./chunk-Z4GC5D6D.js";import"./chunk-FRFR27IN.js";import"./chunk-SFQUP3BP.js";import"./chunk-MGMZNJCE.js";import"./chunk-M7HKBG3V.js";import"./chunk-4YCH6IZV.js";export{a as createAgentContext,b as generate,c as generateStream};
2
- //# sourceMappingURL=agent-K2YOEOJ5.js.map