tokentracker-cli 1.5.16 → 1.5.17

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 (112) hide show
  1. package/dashboard/dist/assets/{AchievementBadge-CnnJGct8.js → AchievementBadge-BiEoQE7Z.js} +1 -1
  2. package/dashboard/dist/assets/{AchievementsPage-CFkUJVxy.js → AchievementsPage-4g0Q8O0U.js} +2 -2
  3. package/dashboard/dist/assets/{AchievementsSection-CoLQX04M.js → AchievementsSection-D5dyOWFj.js} +1 -1
  4. package/dashboard/dist/assets/{BadgeDetailModal-s8rObEHY.js → BadgeDetailModal-Bz067XUw.js} +1 -1
  5. package/dashboard/dist/assets/{BotAnimated-BmBnL-i8.js → BotAnimated-CFiGrlrg.js} +1 -1
  6. package/dashboard/dist/assets/{Card-BIqie5mN.js → Card-CkYKahsn.js} +1 -1
  7. package/dashboard/dist/assets/{CloudCheckoutPage-B_c8Q58A.js → CloudCheckoutPage-BCzIRPkW.js} +1 -1
  8. package/dashboard/dist/assets/{CloudPage-CfW_pDf2.js → CloudPage-C0MZTK-9.js} +2 -2
  9. package/dashboard/dist/assets/{CommandPalette-BRryGPVJ.js → CommandPalette-DwSGE7c-.js} +1 -1
  10. package/dashboard/dist/assets/{CommunityStatsModal-Cyh1Q9Fw.js → CommunityStatsModal-B80ps9B5.js} +1 -1
  11. package/dashboard/dist/assets/{ConfirmModal-DWBYqpLJ.js → ConfirmModal-xthCJoY5.js} +1 -1
  12. package/dashboard/dist/assets/{Controls-CPSiCzVW.js → Controls-DZ9vKkCI.js} +1 -1
  13. package/dashboard/dist/assets/{DashboardPage-JcS1xwUm.js → DashboardPage-C4SwA5lD.js} +1 -1
  14. package/dashboard/dist/assets/{DateRangePopover-DjuS6888.js → DateRangePopover-D8ihZ5SK.js} +1 -1
  15. package/dashboard/dist/assets/{DevicePage-DZ3qiDbT.js → DevicePage-OVnpUpAc.js} +1 -1
  16. package/dashboard/dist/assets/{DialogClose-CfORRnoT.js → DialogClose-DpueWMdH.js} +1 -1
  17. package/dashboard/dist/assets/DialogDescription-CNb40Z5w.js +1 -0
  18. package/dashboard/dist/assets/{DialogTitle-DZO6-sTI.js → DialogTitle-Be_-fYZA.js} +1 -1
  19. package/dashboard/dist/assets/{ElectricLogo-BzR7mRin.js → ElectricLogo-BJek75ac.js} +1 -1
  20. package/dashboard/dist/assets/{FadeIn-BxHaUvz_.js → FadeIn-HIpnpyJ-.js} +1 -1
  21. package/dashboard/dist/assets/{HeaderGithubStar-KGzKAmuQ.js → HeaderGithubStar-Dj0guZ3R.js} +1 -1
  22. package/dashboard/dist/assets/{HoverTooltip-C6pASVDN.js → HoverTooltip-B3p_QB2m.js} +1 -1
  23. package/dashboard/dist/assets/{IpCheckPage-BJ8TROZC.js → IpCheckPage-DrxLV2uL.js} +1 -1
  24. package/dashboard/dist/assets/{LandingPage-B15GRFpI.js → LandingPage-C3RPJvXW.js} +2 -2
  25. package/dashboard/dist/assets/{LeaderboardPage-C3hJ2Gh3.js → LeaderboardPage-CkVKRCA7.js} +2 -2
  26. package/dashboard/dist/assets/{LeaderboardProBadge-CRfBTxpt.js → LeaderboardProBadge-C39qylf0.js} +1 -1
  27. package/dashboard/dist/assets/{LeaderboardProfileModal-DTGmcjWF.js → LeaderboardProfileModal-D1DEHNRN.js} +3 -3
  28. package/dashboard/dist/assets/{LeaderboardProfilePage-BD04D7ML.js → LeaderboardProfilePage-CoBBl1-f.js} +1 -1
  29. package/dashboard/dist/assets/{LimitsPage-LsDCIUKd.js → LimitsPage-BnjPGpcE.js} +1 -1
  30. package/dashboard/dist/assets/{LocalOnlyNotice-B3XQKD8k.js → LocalOnlyNotice-CqCRY_ls.js} +1 -1
  31. package/dashboard/dist/assets/{LoginCard-DF1XcskU.js → LoginCard-BeA3kcgy.js} +1 -1
  32. package/dashboard/dist/assets/{LoginModal-DuyVT0Tt.js → LoginModal-D9S7DnuH.js} +1 -1
  33. package/dashboard/dist/assets/{LoginPage-kge4kJKa.js → LoginPage-CXRATGB_.js} +1 -1
  34. package/dashboard/dist/assets/{PetPage-DuYtsKza.js → PetPage-0_l-kTr4.js} +2 -2
  35. package/dashboard/dist/assets/{PopoverPopup-BkNNS3VG.js → PopoverPopup-CfPgHc44.js} +1 -1
  36. package/dashboard/dist/assets/{ProviderIcon-z2TKXPlS.js → ProviderIcon-DtjD5jVb.js} +1 -1
  37. package/dashboard/dist/assets/{ResetPasswordPage-CXM9E6d1.js → ResetPasswordPage-Bt8QpFOe.js} +1 -1
  38. package/dashboard/dist/assets/{Select-CeoAayzi.js → Select-BgQXA6kK.js} +1 -1
  39. package/dashboard/dist/assets/{SelectItemText-CRxvAgUV.js → SelectItemText-C7hWQpTf.js} +1 -1
  40. package/dashboard/dist/assets/{SelfHostPage-Cavstn-d.js → SelfHostPage-CUK_eL6K.js} +1 -1
  41. package/dashboard/dist/assets/{ServiceStatusPage-CdIeM_DX.js → ServiceStatusPage-CF0nAsAf.js} +1 -1
  42. package/dashboard/dist/assets/{SessionsPage-DPihAS26.js → SessionsPage-CE2cz-4_.js} +1 -1
  43. package/dashboard/dist/assets/{SettingsPage-zxOsLeE5.js → SettingsPage-su2wAKfz.js} +3 -3
  44. package/dashboard/dist/assets/{SkillsPage-BRGonzsC.js → SkillsPage-Bp0PnSf_.js} +1 -1
  45. package/dashboard/dist/assets/{TokenGalaxy-D9-huQJ_.js → TokenGalaxy-CjY25cur.js} +1 -1
  46. package/dashboard/dist/assets/{TooltipPopup-BS99Tf44.js → TooltipPopup-DDztBp5x.js} +1 -1
  47. package/dashboard/dist/assets/{TrendMonitor-DlNT4ObY.js → TrendMonitor-CDaOhv8o.js} +1 -1
  48. package/dashboard/dist/assets/{WidgetsPage-DTFnmTwq.js → WidgetsPage-CjaQe3QN.js} +1 -1
  49. package/dashboard/dist/assets/{WrappedPage-DwMdnusQ.js → WrappedPage-P4LVouC8.js} +1 -1
  50. package/dashboard/dist/assets/{__vite-browser-external-DR_a-OTS.js → __vite-browser-external-CzHn8J8J.js} +2 -2
  51. package/dashboard/dist/assets/{agent-logos-D6kTooyz.js → agent-logos-CS9Iaf0t.js} +1 -1
  52. package/dashboard/dist/assets/{arrow-left-jpuJhYL4.js → arrow-left-nH7mwAsq.js} +1 -1
  53. package/dashboard/dist/assets/{arrow-right-n1hLkwiK.js → arrow-right-BoRjpMCP.js} +1 -1
  54. package/dashboard/dist/assets/{arrow-up-right-fZmEfh7R.js → arrow-up-right-Cg0soM7i.js} +1 -1
  55. package/dashboard/dist/assets/{calendar-days-B0LdECvD.js → calendar-days-6BSY0SCe.js} +1 -1
  56. package/dashboard/dist/assets/{check-CcnNd8bi.js → check-Ldxu9X3c.js} +1 -1
  57. package/dashboard/dist/assets/{chevron-down-DhbHBjVC.js → chevron-down-Cl1UIsFC.js} +1 -1
  58. package/dashboard/dist/assets/{cloud-checkout-9XOoux-p.js → cloud-checkout-CgoKsrLa.js} +1 -1
  59. package/dashboard/dist/assets/{composite-DIDAkYhy.js → composite-CqtsbFSD.js} +1 -1
  60. package/dashboard/dist/assets/{copy-BNDBunFG.js → copy-CHDv4TDb.js} +1 -1
  61. package/dashboard/dist/assets/{download-wlqdqJmq.js → download-bExf6Ccu.js} +1 -1
  62. package/dashboard/dist/assets/{external-link-BvssZ_45.js → external-link-DPe3LHcW.js} +1 -1
  63. package/dashboard/dist/assets/{flame-DP8IUT3E.js → flame-CYUEYQbn.js} +1 -1
  64. package/dashboard/dist/assets/{format-tokens-DMsx_fWk.js → format-tokens-CJ73U0H5.js} +1 -1
  65. package/dashboard/dist/assets/{gift-zF4D6O4a.js → gift-BCmo7fKV.js} +1 -1
  66. package/dashboard/dist/assets/{icons-Batw5aOg.js → icons-BtAa7a8Q.js} +1 -1
  67. package/dashboard/dist/assets/{index-Dc8PQ8ZR.js → index--VJpPvce.js} +1 -1
  68. package/dashboard/dist/assets/{index-3qKpTOzz.js → index-CKwNx_s1.js} +1 -1
  69. package/dashboard/dist/assets/{index-dCfimErX.js → index-CSFt_XvV.js} +1 -1
  70. package/dashboard/dist/assets/{index-Cqla2Zq5.js → index-CyhRNpQp.js} +1 -1
  71. package/dashboard/dist/assets/{info-DcUyOPKG.js → info-Cc5_kre6.js} +1 -1
  72. package/dashboard/dist/assets/{link-2-CS-cWLmx.js → link-2-_RZOZ7kJ.js} +1 -1
  73. package/dashboard/dist/assets/{loader-circle-DKc-gwgL.js → loader-circle-7GinPf0v.js} +1 -1
  74. package/dashboard/dist/assets/{local-usage-transfer-bHATORmq.js → local-usage-transfer-Cx5WBzma.js} +1 -1
  75. package/dashboard/dist/assets/{modifiers.esm-B4QifJzx.js → modifiers.esm-CO1bm3IT.js} +1 -1
  76. package/dashboard/dist/assets/{monitor-smartphone-D8vpN9Jv.js → monitor-smartphone-CjBB2EQT.js} +1 -1
  77. package/dashboard/dist/assets/{play-D70P7DVT.js → play-B9AHJ0ir.js} +1 -1
  78. package/dashboard/dist/assets/{plus-YomnSdqY.js → plus-BYHC32xe.js} +1 -1
  79. package/dashboard/dist/assets/{provider-display-VXu7Hzwq.js → provider-display-N2l_YZhb.js} +1 -1
  80. package/dashboard/dist/assets/{react-CUO9Gs2G.js → react-DSS6zSQ7.js} +1 -1
  81. package/dashboard/dist/assets/{safePolygon-CbVKM3Lv.js → safePolygon-BdbLh1jE.js} +1 -1
  82. package/dashboard/dist/assets/{search-BUi1hAmV.js → search-D89mjm04.js} +1 -1
  83. package/dashboard/dist/assets/{server-B-agbJYI.js → server-PR9yTCiu.js} +1 -1
  84. package/dashboard/dist/assets/{shield-check-yHx3fQDo.js → shield-check-BYLC3hFn.js} +1 -1
  85. package/dashboard/dist/assets/{skills-api-DojEO2dS.js → skills-api-CM8yP8ZQ.js} +1 -1
  86. package/dashboard/dist/assets/{sortable.esm-r4Lz4ugj.js → sortable.esm-4l8igdkd.js} +1 -1
  87. package/dashboard/dist/assets/{store-GzQbKyT-.js → store-uku0hfBl.js} +1 -1
  88. package/dashboard/dist/assets/{terminal-BLCZgZTm.js → terminal-CQsyMIKh.js} +1 -1
  89. package/dashboard/dist/assets/{trash-BFGtCBJS.js → trash-Du6DwmPp.js} +1 -1
  90. package/dashboard/dist/assets/{use-community-stats-DGdLAa8L.js → use-community-stats-BI2Vkwhm.js} +1 -1
  91. package/dashboard/dist/assets/{use-latest-request-guard-l39bM4s0.js → use-latest-request-guard-AGXK-7W_.js} +1 -1
  92. package/dashboard/dist/assets/{use-limits-display-prefs-JcWgMNA0.js → use-limits-display-prefs-XaEErSEN.js} +1 -1
  93. package/dashboard/dist/assets/{use-native-settings-0sXFw6mq.js → use-native-settings-BzNwI3lk.js} +1 -1
  94. package/dashboard/dist/assets/{use-ordered-list-mRdyZ18r.js → use-ordered-list-BUkFot2m.js} +1 -1
  95. package/dashboard/dist/assets/use-reduced-motion-Dl-5CnUW.js +1 -0
  96. package/dashboard/dist/assets/{use-transform-CbJqMa_Y.js → use-transform-CRTGmr0C.js} +1 -1
  97. package/dashboard/dist/assets/{use-usage-limits-qQKS4sHR.js → use-usage-limits-DMHAKEU7.js} +1 -1
  98. package/dashboard/dist/assets/{useCurrency-BJyZCVtd.js → useCurrency-D7bYEIAY.js} +1 -1
  99. package/dashboard/dist/assets/{usePositioner-zsiJqVGU.js → usePositioner-PRBIy_6t.js} +1 -1
  100. package/dashboard/dist/assets/{useTokenFormat-DxEKSp5H.js → useTokenFormat-CGacmoDz.js} +1 -1
  101. package/dashboard/dist/assets/{zap-D40-8VPk.js → zap-B8svUQzd.js} +1 -1
  102. package/dashboard/dist/index.html +1 -1
  103. package/dashboard/dist/ip-check.html +1 -1
  104. package/dashboard/dist/leaderboard.html +1 -1
  105. package/dashboard/dist/share.html +1 -1
  106. package/package.json +1 -1
  107. package/src/lib/dsh-session.js +81 -0
  108. package/src/lib/pricing/seed-snapshot.json +1 -1
  109. package/src/lib/session-analytics.js +4 -1
  110. package/src/lib/session-performance.js +15 -0
  111. package/dashboard/dist/assets/DialogDescription-ChihKLnm.js +0 -1
  112. package/dashboard/dist/assets/use-reduced-motion-D2g3iGbi.js +0 -1
