tokentracker-cli 0.5.69 → 0.5.71

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 (24) hide show
  1. package/README.md +3 -2
  2. package/dashboard/dist/assets/{Card-ClNKd74W.js → Card-5ebScQbM.js} +1 -1
  3. package/dashboard/dist/assets/{DashboardPage-DiUhik_k.js → DashboardPage-B32RhUB1.js} +2 -2
  4. package/dashboard/dist/assets/{FadeIn-c2wFBL_u.js → FadeIn-CHjFUAEe.js} +1 -1
  5. package/dashboard/dist/assets/{IpCheckPage-UPn-zQGB.js → IpCheckPage-CrbKufId.js} +1 -1
  6. package/dashboard/dist/assets/{LeaderboardPage-ZpuPopCf.js → LeaderboardPage-CVKBhGzY.js} +2 -2
  7. package/dashboard/dist/assets/{LeaderboardProfilePage-C62TdxVy.js → LeaderboardProfilePage-CbpzxvLA.js} +1 -1
  8. package/dashboard/dist/assets/{LimitsPage-CQEaB_b2.js → LimitsPage-BwQ4isbM.js} +1 -1
  9. package/dashboard/dist/assets/{SettingsPage-8RdfHCcA.js → SettingsPage-Y3Znzs1i.js} +1 -1
  10. package/dashboard/dist/assets/{WidgetsPage-DiKFOpFH.js → WidgetsPage-tNojCBaj.js} +1 -1
  11. package/dashboard/dist/assets/{download-BmThIfGZ.js → download-CQASvwEL.js} +1 -1
  12. package/dashboard/dist/assets/leaderboard-columns-DFG1TWe9.js +1 -0
  13. package/dashboard/dist/assets/{main-D49FUfq7.js → main-Cv6YpYdZ.js} +16 -15
  14. package/dashboard/dist/assets/{use-limits-display-prefs-BHo0gzBa.js → use-limits-display-prefs-BUrHqTkA.js} +1 -1
  15. package/dashboard/dist/assets/{use-usage-limits-BGttWixw.js → use-usage-limits-D-gv2i1R.js} +1 -1
  16. package/dashboard/dist/brand-logos/kimi.svg +1 -0
  17. package/dashboard/dist/index.html +1 -1
  18. package/dashboard/dist/share.html +1 -1
  19. package/package.json +1 -1
  20. package/src/commands/init.js +11 -0
  21. package/src/commands/status.js +9 -0
  22. package/src/commands/sync.js +26 -0
  23. package/src/lib/rollout.js +172 -0
  24. package/dashboard/dist/assets/leaderboard-columns-9wPbwNaz.js +0 -1
