tokentracker-cli 0.96.4 → 0.97.2

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 (110) hide show
  1. package/README.de.md +3 -3
  2. package/README.ja.md +3 -3
  3. package/README.ko.md +3 -3
  4. package/README.md +7 -5
  5. package/README.zh-CN.md +3 -3
  6. package/dashboard/dist/assets/{AchievementBadge-CCcvmz6R.js → AchievementBadge-Bf2T612R.js} +1 -1
  7. package/dashboard/dist/assets/{AchievementsPage-C5jdktOK.js → AchievementsPage-CnkSNpJx.js} +2 -2
  8. package/dashboard/dist/assets/{AchievementsSection-BFMtUzn1.js → AchievementsSection-CPwsy04Y.js} +1 -1
  9. package/dashboard/dist/assets/{BadgeDetailModal-Be8gM7tM.js → BadgeDetailModal-BJBrgn24.js} +1 -1
  10. package/dashboard/dist/assets/{BotAnimated-CXTGR71z.js → BotAnimated-BJM20N9T.js} +1 -1
  11. package/dashboard/dist/assets/{Card-CsUsp3CV.js → Card-BRWOMoBk.js} +1 -1
  12. package/dashboard/dist/assets/{ClawdAnimated-BEjpZjEE.js → ClawdAnimated-CtX8cne4.js} +2 -2
  13. package/dashboard/dist/assets/{CommandPalette-CHc_Z1r8.js → CommandPalette-C8BwOnSn.js} +1 -1
  14. package/dashboard/dist/assets/{CommunityStatsModal-Gs6kZ_Mp.js → CommunityStatsModal-BGMbgSjq.js} +1 -1
  15. package/dashboard/dist/assets/{ConfirmModal-niHkpv2O.js → ConfirmModal-ZZXg_OLV.js} +1 -1
  16. package/dashboard/dist/assets/{Controls-X2Z1UNUx.js → Controls-VDvgw_ed.js} +1 -1
  17. package/dashboard/dist/assets/{DashboardPage-B66s3Exi.js → DashboardPage-BcJGzQWK.js} +1 -1
  18. package/dashboard/dist/assets/{DevicePage-DQdLdEI8.js → DevicePage-CP5m8azV.js} +1 -1
  19. package/dashboard/dist/assets/{DialogClose-CCUjTxl8.js → DialogClose-8pTCallP.js} +1 -1
  20. package/dashboard/dist/assets/DialogDescription-DRQEfAWH.js +1 -0
  21. package/dashboard/dist/assets/{DialogTitle-CgkUGAag.js → DialogTitle-BWYdq4TT.js} +1 -1
  22. package/dashboard/dist/assets/{FadeIn-D4QD1bPo.js → FadeIn-CEJfaKnL.js} +1 -1
  23. package/dashboard/dist/assets/{HeaderGithubStar-D0my-Z3a.js → HeaderGithubStar-Bg2vijF8.js} +1 -1
  24. package/dashboard/dist/assets/{HoverTooltip-nSWgrKlK.js → HoverTooltip-B03JQ3PO.js} +1 -1
  25. package/dashboard/dist/assets/{IpCheckPage-4hfqHAgi.js → IpCheckPage-DYZucBOf.js} +1 -1
  26. package/dashboard/dist/assets/{LandingPage-wIc4tVRI.js → LandingPage-m-byhnVx.js} +2 -2
  27. package/dashboard/dist/assets/{LeaderboardAvatar-DGlN8Vy8.js → LeaderboardAvatar-JtGhJC1s.js} +1 -1
  28. package/dashboard/dist/assets/{LeaderboardPage-CybuzE87.js → LeaderboardPage-vVDKFLhl.js} +2 -2
  29. package/dashboard/dist/assets/{LeaderboardProfileModal-D9la3tNd.js → LeaderboardProfileModal-Cm4DDrcY.js} +3 -3
  30. package/dashboard/dist/assets/{LeaderboardProfilePage-gxXSeJYb.js → LeaderboardProfilePage-bKbMm856.js} +1 -1
  31. package/dashboard/dist/assets/{LimitsPage-CZH3G54Y.js → LimitsPage-B271tZOj.js} +1 -1
  32. package/dashboard/dist/assets/{LocalOnlyNotice-Ckc7zohC.js → LocalOnlyNotice-DKIxuBP0.js} +1 -1
  33. package/dashboard/dist/assets/{LoginCard-BqeRHqWK.js → LoginCard-DA46RXDo.js} +1 -1
  34. package/dashboard/dist/assets/{LoginModal-BjH6aIBG.js → LoginModal-PxTgIoLk.js} +1 -1
  35. package/dashboard/dist/assets/{LoginPage-BOyPLNU3.js → LoginPage-uEUnU7NP.js} +1 -1
  36. package/dashboard/dist/assets/{PetPage-BXRXG40D.js → PetPage-DDPZtxMw.js} +1 -1
  37. package/dashboard/dist/assets/{PopoverPopup-Dad1ZYVd.js → PopoverPopup-DWIMb8D6.js} +1 -1
  38. package/dashboard/dist/assets/{ProviderIcon-BDmrNJSl.js → ProviderIcon-DqqwXu3b.js} +1 -1
  39. package/dashboard/dist/assets/{ResetPasswordPage-CZpE6qfa.js → ResetPasswordPage-BVuJTR9A.js} +1 -1
  40. package/dashboard/dist/assets/{SegmentedControl-CE1hrQFi.js → SegmentedControl-iHtWKWtc.js} +1 -1
  41. package/dashboard/dist/assets/{Select-YVj7u6Nv.js → Select-Cr9wq8mD.js} +1 -1
  42. package/dashboard/dist/assets/{SelectItemText-BMYGgQ3o.js → SelectItemText-BWnP4yuq.js} +1 -1
  43. package/dashboard/dist/assets/{ServiceStatusPage-HehjDbZg.js → ServiceStatusPage-DLuiUUYV.js} +1 -1
  44. package/dashboard/dist/assets/{SessionsPage-Chvu4YqZ.js → SessionsPage-CBAH4ieT.js} +1 -1
  45. package/dashboard/dist/assets/{SettingsPage-BXjS7u9_.js → SettingsPage-Djku-i8K.js} +2 -2
  46. package/dashboard/dist/assets/{SkillsPage-q3Rjlj9h.js → SkillsPage-DtBRoB8R.js} +1 -1
  47. package/dashboard/dist/assets/{TokenGalaxy-BqZyj82r.js → TokenGalaxy-nvyPu5eV.js} +1 -1
  48. package/dashboard/dist/assets/{ToolbarRootContext-Ch8ueI_C.js → ToolbarRootContext-DhpHv55w.js} +1 -1
  49. package/dashboard/dist/assets/{TrendMonitor-C2aTL9p1.js → TrendMonitor-CCzwGDst.js} +1 -1
  50. package/dashboard/dist/assets/{WidgetsPage-DYaIai8j.js → WidgetsPage-CcWCidAd.js} +1 -1
  51. package/dashboard/dist/assets/{WrappedPage-51B0v-Sr.js → WrappedPage-B6dn8eyh.js} +1 -1
  52. package/dashboard/dist/assets/__vite-browser-external-sJsF0ioo.js +45 -0
  53. package/dashboard/dist/assets/{agent-logos-DXrPSAdX.js → agent-logos-Dh2k8E_G.js} +1 -1
  54. package/dashboard/dist/assets/{arrow-up-right-BFkf7l0U.js → arrow-up-right-BLDQog1A.js} +1 -1
  55. package/dashboard/dist/assets/{check--N8wmgIJ.js → check-DNq_ySSn.js} +1 -1
  56. package/dashboard/dist/assets/{composite-zF5Pj94e.js → composite-CSBcryzA.js} +1 -1
  57. package/dashboard/dist/assets/{copy-BG0JMr6A.js → copy-DHRrNtRb.js} +1 -1
  58. package/dashboard/dist/assets/{download-CPFJf-Sf.js → download-CluyujgG.js} +1 -1
  59. package/dashboard/dist/assets/{external-link-D2yF0kgP.js → external-link-Cf12tdLf.js} +1 -1
  60. package/dashboard/dist/assets/{flame-l460AFx9.js → flame-CJEYinxo.js} +1 -1
  61. package/dashboard/dist/assets/{format-tokens-DKO4ljuH.js → format-tokens-CqiCmYtk.js} +1 -1
  62. package/dashboard/dist/assets/{icons-RoxRGkz4.js → icons-DD8OvYVG.js} +1 -1
  63. package/dashboard/dist/assets/{index--ouT5L4N.js → index-21lDN4rA.js} +1 -1
  64. package/dashboard/dist/assets/{index-PTJ4368-.js → index-Cm8jn8Va.js} +1 -1
  65. package/dashboard/dist/assets/{index-DhyLCvvv.js → index-DLLivlEh.js} +1 -1
  66. package/dashboard/dist/assets/{info-DNWMO4Ca.js → info-dv3Y0z8Q.js} +1 -1
  67. package/dashboard/dist/assets/{link-2-DzWXAz1h.js → link-2-CWHBxVuk.js} +1 -1
  68. package/dashboard/dist/assets/{loader-circle-BzGMqXNu.js → loader-circle-9l5p9Dwa.js} +1 -1
  69. package/dashboard/dist/assets/{maximize-2-Dkpyk4x3.js → maximize-2-DQ2t3MJB.js} +1 -1
  70. package/dashboard/dist/assets/{modifiers.esm-lggHUQpW.js → modifiers.esm-Cwj0l9Zb.js} +1 -1
  71. package/dashboard/dist/assets/{monitor-smartphone-Ck0-gz9l.js → monitor-smartphone-B-9at3iV.js} +1 -1
  72. package/dashboard/dist/assets/{plus-qTJpnn43.js → plus-C_CTQjDD.js} +1 -1
  73. package/dashboard/dist/assets/{provider-display-psY26qmp.js → provider-display-XJQod7k9.js} +2 -2
  74. package/dashboard/dist/assets/{react-CYS24KmX.js → react-xH4nkyuj.js} +1 -1
  75. package/dashboard/dist/assets/{search-CUzE6zxr.js → search-Ut41Fw1G.js} +1 -1
  76. package/dashboard/dist/assets/{skills-api-D9SzxPFG.js → skills-api-B7lb1cjO.js} +1 -1
  77. package/dashboard/dist/assets/{sortable.esm-Bl2hAUyR.js → sortable.esm-BUPRsWL6.js} +1 -1
  78. package/dashboard/dist/assets/{store-mHSJAJtE.js → store-DneqOW0h.js} +1 -1
  79. package/dashboard/dist/assets/{terminal-BlQNEvn1.js → terminal-DPQyZyHR.js} +1 -1
  80. package/dashboard/dist/assets/{trash-CHdgmOyk.js → trash-CVdV1bBR.js} +1 -1
  81. package/dashboard/dist/assets/{use-community-stats-DUiCs91N.js → use-community-stats-DB98TGn9.js} +1 -1
  82. package/dashboard/dist/assets/{use-latest-request-guard-ehXfkvuU.js → use-latest-request-guard-DK3KulKx.js} +1 -1
  83. package/dashboard/dist/assets/{use-limits-display-prefs-CcwwQ0Fq.js → use-limits-display-prefs-BACCRUMZ.js} +1 -1
  84. package/dashboard/dist/assets/{use-ordered-list-CCOtI3Wa.js → use-ordered-list-DnKFdI9a.js} +1 -1
  85. package/dashboard/dist/assets/use-reduced-motion-BfdrKOsS.js +1 -0
  86. package/dashboard/dist/assets/{use-session-efficiency-pref-CYRDpcc_.js → use-session-efficiency-pref-BTm6RoSm.js} +1 -1
  87. package/dashboard/dist/assets/{use-transform-btLlTJpj.js → use-transform-DweC2iKa.js} +1 -1
  88. package/dashboard/dist/assets/{use-usage-limits-BGr5sR-c.js → use-usage-limits-CN5xWIBs.js} +1 -1
  89. package/dashboard/dist/assets/{useCurrency-CNutuEKd.js → useCurrency-CFjvWawL.js} +1 -1
  90. package/dashboard/dist/assets/{useTokenFormat-C0bAJFMC.js → useTokenFormat-Cf81HqWi.js} +1 -1
  91. package/dashboard/dist/assets/{zap-B2fbyjbc.js → zap-Vx_j5oJN.js} +1 -1
  92. package/dashboard/dist/index.html +13 -11
  93. package/dashboard/dist/ip-check.html +1 -1
  94. package/dashboard/dist/leaderboard.html +1 -1
  95. package/dashboard/dist/llms.txt +3 -2
  96. package/dashboard/dist/share.html +1 -1
  97. package/package.json +2 -2
  98. package/src/commands/init.js +1 -0
  99. package/src/commands/status.js +13 -0
  100. package/src/commands/sync.js +46 -0
  101. package/src/lib/codex-rollout-parser.js +48 -1
  102. package/src/lib/codex-service-tier.js +49 -0
  103. package/src/lib/pricing/curated-overrides.json +2 -1
  104. package/src/lib/pricing/index.js +68 -4
  105. package/src/lib/pricing/seed-snapshot.json +1 -1
  106. package/src/lib/rollout.js +283 -34
  107. package/src/lib/session-analytics.js +11 -0
  108. package/dashboard/dist/assets/DialogDescription-CjMjYG3N.js +0 -1
  109. package/dashboard/dist/assets/__vite-browser-external-Cp7dNuCm.js +0 -45
  110. package/dashboard/dist/assets/use-reduced-motion-CDlahPqe.js +0 -1
