tokentracker-cli 0.5.70 → 0.5.72

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 (26) hide show
  1. package/README.md +3 -2
  2. package/dashboard/dist/assets/{Card-Bmd_CiIj.js → Card-D_q1XGfK.js} +1 -1
  3. package/dashboard/dist/assets/{DashboardPage-o3xjHuSr.js → DashboardPage-CuBSoNgI.js} +2 -2
  4. package/dashboard/dist/assets/{FadeIn-Dqezp4M6.js → FadeIn-ClpHby-T.js} +1 -1
  5. package/dashboard/dist/assets/{IpCheckPage-Dvo1fWrV.js → IpCheckPage-B5TpHE6G.js} +1 -1
  6. package/dashboard/dist/assets/{LeaderboardPage-sarzdedp.js → LeaderboardPage-BOrtGeIf.js} +2 -2
  7. package/dashboard/dist/assets/LeaderboardProfilePage-C8xexZ08.js +1 -0
  8. package/dashboard/dist/assets/{LimitsPage-BYVQqh0y.js → LimitsPage-CERWQyIU.js} +1 -1
  9. package/dashboard/dist/assets/{SettingsPage-C0bLU9fQ.js → SettingsPage-DUwt4x-H.js} +1 -1
  10. package/dashboard/dist/assets/{WidgetsPage-DH1pg04g.js → WidgetsPage-Cmr2tbD7.js} +1 -1
  11. package/dashboard/dist/assets/{download-Dqdzgt-u.js → download-M8e1PJC-.js} +1 -1
  12. package/dashboard/dist/assets/leaderboard-columns-Dcg9r7R2.js +1 -0
  13. package/dashboard/dist/assets/{main-Vhl9rhYB.js → main-D1VdJk4V.js} +16 -15
  14. package/dashboard/dist/assets/{use-limits-display-prefs-CJuYd6SN.js → use-limits-display-prefs-CSj55sfK.js} +1 -1
  15. package/dashboard/dist/assets/{use-usage-limits-BEbR2ySJ.js → use-usage-limits-BuWINUAm.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 +52 -1
  23. package/src/lib/local-api.js +159 -56
  24. package/src/lib/rollout.js +217 -4
  25. package/dashboard/dist/assets/LeaderboardProfilePage-DsoEom4U.js +0 -1
  26. package/dashboard/dist/assets/leaderboard-columns-eDzDr_Xs.js +0 -1
@@ -676,12 +676,21 @@ async function parseOpenclawSessionFile({
676
676
 
677
677
  const model = normalizeModelInput(msg.model) || DEFAULT_MODEL;
678
678
 
679
+ // Per CLAUDE.md: cached_input_tokens = cache reads,
680
+ // cache_creation_input_tokens = cache writes. Also re-derive total_tokens
681
+ // as input + output + cache_creation + cache_read so cost math works
682
+ // even when the source's own totalTokens is stale or rounded.
683
+ const inputTok = Number(usage.input || 0);
684
+ const cacheReadTok = Number(usage.cacheRead || 0);
685
+ const cacheWriteTok = Number(usage.cacheWrite || 0);
686
+ const outputTok = Number(usage.output || 0);
679
687
  const delta = {
680
- input_tokens: Number(usage.input || 0),
681
- cached_input_tokens: Number((usage.cacheRead || 0) + (usage.cacheWrite || 0)),
682
- output_tokens: Number(usage.output || 0),
688
+ input_tokens: inputTok,
689
+ cached_input_tokens: cacheReadTok,
690
+ cache_creation_input_tokens: cacheWriteTok,
691
+ output_tokens: outputTok,
683
692
  reasoning_output_tokens: 0,
684
- total_tokens: Number(usage.totalTokens || 0),
693
+ total_tokens: inputTok + outputTok + cacheReadTok + cacheWriteTok,
685
694
  conversation_count: 1,
686
695
  };
687
696
 
@@ -2083,6 +2092,7 @@ function sameGeminiTotals(a, b) {
2083
2092
  return (
2084
2093
  a.input_tokens === b.input_tokens &&
2085
2094
  a.cached_input_tokens === b.cached_input_tokens &&
2095
+ a.cache_creation_input_tokens === b.cache_creation_input_tokens &&
2086
2096
  a.output_tokens === b.output_tokens &&
2087
2097
  a.reasoning_output_tokens === b.reasoning_output_tokens &&
2088
2098
  a.total_tokens === b.total_tokens
@@ -2097,12 +2107,20 @@ function diffGeminiTotals(current, previous) {
2097
2107
  const totalReset = (current.total_tokens || 0) < (previous.total_tokens || 0);
2098
2108
  if (totalReset) return current;
2099
2109
 
2110
+ // Must include cache_creation_input_tokens in both the equality check and
2111
+ // the delta — OpenCode routes through this diff and its cache.write number
2112
+ // would otherwise be permanently reported as zero. Gemini itself always
2113
+ // emits cache_creation=0 so the extra field is a no-op for Gemini.
2100
2114
  const delta = {
2101
2115
  input_tokens: Math.max(0, (current.input_tokens || 0) - (previous.input_tokens || 0)),
2102
2116
  cached_input_tokens: Math.max(
2103
2117
  0,
2104
2118
  (current.cached_input_tokens || 0) - (previous.cached_input_tokens || 0),
2105
2119
  ),
2120
+ cache_creation_input_tokens: Math.max(
2121
+ 0,
2122
+ (current.cache_creation_input_tokens || 0) - (previous.cache_creation_input_tokens || 0),
2123
+ ),
2106
2124
  output_tokens: Math.max(0, (current.output_tokens || 0) - (previous.output_tokens || 0)),
2107
2125
  reasoning_output_tokens: Math.max(
2108
2126
  0,
@@ -2651,6 +2669,16 @@ function readKiroDbTokens(dbPath, sinceId) {
2651
2669
  // The fallback file does not include per-row timestamps, so newly appended rows are
2652
2670
  // bucketed using the file mtime observed during this sync. We track a separate JSONL
2653
2671
  // cursor so it never shares state with the SQLite path.
2672
+ function countKiroJsonlLines(jsonlPath) {
2673
+ if (!jsonlPath || !fssync.existsSync(jsonlPath)) return 0;
2674
+ try {
2675
+ const raw = fssync.readFileSync(jsonlPath, "utf8");
2676
+ return raw.split("\n").filter((l) => l.trim()).length;
2677
+ } catch (_e) {
2678
+ return 0;
2679
+ }
2680
+ }
2681
+
2654
2682
  function readKiroJsonlTokens(jsonlPath, sinceLineIndex) {
2655
2683
  if (!jsonlPath || !fssync.existsSync(jsonlPath)) {
2656
2684
  return { rows: [], lineCount: 0, reset: false };
@@ -2795,6 +2823,14 @@ async function parseKiroIncremental({ dbPath, jsonlPath, cursors, queuePath, onP
2795
2823
  if (fssync.existsSync(resolvedDbPath)) {
2796
2824
  rows = readKiroDbTokens(resolvedDbPath, lastDbId);
2797
2825
  usingDb = true;
2826
+ // DB and JSONL are siblings for the same usage events. If the DB ever
2827
+ // disappears (corrupted / wiped) and we fall back to JSONL in a later
2828
+ // run, we must not re-read lines that the DB path already consumed.
2829
+ // Advance the JSONL line cursor to the current file tail.
2830
+ if (fssync.existsSync(resolvedJsonlPath)) {
2831
+ const tailLineCount = countKiroJsonlLines(resolvedJsonlPath);
2832
+ if (tailLineCount > nextJsonlLine) nextJsonlLine = tailLineCount;
2833
+ }
2798
2834
  } else if (fssync.existsSync(resolvedJsonlPath)) {
2799
2835
  const jsonlResult = readKiroJsonlTokens(resolvedJsonlPath, lastJsonlLine);
2800
2836
  rows = jsonlResult.rows;
@@ -2999,6 +3035,175 @@ async function parseHermesIncremental({ dbPath, cursors, queuePath, onProgress }
2999
3035
  return { recordsProcessed: rows.length, eventsAggregated, bucketsQueued };
3000
3036
  }
3001
3037
 
3038
+ // ─────────────────────────────────────────────────────────────────────────────
3039
+ // Kimi — passive JSONL reader (~/.kimi/sessions/**/wire.jsonl)
3040
+ // No hook installation needed; Kimi writes wire.jsonl automatically.
3041
+
3042
+ function resolveKimiDefaultModel(env = process.env) {
3043
+ const fallback = "kimi-for-coding";
3044
+ try {
3045
+ const home = env.HOME || require("node:os").homedir();
3046
+ const cfgPath = path.join(env.KIMI_HOME || path.join(home, ".kimi"), "config.toml");
3047
+ const raw = fssync.readFileSync(cfgPath, "utf8");
3048
+ const defaultMatch = raw.match(/^\s*default_model\s*=\s*"([^"]+)"/m);
3049
+ if (!defaultMatch) return fallback;
3050
+ const sectionKey = defaultMatch[1];
3051
+ const escaped = sectionKey.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3052
+ const sectionRe = new RegExp(
3053
+ `\\[models\\."${escaped}"\\]([\\s\\S]*?)(?:\\n\\[|$)`,
3054
+ );
3055
+ const section = raw.match(sectionRe);
3056
+ if (section) {
3057
+ const modelMatch = section[1].match(/^\s*model\s*=\s*"([^"]+)"/m);
3058
+ if (modelMatch && modelMatch[1]) return modelMatch[1];
3059
+ }
3060
+ if (sectionKey.includes("/")) return sectionKey.split("/").pop();
3061
+ return sectionKey || fallback;
3062
+ } catch {
3063
+ return fallback;
3064
+ }
3065
+ }
3066
+ // ─────────────────────────────────────────────────────────────────────────────
3067
+
3068
+ function resolveKimiWireFiles(env = process.env) {
3069
+ const home = require("node:os").homedir();
3070
+ const kimiHome = env.KIMI_HOME || path.join(home, ".kimi");
3071
+ const sessionsDir = path.join(kimiHome, "sessions");
3072
+ if (!fssync.existsSync(sessionsDir)) return [];
3073
+ const files = [];
3074
+ try {
3075
+ for (const ws of fssync.readdirSync(sessionsDir)) {
3076
+ const wsDir = path.join(sessionsDir, ws);
3077
+ let wsStat;
3078
+ try { wsStat = fssync.statSync(wsDir); } catch { continue; }
3079
+ if (!wsStat.isDirectory()) continue;
3080
+ for (const sess of fssync.readdirSync(wsDir)) {
3081
+ const wireFile = path.join(wsDir, sess, "wire.jsonl");
3082
+ if (fssync.existsSync(wireFile)) files.push(wireFile);
3083
+ }
3084
+ }
3085
+ } catch { /* ignore */ }
3086
+ return files;
3087
+ }
3088
+
3089
+ async function parseKimiIncremental({ wireFiles, cursors, queuePath, onProgress, env, model } = {}) {
3090
+ await ensureDir(path.dirname(queuePath));
3091
+ const kimiState = cursors.kimi && typeof cursors.kimi === "object" ? cursors.kimi : {};
3092
+ const seenIds = new Set(Array.isArray(kimiState.seenIds) ? kimiState.seenIds : []);
3093
+ const fileOffsets =
3094
+ kimiState.fileOffsets && typeof kimiState.fileOffsets === "object"
3095
+ ? { ...kimiState.fileOffsets }
3096
+ : {};
3097
+
3098
+ const files = Array.isArray(wireFiles)
3099
+ ? wireFiles
3100
+ : resolveKimiWireFiles(env || process.env);
3101
+ const kimiModel = model || resolveKimiDefaultModel(env || process.env);
3102
+ if (files.length === 0) {
3103
+ cursors.kimi = { ...kimiState, seenIds: Array.from(seenIds), fileOffsets, updatedAt: new Date().toISOString() };
3104
+ return { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
3105
+ }
3106
+
3107
+ const hourlyState = normalizeHourlyState(cursors?.hourly);
3108
+ const touchedBuckets = new Set();
3109
+ const cb = typeof onProgress === "function" ? onProgress : null;
3110
+ let recordsProcessed = 0;
3111
+ let eventsAggregated = 0;
3112
+
3113
+ for (let fileIdx = 0; fileIdx < files.length; fileIdx++) {
3114
+ const filePath = files[fileIdx];
3115
+ let stat;
3116
+ try { stat = fssync.statSync(filePath); } catch { continue; }
3117
+
3118
+ const prevEntry = fileOffsets[filePath] || {};
3119
+ const prevSize = Number(prevEntry.size) || 0;
3120
+ const prevIno = prevEntry.ino;
3121
+ const inodeChanged = typeof prevIno === "number" && prevIno !== stat.ino;
3122
+ const startOffset = stat.size < prevSize || inodeChanged ? 0 : prevSize;
3123
+ if (stat.size <= startOffset) continue;
3124
+
3125
+ let stream;
3126
+ try {
3127
+ stream = fssync.createReadStream(filePath, { encoding: "utf8", start: startOffset });
3128
+ } catch { continue; }
3129
+ const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
3130
+
3131
+ for await (const line of rl) {
3132
+ if (!line || !line.trim()) continue;
3133
+ let entry;
3134
+ try { entry = JSON.parse(line); } catch { continue; }
3135
+
3136
+ const msg = entry.message;
3137
+ if (!msg || msg.type !== "StatusUpdate") continue;
3138
+
3139
+ const payload = msg.payload;
3140
+ if (!payload) continue;
3141
+ const { token_usage, message_id } = payload;
3142
+ if (!token_usage || !message_id) continue;
3143
+ if (seenIds.has(message_id)) continue;
3144
+
3145
+ recordsProcessed++;
3146
+
3147
+ const input = toNonNegativeInt(token_usage.input_other);
3148
+ const output = toNonNegativeInt(token_usage.output);
3149
+ const cacheRead = toNonNegativeInt(token_usage.input_cache_read);
3150
+ const cacheCreation = toNonNegativeInt(token_usage.input_cache_creation);
3151
+ if (input === 0 && output === 0 && cacheRead === 0 && cacheCreation === 0) {
3152
+ seenIds.add(message_id);
3153
+ continue;
3154
+ }
3155
+
3156
+ const epochSec = entry.timestamp ?? payload.timestamp;
3157
+ if (epochSec == null || !Number.isFinite(Number(epochSec))) continue;
3158
+ const tsIso = new Date(Number(epochSec) * 1000).toISOString();
3159
+ const bucketStart = toUtcHalfHourStart(tsIso);
3160
+ if (!bucketStart) continue;
3161
+
3162
+ const delta = {
3163
+ input_tokens: input,
3164
+ cached_input_tokens: cacheRead,
3165
+ cache_creation_input_tokens: cacheCreation,
3166
+ output_tokens: output,
3167
+ reasoning_output_tokens: 0,
3168
+ total_tokens: input + output + cacheRead + cacheCreation,
3169
+ conversation_count: 1,
3170
+ };
3171
+
3172
+ const bucket = getHourlyBucket(hourlyState, "kimi", kimiModel, bucketStart);
3173
+ addTotals(bucket.totals, delta);
3174
+ touchedBuckets.add(bucketKey("kimi", kimiModel, bucketStart));
3175
+ seenIds.add(message_id);
3176
+ eventsAggregated++;
3177
+
3178
+ if (cb) {
3179
+ cb({
3180
+ index: fileIdx + 1,
3181
+ total: files.length,
3182
+ recordsProcessed,
3183
+ eventsAggregated,
3184
+ bucketsQueued: touchedBuckets.size,
3185
+ });
3186
+ }
3187
+ }
3188
+
3189
+ let postStat = stat;
3190
+ try { postStat = fssync.statSync(filePath); } catch {}
3191
+ fileOffsets[filePath] = { size: postStat.size, mtimeMs: postStat.mtimeMs, ino: postStat.ino };
3192
+ }
3193
+
3194
+ // Cap seenIds to last 10k to bound cursor state size
3195
+ const seenArr = Array.from(seenIds);
3196
+ const cappedSeen = seenArr.length > 10_000 ? seenArr.slice(seenArr.length - 10_000) : seenArr;
3197
+
3198
+ const bucketsQueued = await enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets });
3199
+ const updatedAt = new Date().toISOString();
3200
+ hourlyState.updatedAt = updatedAt;
3201
+ cursors.hourly = hourlyState;
3202
+ cursors.kimi = { ...kimiState, seenIds: cappedSeen, fileOffsets, updatedAt };
3203
+
3204
+ return { recordsProcessed, eventsAggregated, bucketsQueued };
3205
+ }
3206
+
3002
3207
  // ─────────────────────────────────────────────────────────────────────────────
3003
3208
  // GitHub Copilot CLI — OpenTelemetry JSONL exporter
3004
3209
  // User must opt in by setting:
@@ -3209,4 +3414,12 @@ module.exports = {
3209
3414
  parseKiroIncremental,
3210
3415
  parseHermesIncremental,
3211
3416
  parseCopilotIncremental,
3417
+ resolveKimiWireFiles,
3418
+ resolveKimiDefaultModel,
3419
+ parseKimiIncremental,
3420
+ // Exposed for regression tests covering cache-token accounting.
3421
+ normalizeGeminiTokens,
3422
+ normalizeOpencodeTokens,
3423
+ sameGeminiTotals,
3424
+ diffGeminiTotals,
3212
3425
  };
@@ -1 +0,0 @@
1
- import{r as n,D as e,aA as D,C as H,aC as W,h as Y,j as Z,aE as G,aI as J,B as a,az as L,ax as R,a9 as E,aJ as q,aK as F}from"./main-Vhl9rhYB.js";import{b as B,d as Q,l as V,f as X,e as ee,L as re,g as ae}from"./leaderboard-columns-eDzDr_Xs.js";const y=18;function O(){return e.jsxs("svg",{"aria-hidden":!0,width:y,height:y,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("circle",{cx:"12",cy:"12",r:"4"}),e.jsx("path",{d:"M12 2v2"}),e.jsx("path",{d:"M12 20v2"}),e.jsx("path",{d:"m4.93 4.93 1.41 1.41"}),e.jsx("path",{d:"m17.66 17.66 1.41 1.41"}),e.jsx("path",{d:"M2 12h2"}),e.jsx("path",{d:"M20 12h2"}),e.jsx("path",{d:"m6.34 17.66-1.41 1.41"}),e.jsx("path",{d:"m19.07 4.93-1.41 1.41"})]})}function P(){return e.jsx("svg",{"aria-hidden":!0,width:y,height:y,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:e.jsx("path",{d:"M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"})})}function te(){return e.jsxs("svg",{"aria-hidden":!0,width:y,height:y,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("rect",{x:"2",y:"3",width:"20",height:"14",rx:"2"}),e.jsx("path",{d:"M8 21h8"}),e.jsx("path",{d:"M12 17v4"})]})}const oe=[{value:"light",label:"Light",Icon:O},{value:"dark",label:"Dark",Icon:P},{value:"system",label:"System",Icon:te}];function se(r){return r==="dark"?P:O}function ne({theme:r,resolvedTheme:s,onSetTheme:b,className:d="",direction:p="down",align:T="right"}){const[c,k]=n.useState(!1),h=n.useRef(null),i=n.useCallback(()=>k(!1),[]);n.useEffect(()=>{if(!c)return;const t=l=>{h.current&&!h.current.contains(l.target)&&i()};return document.addEventListener("mousedown",t),()=>document.removeEventListener("mousedown",t)},[c,i]),n.useEffect(()=>{if(!c)return;const t=l=>{l.key==="Escape"&&i()};return document.addEventListener("keydown",t),()=>document.removeEventListener("keydown",t)},[c,i]);const x=se(s);return e.jsxs("div",{ref:h,className:`relative ${d}`,children:[e.jsx("button",{type:"button","aria-label":"Theme","aria-expanded":c,onClick:()=>k(t=>!t),className:"flex items-center justify-center w-9 h-9 rounded-lg text-oai-gray-600 dark:text-oai-gray-400 hover:bg-oai-gray-100 dark:hover:bg-oai-gray-800 hover:text-oai-black dark:hover:text-white transition-colors",children:e.jsx(x,{})}),c&&e.jsx("div",{className:`absolute z-50 min-w-[140px] py-1 rounded-lg border border-oai-gray-200 dark:border-oai-gray-800 bg-white dark:bg-oai-gray-900 shadow-lg ${p==="up"?"bottom-full mb-1":"top-full mt-1"} ${T==="left"?"left-0":"right-0"}`,children:oe.map(({value:t,label:l,Icon:j})=>{const m=r===t;return e.jsxs("button",{type:"button",onClick:()=>{b(t),i()},className:`flex w-full items-center gap-2.5 px-3 py-2 text-sm transition-colors ${m?"text-oai-black dark:text-white bg-oai-gray-100 dark:bg-oai-gray-800":"text-oai-gray-600 dark:text-oai-gray-400 hover:bg-oai-gray-50 dark:hover:bg-oai-gray-800/60 hover:text-oai-black dark:hover:text-white"}`,children:[e.jsx(j,{}),e.jsx("span",{children:l})]},t)})})]})}function ie(r){if(!r)return a("shared.error.prefix",{error:a("leaderboard.error.unknown")});const s=r?.message||String(r),b=String(s||"").trim()||a("leaderboard.error.unknown");return a("shared.error.prefix",{error:b})}function le(r){return typeof r!="string"?"":r.trim()}function de(r){if(typeof r!="string")return null;const s=r.trim().toLowerCase();return s==="week"||s==="month"||s==="total"?s:null}function me({auth:r,signedIn:s,sessionSoftExpired:b,userId:d}){const p=D(),{theme:T,resolvedTheme:c,setTheme:k}=H(),h=n.useMemo(()=>W(),[]),i=Y(),x=s&&!b,t=n.useMemo(()=>x&&(typeof r=="function"||typeof r=="string"||r&&typeof r=="object")?r:null,[r,x]),l=x?t:null,j=x&&Z(l),m=n.useMemo(()=>{const o=new URLSearchParams(p?.search||"");return de(o.get("period"))||"week"},[p?.search]),_=p?.search||"",[v,w]=n.useState(()=>({loading:!1,error:null,data:null}));n.useEffect(()=>{if(!h&&!i||!d||!i&&(!x||!j))return;let o=!0;return w(f=>({...f,loading:!0,error:null})),(async()=>{const f=await G(l);if(!o)return;if(!f){w({loading:!1,error:null,data:null});return}const $=await J({accessToken:f,userId:d,period:m});o&&w({loading:!1,error:null,data:$})})().catch(f=>{o&&w({loading:!1,error:ie(f),data:null})}),()=>{o=!1}},[x,j,h,l,i,m,d]);const N=v.data,C=N?.from||null,A=N?.to||null,M=N?.generated_at||null,g=N?.entry||null,S=le(g?.display_name)||a("leaderboard.anon_label"),z=a("leaderboard.period.week"),K=a("leaderboard.period.month"),U=a("leaderboard.period.total"),I=m==="month"?K:m==="total"?U:z;let u=null;return d?v.loading?u=e.jsx("div",{className:"px-6 py-12 text-center",children:e.jsx("p",{className:"text-sm text-oai-gray-500 dark:text-oai-gray-400",children:a("leaderboard.loading")})}):v.error?u=e.jsx("div",{className:"px-6 py-12 text-center",children:e.jsx("p",{className:"text-sm text-red-500 dark:text-red-400",children:v.error})}):g?u=e.jsx("div",{className:"w-full overflow-x-auto",children:e.jsxs("table",{className:"min-w-max w-full text-left text-sm",children:[e.jsx("thead",{className:"border-b border-oai-gray-200 dark:border-oai-gray-800",children:e.jsxs("tr",{children:[e.jsx("th",{className:L(re,"font-medium text-oai-gray-500 dark:text-oai-gray-400"),children:a("leaderboard.column.rank")}),e.jsx("th",{className:L(ae,"font-medium text-oai-gray-500 dark:text-oai-gray-400 whitespace-nowrap"),children:a("leaderboard.column.total")}),B.map(o=>e.jsx("th",{className:"px-4 py-4 font-medium text-oai-gray-500 dark:text-oai-gray-400 whitespace-nowrap",children:e.jsx(Q,{iconSrc:o.icon,label:a(o.copyKey)})},o.key))]})}),e.jsx("tbody",{className:"divide-y divide-oai-gray-100 dark:divide-oai-gray-800/50",children:e.jsxs("tr",{className:"transition-colors hover:bg-oai-gray-50 dark:hover:bg-oai-gray-900/60",children:[e.jsx("td",{className:L(V(!1),"font-medium text-oai-gray-500 dark:text-oai-gray-400"),children:g?.rank??a("shared.placeholder.short")}),e.jsx("td",{className:L(X(),"text-oai-gray-700 dark:text-oai-gray-300"),children:R(g?.total_tokens)}),B.map(o=>e.jsx("td",{className:"px-4 py-4 text-oai-gray-500 dark:text-oai-gray-400 whitespace-nowrap",children:R(g?.[o.key])},o.key))]})})]})}):u=e.jsx("div",{className:"px-6 py-12 text-center",children:e.jsx("p",{className:"text-sm text-oai-gray-500 dark:text-oai-gray-400",children:a("leaderboard.empty")})}):u=e.jsx("div",{className:"px-6 py-12 text-center",children:e.jsx("p",{className:"text-sm text-oai-gray-500 dark:text-oai-gray-400",children:a("leaderboard.empty")})}),e.jsxs("div",{className:"flex flex-col min-h-screen bg-oai-white dark:bg-oai-gray-950 text-oai-black dark:text-oai-white font-oai antialiased transition-colors duration-200",children:[e.jsx("header",{className:"sticky top-0 z-50 bg-white/80 dark:bg-oai-gray-950/80 backdrop-blur-md border-b border-oai-gray-200 dark:border-oai-gray-900 transition-colors duration-200",children:e.jsxs("div",{className:"mx-auto flex h-14 max-w-6xl items-center justify-between px-4 sm:px-6",children:[e.jsxs("div",{className:"flex items-center gap-5",children:[e.jsxs(E,{to:"/",className:"flex items-center gap-3 no-underline outline-none rounded focus-visible:ring-2 focus-visible:ring-oai-brand-500 focus-visible:ring-offset-2 dark:ring-offset-oai-gray-950 transition-opacity hover:opacity-80",children:[e.jsx("img",{src:"/app-icon.png",alt:"",width:24,height:24,className:"rounded-md"}),e.jsx("span",{className:"text-sm font-semibold tracking-wide text-oai-black dark:text-white uppercase",children:"Token Tracker"})]}),e.jsx("div",{className:"hidden sm:block",children:e.jsx(q,{})})]}),e.jsxs("div",{className:"flex items-center gap-2 sm:gap-3",children:[e.jsx(E,{to:`/leaderboard${_}`,className:"no-underline inline-flex items-center justify-center h-9 px-5 text-sm font-medium rounded-full shadow-sm ring-1 ring-oai-gray-200 dark:ring-white/10 bg-oai-gray-900 dark:bg-white text-white dark:text-oai-gray-900 hover:bg-oai-gray-800 dark:hover:bg-oai-gray-100 transition-colors",children:a("leaderboard.profile.nav.back")}),e.jsx(ne,{theme:T,resolvedTheme:c,onSetTheme:k}),e.jsx(F,{})]})]})}),e.jsx("main",{className:"flex-1 py-12 sm:py-16",children:e.jsxs("div",{className:"mx-auto max-w-6xl px-4 sm:px-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center gap-6 mb-10",children:[e.jsx(ee,{avatarUrl:g?.avatar_url,displayName:S,seed:typeof d=="string"?d:S,size:"lg",className:"shrink-0 ring-2 ring-oai-gray-200 dark:ring-oai-gray-800"}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("h1",{className:"text-3xl sm:text-4xl font-semibold tracking-tight text-oai-black dark:text-white mb-3",children:S}),e.jsxs("p",{className:"text-oai-gray-500 dark:text-oai-gray-400 text-sm sm:text-base",children:[m==="total"?a("leaderboard.range.total"):C&&A?a("leaderboard.range",{period:I,from:C,to:A}):a("leaderboard.range_loading",{period:I}),M&&e.jsx("span",{className:"ml-2 pl-2 border-l border-oai-gray-200 dark:border-oai-gray-800 inline-block text-oai-gray-400 dark:text-oai-gray-500 text-xs",children:a("leaderboard.generated_at",{ts:M})})]})]})]}),e.jsx("div",{className:"rounded-xl border border-oai-gray-200 dark:border-oai-gray-800 overflow-hidden",children:u})]})}),e.jsx("footer",{className:"border-t border-oai-gray-200 dark:border-oai-gray-900 py-8 transition-colors duration-200",children:e.jsxs("div",{className:"mx-auto flex max-w-6xl items-center justify-between px-4 sm:px-6 text-sm text-oai-gray-400 dark:text-oai-gray-500",children:[e.jsx("p",{children:a("landing.v2.footer.line")}),e.jsx(E,{to:`/leaderboard${_}`,className:"text-oai-gray-400 dark:text-oai-gray-500 hover:text-oai-black dark:hover:text-white transition-colors",children:a("leaderboard.profile.nav.back")})]})})]})}export{me as LeaderboardProfilePage};
@@ -1 +0,0 @@
1
- import{ad as l,D as n,az as i}from"./main-Vhl9rhYB.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};