@@ -1 +1 @@
1
- import{r as a}from"./main-D49FUfq7.js";const d=["claude","codex","cursor","gemini","kiro","copilot","antigravity"],v={claude:"Claude",codex:"Codex",cursor:"Cursor",gemini:"Gemini",kiro:"Kiro",copilot:"GitHub Copilot",antigravity:"Antigravity"},k={claude:"/brand-logos/claude-code.svg",codex:"/brand-logos/codex.svg",cursor:"/brand-logos/cursor.svg",gemini:"/brand-logos/gemini.svg",kiro:"/brand-logos/kiro.svg",copilot:"/brand-logos/copilot.svg",antigravity:"/brand-logos/antigravity.svg"},l="tt.limits.providerOrder",g="tt.limits.providerVisibility";function y(){if(typeof window>"u")return[...d];try{const r=window.localStorage.getItem(l);if(!r)return[...d];const s=JSON.parse(r);if(!Array.isArray(s))return[...d];const n=s.filter(c=>d.includes(c));for(const c of d)n.includes(c)||n.push(c);return n}catch{return[...d]}}function m(){const r=Object.fromEntries(d.map(s=>[s,!0]));if(typeof window>"u")return r;try{const s=window.localStorage.getItem(g);if(!s)return r;const n=JSON.parse(s);if(!n||typeof n!="object")return r;const c={...r};for(const u of d)typeof n[u]=="boolean"&&(c[u]=n[u]);return c}catch{return r}}function C(){const[r,s]=a.useState(y),[n,c]=a.useState(m);a.useEffect(()=>{if(!(typeof window>"u"))try{window.localStorage.setItem(l,JSON.stringify(r))}catch{}},[r]),a.useEffect(()=>{if(!(typeof window>"u"))try{window.localStorage.setItem(g,JSON.stringify(n))}catch{}},[n]),a.useEffect(()=>{if(typeof window>"u")return;const o=t=>{t.key===l&&s(y()),t.key===g&&c(m())};return window.addEventListener("storage",o),()=>window.removeEventListener("storage",o)},[]);const u=a.useCallback(o=>{c(t=>({...t,[o]:!t[o]}))},[]),b=a.useCallback(o=>{s(t=>{const e=t.indexOf(o);if(e<=0)return t;const i=[...t];return[i[e-1],i[e]]=[i[e],i[e-1]],i})},[]),p=a.useCallback(o=>{s(t=>{const e=t.indexOf(o);if(e<0||e>=t.length-1)return t;const i=[...t];return[i[e],i[e+1]]=[i[e+1],i[e]],i})},[]),O=a.useCallback((o,t)=>{o!==t&&s(e=>{const i=e.indexOf(o),w=e.indexOf(t);if(i<0||w<0)return e;const f=[...e],[E]=f.splice(i,1);return f.splice(w,0,E),f})},[]),x=a.useCallback(()=>{s([...d]),c(Object.fromEntries(d.map(o=>[o,!0])))},[]),I=a.useMemo(()=>r.filter(o=>n[o]!==!1),[r,n]);return{order:r,visibility:n,visibleOrdered:I,toggle:u,moveUp:b,moveDown:p,moveToward:O,reset:x}}export{k as L,v as a,C as u};
1
+ import{r as a}from"./main-Cv6YpYdZ.js";const d=["claude","codex","cursor","gemini","kiro","copilot","antigravity"],v={claude:"Claude",codex:"Codex",cursor:"Cursor",gemini:"Gemini",kiro:"Kiro",copilot:"GitHub Copilot",antigravity:"Antigravity"},k={claude:"/brand-logos/claude-code.svg",codex:"/brand-logos/codex.svg",cursor:"/brand-logos/cursor.svg",gemini:"/brand-logos/gemini.svg",kiro:"/brand-logos/kiro.svg",copilot:"/brand-logos/copilot.svg",antigravity:"/brand-logos/antigravity.svg"},l="tt.limits.providerOrder",g="tt.limits.providerVisibility";function y(){if(typeof window>"u")return[...d];try{const r=window.localStorage.getItem(l);if(!r)return[...d];const s=JSON.parse(r);if(!Array.isArray(s))return[...d];const n=s.filter(c=>d.includes(c));for(const c of d)n.includes(c)||n.push(c);return n}catch{return[...d]}}function m(){const r=Object.fromEntries(d.map(s=>[s,!0]));if(typeof window>"u")return r;try{const s=window.localStorage.getItem(g);if(!s)return r;const n=JSON.parse(s);if(!n||typeof n!="object")return r;const c={...r};for(const u of d)typeof n[u]=="boolean"&&(c[u]=n[u]);return c}catch{return r}}function C(){const[r,s]=a.useState(y),[n,c]=a.useState(m);a.useEffect(()=>{if(!(typeof window>"u"))try{window.localStorage.setItem(l,JSON.stringify(r))}catch{}},[r]),a.useEffect(()=>{if(!(typeof window>"u"))try{window.localStorage.setItem(g,JSON.stringify(n))}catch{}},[n]),a.useEffect(()=>{if(typeof window>"u")return;const o=t=>{t.key===l&&s(y()),t.key===g&&c(m())};return window.addEventListener("storage",o),()=>window.removeEventListener("storage",o)},[]);const u=a.useCallback(o=>{c(t=>({...t,[o]:!t[o]}))},[]),b=a.useCallback(o=>{s(t=>{const e=t.indexOf(o);if(e<=0)return t;const i=[...t];return[i[e-1],i[e]]=[i[e],i[e-1]],i})},[]),p=a.useCallback(o=>{s(t=>{const e=t.indexOf(o);if(e<0||e>=t.length-1)return t;const i=[...t];return[i[e],i[e+1]]=[i[e+1],i[e]],i})},[]),O=a.useCallback((o,t)=>{o!==t&&s(e=>{const i=e.indexOf(o),w=e.indexOf(t);if(i<0||w<0)return e;const f=[...e],[E]=f.splice(i,1);return f.splice(w,0,E),f})},[]),x=a.useCallback(()=>{s([...d]),c(Object.fromEntries(d.map(o=>[o,!0])))},[]),I=a.useMemo(()=>r.filter(o=>n[o]!==!1),[r,n]);return{order:r,visibility:n,visibleOrdered:I,toggle:u,moveUp:b,moveDown:p,moveToward:O,reset:x}}export{k as L,v as a,C as u};
@@ -1 +1 @@
1
- import{r,aM as l}from"./main-D49FUfq7.js";function y(i){const[o,a]=r.useState(null),[u,s]=r.useState(null),[c,f]=r.useState(!0),n=!!i?.initialRefresh,g=r.useCallback(async()=>{try{const e=await l({refresh:!0});a(e&&typeof e=="object"?e:null),s(null)}catch(e){s(e?.message||String(e))}},[]);return r.useEffect(()=>{let e=!1;return(async()=>{try{const t=await l(n?{refresh:!0}:{});if(e)return;a(t&&typeof t=="object"?t:null),s(null)}catch(t){if(e)return;s(t?.message||String(t))}finally{e||f(!1)}})(),()=>{e=!0}},[n]),{data:o,error:u,isLoading:c,refresh:g}}export{y as u};
1
+ import{r,aM as l}from"./main-Cv6YpYdZ.js";function y(i){const[o,a]=r.useState(null),[u,s]=r.useState(null),[c,f]=r.useState(!0),n=!!i?.initialRefresh,g=r.useCallback(async()=>{try{const e=await l({refresh:!0});a(e&&typeof e=="object"?e:null),s(null)}catch(e){s(e?.message||String(e))}},[]);return r.useEffect(()=>{let e=!1;return(async()=>{try{const t=await l(n?{refresh:!0}:{});if(e)return;a(t&&typeof t=="object"?t:null),s(null)}catch(t){if(e)return;s(t?.message||String(t))}finally{e||f(!1)}})(),()=>{e=!0}},[n]),{data:o,error:u,isLoading:c,refresh:g}}export{y as u};
@@ -0,0 +1 @@
1
+ <svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Kimi</title><path d="M21.846 0a1.923 1.923 0 110 3.846H20.15a.226.226 0 01-.227-.226V1.923C19.923.861 20.784 0 21.846 0z"></path><path d="M11.065 11.199l7.257-7.2c.137-.136.06-.41-.116-.41H14.3a.164.164 0 00-.117.051l-7.82 7.756c-.122.12-.302.013-.302-.179V3.82c0-.127-.083-.23-.185-.23H3.186c-.103 0-.186.103-.186.23V19.77c0 .128.083.23.186.23h2.69c.103 0 .186-.102.186-.23v-3.25c0-.069.025-.135.069-.178l2.424-2.406a.158.158 0 01.205-.023l6.484 4.772a7.677 7.677 0 003.453 1.283c.108.012.2-.095.2-.23v-3.06c0-.117-.07-.212-.164-.227a5.028 5.028 0 01-2.027-.807l-5.613-4.064c-.117-.078-.132-.279-.028-.381z"></path></svg>
@@ -135,7 +135,7 @@
135
135
  ]