@@ -21,6 +21,11 @@ const {
21
21
  currentCodexModel,
22
22
  snapshotCodexModelAttributionState,
23
23
  } = require("./codex-model-attribution");
24
+ const {
25
+ CODEX_SERVICE_TIER_MARKER,
26
+ readCodexServiceTier,
27
+ isPriorityServiceTier,
28
+ } = require("./codex-service-tier");
24
29
  const {
25
30
  DEVIN_TABLE_PROBE_SQL,
26
31
  devinUsageSql,
@@ -471,6 +476,7 @@ async function parseRolloutIncremental({
471
476
  ? prev.tokenUsageBaselines || null
472
477
  : null;
473
478
  const lastModel = sameInode && !truncated ? prev.lastModel || null : null;
479
+ const lastServiceTier = sameInode && !truncated ? prev.lastServiceTier || null : null;
474
480
  const modelAttributionState = sameInode && !truncated
475
481
  ? prev.modelAttributionState || null
476
482
  : null;
@@ -551,6 +557,7 @@ async function parseRolloutIncremental({
551
557
  lastTotal,
552
558
  tokenUsageBaselines,
553
559
  lastModel,
560
+ lastServiceTier,
554
561
  modelAttributionState,
555
562
  projectState,
556
563
  projectMetaCache,
@@ -566,6 +573,7 @@ async function parseRolloutIncremental({
566
573
  lastTotal,
567
574
  tokenUsageBaselines,
568
575
  lastModel,
576
+ lastServiceTier,
569
577
  modelAttributionState,
570
578
  hourlyState,
571
579
  touchedBuckets,
@@ -589,6 +597,7 @@ async function parseRolloutIncremental({
589
597
  lastTotal: result.lastTotal,
590
598
  tokenUsageBaselines: result.tokenUsageBaselines,
591
599
  lastModel: result.lastModel,
600
+ lastServiceTier: result.lastServiceTier || null,
592
601
  modelAttributionState: result.modelAttributionState,
593
602
  updatedAt: new Date().toISOString(),
594
603
  };
@@ -2060,6 +2069,7 @@ async function parseRolloutFile({
2060
2069
  lastTotal,
2061
2070
  tokenUsageBaselines,
2062
2071
  lastModel,
2072
+ lastServiceTier,
2063
2073
  modelAttributionState: previousModelAttributionState,
2064
2074
  hourlyState,
2065
2075
  touchedBuckets,
@@ -2086,6 +2096,7 @@ async function parseRolloutFile({
2086
2096
  lastTotal,
2087
2097
  tokenUsageBaselines,
2088
2098
  lastModel,
2099
+ lastServiceTier: typeof lastServiceTier === "string" ? lastServiceTier : null,
2089
2100
  modelAttributionState: previousModelAttributionState,
2090
2101
  eventsAggregated: 0,
2091
2102
  projectFileContexts,
@@ -2098,6 +2109,12 @@ async function parseRolloutFile({
2098
2109
  });
2099
2110
 
2100
2111
  let model = typeof lastModel === "string" ? lastModel : null;
2112
+ // Codex writes thread_settings_applied before the turn_context of the turn it
2113
+ // takes effect on, and token_count rows carry no turn id, so a row's tier is
2114
+ // whatever the last such record said. A session's first turn has none, and
2115
+ // most CLI sessions have none at all — that stays null, and null is billed at
2116
+ // Standard rather than guessed from the current config.
2117
+ let serviceTier = typeof lastServiceTier === "string" ? lastServiceTier : null;
2101
2118
  const modelAttributionState = createCodexModelAttributionState(
2102
2119
  previousModelAttributionState || { model },
2103
2120
  );
@@ -2148,7 +2165,10 @@ async function parseRolloutFile({
2148
2165
  line.includes('"cwd"') ||
2149
2166
  line.includes('"current_date"') ||
2150
2167
  line.includes('"forked_from_id"'));
2151
- if (!maybeTokenCount && !maybeTurnContext && !maybeModelReroute) {
2168
+ const maybeServiceTier =
2169
+ !maybeTokenCount && !maybeModelReroute && !maybeTurnContext &&
2170
+ line.includes(CODEX_SERVICE_TIER_MARKER);
2171
+ if (!maybeTokenCount && !maybeTurnContext && !maybeModelReroute && !maybeServiceTier) {
2152
2172
  if (invalidRecordPolicy === "throw" || !record.terminated) {
2153
2173
  try {
2154
2174
  JSON.parse(line);
@@ -2174,6 +2194,12 @@ async function parseRolloutFile({
2174
2194
  applyCodexModelEvent(modelAttributionState, obj);
2175
2195
  model = currentCodexModel(modelAttributionState) || model;
2176
2196
 
2197
+ const appliedServiceTier = readCodexServiceTier(obj);
2198
+ if (appliedServiceTier) {
2199
+ serviceTier = appliedServiceTier;
2200
+ continue;
2201
+ }
2202
+
2177
2203
  if (
2178
2204
  (obj?.type === "turn_context" || obj?.type === "session_meta") &&
2179
2205
  obj?.payload &&
@@ -2301,6 +2327,9 @@ async function parseRolloutFile({
2301
2327
 
2302
2328
  const bucket = getHourlyBucket(hourlyState, source, model, bucketStart);
2303
2329
  addTotals(bucket.totals, delta);
2330
+ // Only the model bucket gets the subset: the project bucket below carries
2331
+ // no model, so no per-model rate can be applied to it anyway.
2332
+ if (isPriorityServiceTier(serviceTier)) addPriorityUsage(bucket.totals, delta);
2304
2333
  touchedBuckets.add(bucketKey(source, model, bucketStart));
2305
2334
  if (currentProjectKey && projectState && projectTouchedBuckets) {
2306
2335
  const projectBucket = getProjectBucket(
@@ -2321,6 +2350,7 @@ async function parseRolloutFile({
2321
2350
  lastTotal: latestTotal,
2322
2351
  tokenUsageBaselines: snapshotUsageBaselines(usageDeltaState),
2323
2352
  lastModel: model,
2353
+ lastServiceTier: serviceTier,
2324
2354
  modelAttributionState: snapshotCodexModelAttributionState(modelAttributionState),
2325
2355
  eventsAggregated,
2326
2356
  projectFileContexts,
@@ -2333,6 +2363,7 @@ async function scanRolloutProjectFileContexts({
2333
2363
  lastTotal,
2334
2364
  tokenUsageBaselines,
2335
2365
  lastModel,
2366
+ lastServiceTier,
2336
2367
  modelAttributionState,
2337
2368
  projectState,
2338
2369
  projectMetaCache,
@@ -2351,6 +2382,7 @@ async function scanRolloutProjectFileContexts({
2351
2382
  lastTotal,
2352
2383
  tokenUsageBaselines,
2353
2384
  lastModel,
2385
+ lastServiceTier: lastServiceTier || null,
2354
2386
  modelAttributionState,
2355
2387
  eventsAggregated: 0,
2356
2388
  projectFileContexts,
@@ -2428,6 +2460,7 @@ async function scanRolloutProjectFileContexts({
2428
2460
  lastTotal,
2429
2461
  tokenUsageBaselines,
2430
2462
  lastModel,
2463
+ lastServiceTier: lastServiceTier || null,
2431
2464
  modelAttributionState,
2432
2465
  eventsAggregated: 0,
2433
2466
  projectFileContexts,
@@ -3003,6 +3036,7 @@ async function enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets })
3003
3036
  billable_total_tokens: totals.billable_total_tokens ?? totals.total_tokens,
3004
3037
  total_cost_usd: totals.total_cost_usd || 0,
3005
3038
  usage_precision: usagePrecision || undefined,
3039
+ ...prioritySubsetOf(totals),
3006
3040
  conversation_count: totals.conversation_count,
3007
3041
  }),
3008
3042
  );
@@ -3083,6 +3117,7 @@ async function enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets })
3083
3117
  billable_total_tokens: unknownBucket.totals.billable_total_tokens ?? unknownBucket.totals.total_tokens,
3084
3118
  total_cost_usd: unknownBucket.totals.total_cost_usd || 0,
3085
3119
  usage_precision: usagePrecision || undefined,
3120
+ ...prioritySubsetOf(unknownBucket.totals),
3086
3121
  conversation_count: unknownBucket.totals.conversation_count,
3087
3122
  }),
3088
3123
  );
@@ -3131,6 +3166,7 @@ async function enqueueTouchedBuckets({ queuePath, hourlyState, touchedBuckets })
3131
3166
  total_tokens: group.totals.total_tokens,
3132
3167
  billable_total_tokens: group.totals.billable_total_tokens ?? group.totals.total_tokens,
3133
3168
  total_cost_usd: group.totals.total_cost_usd || 0,
3169
+ ...prioritySubsetOf(group.totals),
3134
3170
  conversation_count: group.totals.conversation_count,
3135
3171
  }),
3136
3172
  );
@@ -3716,7 +3752,43 @@ function initTotals() {
3716
3752
  };
3717
3753
  }
3718
3754
 
3755
+ // Observed-subset markers, same shape as the session sidecar's
3756
+ // long_context_* columns: "how much of the columns above came from requests on
3757
+ // the priority (Astra Fast) service tier". They annotate the existing columns
3758
+ // and are NEVER part of any sum — total_tokens stays
3759
+ // input + output + cache_creation + cache_read + reasoning_output. They are
3760
+ // omitted entirely when zero so no other provider's queue rows change.
3761
+ const PRIORITY_SUBSET_FIELDS = [
3762
+ ["priority_input_tokens", "input_tokens"],
3763
+ ["priority_cached_input_tokens", "cached_input_tokens"],
3764
+ ["priority_cache_creation_input_tokens", "cache_creation_input_tokens"],
3765
+ ["priority_output_tokens", "output_tokens"],
3766
+ ["priority_reasoning_output_tokens", "reasoning_output_tokens"],
3767
+ ];
3768
+
3769
+ // The whole delta belongs to a priority request, so every base column it
3770
+ // carries is priority usage.
3771
+ function addPriorityUsage(target, delta) {
3772
+ for (const [field, base] of PRIORITY_SUBSET_FIELDS) {
3773
+ const value = Number(delta?.[base] || 0);
3774
+ if (value > 0) target[field] = (Number(target[field]) || 0) + value;
3775
+ }
3776
+ }
3777
+
3778
+ function prioritySubsetOf(totals) {
3779
+ const subset = {};
3780
+ for (const [field] of PRIORITY_SUBSET_FIELDS) {
3781
+ const value = Number(totals?.[field]) || 0;
3782
+ if (value > 0) subset[field] = value;
3783
+ }
3784
+ return subset;
3785
+ }
3786
+
3719
3787
  function addTotals(target, delta) {
3788
+ for (const [field] of PRIORITY_SUBSET_FIELDS) {
3789
+ const value = Number(delta?.[field]) || 0;
3790
+ if (value > 0) target[field] = (Number(target[field]) || 0) + value;
3791
+ }
3720
3792
  target.input_tokens += delta.input_tokens || 0;
3721
3793
  target.cached_input_tokens += delta.cached_input_tokens || 0;
3722
3794
  target.cache_creation_input_tokens += delta.cache_creation_input_tokens || 0;
@@ -3731,6 +3803,11 @@ function addTotals(target, delta) {
3731
3803
  }
3732
3804
 
3733
3805
  function subtractTotals(target, totals) {
3806
+ for (const [field] of PRIORITY_SUBSET_FIELDS) {
3807
+ const current = Number(target[field]) || 0;
3808
+ if (current <= 0) continue;
3809
+ target[field] = Math.max(0, current - (Number(totals?.[field]) || 0));
3810
+ }
3734
3811
  target.input_tokens = Math.max(0, target.input_tokens - (totals.input_tokens || 0));
3735
3812
  target.cached_input_tokens = Math.max(
3736
3813
  0,
@@ -3764,7 +3841,7 @@ function subtractTotals(target, totals) {
3764
3841
  }
3765
3842
 
3766
3843
  function totalsKey(totals) {
3767
- return [
3844
+ const base = [
3768
3845
  totals.input_tokens || 0,
3769
3846
  totals.cached_input_tokens || 0,
3770
3847
  totals.cache_creation_input_tokens || 0,
@@ -3775,6 +3852,10 @@ function totalsKey(totals) {
3775
3852
  totals.total_cost_usd || 0,
3776
3853
  totals.conversation_count || 0,
3777
3854
  ].join("|");
3855
+ // Appended only when a priority subset exists, so buckets that never see the
3856
+ // tier keep their previously persisted queuedKey and are not re-enqueued.
3857
+ const priority = PRIORITY_SUBSET_FIELDS.map(([field]) => Number(totals[field]) || 0);
3858
+ return priority.some((value) => value > 0) ? `${base}|p:${priority.join(",")}` : base;
3778
3859
  }
3779
3860
 
3780
3861
  function toUtcHalfHourStart(ts) {
@@ -10815,8 +10896,10 @@ function resolveOmpAgentDir(env = process.env) {
10815
10896
  return ompHome ? path.join(ompHome, "agent") : null;
10816
10897
  }
10817
10898
 
10818
- function resolveOmpSessionFiles(env = process.env) {
10819
- const agentDir = resolveOmpAgentDir(env);
10899
+ // Session-file discovery is shared with OmO (omo), which persists the exact
10900
+ // same on-disk layout under its own agent dir:
10901
+ // <agentDir>/sessions/--<cwd-encoded>--/<timestamp>_<sessionId>.jsonl
10902
+ function collectPiStyleSessionFiles(agentDir) {
10820
10903
  if (!agentDir) return [];
10821
10904
  const sessionsDir = path.join(agentDir, "sessions");
10822
10905
  if (!fssync.existsSync(sessionsDir)) return [];
@@ -10841,6 +10924,10 @@ function resolveOmpSessionFiles(env = process.env) {
10841
10924
  return files;
10842
10925
  }
10843
10926
 
10927
+ function resolveOmpSessionFiles(env = process.env) {
10928
+ return collectPiStyleSessionFiles(resolveOmpAgentDir(env));
10929
+ }
10930
+
10844
10931
  // Subagent transcripts live in a directory named after the session file:
10845
10932
  // ~/.omp/agent/sessions/<cwd>/<session>.jsonl (main agent)
10846
10933
  // ~/.omp/agent/sessions/<cwd>/<session>/<Agent>.jsonl (task subagent)
@@ -10849,8 +10936,8 @@ function resolveOmpSessionFiles(env = process.env) {
10849
10936
  // rel path <= 2 segments → main, deeper → subagent/advisor), so we mirror
10850
10937
  // that: everything below the cwd level is subagent traffic. Session dirs also
10851
10938
  // hold non-JSONL artefacts (*.bash-original.log, *.md) — skipped by extension.
10852
- function resolveOmpSubagentFiles(env = process.env) {
10853
- const agentDir = resolveOmpAgentDir(env);
10939
+ // OmO nests the same way, so it reuses this walker.
10940
+ function collectPiStyleSubagentFiles(agentDir) {
10854
10941
  if (!agentDir) return [];
10855
10942
  const sessionsDir = path.join(agentDir, "sessions");
10856
10943
  if (!fssync.existsSync(sessionsDir)) return [];
@@ -10898,20 +10985,24 @@ function resolveOmpSubagentFiles(env = process.env) {
10898
10985
  return files;
10899
10986
  }
10900
10987
 
10988
+ function resolveOmpSubagentFiles(env = process.env) {
10989
+ return collectPiStyleSubagentFiles(resolveOmpAgentDir(env));
10990
+ }
10991
+
10901
10992
  function resolveOmpDefaultModel() {
10902
10993
  // oh-my-pi has no global default model setting; model is per-message.
10903
10994
  return "omp-unknown";
10904
10995
  }
10905
10996
 
10906
- const OMP_HEADER_SCAN_MAX_BYTES = 65536;
10997
+ const PI_STYLE_HEADER_SCAN_MAX_BYTES = 65536;
10907
10998
 
10908
- async function resolveOmpFileCwd(filePath) {
10999
+ async function readPiStyleSessionCwd(filePath) {
10909
11000
  let stream;
10910
11001
  try {
10911
11002
  stream = fssync.createReadStream(filePath, {
10912
11003
  encoding: "utf8",
10913
11004
  start: 0,
10914
- end: OMP_HEADER_SCAN_MAX_BYTES,
11005
+ end: PI_STYLE_HEADER_SCAN_MAX_BYTES,
10915
11006
  });
10916
11007
  } catch {
10917
11008
  return null;
@@ -10932,6 +11023,95 @@ async function resolveOmpFileCwd(filePath) {
10932
11023
  return null;
10933
11024
  }
10934
11025
 
11026
+ async function resolveOmpFileCwd(filePath) {
11027
+ return readPiStyleSessionCwd(filePath);
11028
+ }
11029
+
11030
+ // ─────────────────────────────────────────────────────────────────────────────
11031
+ // OmO (omo) — passive JSONL reader (~/.omo/agent/sessions/**/*.jsonl)
11032
+ //
11033
+ // OmO shares oh-my-pi's session persistence format, so it reuses the same
11034
+ // collectors and parser. Layout:
11035
+ // ~/.omo/agent/sessions/--<cwd-encoded>--/<timestamp>_<sessionId>.jsonl
11036
+ //
11037
+ // First line is the type:"session" header (carries the real, unencoded cwd).
11038
+ // Only type:"message" lines with message.role=="assistant" carry usage:
11039
+ //
11040
+ // {
11041
+ // "type": "message",
11042
+ // "id": "7ae3734f", ← 8-char dedup key
11043
+ // "timestamp": "2026-08-27T23:28:16.699Z",
11044
+ // "message": {
11045
+ // "role": "assistant",
11046
+ // "provider": "xai",
11047
+ // "model": "grok-4.6",
11048
+ // "usage": {
11049
+ // "input": 28646, "output": 630, "cacheRead": 512, "cacheWrite": 0,
11050
+ // "reasoning": 218, "totalTokens": 29788,
11051
+ // "cost": { ... } ← OmO's own estimate; ignored, we price it
11052
+ // },
11053
+ // "timestamp": 1787873284870 ← ms epoch, preferred for bucketing
11054
+ // }
11055
+ // }
11056
+ //
11057
+ // Two deliberate differences from oh-my-pi:
11058
+ // 1. The reasoning field is `reasoning`, not `reasoningTokens`.
11059
+ // 2. Reasoning is a SUBSET of `output`, and `totalTokens` excludes it —
11060
+ // verified across a 2,586-message corpus where
11061
+ // input+output+cacheRead+cacheWrite === totalTokens for every row, and
11062
+ // `usage.cost` bills no separate reasoning component. So omo follows the
11063
+ // Codex convention: reasoning_output_tokens is informational and must not
11064
+ // be billed on top of output (see computeRowCost in lib/pricing/index.js).
11065
+ //
11066
+ // OmO is a router — the upstream model name is recorded per message and there
11067
+ // is no global default (fallback: "omo-unknown").
11068
+ //
11069
+ // Path overrides are TokenTracker-only (TOKENTRACKER_OMO_AGENT_DIR /
11070
+ // TOKENTRACKER_OMO_HOME / OMO_HOME). PI_CONFIG_DIR and PI_CODING_AGENT_DIR are
11071
+ // deliberately NOT honored here: those belong to pi/omp, and routing them to a
11072
+ // third provider would reintroduce the ambiguity decidePiCodingAgentDirOwner
11073
+ // exists to resolve.
11074
+ // ─────────────────────────────────────────────────────────────────────────────
11075
+
11076
+ function resolveOmoHome(env = process.env) {
11077
+ if (env.TOKENTRACKER_OMO_HOME) return expandHomePath(env.TOKENTRACKER_OMO_HOME, env);
11078
+ if (env.OMO_HOME) return expandHomePath(env.OMO_HOME, env);
11079
+ const home = env.HOME || require("node:os").homedir();
11080
+ if (process.platform === "win32") {
11081
+ return pickWin32ProviderPath({
11082
+ env,
11083
+ nativeValue: path.join(home, ".omo"),
11084
+ wslProviderDir: ".omo",
11085
+ });
11086
+ }
11087
+ return path.join(home, ".omo");
11088
+ }
11089
+
11090
+ function resolveOmoAgentDir(env = process.env) {
11091
+ if (env.TOKENTRACKER_OMO_AGENT_DIR) {
11092
+ return expandHomePath(env.TOKENTRACKER_OMO_AGENT_DIR, env);
11093
+ }
11094
+ const omoHome = resolveOmoHome(env);
11095
+ return omoHome ? path.join(omoHome, "agent") : null;
11096
+ }
11097
+
11098
+ function resolveOmoSessionFiles(env = process.env) {
11099
+ return collectPiStyleSessionFiles(resolveOmoAgentDir(env));
11100
+ }
11101
+
11102
+ function resolveOmoSubagentFiles(env = process.env) {
11103
+ return collectPiStyleSubagentFiles(resolveOmoAgentDir(env));
11104
+ }
11105
+
11106
+ function resolveOmoDefaultModel() {
11107
+ // OmO has no global default model setting; model is per-message.
11108
+ return "omo-unknown";
11109
+ }
11110
+
11111
+ async function resolveOmoFileCwd(filePath) {
11112
+ return readPiStyleSessionCwd(filePath);
11113
+ }
11114
+
10935
11115
  // ─────────────────────────────────────────────────────────────────────────────
10936
11116
  // Kilo Code VS Code extension — passive reader for VS Code-family
10937
11117
  // globalStorage/kilocode.kilo-code/tasks/<uuid>/ui_messages.json files.
@@ -14513,7 +14693,23 @@ async function parseKilocodeIncremental({
14513
14693
  return { recordsProcessed, eventsAggregated, bucketsQueued };
14514
14694
  }
14515
14695
 
14516
- async function parseOmpIncremental({
14696
+ // Reads the first present numeric field. oh-my-pi emits `reasoningTokens`;
14697
+ // OmO emits `reasoning`. Listing the accepted keys per provider keeps each
14698
+ // one's accounting exact instead of guessing across both spellings.
14699
+ function pickUsageInt(usage, fields) {
14700
+ for (const field of fields) {
14701
+ const raw = usage?.[field];
14702
+ if (raw == null) continue;
14703
+ const value = Number(raw);
14704
+ if (Number.isFinite(value)) return toNonNegativeInt(value);
14705
+ }
14706
+ return 0;
14707
+ }
14708
+
14709
+ // Shared implementation for the oh-my-pi session format. omp and omo both
14710
+ // persist it verbatim, so they differ only in where the sessions live, which
14711
+ // cursor namespace they own, and how reasoning tokens are spelled.
14712
+ async function parseOmpLikeIncremental({
14517
14713
  sessionFiles,
14518
14714
  subagentFiles,
14519
14715
  cursors,
@@ -14523,41 +14719,50 @@ async function parseOmpIncremental({
14523
14719
  onProgress,
14524
14720
  env,
14525
14721
  defaultModel,
14722
+ stateKey,
14723
+ source,
14724
+ resolveSessionFiles,
14725
+ resolveSubagentFiles,
14726
+ resolveDefaultModel,
14727
+ resolveFileCwd,
14728
+ reasoningFields,
14729
+ reasoningIncludedInOutput = false,
14526
14730
  } = {}) {
14527
14731
  await ensureDir(path.dirname(queuePath));
14528
14732
  const projectEnabled = typeof projectQueuePath === "string" && projectQueuePath.length > 0;
14529
- const ompState = cursors.omp && typeof cursors.omp === "object" ? cursors.omp : {};
14530
- const seenIds = new Set(Array.isArray(ompState.seenIds) ? ompState.seenIds : []);
14733
+ const providerState =
14734
+ cursors[stateKey] && typeof cursors[stateKey] === "object" ? cursors[stateKey] : {};
14735
+ const seenIds = new Set(Array.isArray(providerState.seenIds) ? providerState.seenIds : []);
14531
14736
  const projectSeenIds = new Set(
14532
- Array.isArray(ompState.projectSeenIds) ? ompState.projectSeenIds : [],
14737
+ Array.isArray(providerState.projectSeenIds) ? providerState.projectSeenIds : [],
14533
14738
  );
14534
14739
  const fileOffsets =
14535
- ompState.fileOffsets && typeof ompState.fileOffsets === "object"
14536
- ? { ...ompState.fileOffsets }
14740
+ providerState.fileOffsets && typeof providerState.fileOffsets === "object"
14741
+ ? { ...providerState.fileOffsets }
14537
14742
  : {};
14538
14743
  const projectFileOffsets =
14539
- ompState.projectFileOffsets && typeof ompState.projectFileOffsets === "object"
14540
- ? { ...ompState.projectFileOffsets }
14744
+ providerState.projectFileOffsets && typeof providerState.projectFileOffsets === "object"
14745
+ ? { ...providerState.projectFileOffsets }
14541
14746
  : {};
14542
14747
 
14543
14748
  const mainFiles = Array.isArray(sessionFiles)
14544
14749
  ? sessionFiles
14545
- : resolveOmpSessionFiles(env || process.env);
14750
+ : resolveSessionFiles(env || process.env);
14546
14751
  // Subagent transcripts share the session format and count toward the same
14547
- // "omp" totals; they're discovered separately because they nest below the
14752
+ // provider totals; they're discovered separately because they nest below the
14548
14753
  // cwd level. When the caller supplies explicit sessionFiles (tests), don't
14549
14754
  // auto-resolve — keep the parse hermetic.
14550
14755
  const subFiles = Array.isArray(subagentFiles)
14551
14756
  ? subagentFiles
14552
14757
  : Array.isArray(sessionFiles)
14553
14758
  ? []
14554
- : resolveOmpSubagentFiles(env || process.env);
14759
+ : resolveSubagentFiles(env || process.env);
14555
14760
  const files = [...mainFiles, ...subFiles];
14556
- const fallbackModel = defaultModel || resolveOmpDefaultModel();
14761
+ const fallbackModel = defaultModel || resolveDefaultModel();
14557
14762
 
14558
14763
  if (files.length === 0) {
14559
- cursors.omp = {
14560
- ...ompState,
14764
+ cursors[stateKey] = {
14765
+ ...providerState,
14561
14766
  seenIds: Array.from(seenIds),
14562
14767
  fileOffsets,
14563
14768
  ...(projectEnabled
@@ -14635,7 +14840,7 @@ async function parseOmpIncremental({
14635
14840
  const output = toNonNegativeInt(usage.output);
14636
14841
  const cacheRead = toNonNegativeInt(usage.cacheRead);
14637
14842
  const cacheWrite = toNonNegativeInt(usage.cacheWrite);
14638
- const reasoningTokens = toNonNegativeInt(usage.reasoningTokens);
14843
+ const reasoningTokens = pickUsageInt(usage, reasoningFields);
14639
14844
 
14640
14845
  if (
14641
14846
  input === 0 &&
@@ -14668,10 +14873,12 @@ async function parseOmpIncremental({
14668
14873
  if (!bucketStart) continue;
14669
14874
 
14670
14875
  // Use provided totalTokens when available; otherwise sum all components.
14876
+ // OmO folds reasoning into output, so the fallback must not add it again.
14671
14877
  const totalTokens =
14672
14878
  Number.isFinite(Number(usage.totalTokens)) && Number(usage.totalTokens) > 0
14673
14879
  ? toNonNegativeInt(usage.totalTokens)
14674
- : input + output + cacheRead + cacheWrite + reasoningTokens;
14880
+ : input + output + cacheRead + cacheWrite +
14881
+ (reasoningIncludedInOutput ? 0 : reasoningTokens);
14675
14882
 
14676
14883
  const model = normalizeModelInput(msg.model) || fallbackModel;
14677
14884
 
@@ -14685,9 +14892,9 @@ async function parseOmpIncremental({
14685
14892
  conversation_count: 1,
14686
14893
  };
14687
14894
 
14688
- const bucket = getHourlyBucket(hourlyState, "omp", model, bucketStart);
14895
+ const bucket = getHourlyBucket(hourlyState, source, model, bucketStart);
14689
14896
  addTotals(bucket.totals, delta);
14690
- touchedBuckets.add(bucketKey("omp", model, bucketStart));
14897
+ touchedBuckets.add(bucketKey(source, model, bucketStart));
14691
14898
  seenIds.add(entryId);
14692
14899
  eventsAggregated++;
14693
14900
 
@@ -14728,7 +14935,7 @@ async function parseOmpIncremental({
14728
14935
  const startOffset = stat.size < prevSize || inodeChanged ? 0 : prevSize;
14729
14936
  if (stat.size <= startOffset) continue;
14730
14937
 
14731
- const cwd = await resolveOmpFileCwd(filePath);
14938
+ const cwd = await resolveFileCwd(filePath);
14732
14939
  const projectContext = cwd
14733
14940
  ? await resolveProjectContextForPath({
14734
14941
  startDir: wsl.mapWslCwdToUnc(cwd, filePath),
@@ -14767,7 +14974,7 @@ async function parseOmpIncremental({
14767
14974
  const output = toNonNegativeInt(usage.output);
14768
14975
  const cacheRead = toNonNegativeInt(usage.cacheRead);
14769
14976
  const cacheWrite = toNonNegativeInt(usage.cacheWrite);
14770
- const reasoningTokens = toNonNegativeInt(usage.reasoningTokens);
14977
+ const reasoningTokens = pickUsageInt(usage, reasoningFields);
14771
14978
  if (
14772
14979
  input === 0 &&
14773
14980
  output === 0 &&
@@ -14797,7 +15004,8 @@ async function parseOmpIncremental({
14797
15004
  const totalTokens =
14798
15005
  Number.isFinite(Number(usage.totalTokens)) && Number(usage.totalTokens) > 0
14799
15006
  ? toNonNegativeInt(usage.totalTokens)
14800
- : input + output + cacheRead + cacheWrite + reasoningTokens;
15007
+ : input + output + cacheRead + cacheWrite +
15008
+ (reasoningIncludedInOutput ? 0 : reasoningTokens);
14801
15009
  const delta = {
14802
15010
  input_tokens: input,
14803
15011
  cached_input_tokens: cacheRead,
@@ -14810,12 +15018,12 @@ async function parseOmpIncremental({
14810
15018
  const projectBucket = getProjectBucket(
14811
15019
  projectState,
14812
15020
  projectKey,
14813
- "omp",
15021
+ source,
14814
15022
  bucketStart,
14815
15023
  projectRef,
14816
15024
  );
14817
15025
  addTotals(projectBucket.totals, delta);
14818
- projectTouchedBuckets.add(projectBucketKey(projectKey, "omp", bucketStart));
15026
+ projectTouchedBuckets.add(projectBucketKey(projectKey, source, bucketStart));
14819
15027
  projectSeenIds.add(entryId);
14820
15028
  }
14821
15029
  }
@@ -14860,8 +15068,8 @@ async function parseOmpIncremental({
14860
15068
  projectState.updatedAt = updatedAt;
14861
15069
  cursors.projectHourly = projectState;
14862
15070
  }
14863
- cursors.omp = {
14864
- ...ompState,
15071
+ cursors[stateKey] = {
15072
+ ...providerState,
14865
15073
  seenIds: cappedSeen,
14866
15074
  fileOffsets,
14867
15075
  ...(projectEnabled
@@ -14876,6 +15084,33 @@ async function parseOmpIncremental({
14876
15084
  return { recordsProcessed, eventsAggregated, bucketsQueued, projectBucketsQueued };
14877
15085
  }
14878
15086
 
15087
+ async function parseOmpIncremental(options = {}) {
15088
+ return parseOmpLikeIncremental({
15089
+ ...options,
15090
+ stateKey: "omp",
15091
+ source: "omp",
15092
+ resolveSessionFiles: resolveOmpSessionFiles,
15093
+ resolveSubagentFiles: resolveOmpSubagentFiles,
15094
+ resolveDefaultModel: resolveOmpDefaultModel,
15095
+ resolveFileCwd: resolveOmpFileCwd,
15096
+ reasoningFields: ["reasoningTokens"],
15097
+ });
15098
+ }
15099
+
15100
+ async function parseOmoIncremental(options = {}) {
15101
+ return parseOmpLikeIncremental({
15102
+ ...options,
15103
+ stateKey: "omo",
15104
+ source: "omo",
15105
+ resolveSessionFiles: resolveOmoSessionFiles,
15106
+ resolveSubagentFiles: resolveOmoSubagentFiles,
15107
+ resolveDefaultModel: resolveOmoDefaultModel,
15108
+ resolveFileCwd: resolveOmoFileCwd,
15109
+ reasoningFields: ["reasoningTokens", "reasoning"],
15110
+ reasoningIncludedInOutput: true,
15111
+ });
15112
+ }
15113
+
14879
15114
  // ─────────────────────────────────────────────────────────────────────────────
14880
15115
  // pi (@mariozechner/pi-coding-agent) — passive JSONL reader
14881
15116
  // (~/.pi/agent/sessions/**/*.jsonl)
@@ -14926,6 +15161,13 @@ function piAgentDirCollidesWithOmp(env = process.env) {
14926
15161
  return path.resolve(piAgentDir) === path.resolve(ompAgentDir);
14927
15162
  }
14928
15163
 
15164
+ function omoAgentDirCollidesWithOmp(env = process.env) {
15165
+ const omoAgentDir = resolveOmoAgentDir(env);
15166
+ const ompAgentDir = resolveOmpAgentDir(env);
15167
+ if (!omoAgentDir || !ompAgentDir) return false;
15168
+ return path.resolve(omoAgentDir) === path.resolve(ompAgentDir);
15169
+ }
15170
+
14929
15171
  function resolvePiSessionFiles(env = process.env) {
14930
15172
  const agentDir = resolvePiAgentDir(env);
14931
15173
  if (!agentDir) return [];
@@ -21692,6 +21934,12 @@ module.exports = {
21692
21934
  resolveOmpSubagentFiles,
21693
21935
  resolveOmpDefaultModel,
21694
21936
  parseOmpIncremental,
21937
+ resolveOmoHome,
21938
+ resolveOmoAgentDir,
21939
+ resolveOmoSessionFiles,
21940
+ resolveOmoSubagentFiles,
21941
+ resolveOmoDefaultModel,
21942
+ parseOmoIncremental,
21695
21943
  resolveKilocodeRoots,
21696
21944
  resolveKilocodeTaskFiles,
21697
21945
  normalizeKilocodeProviderToModel,
@@ -21745,6 +21993,7 @@ module.exports = {
21745
21993
  resolvePiDefaultModel,
21746
21994
  parsePiIncremental,
21747
21995
  piAgentDirCollidesWithOmp,
21996
+ omoAgentDirCollidesWithOmp,
21748
21997
  resolvePrimeAgentHome,
21749
21998
  resolvePrimeAgentDir,
21750
21999
  resolvePrimeAgentSessionFiles,
@@ -131,9 +131,20 @@ const MODEL_USAGE_SUM_FIELDS = [
131
131
  "long_context_cache_creation_input_tokens",
132
132
  "long_context_output_tokens",
133
133
  "long_context_reasoning_output_tokens",
134
+ "priority_input_tokens",
135
+ "priority_cached_input_tokens",
136
+ "priority_cache_creation_input_tokens",
137
+ "priority_output_tokens",
138
+ "priority_reasoning_output_tokens",
139
+ "priority_long_context_input_tokens",
140
+ "priority_long_context_cached_input_tokens",
141
+ "priority_long_context_cache_creation_input_tokens",
142
+ "priority_long_context_output_tokens",
143
+ "priority_long_context_reasoning_output_tokens",
134
144
  "usage_events",
135
145
  "rerouted_usage_events",
136
146
  "long_context_usage_events",
147
+ "priority_usage_events",
137
148
  // Not a token counter: an edit turn is a turn, and turn_context both marks
138
149
  // where a turn begins and names its model, so an edit turn has exactly one
139
150
  // owner. Splitting it here keeps by_model.tokens_per_edit a ratio over one
@@ -1 +0,0 @@
1
- import{r as n,v as a}from"./__vite-browser-external-Cp7dNuCm.js";import{u as p}from"./DialogTitle-CgkUGAag.js";import{u as c}from"./composite-zF5Pj94e.js";const x=n.forwardRef(function(e,r){const{render:l,className:u,style:m,id:s,...t}=e,i=p(),o=c(s);return i.useSyncedValueWithCleanup("descriptionElementId",o),a("p",e,{ref:r,props:[{id:o},t]})});export{x as D};