tokentracker-cli 0.93.4 → 0.93.5
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.
- package/dashboard/dist/assets/{AchievementBadge-BcNvxrVM.js → AchievementBadge-td60VwNO.js} +1 -1
- package/dashboard/dist/assets/{AchievementsPage-DhipQygJ.js → AchievementsPage-C3yKXgId.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-BJyb_mIr.js → AchievementsSection-XM39rQkD.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-CoZv7o6t.js → BadgeDetailModal-2TgBBPmw.js} +1 -1
- package/dashboard/dist/assets/{BotAnimated-eVBNtvcG.js → BotAnimated-CG6_x0d2.js} +1 -1
- package/dashboard/dist/assets/{Card-BEfG2im9.js → Card-BUnCudVB.js} +1 -1
- package/dashboard/dist/assets/{ClawdAnimated-C-30t4dC.js → ClawdAnimated-CNRu6v7I.js} +2 -2
- package/dashboard/dist/assets/{CommandPalette-DF-TGB1C.js → CommandPalette-D5vVqYkW.js} +1 -1
- package/dashboard/dist/assets/{CommunityStatsModal-D-0eI3Pz.js → CommunityStatsModal-D0V4iTI6.js} +1 -1
- package/dashboard/dist/assets/{ConfirmModal-BQ7Aor1C.js → ConfirmModal-CzxTtnXo.js} +1 -1
- package/dashboard/dist/assets/{Controls-COThRtMS.js → Controls-nR5gzX__.js} +1 -1
- package/dashboard/dist/assets/{DashboardPage-Ci_Gb5I1.js → DashboardPage-CpHXkuZn.js} +1 -1
- package/dashboard/dist/assets/{DevicePage-BmlmimUg.js → DevicePage-Emw9iVMd.js} +1 -1
- package/dashboard/dist/assets/{DialogClose-BdALEZzc.js → DialogClose-Bh-pvxsM.js} +1 -1
- package/dashboard/dist/assets/DialogDescription-DJ-RHxIt.js +1 -0
- package/dashboard/dist/assets/{DialogTitle-F6W1aTiE.js → DialogTitle-BG3ngtew.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-S2d3D28d.js → FadeIn-DOEfAW5p.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-DBBwOwc_.js → HeaderGithubStar-DslGxMu4.js} +1 -1
- package/dashboard/dist/assets/{HoverTooltip-rLWQC9Va.js → HoverTooltip-O2OKCBc3.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-BpPoAIry.js → IpCheckPage-Dv6LbNU_.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-BUm_ZMew.js → LandingPage-BBfteqDF.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardAvatar-DQxbOYZb.js → LeaderboardAvatar-Ct6QagwN.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardPage-DzLrFQm8.js → LeaderboardPage-CSbIdSm7.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardProfileModal-Cq4B8Les.js → LeaderboardProfileModal-BuUWkmBN.js} +3 -3
- package/dashboard/dist/assets/{LeaderboardProfilePage-C-Xj65xf.js → LeaderboardProfilePage-fVnV0Lo-.js} +1 -1
- package/dashboard/dist/assets/{LimitsPage-Bjcmr0bd.js → LimitsPage-BHkkA3xN.js} +1 -1
- package/dashboard/dist/assets/{LocalOnlyNotice-9mWINkVj.js → LocalOnlyNotice-BLlrqreb.js} +1 -1
- package/dashboard/dist/assets/{LoginCard-BlKleF8M.js → LoginCard-CKV1uACo.js} +1 -1
- package/dashboard/dist/assets/{LoginModal-BUYa13hj.js → LoginModal-RCpQtFuG.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-DbQhApOd.js → LoginPage-vMV2kpef.js} +1 -1
- package/dashboard/dist/assets/{PetPage-DuAf3OOf.js → PetPage-CTgwpnsA.js} +1 -1
- package/dashboard/dist/assets/{PopoverPopup-CG76MkbK.js → PopoverPopup-Bddr9R6x.js} +1 -1
- package/dashboard/dist/assets/{ProviderIcon-N7OTtgte.js → ProviderIcon-BeXu2voQ.js} +1 -1
- package/dashboard/dist/assets/{ResetPasswordPage-D48--1wC.js → ResetPasswordPage-CilGTQWZ.js} +1 -1
- package/dashboard/dist/assets/{SegmentedControl-zRvbFqyY.js → SegmentedControl-r5MP3Uyx.js} +1 -1
- package/dashboard/dist/assets/{Select-Bi3B21Fb.js → Select-BBUIbPTj.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-Bg8I618N.js → SelectItemText-CbuN7Sui.js} +1 -1
- package/dashboard/dist/assets/{ServiceStatusPage-CeeYx4XY.js → ServiceStatusPage-WgmQviZa.js} +1 -1
- package/dashboard/dist/assets/{SessionsPage-CZF3qLEm.js → SessionsPage-BDkdXQhW.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-D2wa8i5u.js → SettingsPage-CsF8cG7I.js} +2 -2
- package/dashboard/dist/assets/{SkillsPage-OxW2w6up.js → SkillsPage-CVGra4ar.js} +1 -1
- package/dashboard/dist/assets/{TokenGalaxy-DmtP_r86.js → TokenGalaxy-B0kFIG0N.js} +1 -1
- package/dashboard/dist/assets/{ToolbarRootContext-DC6BLLoO.js → ToolbarRootContext-BlWkiH2k.js} +1 -1
- package/dashboard/dist/assets/{TrendMonitor-OvvLCD3K.js → TrendMonitor-C18_ADhU.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-DhOC8rae.js → WidgetsPage-Ck7L4vBj.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-C0boSobK.js → WrappedPage-Bm5HMj3a.js} +1 -1
- package/dashboard/dist/assets/{__vite-browser-external-D_dICEUB.js → __vite-browser-external-BCyVFzdP.js} +15 -15
- package/dashboard/dist/assets/{agent-logos-Dzyq5cDh.js → agent-logos-PZX7lWJo.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-DrLfm7Vy.js → arrow-up-right-DPSDEZPh.js} +1 -1
- package/dashboard/dist/assets/{check-DAsdH-MF.js → check-GGrgivnu.js} +1 -1
- package/dashboard/dist/assets/{chevron-right-CdSgby9-.js → chevron-right-CmSOUizu.js} +1 -1
- package/dashboard/dist/assets/{copy-TuVoW7qK.js → copy-ChMyV-hy.js} +1 -1
- package/dashboard/dist/assets/{download-BZ61xuhi.js → download-DGUkE9Jc.js} +1 -1
- package/dashboard/dist/assets/{external-link-DJrRSKF9.js → external-link-B_W-UDpi.js} +1 -1
- package/dashboard/dist/assets/{flame-9JS9yMju.js → flame-C9ccP-R8.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-Blp6lI_n.js → format-tokens-CkXJmbVP.js} +1 -1
- package/dashboard/dist/assets/{icons-CbF0cL6i.js → icons-D37cRKGk.js} +1 -1
- package/dashboard/dist/assets/{index-FnWiMfqV.js → index-C-_fimm3.js} +1 -1
- package/dashboard/dist/assets/{index-I81NzV7H.js → index-C9OzYqU0.js} +1 -1
- package/dashboard/dist/assets/{index-Bu3I2hmd.js → index-Dt6WIU71.js} +1 -1
- package/dashboard/dist/assets/{info-B_iryt84.js → info-C3-0C2W0.js} +1 -1
- package/dashboard/dist/assets/{limits-providers-Cli4pkKC.js → limits-providers-DB1Zr3WN.js} +1 -1
- package/dashboard/dist/assets/{link-2-pB3-7Waa.js → link-2-DqNEbzji.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-DivA-LsF.js → loader-circle-BYoKm-f5.js} +1 -1
- package/dashboard/dist/assets/{maximize-2-WNMF5NUU.js → maximize-2-lVQDTDqs.js} +1 -1
- package/dashboard/dist/assets/{modifiers.esm-BaJJxzf2.js → modifiers.esm-Bww85WOd.js} +1 -1
- package/dashboard/dist/assets/module-D2D5r9gC.js +3 -0
- package/dashboard/dist/assets/{monitor-smartphone-pAR3IHow.js → monitor-smartphone--KubNwvP.js} +1 -1
- package/dashboard/dist/assets/{provider-display-CyYhYVar.js → provider-display-COV_Ft4A.js} +1 -1
- package/dashboard/dist/assets/{react-BldsIPA1.js → react-lNnu0y7U.js} +1 -1
- package/dashboard/dist/assets/{search-xIfdCEo0.js → search-CpHNMxpD.js} +1 -1
- package/dashboard/dist/assets/{skills-api-DZNsCHPo.js → skills-api-Cf2qRQ1h.js} +1 -1
- package/dashboard/dist/assets/{sortable.esm-DMaj448G.js → sortable.esm-DWdlF_7j.js} +1 -1
- package/dashboard/dist/assets/{store-VTEegajU.js → store-DJQqZJtg.js} +1 -1
- package/dashboard/dist/assets/{terminal-Bj8SotRv.js → terminal-Cban5byW.js} +1 -1
- package/dashboard/dist/assets/{trash-2-CWgY_FBc.js → trash-2-nelaUHSh.js} +1 -1
- package/dashboard/dist/assets/{use-community-stats-BOVvh_Gv.js → use-community-stats-CBupXLW7.js} +1 -1
- package/dashboard/dist/assets/{use-limits-display-prefs-MtLsQ5kN.js → use-limits-display-prefs-B4y_kzcd.js} +1 -1
- package/dashboard/dist/assets/{use-ordered-list-DjCZVinv.js → use-ordered-list-DEV58tGc.js} +1 -1
- package/dashboard/dist/assets/use-reduced-motion-CRf4pBTt.js +1 -0
- package/dashboard/dist/assets/{use-session-efficiency-pref-DASihY0W.js → use-session-efficiency-pref-wSk1wV6R.js} +1 -1
- package/dashboard/dist/assets/{use-transform-tHlm2id8.js → use-transform-NKavwYrX.js} +1 -1
- package/dashboard/dist/assets/{use-usage-limits-BBEHNJKl.js → use-usage-limits-Blr1HBCj.js} +1 -1
- package/dashboard/dist/assets/{useCurrency-DgTCDMXb.js → useCurrency-B2704dMx.js} +1 -1
- package/dashboard/dist/assets/{useScrollLock-C3TFkbz0.js → useScrollLock-BuPQ8T9m.js} +1 -1
- package/dashboard/dist/assets/{useTokenFormat-BtqPANfZ.js → useTokenFormat-DPxAFuMj.js} +1 -1
- package/dashboard/dist/assets/{zap-CJNTZ87b.js → zap-BgtTdM4q.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dashboard/dist/ip-check.html +1 -1
- package/dashboard/dist/leaderboard.html +1 -1
- package/dashboard/dist/share.html +1 -1
- package/package.json +1 -1
- package/src/commands/serve.js +115 -4
- package/src/commands/sync.js +146 -3
- package/src/lib/opencode-go-limits.js +11 -3
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +189 -5
- package/src/lib/usage-limits.js +119 -1
- package/dashboard/dist/assets/DialogDescription-DAKoQCEv.js +0 -1
- package/dashboard/dist/assets/module-CV1mYFsv.js +0 -3
- package/dashboard/dist/assets/use-reduced-motion-DjWNXuSi.js +0 -1
package/src/lib/rollout.js
CHANGED
|
@@ -4422,8 +4422,7 @@ function readOpencodeDbMessages(dbPath, sqliteOptions = {}) {
|
|
|
4422
4422
|
// by the existing cursor-key + #426 fingerprint dedup in
|
|
4423
4423
|
// parseOpencodeDbIncremental, so unioning here is safe — the downstream
|
|
4424
4424
|
// parser collapses identical sessionID|messageID pairs before bucketing.
|
|
4425
|
-
const
|
|
4426
|
-
const out = [];
|
|
4425
|
+
const appendRows = (rows, isV2, out) => {
|
|
4427
4426
|
for (const row of rows) {
|
|
4428
4427
|
if (!row || typeof row.data !== "string") continue;
|
|
4429
4428
|
let data;
|
|
@@ -4450,7 +4449,6 @@ function readOpencodeDbMessages(dbPath, sqliteOptions = {}) {
|
|
|
4450
4449
|
data,
|
|
4451
4450
|
});
|
|
4452
4451
|
}
|
|
4453
|
-
return out;
|
|
4454
4452
|
};
|
|
4455
4453
|
|
|
4456
4454
|
const readGeneration = (sql) => {
|
|
@@ -4477,11 +4475,11 @@ function readOpencodeDbMessages(dbPath, sqliteOptions = {}) {
|
|
|
4477
4475
|
const out = [];
|
|
4478
4476
|
|
|
4479
4477
|
const rows1 = readGeneration(OPENCODE_DB_V1_MESSAGE_SQL);
|
|
4480
|
-
if (rows1)
|
|
4478
|
+
if (rows1) appendRows(rows1, false, out);
|
|
4481
4479
|
|
|
4482
4480
|
if (probe?.hasRows) {
|
|
4483
4481
|
const rows2 = readGeneration(buildV2Sql(probe.sessionTable));
|
|
4484
|
-
if (rows2)
|
|
4482
|
+
if (rows2) appendRows(rows2, true, out);
|
|
4485
4483
|
}
|
|
4486
4484
|
|
|
4487
4485
|
return out;
|
|
@@ -4551,10 +4549,195 @@ function isZcodeNativeMessage(data) {
|
|
|
4551
4549
|
);
|
|
4552
4550
|
}
|
|
4553
4551
|
|
|
4552
|
+
const ZCODE_NATIVE_USAGE_COLUMNS = new Set([
|
|
4553
|
+
"id",
|
|
4554
|
+
"logical_request_id",
|
|
4555
|
+
"attempt_index",
|
|
4556
|
+
"session_id",
|
|
4557
|
+
"provider_id",
|
|
4558
|
+
"model_id",
|
|
4559
|
+
"status",
|
|
4560
|
+
"started_at",
|
|
4561
|
+
"input_tokens",
|
|
4562
|
+
"output_tokens",
|
|
4563
|
+
"reasoning_tokens",
|
|
4564
|
+
"cache_creation_input_tokens",
|
|
4565
|
+
"cache_read_input_tokens",
|
|
4566
|
+
]);
|
|
4567
|
+
|
|
4568
|
+
function detectZcodeNativeUsageLayout(dbPath, sqliteOptions = {}) {
|
|
4569
|
+
if (!dbPath || !fssync.existsSync(dbPath)) return null;
|
|
4570
|
+
let rows;
|
|
4571
|
+
try {
|
|
4572
|
+
rows = readSqliteJsonRows(
|
|
4573
|
+
dbPath,
|
|
4574
|
+
`SELECT 'model_usage' AS table_name, name FROM pragma_table_info('model_usage')
|
|
4575
|
+
UNION ALL
|
|
4576
|
+
SELECT 'session' AS table_name, name FROM pragma_table_info('session')`,
|
|
4577
|
+
{
|
|
4578
|
+
label: "ZCode",
|
|
4579
|
+
timeout: 10_000,
|
|
4580
|
+
maxBuffer: 1024 * 1024,
|
|
4581
|
+
...sqliteOptions,
|
|
4582
|
+
throwOnReadFailure: true,
|
|
4583
|
+
},
|
|
4584
|
+
);
|
|
4585
|
+
} catch (_error) {
|
|
4586
|
+
return null;
|
|
4587
|
+
}
|
|
4588
|
+
const modelUsageColumns = new Set(
|
|
4589
|
+
rows
|
|
4590
|
+
.filter((row) => !row?.table_name || row.table_name === "model_usage")
|
|
4591
|
+
.map((row) => String(row?.name || "")),
|
|
4592
|
+
);
|
|
4593
|
+
if (![...ZCODE_NATIVE_USAGE_COLUMNS].every((name) => modelUsageColumns.has(name))) {
|
|
4594
|
+
return null;
|
|
4595
|
+
}
|
|
4596
|
+
const sessionColumns = new Set(
|
|
4597
|
+
rows
|
|
4598
|
+
.filter((row) => row?.table_name === "session")
|
|
4599
|
+
.map((row) => String(row?.name || "")),
|
|
4600
|
+
);
|
|
4601
|
+
return {
|
|
4602
|
+
hasSessionDirectory: sessionColumns.has("id") && sessionColumns.has("directory"),
|
|
4603
|
+
};
|
|
4604
|
+
}
|
|
4605
|
+
|
|
4606
|
+
function hasZcodeNativeUsageSchema(dbPath, sqliteOptions = {}) {
|
|
4607
|
+
if (!dbPath || !fssync.existsSync(dbPath)) return false;
|
|
4608
|
+
let snapshot = null;
|
|
4609
|
+
let effectiveDbPath = dbPath;
|
|
4610
|
+
if (isUncPath(dbPath)) {
|
|
4611
|
+
try {
|
|
4612
|
+
snapshot = snapshotSqliteDb(dbPath);
|
|
4613
|
+
effectiveDbPath = snapshot.path;
|
|
4614
|
+
} catch (_error) {
|
|
4615
|
+
// Fall through to the direct read: some UNC servers support SQLite's
|
|
4616
|
+
// read-only locking semantics even when the WSL bridge does not.
|
|
4617
|
+
}
|
|
4618
|
+
}
|
|
4619
|
+
try {
|
|
4620
|
+
return detectZcodeNativeUsageLayout(effectiveDbPath, sqliteOptions) !== null;
|
|
4621
|
+
} finally {
|
|
4622
|
+
if (snapshot) snapshot.cleanup();
|
|
4623
|
+
}
|
|
4624
|
+
}
|
|
4625
|
+
|
|
4626
|
+
function buildZcodeNativeUsageSql({ hasSessionDirectory }) {
|
|
4627
|
+
const directorySelect = hasSessionDirectory ? ", s.directory AS directory" : "";
|
|
4628
|
+
const directoryJoin = hasSessionDirectory
|
|
4629
|
+
? " LEFT JOIN session AS s ON s.id = mu.session_id"
|
|
4630
|
+
: "";
|
|
4631
|
+
return `SELECT
|
|
4632
|
+
mu.id,
|
|
4633
|
+
mu.logical_request_id,
|
|
4634
|
+
mu.attempt_index,
|
|
4635
|
+
mu.session_id,
|
|
4636
|
+
mu.provider_id,
|
|
4637
|
+
mu.model_id,
|
|
4638
|
+
mu.started_at,
|
|
4639
|
+
mu.input_tokens,
|
|
4640
|
+
mu.output_tokens,
|
|
4641
|
+
mu.reasoning_tokens,
|
|
4642
|
+
mu.cache_creation_input_tokens,
|
|
4643
|
+
mu.cache_read_input_tokens
|
|
4644
|
+
${directorySelect}
|
|
4645
|
+
FROM model_usage AS mu${directoryJoin}
|
|
4646
|
+
WHERE mu.status = 'completed'
|
|
4647
|
+
AND trim(mu.model_id) != ''
|
|
4648
|
+
AND (
|
|
4649
|
+
mu.input_tokens > 0 OR mu.output_tokens > 0 OR mu.reasoning_tokens > 0 OR
|
|
4650
|
+
mu.cache_creation_input_tokens > 0 OR mu.cache_read_input_tokens > 0
|
|
4651
|
+
)
|
|
4652
|
+
ORDER BY mu.started_at ASC, mu.id ASC`;
|
|
4653
|
+
}
|
|
4654
|
+
|
|
4655
|
+
function readZcodeNativeUsageMessages(dbPath, sqliteOptions = {}) {
|
|
4656
|
+
let snapshot = null;
|
|
4657
|
+
let effectiveDbPath = dbPath;
|
|
4658
|
+
if (isUncPath(dbPath)) {
|
|
4659
|
+
try {
|
|
4660
|
+
snapshot = snapshotSqliteDb(dbPath);
|
|
4661
|
+
effectiveDbPath = snapshot.path;
|
|
4662
|
+
} catch (_error) {
|
|
4663
|
+
// Preserve the existing direct-read fallback for transient snapshot
|
|
4664
|
+
// failures and UNC implementations that support SQLite locking.
|
|
4665
|
+
}
|
|
4666
|
+
}
|
|
4667
|
+
|
|
4668
|
+
let rows;
|
|
4669
|
+
try {
|
|
4670
|
+
const layout = detectZcodeNativeUsageLayout(effectiveDbPath, sqliteOptions);
|
|
4671
|
+
if (!layout) return null;
|
|
4672
|
+
rows = readSqliteJsonRows(effectiveDbPath, buildZcodeNativeUsageSql(layout), {
|
|
4673
|
+
label: "ZCode",
|
|
4674
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
4675
|
+
timeout: 30_000,
|
|
4676
|
+
...sqliteOptions,
|
|
4677
|
+
throwOnReadFailure: true,
|
|
4678
|
+
});
|
|
4679
|
+
} catch (_error) {
|
|
4680
|
+
return null;
|
|
4681
|
+
} finally {
|
|
4682
|
+
if (snapshot) snapshot.cleanup();
|
|
4683
|
+
}
|
|
4684
|
+
|
|
4685
|
+
const messages = [];
|
|
4686
|
+
for (const row of rows) {
|
|
4687
|
+
const providerID = String(row?.provider_id || "").trim();
|
|
4688
|
+
const modelID = String(row?.model_id || "").trim();
|
|
4689
|
+
const sessionID = String(row?.session_id || "").trim();
|
|
4690
|
+
const logicalRequestId = String(row?.logical_request_id || "").trim();
|
|
4691
|
+
const attemptIndex = toNonNegativeInt(row?.attempt_index);
|
|
4692
|
+
const id = String(row?.id || "").trim() ||
|
|
4693
|
+
(logicalRequestId ? `${logicalRequestId}#${attemptIndex}` : "");
|
|
4694
|
+
const startedAt = coerceEpochMs(row?.started_at);
|
|
4695
|
+
if (!providerID || !modelID || !sessionID || !id || !startedAt) continue;
|
|
4696
|
+
|
|
4697
|
+
// ZCode's persisted input/output columns are inclusive parents:
|
|
4698
|
+
// cache read/write are subsets of input, and reasoning is a subset of
|
|
4699
|
+
// output. TokenTracker stores those five columns disjointly, so split the
|
|
4700
|
+
// subsets here before entering the shared OpenCode parser. This preserves
|
|
4701
|
+
// sum(input + cache read + cache write + output + reasoning) without
|
|
4702
|
+
// billing either subset twice.
|
|
4703
|
+
const rawInput = toNonNegativeInt(row?.input_tokens);
|
|
4704
|
+
const rawOutput = toNonNegativeInt(row?.output_tokens);
|
|
4705
|
+
const cacheRead = toNonNegativeInt(row?.cache_read_input_tokens);
|
|
4706
|
+
const cacheWrite = toNonNegativeInt(row?.cache_creation_input_tokens);
|
|
4707
|
+
const reasoning = toNonNegativeInt(row?.reasoning_tokens);
|
|
4708
|
+
|
|
4709
|
+
const data = {
|
|
4710
|
+
id,
|
|
4711
|
+
sessionID,
|
|
4712
|
+
role: "assistant",
|
|
4713
|
+
providerID,
|
|
4714
|
+
modelID,
|
|
4715
|
+
time: { created: startedAt, completed: startedAt },
|
|
4716
|
+
tokens: {
|
|
4717
|
+
input: Math.max(0, rawInput - cacheRead - cacheWrite),
|
|
4718
|
+
output: Math.max(0, rawOutput - reasoning),
|
|
4719
|
+
reasoning,
|
|
4720
|
+
cache: {
|
|
4721
|
+
read: cacheRead,
|
|
4722
|
+
write: cacheWrite,
|
|
4723
|
+
},
|
|
4724
|
+
},
|
|
4725
|
+
};
|
|
4726
|
+
if (typeof row?.directory === "string" && row.directory.trim()) {
|
|
4727
|
+
data.path = { cwd: row.directory.trim() };
|
|
4728
|
+
}
|
|
4729
|
+
if (!isZcodeNativeMessage(data)) continue;
|
|
4730
|
+
messages.push({ id, sessionID, timeUpdated: startedAt, data });
|
|
4731
|
+
}
|
|
4732
|
+
return messages;
|
|
4733
|
+
}
|
|
4734
|
+
|
|
4554
4735
|
// Read only genuine ZCode assistant messages (its own GLM models via Z.ai /
|
|
4555
4736
|
// BigModel), dropping any bundled sub-agent turns. See isZcodeNativeMessage.
|
|
4556
4737
|
function readZcodeDbMessages(dbPath, sqliteOptions = {}) {
|
|
4557
4738
|
if (!dbPath || !fssync.existsSync(dbPath)) return [];
|
|
4739
|
+
const nativeMessages = readZcodeNativeUsageMessages(dbPath, sqliteOptions);
|
|
4740
|
+
if (nativeMessages !== null) return nativeMessages;
|
|
4558
4741
|
const all = readOpencodeDbMessages(dbPath, sqliteOptions);
|
|
4559
4742
|
return all.filter((m) => isZcodeNativeMessage(m.data));
|
|
4560
4743
|
}
|
|
@@ -18054,6 +18237,7 @@ module.exports = {
|
|
|
18054
18237
|
readOpencodeDbMessages,
|
|
18055
18238
|
readMimoDbMessages,
|
|
18056
18239
|
readZcodeDbMessages,
|
|
18240
|
+
hasZcodeNativeUsageSchema,
|
|
18057
18241
|
resolveQoderDbPath,
|
|
18058
18242
|
resolveQoderDbPaths,
|
|
18059
18243
|
resolveQoderCnDbPaths,
|
package/src/lib/usage-limits.js
CHANGED
|
@@ -66,6 +66,13 @@ const CLAUDE_LIMITS_CACHE_FRESH_TTL_MS = 10 * 60 * 1000;
|
|
|
66
66
|
// error, mirroring the Claude stale-fallback path.
|
|
67
67
|
const CODEX_LIMITS_CACHE_FILE = "codex-usage-limits-cache.json";
|
|
68
68
|
const CODEX_LIMITS_CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
69
|
+
// OpenCode Go hits opencode.ai over the public internet (15s timeout) with no local CLI to
|
|
70
|
+
// fall back on. A transient 5xx / timeout previously left the panel blank until the next
|
|
71
|
+
// 2-minute poll — persist the last successful windows so a blip serves stale bars instead
|
|
72
|
+
// of a flash of "fetch failed" (mirrors Claude / Codex / Antigravity).
|
|
73
|
+
const OPENCODE_GO_LIMITS_CACHE_FILE = "opencode-go-usage-limits-cache.json";
|
|
74
|
+
const OPENCODE_GO_LIMITS_CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
75
|
+
const OPENCODE_GO_LOCAL_ESTIMATE_CACHE_MAX_AGE_MS = 60 * 60 * 1000;
|
|
69
76
|
// A 429 from the usage endpoint carries a long `retry-after` (often 20+ minutes). Persist
|
|
70
77
|
// the cooldown so every surface — this process, the menu bar app's embedded server, a later
|
|
71
78
|
// restart — stops calling until it expires. Hammering during the cooldown just renews the
|
|
@@ -2398,6 +2405,82 @@ function writeCodexLimitsCache(limits, { home, nowMs = Date.now() } = {}) {
|
|
|
2398
2405
|
} catch (_error) {}
|
|
2399
2406
|
}
|
|
2400
2407
|
|
|
2408
|
+
function resolveOpencodeGoLimitsCachePath({ home } = {}) {
|
|
2409
|
+
return path.join(home || os.homedir(), ".tokentracker", "tracker", OPENCODE_GO_LIMITS_CACHE_FILE);
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2412
|
+
function hasOpencodeGoWindow(limits) {
|
|
2413
|
+
return Boolean(limits?.primary_window || limits?.secondary_window || limits?.tertiary_window);
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2416
|
+
function isOpencodeGoCacheWindowUsable(window, { nowMs } = {}) {
|
|
2417
|
+
if (!window || typeof window !== "object") return false;
|
|
2418
|
+
const resetAtMs = parseTimeMs(window.reset_at);
|
|
2419
|
+
if (resetAtMs === null) return true;
|
|
2420
|
+
return resetAtMs > nowMs;
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
function normalizeOpencodeGoCachedLimits(
|
|
2424
|
+
raw,
|
|
2425
|
+
{ nowMs = Date.now(), maxAgeMs } = {},
|
|
2426
|
+
) {
|
|
2427
|
+
const effectiveMaxAge = Number.isFinite(maxAgeMs)
|
|
2428
|
+
? maxAgeMs
|
|
2429
|
+
: raw?.source === "local-estimate"
|
|
2430
|
+
? OPENCODE_GO_LOCAL_ESTIMATE_CACHE_MAX_AGE_MS
|
|
2431
|
+
: OPENCODE_GO_LIMITS_CACHE_MAX_AGE_MS;
|
|
2432
|
+
const cachedAtMs = parseTimeMs(raw?.cached_at);
|
|
2433
|
+
if (!Number.isFinite(cachedAtMs)) return null;
|
|
2434
|
+
if (cachedAtMs > nowMs + 60_000) return null;
|
|
2435
|
+
if (nowMs - cachedAtMs > effectiveMaxAge) return null;
|
|
2436
|
+
|
|
2437
|
+
const cached = {
|
|
2438
|
+
configured: true,
|
|
2439
|
+
error: null,
|
|
2440
|
+
source: typeof raw?.source === "string" ? raw.source : "api",
|
|
2441
|
+
subscription_status: typeof raw?.subscription_status === "string" ? raw.subscription_status : null,
|
|
2442
|
+
plan_label: typeof raw?.plan_label === "string" ? raw.plan_label : null,
|
|
2443
|
+
primary_window: isOpencodeGoCacheWindowUsable(raw?.primary_window, { nowMs }) ? raw.primary_window : null,
|
|
2444
|
+
secondary_window: isOpencodeGoCacheWindowUsable(raw?.secondary_window, { nowMs }) ? raw.secondary_window : null,
|
|
2445
|
+
tertiary_window: isOpencodeGoCacheWindowUsable(raw?.tertiary_window, { nowMs }) ? raw.tertiary_window : null,
|
|
2446
|
+
stale: true,
|
|
2447
|
+
cached_at: raw.cached_at,
|
|
2448
|
+
};
|
|
2449
|
+
return hasOpencodeGoWindow(cached) ? cached : null;
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
function readOpencodeGoLimitsCache({ home, nowMs = Date.now() } = {}) {
|
|
2453
|
+
const cachePath = resolveOpencodeGoLimitsCachePath({ home });
|
|
2454
|
+
try {
|
|
2455
|
+
const parsed = JSON.parse(fs.readFileSync(cachePath, "utf8"));
|
|
2456
|
+
return normalizeOpencodeGoCachedLimits(parsed?.opencodeGo, { nowMs });
|
|
2457
|
+
} catch (_error) {
|
|
2458
|
+
return null;
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
function writeOpencodeGoLimitsCache(limits, { home, nowMs = Date.now() } = {}) {
|
|
2463
|
+
if (!limits?.configured || limits.error || !hasOpencodeGoWindow(limits)) return;
|
|
2464
|
+
const cachePath = resolveOpencodeGoLimitsCachePath({ home });
|
|
2465
|
+
const payload = {
|
|
2466
|
+
opencodeGo: {
|
|
2467
|
+
source: limits.source || "api",
|
|
2468
|
+
subscription_status: limits.subscription_status || null,
|
|
2469
|
+
plan_label: limits.plan_label || null,
|
|
2470
|
+
primary_window: limits.primary_window || null,
|
|
2471
|
+
secondary_window: limits.secondary_window || null,
|
|
2472
|
+
tertiary_window: limits.tertiary_window || null,
|
|
2473
|
+
cached_at: new Date(nowMs).toISOString(),
|
|
2474
|
+
},
|
|
2475
|
+
};
|
|
2476
|
+
try {
|
|
2477
|
+
fs.mkdirSync(path.dirname(cachePath), { recursive: true });
|
|
2478
|
+
const tmpPath = `${cachePath}.${process.pid}.tmp`;
|
|
2479
|
+
fs.writeFileSync(tmpPath, JSON.stringify(payload, null, 2), { encoding: "utf8", mode: 0o600 });
|
|
2480
|
+
fs.renameSync(tmpPath, cachePath);
|
|
2481
|
+
} catch (_error) {}
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2401
2484
|
function resolveClaudeRateLimitPath({ home } = {}) {
|
|
2402
2485
|
return path.join(home || os.homedir(), ".tokentracker", "tracker", CLAUDE_RATE_LIMIT_FILE);
|
|
2403
2486
|
}
|
|
@@ -3063,7 +3146,7 @@ async function fetchUsageLimitsUncached({
|
|
|
3063
3146
|
: null;
|
|
3064
3147
|
|
|
3065
3148
|
const providerFetch = withFetchTimeout(fetchImpl, providerTimeoutMs);
|
|
3066
|
-
const [claudeResult, codexResult, cursor, kimi, gemini, kiro, antigravity, copilot, grok, zcode,
|
|
3149
|
+
const [claudeResult, codexResult, cursor, kimi, gemini, kiro, antigravity, copilot, grok, zcode, opencodeGoRaw, qoder, qoderCn, codingPlan, claudeServiceStatus] = await Promise.all([
|
|
3067
3150
|
claudeToken && !freshClaudeCache && !claudeRetryAtMs
|
|
3068
3151
|
? withProviderTimeout(fetchClaudeUsageLimits(claudeToken, { fetchImpl: providerFetch, maxAttempts: 1 }), "Claude", providerTimeoutMs).then(
|
|
3069
3152
|
(value) => ({ status: "fulfilled", value }),
|
|
@@ -3276,6 +3359,41 @@ async function fetchUsageLimitsUncached({
|
|
|
3276
3359
|
}
|
|
3277
3360
|
}
|
|
3278
3361
|
|
|
3362
|
+
// OpenCode Go: persist last successful windows so a transient timeout/5xx
|
|
3363
|
+
// (common on GFW-affected routes to opencode.ai) serves stale bars instead of
|
|
3364
|
+
// a flashing "fetch failed". Mirrors Codex / Claude / Antigravity.
|
|
3365
|
+
// Auth errors (401/403 invalid key, missing subscription, expired cookie) are
|
|
3366
|
+
// actionable and must not be hidden behind stale cache — they carry
|
|
3367
|
+
// `auth_error:true` from opencode-go-limits.js.
|
|
3368
|
+
const opencodeGoIsAuthError =
|
|
3369
|
+
Boolean(opencodeGoRaw?.auth_error) ||
|
|
3370
|
+
(typeof opencodeGoRaw?.error === "string" &&
|
|
3371
|
+
/Not signed in|auth cookie|Refresh the auth cookie|Failed to resolve Workspace ID.*401|Failed to resolve Workspace ID.*403/i.test(
|
|
3372
|
+
opencodeGoRaw.error,
|
|
3373
|
+
));
|
|
3374
|
+
let opencodeGo;
|
|
3375
|
+
if (opencodeGoRaw && opencodeGoRaw.configured === false) {
|
|
3376
|
+
opencodeGo = opencodeGoRaw;
|
|
3377
|
+
} else if (opencodeGoIsAuthError) {
|
|
3378
|
+
opencodeGo = opencodeGoRaw;
|
|
3379
|
+
} else if (opencodeGoRaw?.subscription_status === "inactive") {
|
|
3380
|
+
opencodeGo = opencodeGoRaw;
|
|
3381
|
+
} else if (opencodeGoRaw && !opencodeGoRaw.error && hasOpencodeGoWindow(opencodeGoRaw)) {
|
|
3382
|
+
opencodeGo = {
|
|
3383
|
+
...opencodeGoRaw,
|
|
3384
|
+
stale: false,
|
|
3385
|
+
cached_at: new Date(nowMs).toISOString(),
|
|
3386
|
+
};
|
|
3387
|
+
writeOpencodeGoLimitsCache(opencodeGo, { home, nowMs });
|
|
3388
|
+
} else {
|
|
3389
|
+
const cached = readOpencodeGoLimitsCache({ home, nowMs });
|
|
3390
|
+
if (cached) {
|
|
3391
|
+
opencodeGo = cached;
|
|
3392
|
+
} else {
|
|
3393
|
+
opencodeGo = opencodeGoRaw || { configured: true, error: "Unknown error" };
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
3396
|
+
|
|
3279
3397
|
const data = {
|
|
3280
3398
|
fetched_at: new Date(nowMs).toISOString(),
|
|
3281
3399
|
claude: withPlanLabel(claude, claudePlanType, "Claude"),
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as n,z as a}from"./__vite-browser-external-D_dICEUB.js";import{u as p}from"./DialogTitle-F6W1aTiE.js";import{u as c}from"./useScrollLock-C3TFkbz0.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};
|