136
136
  }
137
137
  </script>
138
- <script type="module" crossorigin src="/assets/main-D49FUfq7.js"></script>
138
+ <script type="module" crossorigin src="/assets/main-Cv6YpYdZ.js"></script>
139
139
  <link rel="stylesheet" crossorigin href="/assets/main-CNzfq4Ln.css">
140
140
  </head>
141
141
  <body>
@@ -51,7 +51,7 @@
51
51
  "description": "Shareable Token Tracker dashboard snapshot."
52
52
  }
53
53
  </script>
54
- <script type="module" crossorigin src="/assets/main-D49FUfq7.js"></script>
54
+ <script type="module" crossorigin src="/assets/main-Cv6YpYdZ.js"></script>
55
55
  <link rel="stylesheet" crossorigin href="/assets/main-CNzfq4Ln.css">
56
56
  </head>
57
57
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tokentracker-cli",
3
- "version": "0.5.69",
3
+ "version": "0.5.71",
4
4
  "description": "Token usage tracker for AI agent CLIs (Claude Code, Codex, Cursor, Kiro, Gemini, OpenCode, OpenClaw, Hermes, GitHub Copilot)",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
@@ -404,6 +404,17 @@ async function applyIntegrationSetup({ home, trackerDir, notifyPath, notifyOrigi
404
404
  summary.push({ label: "Cursor", status: "skipped", detail: "Not installed" });
405
405
  }
406
406
 
407
+ // Kimi: passive reader — no hook installation needed.
408
+ // TokenTracker reads ~/.kimi/sessions/**/wire.jsonl directly.
409
+ {
410
+ const kimiHome = process.env.KIMI_HOME || path.join(home, ".kimi");
411
+ const kimiSessions = path.join(kimiHome, "sessions");
412
+ const fssync = require("node:fs");
413
+ if (fssync.existsSync(kimiSessions)) {
414
+ summary.push({ label: "Kimi Code", status: "detected", detail: "Passive reader (no hook needed)" });
415
+ }
416
+ }
417
+
407
418
  const openclawBefore = await probeOpenclawSessionPluginState({
408
419
  home,
409
420
  trackerDir,
@@ -1,6 +1,7 @@
1
1
  const os = require("node:os");
2
2
  const path = require("node:path");
3
3
  const fs = require("node:fs/promises");
4
+ const fssync = require("node:fs");
4
5
 
5
6
  const { readJson } = require("../lib/fs");
6
7
  const { readCodexNotify, readEveryCodeNotify } = require("../lib/codex-config");
@@ -19,6 +20,7 @@ const { collectTrackerDiagnostics } = require("../lib/diagnostics");
19
20
  const { probeOpenclawHookState } = require("../lib/openclaw-hook");
20
21
  const { probeOpenclawSessionPluginState } = require("../lib/openclaw-session-plugin");
21
22
  const { resolveTrackerPaths } = require("../lib/tracker-paths");
23
+ const { resolveKimiWireFiles } = require("../lib/rollout");
22
24
 
23
25
  async function cmdStatus(argv = []) {
24
26
  const opts = parseArgs(argv);
@@ -112,6 +114,10 @@ async function cmdStatus(argv = []) {
112
114
  const subscriptionLines =
113
115
  subscriptions.length > 0 ? subscriptions.map(formatSubscriptionLine) : [];
114
116
 
117
+ const kimiWireFiles = resolveKimiWireFiles(process.env);
118
+ const kimiHome = process.env.KIMI_HOME || path.join(home, ".kimi");
119
+ const kimiInstalled = fssync.existsSync(path.join(kimiHome, "sessions"));
120
+
115
121
  const copilotToken = readCopilotOauthToken({ home });
116
122
  const copilotOtel = describeCopilotOtelStatus({ home, env: process.env });
117
123
  const copilotLines = formatCopilotLines({ token: copilotToken, otel: copilotOtel });
@@ -138,6 +144,9 @@ async function cmdStatus(argv = []) {
138
144
  `- Opencode plugin: ${opencodePluginConfigured ? "set" : "unset"}`,
139
145
  `- OpenClaw session plugin: ${openclawSessionPluginState?.configured ? "set" : "unset"}`,
140
146
  `- OpenClaw hook (legacy): ${openclawHookState?.configured ? "set" : "unset"}`,
147
+ kimiInstalled
148
+ ? `- Kimi Code: passive reader (${kimiWireFiles.length} wire.jsonl file${kimiWireFiles.length !== 1 ? "s" : ""} found)`
149
+ : null,
141
150
  ...copilotLines,
142
151
  ...subscriptionLines,
143
152
  "",
@@ -25,6 +25,8 @@ const {
25
25
  parseKiroIncremental,
26
26
  parseHermesIncremental,
27
27
  parseCopilotIncremental,
28
+ resolveKimiWireFiles,
29
+ parseKimiIncremental,
28
30
  } = require("../lib/rollout");
29
31
  const { createProgress, renderBar, formatNumber, formatBytes } = require("../lib/progress");
30
32
  const {
@@ -354,6 +356,28 @@ async function cmdSync(argv) {
354
356
  });
355
357
  }
356
358
 
359
+ // ── Kimi (passive wire.jsonl reader) ──
360
+ let kimiResult = { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
361
+ const kimiWireFiles = resolveKimiWireFiles(process.env);
362
+ if (kimiWireFiles.length > 0) {
363
+ if (progress?.enabled) {
364
+ progress.start(`Parsing Kimi Code ${renderBar(0)} | buckets 0`);
365
+ }
366
+ kimiResult = await parseKimiIncremental({
367
+ wireFiles: kimiWireFiles,
368
+ cursors,
369
+ queuePath,
370
+ env: process.env,
371
+ onProgress: (p) => {
372
+ if (!progress?.enabled) return;
373
+ const pct = p.total > 0 ? p.index / p.total : 1;
374
+ progress.update(
375
+ `Parsing Kimi Code ${renderBar(pct)} ${formatNumber(p.index)}/${formatNumber(p.total)} files | buckets ${formatNumber(p.bucketsQueued)}`,
376
+ );
377
+ },
378
+ });
379
+ }
380
+
357
381
  // ── GitHub Copilot CLI (OTEL JSONL files) ──
358
382
  let copilotResult = { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
359
383
  const copilotPaths = resolveCopilotOtelPaths(process.env);
@@ -453,6 +477,7 @@ async function cmdSync(argv) {
453
477
  cursorResult.recordsProcessed +
454
478
  kiroResult.recordsProcessed +
455
479
  hermesResult.recordsProcessed +
480
+ kimiResult.recordsProcessed +
456
481
  copilotResult.recordsProcessed;
457
482
  const totalBuckets =
458
483
  parseResult.bucketsQueued +
@@ -463,6 +488,7 @@ async function cmdSync(argv) {
463
488
  cursorResult.bucketsQueued +
464
489
  kiroResult.bucketsQueued +
465
490
  hermesResult.bucketsQueued +
491
+ kimiResult.bucketsQueued +
466
492
  copilotResult.bucketsQueued;
467
493
  process.stdout.write(
468
494
  [
@@ -2999,6 +2999,175 @@ async function parseHermesIncremental({ dbPath, cursors, queuePath, onProgress }
2999
2999
  return { recordsProcessed: rows.length, eventsAggregated, bucketsQueued };
3000
3000
  }
3001
3001
 
3002
+ // ─────────────────────────────────────────────────────────────────────────────
3003
+ // Kimi — passive JSONL reader (~/.kimi/sessions/**/wire.jsonl)
3004
+ // No hook installation needed; Kimi writes wire.jsonl automatically.
3005
+
3006
+ function resolveKimiDefaultModel(env = process.env) {
3007
+ const fallback = "kimi-for-coding";
3008
+ try {
3009
+ const home = env.HOME || require("node:os").homedir();
3010
+ const cfgPath = path.join(env.KIMI_HOME || path.join(home, ".kimi"), "config.toml");
3011
+ const raw = fssync.readFileSync(cfgPath, "utf8");
3012
+ const defaultMatch = raw.match(/^\s*default_model\s*=\s*"([^"]+)"/m);
3013
+ if (!defaultMatch) return fallback;
3014
+ const sectionKey = defaultMatch[1];
3015
+ const escaped = sectionKey.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3016
+ const sectionRe = new RegExp(
3017
+ `\\[models\\."${escaped}"\\]([\\s\\S]*?)(?:\\n\\[|$)`,
3018
+ );
3019
+ const section = raw.match(sectionRe);
3020
+ if (section) {
3021
+ const modelMatch = section[1].match(/^\s*model\s*=\s*"([^"]+)"/m);
3022
+ if (modelMatch && modelMatch[1]) return modelMatch[1];
3023
+ }
3024
+ if (sectionKey.includes("/")) return sectionKey.split("/").pop();
3025
+ return sectionKey || fallback;
3026
+ } catch {
3027
+ return fallback;
3028
+ }
3029
+ }
3030
+ // ─────────────────────────────────────────────────────────────────────────────
3031
+
3032
+ function resolveKimiWireFiles(env = process.env) {
3033
+ const home = require("node:os").homedir();
3034
+ const kimiHome = env.KIMI_HOME || path.join(home, ".kimi");
3035
+ const sessionsDir = path.join(kimiHome, "sessions");
3036
+ if (!fssync.existsSync(sessionsDir)) return [];
3037
+ const files = [];
3038
+ try {
3039
+ for (const ws of fssync.readdirSync(sessionsDir)) {
3040
+ const wsDir = path.join(sessionsDir, ws);
3041
+ let wsStat;
3042
+ try { wsStat = fssync.statSync(wsDir); } catch { continue; }
3043
+ if (!wsStat.isDirectory()) continue;
3044
+ for (const sess of fssync.readdirSync(wsDir)) {
3045
+ const wireFile = path.join(wsDir, sess, "wire.jsonl");
3046
+ if (fssync.existsSync(wireFile)) files.push(wireFile);
3047
+ }
3048
+ }
3049
+ } catch { /* ignore */ }
3050
+ return files;
3051
+ }
3052
+
3053
+ async function parseKimiIncremental({ wireFiles, cursors, queuePath, onProgress, env, model } = {}) {
3054
+ await ensureDir(path.dirname(queuePath));
3055
+ const kimiState = cursors.kimi && typeof cursors.kimi === "object" ? cursors.kimi : {};
3056
+ const seenIds = new Set(Array.isArray(kimiState.seenIds) ? kimiState.seenIds : []);
3057
+ const fileOffsets =
3058
+ kimiState.fileOffsets && typeof kimiState.fileOffsets === "object"
3059
+ ? { ...kimiState.fileOffsets }
3060
+ : {};
3061
+
3062
+ const files = Array.isArray(wireFiles)
3063
+ ? wireFiles
3064
+ : resolveKimiWireFiles(env || process.env);
3065
+ const kimiModel = model || resolveKimiDefaultModel(env || process.env);
3066
+ if (files.length === 0) {
3067
+ cursors.kimi = { ...kimiState, seenIds: Array.from(seenIds), fileOffsets, updatedAt: new Date().toISOString() };
3068
+ return { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
3069
+ }
3070
+
3071
+ const hourlyState = normalizeHourlyState(cursors?.hourly);
3072
+ const touchedBuckets = new Set();
3073
+ const cb = typeof onProgress === "function" ? onProgress : null;
3074
+ let recordsProcessed = 0;
3075
+ let eventsAggregated = 0;
3076
+
3077
+ for (let fileIdx = 0; fileIdx < files.length; fileIdx++) {
3078
+ const filePath = files[fileIdx];
3079
+ let stat;
3080
+ try { stat = fssync.statSync(filePath); } catch { continue; }
3081
+
3082
+ const prevEntry = fileOffsets[filePath] || {};
3083
+ const prevSize = Number(prevEntry.size) || 0;
3084
+ const prevIno = prevEntry.ino;
3085
+ const inodeChanged = typeof prevIno === "number" && prevIno !== stat.ino;
3086
+ const startOffset = stat.size < prevSize || inodeChanged ? 0 : prevSize;
3087
+ if (stat.size <= startOffset) continue;
3088
+
3089
+ let stream;
3090
+ try {
3091
+ stream = fssync.createReadStream(filePath, { encoding: "utf8", start: startOffset });
3092
+ } catch { continue; }
3093
+ const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
3094
+
3095
+ for await (const line of rl) {
3096
+ if (!line || !line.trim()) continue;
3097
+ let entry;
3098
+ try { entry = JSON.parse(line); } catch { continue; }
3099
+
3100
+ const msg = entry.message;
3101
+ if (!msg || msg.type !== "StatusUpdate") continue;
3102
+
3103
+ const payload = msg.payload;
3104
+ if (!payload) continue;
3105
+ const { token_usage, message_id } = payload;
3106
+ if (!token_usage || !message_id) continue;
3107
+ if (seenIds.has(message_id)) continue;
3108
+
3109
+ recordsProcessed++;
3110
+
3111
+ const input = toNonNegativeInt(token_usage.input_other);
3112
+ const output = toNonNegativeInt(token_usage.output);
3113
+ const cacheRead = toNonNegativeInt(token_usage.input_cache_read);
3114
+ const cacheCreation = toNonNegativeInt(token_usage.input_cache_creation);
3115
+ if (input === 0 && output === 0 && cacheRead === 0 && cacheCreation === 0) {
3116
+ seenIds.add(message_id);
3117
+ continue;
3118
+ }
3119
+
3120
+ const epochSec = entry.timestamp ?? payload.timestamp;
3121
+ if (epochSec == null || !Number.isFinite(Number(epochSec))) continue;
3122
+ const tsIso = new Date(Number(epochSec) * 1000).toISOString();
3123
+ const bucketStart = toUtcHalfHourStart(tsIso);
3124
+ if (!bucketStart) continue;
3125
+
3126
+ const delta = {
3127
+ input_tokens: input,
3128
+ cached_input_tokens: cacheRead,
3129
+ cache_creation_input_tokens: cacheCreation,
3130
+ output_tokens: output,
3131
+ reasoning_output_tokens: 0,
3132
+ total_tokens: input + output + cacheRead + cacheCreation,
3133
+ conversation_count: 1,
3134
+ };
3135
+
3136
+ const bucket = getHourlyBucket(hourlyState, "kimi", kimiModel, bucketStart);
3137
+ addTotals(bucket.totals, delta);
3138
+ touchedBuckets.add(bucketKey("kimi", kimiModel, bucketStart));
3139
+ seenIds.add(message_id);
3140
+ eventsAggregated++;
3141
+
3142
+ if (cb) {
3143
+ cb({
3144
+ index: fileIdx + 1,
3145
+ total: files.length,
3146
+ recordsProcessed,
3147
+ eventsAggregated,
3148
+ bucketsQueued: touchedBuckets.size,
3149
+ });
3150
+ }
3151
+ }
3152
+
3153
+ let postStat = stat;
3154
+ try { postStat = fssync.statSync(filePath); } catch {}
3155
+ fileOffsets[filePath] = { size: postStat.size, mtimeMs: postStat.mtimeMs, ino: postStat.ino };
3156
+ }
3157
+
3158
+ // Cap seenIds to last 10k to bound cursor state size
3159
+ const seenArr = Array.from(seenIds);
3160
+ const cappedSeen = seenArr.length > 10_000 ? seenArr.slice(seenArr.length - 10_000) : seenArr;
3161
+
3162
+ const bucketsQueued = await enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets });
3163
+ const updatedAt = new Date().toISOString();
3164
+ hourlyState.updatedAt = updatedAt;
3165
+ cursors.hourly = hourlyState;
3166
+ cursors.kimi = { ...kimiState, seenIds: cappedSeen, fileOffsets, updatedAt };
3167
+
3168
+ return { recordsProcessed, eventsAggregated, bucketsQueued };
3169
+ }
3170
+
3002
3171
  // ─────────────────────────────────────────────────────────────────────────────
3003
3172
  // GitHub Copilot CLI — OpenTelemetry JSONL exporter
3004
3173
  // User must opt in by setting:
@@ -3209,4 +3378,7 @@ module.exports = {
3209
3378
  parseKiroIncremental,
3210
3379
  parseHermesIncremental,
3211
3380
  parseCopilotIncremental,
3381
+ resolveKimiWireFiles,
3382
+ resolveKimiDefaultModel,
3383
+ parseKimiIncremental,
3212
3384
  };
@@ -1 +0,0 @@
1
- import{ad as l,D as n,az as i}from"./main-D49FUfq7.js";function y(r){let e=0;const o=String(r??"");for(let a=0;a<o.length;a+=1)e=Math.imul(31,e)+o.charCodeAt(a)|0;return Math.abs(e)%360}function m(r){const e=String(r??"").trim();if(!e)return"?";const o=e.split(/\s+/).filter(Boolean);if(o.length>=2){const a=o[0][0]||"",t=o[1][0]||"";return`${a}${t}`.toUpperCase()}return e.slice(0,2).toUpperCase()}const g={sm:"h-7 w-7 min-h-7 min-w-7 text-[10px]",md:"h-8 w-8 min-h-8 min-w-8 text-[11px]",lg:"h-14 w-14 min-h-14 min-w-14 text-base"};function h({avatarUrl:r,displayName:e,seed:o,size:a="md",className:t}){const d=g[a]||g.md,b=y(o??e??""),s=typeof r=="string"?r.trim():"",[p,c]=l.useState(!1);return l.useEffect(()=>{c(!1)},[s]),s&&!p?n.jsx("img",{src:s,alt:"",referrerPolicy:"no-referrer",onError:()=>c(!0),className:i("rounded-full object-cover ring-1 ring-white/10",d,t)}):n.jsx("div",{className:i("flex shrink-0 items-center justify-center rounded-full font-semibold text-white ring-1 ring-white/10",d,t),style:{backgroundColor:`hsl(${b} 42% 34%)`},"aria-hidden":!0,children:m(e)})}const u=new Set(["/brand-logos/cursor.svg","/brand-logos/kiro.svg","/brand-logos/copilot.svg"]);function w({iconSrc:r,label:e}){return n.jsxs("span",{className:"inline-flex items-center gap-3",children:[r?n.jsx("img",{src:r,alt:"",width:16,height:16,className:`h-4 w-4 shrink-0 object-contain opacity-90 ${u.has(r)?"dark:invert":""}`}):null,n.jsx("span",{className:"whitespace-nowrap",children:e})]})}const x=[{key:"gpt_tokens",copyKey:"leaderboard.column.codex",icon:"/brand-logos/codex.svg"},{key:"claude_tokens",copyKey:"leaderboard.column.claude",icon:"/brand-logos/claude-code.svg"},{key:"gemini_tokens",copyKey:"leaderboard.column.gemini",icon:"/brand-logos/gemini.svg"},{key:"cursor_tokens",copyKey:"leaderboard.column.cursor",icon:"/brand-logos/cursor.svg"},{key:"kiro_tokens",copyKey:"leaderboard.column.kiro",icon:"/brand-logos/kiro.svg"},{key:"copilot_tokens",copyKey:"leaderboard.column.copilot",icon:"/brand-logos/copilot.svg"},{key:"opencode_tokens",copyKey:"leaderboard.column.opencode",icon:"/brand-logos/opencode.svg"},{key:"openclaw_tokens",copyKey:"leaderboard.column.openclaw",icon:"/brand-logos/openclaw.svg"},{key:"hermes_tokens",copyKey:"leaderboard.column.hermes",icon:null},{key:"other_tokens",copyKey:"leaderboard.column.supplemental",icon:null}],f="sticky left-0 z-40 w-[72px] min-w-[72px] max-w-[72px] border-r border-oai-gray-200 dark:border-oai-gray-800 bg-white dark:bg-oai-gray-950 px-4 py-4 align-middle",_="sticky left-[72px] z-40 min-w-[140px] max-w-[min(180px,35vw)] border-r border-oai-gray-200 dark:border-oai-gray-800 bg-white dark:bg-oai-gray-950 px-4 py-4 align-middle",v="sticky left-[72px] z-40 min-w-[6rem] border-r border-oai-gray-200 dark:border-oai-gray-800 bg-white dark:bg-oai-gray-950 px-4 py-4";function K(r){return i("sticky left-0 z-30 w-[72px] min-w-[72px] max-w-[72px] border-r border-oai-gray-200 dark:border-oai-gray-800 px-4 py-4 whitespace-nowrap",r?"bg-oai-brand-50 dark:bg-emerald-950":"bg-white dark:bg-oai-gray-950 group-hover:bg-oai-gray-50 dark:group-hover:bg-oai-gray-900/60")}function T(r){return i("sticky left-[72px] z-30 min-w-[140px] max-w-[min(180px,35vw)] border-r border-oai-gray-200 dark:border-oai-gray-800 px-4 py-4 min-w-0",r?"bg-oai-brand-50 dark:bg-emerald-950":"bg-white dark:bg-oai-gray-950 group-hover:bg-oai-gray-50 dark:group-hover:bg-oai-gray-900/60")}function S(r){return i("sticky left-[72px] z-30 min-w-[6rem] border-r border-oai-gray-200 dark:border-oai-gray-800 px-4 py-4 whitespace-nowrap","bg-white dark:bg-oai-gray-950")}export{f as L,_ as a,x as b,T as c,w as d,h as e,S as f,v as g,K as l};