@@ -8,6 +8,7 @@
8
8
  const fs = require("node:fs");
9
9
  const path = require("node:path");
10
10
  const crypto = require("node:crypto");
11
+ const { createDshPerformanceCollector, normalizePerformance } = require("./session-performance");
11
12
  const {
12
13
  isDshSessionLogName,
13
14
  parseDshVersion,
@@ -101,6 +102,48 @@ function eventTimestampMs(entry) {
101
102
  return Number.isFinite(time) && time >= MIN_DSH_TIMESTAMP_MS ? time : null;
102
103
  }
103
104
 
105
+ function firstStreamTokenTime(stream) {
106
+ // DSH v4 stores raw chunks and packed delta runs together. Only non-empty
107
+ // deltas (or a name-bearing tool delta) mark a token; block-start does not.
108
+ for (const record of stream) {
109
+ if (record?.type === "chunk") {
110
+ const chunk = record.chunk;
111
+ const token = ["text-delta", "reasoning-delta"].includes(chunk?.type)
112
+ ? typeof chunk.text === "string" && chunk.text.length > 0
113
+ : chunk?.type === "tool-call-delta" && (
114
+ (typeof chunk.argumentsDelta === "string" && chunk.argumentsDelta.length > 0)
115
+ || (typeof chunk.name === "string" && chunk.name.length > 0));
116
+ const time = eventTimestampMs(record);
117
+ if (token && time !== null) return time;
118
+ } else if (["text-chunks", "reasoning-chunks", "tool-call-chunks"].includes(record?.type)) {
119
+ const tool = record.type === "tool-call-chunks";
120
+ const fragments = tool ? record.args : record.texts;
121
+ let time = eventTimestampMs({ time: record.time0 });
122
+ if (time === null || !Array.isArray(fragments)) continue;
123
+ for (let index = 0; index < fragments.length; index += 1) {
124
+ if (index > 0) {
125
+ const gap = record.dt?.[index - 1];
126
+ if (typeof gap !== "number" || !Number.isFinite(gap)) break;
127
+ time += gap;
128
+ }
129
+ if ((typeof fragments[index] === "string" && fragments[index].length > 0)
130
+ || (tool && typeof record.name === "string" && record.name.length > 0)) return time;
131
+ }
132
+ }
133
+ }
134
+ return null;
135
+ }
136
+
137
+ function messageTiming(data, step, end) {
138
+ if (!step || step.failed || data?.interrupted || step.turn !== data?.turn || step.step !== data?.step) return null;
139
+ const stream = Array.isArray(data?.stream) ? data.stream : null;
140
+ if (stream) {
141
+ const finish = stream.findLast((record) => record?.type === "chunk" && record.chunk?.type === "finish");
142
+ if (!finish || !finish.chunk.reason?.kind || ["error", "aborted"].includes(finish.chunk.reason.kind)) return null;
143
+ }
144
+ return { start: step.ts, end, firstToken: stream ? firstStreamTokenTime(stream) : null };
145
+ }
146
+
104
147
  function directoryEntryIs(entry, fullPath, kind) {
105
148
  const check = kind === "dir" ? entry.isDirectory() : entry.isFile();
106
149
  if (check) return true;
@@ -279,6 +322,7 @@ async function parseDshTranscript(filePath) {
279
322
  events: [],
280
323
  };
281
324
  const lines = text.split("\n");
325
+ let openStep = null;
282
326
  for (let index = 0; index < lines.length; index += 1) {
283
327
  const line = lines[index];
284
328
  if (!line) continue;
@@ -292,6 +336,33 @@ async function parseDshTranscript(filePath) {
292
336
  const data = entry.data && typeof entry.data === "object" ? entry.data : null;
293
337
  const seq = Number.isFinite(entry.seq) ? entry.seq : index;
294
338
  switch (entry.type) {
339
+ case "step/start": {
340
+ openStep = Number.isInteger(data?.turn) && Number.isInteger(data?.step)
341
+ ? { turn: data.turn, step: data.step, ts: eventTimestampMs(entry), failed: false } : null;
342
+ break;
343
+ }
344
+ case "assistant/attempt":
345
+ case "assistant/chunk": {
346
+ // A retry's step time includes failed work/backoff, so it cannot be a
347
+ // clean request sample even if the eventual message reports usage.
348
+ // v4 records the failed try as assistant/attempt. v1 has no attempt
349
+ // event: the failed try ends as a top-level assistant/chunk whose
350
+ // chunk is a finish with an error or aborted reason.
351
+ const chunk = data?.chunk;
352
+ const failedFinish = entry.type === "assistant/chunk"
353
+ && chunk?.type === "finish"
354
+ && ["error", "aborted"].includes(chunk.reason?.kind);
355
+ if ((entry.type === "assistant/attempt" || failedFinish)
356
+ && openStep && openStep.turn === data?.turn && openStep.step === data?.step) {
357
+ openStep.failed = true;
358
+ }
359
+ break;
360
+ }
361
+ case "step/end":
362
+ case "turn/start":
363
+ case "turn/end":
364
+ openStep = null;
365
+ break;
295
366
  case "session": {
296
367
  transcript.header = entry;
297
368
  break;
@@ -329,6 +400,8 @@ async function parseDshTranscript(filePath) {
329
400
  const ts = eventTimestampMs(entry);
330
401
  const model = modelName(message?.source?.model) || transcript.fallbackModel || "unknown";
331
402
  const delta = dshUsageDelta(data?.usage);
403
+ const timing = messageTiming(data, openStep, ts);
404
+ openStep = null;
332
405
  if (delta) {
333
406
  transcript.events.push({
334
407
  kind: "usage",
@@ -336,6 +409,7 @@ async function parseDshTranscript(filePath) {
336
409
  ts,
337
410
  model,
338
411
  delta,
412
+ timing,
339
413
  });
340
414
  }
341
415
  break;
@@ -405,6 +479,7 @@ function buildRow(transcript, owners) {
405
479
  const times = new Set();
406
480
  const agentTypes = new Map();
407
481
  const modelsForEdits = new Map();
482
+ const performanceCollector = createDshPerformanceCollector();
408
483
  let turns = 0;
409
484
  let edits = 0;
410
485
  let retries = 0;
@@ -451,6 +526,9 @@ function buildRow(transcript, owners) {
451
526
  addUsage(modelRow, delta);
452
527
  modelRow.usage_events += 1;
453
528
  modelUsage.set(model, modelRow);
529
+ if (event.timing) performanceCollector.consumeUsage({
530
+ model, outputTokens: delta.output_tokens + delta.reasoning_output_tokens, ...event.timing,
531
+ });
454
532
  if (event.ts != null) {
455
533
  const bucketTime = new Date(Math.floor(event.ts / 60000) * 60000).toISOString();
456
534
  const key = `${model}\u0000${bucketTime}`;
@@ -478,9 +556,11 @@ function buildRow(transcript, owners) {
478
556
  const gap = orderedTimes[index] - orderedTimes[index - 1];
479
557
  if (gap > 0 && gap <= DSH_ACTIVE_GAP_MS) activeMs += gap;
480
558
  }
559
+ const performance = performanceCollector.finish();
481
560
  const models = [...modelUsage.values()].map((row) => ({
482
561
  ...row,
483
562
  edit_turns: modelsForEdits.get(row.model) || 0,
563
+ performance: performance.byModel.get(row.model) || normalizePerformance(),
484
564
  }));
485
565
  // A session that only handshook (no user turn, no usage) has nothing to say.
486
566
  if (!tokens.total_tokens && !turns) return null;
@@ -507,6 +587,7 @@ function buildRow(transcript, owners) {
507
587
  started_at: orderedTimes.length ? new Date(orderedTimes[0]).toISOString() : null,
508
588
  ended_at: orderedTimes.length ? new Date(orderedTimes.at(-1)).toISOString() : null,
509
589
  active_ms: activeMs,
590
+ performance: performance.performance,
510
591
  provenance: {
511
592
  source: "local-session-log",
512
593
  confidence: "observed",