tokentracker-cli 0.87.6 → 0.87.7
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/LICENSE +1 -1
- package/README.de.md +32 -32
- package/README.ja.md +31 -31
- package/README.ko.md +31 -31
- package/README.md +34 -34
- package/README.zh-CN.md +31 -31
- package/dashboard/dist/assets/{AchievementBadge-BRh6I-jK.js → AchievementBadge-4SSFyzNE.js} +1 -1
- package/dashboard/dist/assets/{AchievementsPage-BsAJOqK8.js → AchievementsPage-4ASCXja2.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-DebeB3vT.js → AchievementsSection-CyaMYMol.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-DniVJwrw.js → BadgeDetailModal-CUWTCEru.js} +1 -1
- package/dashboard/dist/assets/{Card-DvKbmZEl.js → Card-C79yXijL.js} +1 -1
- package/dashboard/dist/assets/{ClawdAnimated-DCyXpvgK.js → ClawdAnimated-Cw6J-x_d.js} +1 -1
- package/dashboard/dist/assets/{CommandPalette-BadO9q-D.js → CommandPalette-C1RQ58De.js} +1 -1
- package/dashboard/dist/assets/{CommunityStatsModal-DzBeGuLk.js → CommunityStatsModal-CycaCGsd.js} +1 -1
- package/dashboard/dist/assets/{ConfirmModal-BLppThU-.js → ConfirmModal-hPuA2aup.js} +1 -1
- package/dashboard/dist/assets/{Controls-BBVOO6-V.js → Controls-DjunxsRS.js} +1 -1
- package/dashboard/dist/assets/{DashboardPage-DgV2-5pv.js → DashboardPage-C5H5_EZN.js} +1 -1
- package/dashboard/dist/assets/{DevicePage-BZ8Z3veC.js → DevicePage-a1TT-0Bd.js} +1 -1
- package/dashboard/dist/assets/{DialogClose-Be7JwC-H.js → DialogClose-CCRfnIbO.js} +1 -1
- package/dashboard/dist/assets/DialogDescription-C99d5K4r.js +1 -0
- package/dashboard/dist/assets/{DialogTitle-Bgr5ftrn.js → DialogTitle-2Qa5pApU.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-Cc5Grbxc.js → FadeIn-C3mpVy83.js} +1 -1
- package/dashboard/dist/assets/HeaderGithubStar-Dn_F7ByX.js +1 -0
- package/dashboard/dist/assets/{HoverTooltip-BwRvWZqo.js → HoverTooltip-DaywO0Zz.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-Ce4dWLI1.js → IpCheckPage-oqGfnWb7.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-CuDfsomP.js → LandingPage-CX7dYsEX.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardAvatar-D50UCqhG.js → LeaderboardAvatar-Bl-OMQ2x.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardPage-fXYjgVOH.js → LeaderboardPage-yeWcgiVo.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardProfileModal-DiIM1-8L.js → LeaderboardProfileModal-CDmZtQ_m.js} +3 -3
- package/dashboard/dist/assets/{LeaderboardProfilePage-UzcVaHbK.js → LeaderboardProfilePage-BqJYxoN1.js} +2 -2
- package/dashboard/dist/assets/LimitsPage-D8NFgXbZ.js +4 -0
- package/dashboard/dist/assets/LocalOnlyNotice-DjdhDEiq.js +1 -0
- package/dashboard/dist/assets/{LoginCard-e4xbbFLq.js → LoginCard-jQXAmSQb.js} +1 -1
- package/dashboard/dist/assets/{LoginModal-CLxWc3FD.js → LoginModal-q4G6EN7b.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-sf34MK6Q.js → LoginPage-BklWSXzs.js} +1 -1
- package/dashboard/dist/assets/{PetPage-BA_BAFKG.js → PetPage-DyWuMUTA.js} +1 -1
- package/dashboard/dist/assets/{PopoverPopup-BwFAXu-Z.js → PopoverPopup-Dbxed_FL.js} +1 -1
- package/dashboard/dist/assets/{ProviderIcon-MRSlzNzV.js → ProviderIcon-ChYuSSfj.js} +1 -1
- package/dashboard/dist/assets/{ResetPasswordPage-DJAq2p4v.js → ResetPasswordPage-DJww1dxo.js} +1 -1
- package/dashboard/dist/assets/{SegmentedControl-LWEqN03-.js → SegmentedControl-Dr73_QVm.js} +1 -1
- package/dashboard/dist/assets/{Select-tkoxDrUN.js → Select-BMCy_8oY.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-bBnvuF48.js → SelectItemText-BRU7mlBI.js} +1 -1
- package/dashboard/dist/assets/{ServiceStatusPage-DDGNQfQ1.js → ServiceStatusPage-DDao-oTH.js} +1 -1
- package/dashboard/dist/assets/{SessionsPage-x7-I3BLn.js → SessionsPage-BjngkrsY.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-ColZX8Yi.js → SettingsPage-Dsftjg5j.js} +1 -1
- package/dashboard/dist/assets/{SkillsPage-DELWPebQ.js → SkillsPage-igML0DOZ.js} +1 -1
- package/dashboard/dist/assets/{TokenGalaxy-Bz8Cto8i.js → TokenGalaxy-BBETSYe7.js} +1 -1
- package/dashboard/dist/assets/{ToolbarRootContext-BvOVtmfA.js → ToolbarRootContext-CzEAxfqj.js} +1 -1
- package/dashboard/dist/assets/{TrendMonitor-DuNGP2Rf.js → TrendMonitor-JV6lkw-s.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-CRGlX9WP.js → WidgetsPage-GpUmv0hI.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-DQ3hLeL1.js → WrappedPage-SP2r4wf1.js} +1 -1
- package/dashboard/dist/assets/{__vite-browser-external-CGdlUam8.js → __vite-browser-external-AQgdBxou.js} +5 -4
- package/dashboard/dist/assets/{agent-logos-FfNeyajM.js → agent-logos-DxwSc05k.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-BEQHH_0c.js → arrow-up-right-CDW5zn0Q.js} +1 -1
- package/dashboard/dist/assets/{check-Bl_xgq6c.js → check-CQfDkdqM.js} +1 -1
- package/dashboard/dist/assets/{chevron-right-YO2OTiWy.js → chevron-right-DDFSY4w-.js} +1 -1
- package/dashboard/dist/assets/{copy-DtRgnD2D.js → copy-hxnyMdBa.js} +1 -1
- package/dashboard/dist/assets/{download-BiCrU4Wh.js → download-DOUBKxcf.js} +1 -1
- package/dashboard/dist/assets/{external-link-CVogXP9K.js → external-link-CVipCZOa.js} +1 -1
- package/dashboard/dist/assets/{flame-GFlQvi3d.js → flame-C-QU6mPf.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-BZrnF3-R.js → format-tokens-DRX15id1.js} +1 -1
- package/dashboard/dist/assets/{icons-CzzsWeR-.js → icons-ajxtn_0O.js} +1 -1
- package/dashboard/dist/assets/{index-CyOwnTlp.js → index-Bq5VZMkS.js} +1 -1
- package/dashboard/dist/assets/{index-B1S00F5t.js → index-DnVXRsqb.js} +1 -1
- package/dashboard/dist/assets/{index-mrU077Y8.js → index-OJC-yROZ.js} +1 -1
- package/dashboard/dist/assets/{info-CL-k0W8L.js → info-eITfPd17.js} +1 -1
- package/dashboard/dist/assets/{limits-providers-DGKlD0uY.js → limits-providers-TMq74bRy.js} +1 -1
- package/dashboard/dist/assets/{link-2-DOsRG9tT.js → link-2-D778MOmL.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-Da-W_cCG.js → loader-circle-uN5rBNIF.js} +1 -1
- package/dashboard/dist/assets/{maximize-2-CPp2Asek.js → maximize-2-C4FBbMpN.js} +1 -1
- package/dashboard/dist/assets/{modifiers.esm-B0cihd2s.js → modifiers.esm-DLeiQDTT.js} +1 -1
- package/dashboard/dist/assets/{monitor-smartphone-CLMr7OcT.js → monitor-smartphone-C-obu2-u.js} +1 -1
- package/dashboard/dist/assets/{provider-display-h1GGY5sy.js → provider-display-Bjl8tmYu.js} +1 -1
- package/dashboard/dist/assets/{react-BXj1W2tW.js → react-Diah7uAT.js} +1 -1
- package/dashboard/dist/assets/{search-DTwQkbLa.js → search-B0bPOquo.js} +1 -1
- package/dashboard/dist/assets/{skills-api-B7_r_5CR.js → skills-api-6otf2Sdl.js} +1 -1
- package/dashboard/dist/assets/{sortable.esm-Ba4_NOAf.js → sortable.esm-DcrJaOfF.js} +1 -1
- package/dashboard/dist/assets/{store-CZZj0fmU.js → store-DOs4omJM.js} +1 -1
- package/dashboard/dist/assets/{terminal-Dd0uhXcN.js → terminal-CpMZjaGk.js} +1 -1
- package/dashboard/dist/assets/{trash-2-CyBqbulx.js → trash-2-BQYnn3zf.js} +1 -1
- package/dashboard/dist/assets/{use-community-stats-D657285K.js → use-community-stats-CdL4zXXV.js} +1 -1
- package/dashboard/dist/assets/{use-limits-display-prefs-z0wBtxb1.js → use-limits-display-prefs-DUh4f8f4.js} +1 -1
- package/dashboard/dist/assets/{use-ordered-list-CiIuzdVF.js → use-ordered-list-DVs0Ik3O.js} +1 -1
- package/dashboard/dist/assets/use-reduced-motion--_Yc7AWk.js +1 -0
- package/dashboard/dist/assets/{use-session-efficiency-pref-BiHWvNJQ.js → use-session-efficiency-pref-CGggPI6Y.js} +1 -1
- package/dashboard/dist/assets/{use-transform-DcbCiXLq.js → use-transform-DMj91FEL.js} +1 -1
- package/dashboard/dist/assets/{use-usage-limits-tUq-_GSd.js → use-usage-limits-xJOXzuZG.js} +1 -1
- package/dashboard/dist/assets/{useCurrency-BlOEzUvV.js → useCurrency-BQRBx-KO.js} +1 -1
- package/dashboard/dist/assets/{useScrollLock-CFKQBf15.js → useScrollLock-DuTPOBl8.js} +1 -1
- package/dashboard/dist/assets/{useTokenFormat-ggxahHK0.js → useTokenFormat-Dd95ph6d.js} +1 -1
- package/dashboard/dist/assets/{zap-De7YrxAq.js → zap-DJMdRI6y.js} +1 -1
- package/dashboard/dist/index.html +7 -7
- package/dashboard/dist/ip-check.html +1 -1
- package/dashboard/dist/leaderboard.html +1 -1
- package/dashboard/dist/llms.txt +4 -4
- package/dashboard/dist/share.html +2 -2
- package/package.json +3 -3
- package/src/commands/sync.js +1 -0
- package/src/lib/grok-hook.js +11 -2
- package/src/lib/opencode-go-limits.js +59 -30
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +283 -68
- package/src/lib/star-cta.js +1 -1
- package/src/lib/usage-limits.js +3 -3
- package/dashboard/dist/assets/DialogDescription-fYPOWV-6.js +0 -1
- package/dashboard/dist/assets/HeaderGithubStar-BN1WZPnH.js +0 -1
- package/dashboard/dist/assets/LimitsPage-Clg8P5-M.js +0 -4
- package/dashboard/dist/assets/LocalOnlyNotice-rdNf4GvF.js +0 -1
- package/dashboard/dist/assets/use-reduced-motion-DXlYG36v.js +0 -1
|
@@ -5,32 +5,23 @@ const { readSqliteJsonRowsAsync } = require("./sqlite-reader");
|
|
|
5
5
|
|
|
6
6
|
// OpenCode Go usage limits.
|
|
7
7
|
//
|
|
8
|
-
// Two data sources
|
|
8
|
+
// Two data sources are available:
|
|
9
9
|
//
|
|
10
|
-
// 1.
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// heuristic. Its only blind spot is usage that did NOT go through the
|
|
16
|
-
// local CLI (e.g. the web console, or another machine). This is what
|
|
17
|
-
// token-monitor (Javis603/token-monitor) falls back to, and the only
|
|
18
|
-
// source that survives opencode's OAuth changes (see #225).
|
|
10
|
+
// 1. Web scrape of the workspace dashboard
|
|
11
|
+
// (https://opencode.ai/workspace/<id>/go) for the server's authoritative
|
|
12
|
+
// rolling (5h) / weekly / monthly usagePercent and subscription state.
|
|
13
|
+
// The cookie is sent as `Cookie: auth=<OPENCODE_GO_AUTH_COOKIE>` per
|
|
14
|
+
// slkiser/opencode-quota#41.
|
|
19
15
|
//
|
|
20
|
-
// 2.
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
// page (the #225 saga). The cookie is sent verbatim as
|
|
27
|
-
// `Cookie: auth=<OPENCODE_GO_AUTH_COOKIE>` per slkiser/opencode-quota#41.
|
|
16
|
+
// 2. Local opencode.db cost aggregation, explicitly enabled with
|
|
17
|
+
// TOKENTRACKER_OPENCODE_GO_LOCAL_ESTIMATE=1. The `opencode` CLI records
|
|
18
|
+
// every Go turn's USD `cost` in SQLite, so cost ÷ Go's dollar caps is a
|
|
19
|
+
// useful local estimate. It cannot prove that the account still has an
|
|
20
|
+
// active Go subscription, because the database contains historical turns
|
|
21
|
+
// but no current entitlement state.
|
|
28
22
|
//
|
|
29
|
-
// The
|
|
30
|
-
//
|
|
31
|
-
// only the inference gateway (/zen/go/v1), not the usage windows — so the local
|
|
32
|
-
// DB is the only accurate auth-free option. The returned shape is identical for
|
|
33
|
-
// both sources; `source` is `'local'` or `'web'`.
|
|
23
|
+
// The returned shape is shared by both sources. `source` is `'web'` for
|
|
24
|
+
// authoritative dashboard data or `'local-estimate'` for the opt-in estimate.
|
|
34
25
|
|
|
35
26
|
const SCRAPED_NUMBER_PATTERN = "([0-9]+(?:\\.[0-9]+)?)";
|
|
36
27
|
|
|
@@ -52,6 +43,26 @@ const DASHBOARD_URL_SUFFIX = "/go";
|
|
|
52
43
|
const USER_AGENT =
|
|
53
44
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Gecko/20100101 Firefox/148.0";
|
|
54
45
|
const DEFAULT_SCRAPE_TIMEOUT_MS = 10_000;
|
|
46
|
+
const LOCAL_ESTIMATE_ENV = "TOKENTRACKER_OPENCODE_GO_LOCAL_ESTIMATE";
|
|
47
|
+
|
|
48
|
+
function isTruthyEnvValue(value) {
|
|
49
|
+
return ["1", "true", "yes", "on"].includes(String(value ?? "").trim().toLowerCase());
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function localEstimateEnabled(env = process.env) {
|
|
53
|
+
return Boolean(env && typeof env === "object" && isTruthyEnvValue(env[LOCAL_ESTIMATE_ENV]));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// OpenCode's inactive Go workspace renders a Subscribe button and no usage
|
|
57
|
+
// items. Keep this detection deliberately narrow: an unknown/changed page must
|
|
58
|
+
// remain an error, not be guessed as an inactive subscription.
|
|
59
|
+
function detectSubscriptionStatus(html) {
|
|
60
|
+
if (typeof html !== "string") return "unknown";
|
|
61
|
+
const normalized = html.replace(/\\(["'])/g, "$1");
|
|
62
|
+
return /data-slot\s*=\s*["']subscribe-button["']/i.test(normalized)
|
|
63
|
+
? "inactive"
|
|
64
|
+
: "unknown";
|
|
65
|
+
}
|
|
55
66
|
|
|
56
67
|
function readConfig(env = process.env) {
|
|
57
68
|
if (!env || typeof env !== "object") return null;
|
|
@@ -412,7 +423,8 @@ function buildGoAggregateSql({ sessionStart, weekStart, weekEnd, monthStart, mon
|
|
|
412
423
|
}
|
|
413
424
|
|
|
414
425
|
// Returns { source:'local', primary/secondary/tertiary_window } or null when no
|
|
415
|
-
// opencode.db / no opencode-go rows are found.
|
|
426
|
+
// opencode.db / no opencode-go rows are found. The caller labels this result as
|
|
427
|
+
// an estimate and only exposes it when explicitly opted in.
|
|
416
428
|
async function collectOpencodeGoLocal({ home, env = process.env, nowMs = Date.now(), sqliteOptions = {} } = {}) {
|
|
417
429
|
const paths = discoverOpencodeDbPaths({ home, env });
|
|
418
430
|
if (paths.length === 0) return null;
|
|
@@ -465,7 +477,8 @@ function localGoResult(local) {
|
|
|
465
477
|
return {
|
|
466
478
|
configured: true,
|
|
467
479
|
error: null,
|
|
468
|
-
source: "local",
|
|
480
|
+
source: "local-estimate",
|
|
481
|
+
subscription_status: "unknown",
|
|
469
482
|
// No `plan_label` — the brand name "OpenCode Go" is the row title.
|
|
470
483
|
primary_window: local.primary_window || null,
|
|
471
484
|
secondary_window: local.secondary_window || null,
|
|
@@ -527,6 +540,13 @@ async function scrapeOpencodeGoWeb({ cfg, fetchImpl, nowMs, timeoutMs }) {
|
|
|
527
540
|
|
|
528
541
|
const { rolling, weekly, monthly } = extractWindows(html, nowMs);
|
|
529
542
|
if (!rolling && !weekly && !monthly) {
|
|
543
|
+
if (detectSubscriptionStatus(html) === "inactive") {
|
|
544
|
+
return {
|
|
545
|
+
configured: true,
|
|
546
|
+
error: null,
|
|
547
|
+
subscription_status: "inactive",
|
|
548
|
+
};
|
|
549
|
+
}
|
|
530
550
|
return {
|
|
531
551
|
configured: true,
|
|
532
552
|
error:
|
|
@@ -537,6 +557,7 @@ async function scrapeOpencodeGoWeb({ cfg, fetchImpl, nowMs, timeoutMs }) {
|
|
|
537
557
|
return {
|
|
538
558
|
configured: true,
|
|
539
559
|
error: null,
|
|
560
|
+
subscription_status: "active",
|
|
540
561
|
// No `plan_label` — the brand name "OpenCode Go" is the row title, so
|
|
541
562
|
// appending "Go" again would render "OpenCode Go Go" in the panel.
|
|
542
563
|
primary_window: rolling,
|
|
@@ -554,20 +575,26 @@ async function fetchOpencodeGoLimits({
|
|
|
554
575
|
sqliteOptions = {},
|
|
555
576
|
} = {}) {
|
|
556
577
|
const cfg = readConfig(env);
|
|
578
|
+
const allowLocalEstimate = localEstimateEnabled(env);
|
|
557
579
|
|
|
558
|
-
//
|
|
559
|
-
//
|
|
580
|
+
// A configured cookie gives us the only authoritative subscription state.
|
|
581
|
+
// Never replace an explicit inactive page with historical local usage.
|
|
560
582
|
if (cfg) {
|
|
561
583
|
const web = await scrapeOpencodeGoWeb({ cfg, fetchImpl, nowMs, timeoutMs });
|
|
584
|
+
if (web?.subscription_status === "inactive") return web;
|
|
562
585
|
if (web && !web.error && (web.primary_window || web.secondary_window || web.tertiary_window)) {
|
|
563
586
|
return { ...web, source: "web" };
|
|
564
587
|
}
|
|
565
|
-
|
|
566
|
-
|
|
588
|
+
if (allowLocalEstimate) {
|
|
589
|
+
const local = await collectOpencodeGoLocal({ home, env, nowMs, sqliteOptions });
|
|
590
|
+
if (local) return localGoResult(local);
|
|
591
|
+
}
|
|
567
592
|
return web || { configured: true, error: "OpenCode Go unavailable" };
|
|
568
593
|
}
|
|
569
594
|
|
|
570
|
-
//
|
|
595
|
+
// Local history cannot establish that the account is currently subscribed.
|
|
596
|
+
// Keep it available for users who explicitly accept that limitation.
|
|
597
|
+
if (!allowLocalEstimate) return { configured: false };
|
|
571
598
|
const local = await collectOpencodeGoLocal({ home, env, nowMs, sqliteOptions });
|
|
572
599
|
if (local) return localGoResult(local);
|
|
573
600
|
return { configured: false };
|
|
@@ -576,6 +603,8 @@ async function fetchOpencodeGoLimits({
|
|
|
576
603
|
module.exports = {
|
|
577
604
|
fetchOpencodeGoLimits,
|
|
578
605
|
readConfig,
|
|
606
|
+
localEstimateEnabled,
|
|
607
|
+
detectSubscriptionStatus,
|
|
579
608
|
extractWindows,
|
|
580
609
|
parseWindowUsage,
|
|
581
610
|
parseDataSlotFormat,
|