tokentracker-cli 0.96.0 → 0.96.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.
- package/README.de.md +2 -2
- package/README.ja.md +2 -2
- package/README.ko.md +2 -2
- package/README.md +4 -2
- package/README.zh-CN.md +3 -3
- package/dashboard/dist/assets/{AchievementBadge-Bb2ljquW.js → AchievementBadge-CgEitoX1.js} +1 -1
- package/dashboard/dist/assets/{AchievementsPage-ByUP2x8a.js → AchievementsPage-dnnea0JH.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-_L6sCLTw.js → AchievementsSection-CJqG0UP7.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-B9n_-45B.js → BadgeDetailModal-BLV6SJoI.js} +1 -1
- package/dashboard/dist/assets/{BotAnimated-lWmg-aZg.js → BotAnimated-Cm78yEbz.js} +1 -1
- package/dashboard/dist/assets/{Card-aSp259T0.js → Card-IPGSYT6O.js} +1 -1
- package/dashboard/dist/assets/{ClawdAnimated-Cy-XaTXW.js → ClawdAnimated-04w1U1sm.js} +2 -2
- package/dashboard/dist/assets/{CommandPalette-CNwtKCUm.js → CommandPalette-gSSa1V_s.js} +1 -1
- package/dashboard/dist/assets/{CommunityStatsModal-DJSezaPV.js → CommunityStatsModal-CICwUz14.js} +1 -1
- package/dashboard/dist/assets/{ConfirmModal-CVjmhZd6.js → ConfirmModal-DaWC0cY7.js} +1 -1
- package/dashboard/dist/assets/{Controls-BIj6yVxE.js → Controls-BDihA03F.js} +1 -1
- package/dashboard/dist/assets/DashboardPage-hV7wncKF.js +1 -0
- package/dashboard/dist/assets/{DevicePage-ptsI2fZc.js → DevicePage-BPpo_eiY.js} +1 -1
- package/dashboard/dist/assets/{DialogClose-D1pLoZ56.js → DialogClose-C_dF-r3s.js} +1 -1
- package/dashboard/dist/assets/DialogDescription-GClOSCaE.js +1 -0
- package/dashboard/dist/assets/{DialogTitle-DfSBUjWf.js → DialogTitle-Buh_5688.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-DBn4L_BV.js → FadeIn-DmI9PRLa.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-EJLBwEqp.js → HeaderGithubStar-CBO4cY7i.js} +1 -1
- package/dashboard/dist/assets/{HoverTooltip-DaSrZhYd.js → HoverTooltip-CPFGhi9K.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-diQTVaYt.js → IpCheckPage-Do7w_6z6.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-BqCxjwar.js → LandingPage-at_Ti1ZE.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardAvatar-CQImCsPN.js → LeaderboardAvatar-BH1cnKPp.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardPage-D2ZDUi_O.js → LeaderboardPage-Cd30aXwL.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardProfileModal-DHvADX1d.js → LeaderboardProfileModal-CVsti_HN.js} +3 -3
- package/dashboard/dist/assets/{LeaderboardProfilePage-CJsedB28.js → LeaderboardProfilePage-BfSpDM9e.js} +1 -1
- package/dashboard/dist/assets/LimitsPage-_-BadDAj.js +8 -0
- package/dashboard/dist/assets/{LocalOnlyNotice-Cmnvu9tI.js → LocalOnlyNotice-9-vRgsdn.js} +1 -1
- package/dashboard/dist/assets/{LoginCard-BQmKkD7X.js → LoginCard-DM_ZdFNl.js} +1 -1
- package/dashboard/dist/assets/{LoginModal-2oPROePZ.js → LoginModal-BaNMznwh.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-aqdUJoQK.js → LoginPage-BMMthUf4.js} +1 -1
- package/dashboard/dist/assets/{PetPage-Bn3p_o5r.js → PetPage-Iq8Hswai.js} +1 -1
- package/dashboard/dist/assets/{PopoverPopup-DXD_YdiB.js → PopoverPopup-DXr3JxVV.js} +1 -1
- package/dashboard/dist/assets/{ProviderIcon-BZZ45-gY.js → ProviderIcon-sb2keSY2.js} +1 -1
- package/dashboard/dist/assets/{ResetPasswordPage-Bn5ITiHQ.js → ResetPasswordPage-Ca4SULSV.js} +1 -1
- package/dashboard/dist/assets/{SegmentedControl-hGXboQZy.js → SegmentedControl-Bbsn-qvZ.js} +1 -1
- package/dashboard/dist/assets/{Select-BP8aVRZ1.js → Select-vD-yj-qa.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-Odx47kND.js → SelectItemText-CRtFEuvg.js} +1 -1
- package/dashboard/dist/assets/{ServiceStatusPage-DUueam0N.js → ServiceStatusPage-BPS8KJ3a.js} +1 -1
- package/dashboard/dist/assets/{SessionsPage-BA9IFqQ1.js → SessionsPage-C1yt3TMZ.js} +1 -1
- package/dashboard/dist/assets/SettingsPage-CWVHrMer.js +2 -0
- package/dashboard/dist/assets/{SkillsPage-Ds2vH_PG.js → SkillsPage-DGWEH1xm.js} +1 -1
- package/dashboard/dist/assets/{TokenGalaxy-CWBR4jnB.js → TokenGalaxy-DKvbJbnv.js} +1 -1
- package/dashboard/dist/assets/{ToolbarRootContext-Bmg56vYz.js → ToolbarRootContext-D8yov1dW.js} +1 -1
- package/dashboard/dist/assets/{TrendMonitor-BQzcllvg.js → TrendMonitor-YF5C_-L1.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-Bu3tHDjO.js → WidgetsPage-BKV3DgXg.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-BrAMJhgy.js → WrappedPage-s4IRoLf7.js} +1 -1
- package/dashboard/dist/assets/__vite-browser-external-CvMMIjhi.css +1 -0
- package/dashboard/dist/assets/__vite-browser-external-_LUatzwU.js +45 -0
- package/dashboard/dist/assets/{agent-logos-B8lT-HcI.js → agent-logos-Hbt-wyl2.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-rpBCOTg2.js → arrow-up-right-KeIpKlw3.js} +1 -1
- package/dashboard/dist/assets/{check-DIKw7TYH.js → check-_QKyY1v_.js} +1 -1
- package/dashboard/dist/assets/{composite-_NeXO0lv.js → composite-BidfcMeb.js} +1 -1
- package/dashboard/dist/assets/{copy-CsfAtL7P.js → copy-DpLM3QMD.js} +1 -1
- package/dashboard/dist/assets/{download-DM1W9pIW.js → download-C4NX-JnW.js} +1 -1
- package/dashboard/dist/assets/{external-link-CwbuMbeQ.js → external-link-CG-7FcOF.js} +1 -1
- package/dashboard/dist/assets/{flame-DcYbLdhE.js → flame-CkWid7Ji.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-CEvr3dNy.js → format-tokens-CbwWhioZ.js} +1 -1
- package/dashboard/dist/assets/{icons-DaGMVsJ5.js → icons-BZq17rU3.js} +1 -1
- package/dashboard/dist/assets/{index-ChZkJjpk.js → index-CR9tDiiC.js} +1 -1
- package/dashboard/dist/assets/{index-BVVLPj3N.js → index-CSwEiUn4.js} +1 -1
- package/dashboard/dist/assets/{index-T7OjmEuX.js → index-DDGLE0dz.js} +1 -1
- package/dashboard/dist/assets/{info-CAjN3dX4.js → info-mkeRjzqc.js} +1 -1
- package/dashboard/dist/assets/limits-providers-DRkcWQup.js +1 -0
- package/dashboard/dist/assets/{link-2-DaWH2Tyc.js → link-2-BjMw8csC.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-CnF8qPi1.js → loader-circle-cGWOJnWn.js} +1 -1
- package/dashboard/dist/assets/{maximize-2-B-2Pnj6g.js → maximize-2-Cg_S73tD.js} +1 -1
- package/dashboard/dist/assets/{modifiers.esm-BoDOvUKl.js → modifiers.esm-DNxTWxId.js} +1 -1
- package/dashboard/dist/assets/{monitor-smartphone-DDgwxG_E.js → monitor-smartphone-BvE9Tt2U.js} +1 -1
- package/dashboard/dist/assets/{plus-DIc1YUWB.js → plus-BC2wdPRr.js} +1 -1
- package/dashboard/dist/assets/{provider-display-yeNsVCO_.js → provider-display-B7GggHQy.js} +1 -1
- package/dashboard/dist/assets/{react-DZqS6YTX.js → react-D0kcslTz.js} +1 -1
- package/dashboard/dist/assets/{search-D6tEppYJ.js → search-BuBNF3E3.js} +1 -1
- package/dashboard/dist/assets/{skills-api-vsA1rc1Z.js → skills-api-DxAN5pNx.js} +1 -1
- package/dashboard/dist/assets/{sortable.esm-DDCnS1HI.js → sortable.esm-DoqMcEX-.js} +1 -1
- package/dashboard/dist/assets/{store-Crne4DqF.js → store-Cg1HeUFM.js} +1 -1
- package/dashboard/dist/assets/{terminal-Ca7dkLMF.js → terminal-COWFUJdU.js} +1 -1
- package/dashboard/dist/assets/{trash-2-CjEAS5ic.js → trash-2-Cqjki3RI.js} +1 -1
- package/dashboard/dist/assets/{use-community-stats-BHx2YxyK.js → use-community-stats-DsrlOPDM.js} +1 -1
- package/dashboard/dist/assets/{use-latest-request-guard-BLGbXQdf.js → use-latest-request-guard-ryRFL2gx.js} +1 -1
- package/dashboard/dist/assets/{use-limits-display-prefs-DBkAp6ob.js → use-limits-display-prefs-DkSuu12m.js} +1 -1
- package/dashboard/dist/assets/{use-ordered-list-BTfW5M9u.js → use-ordered-list-D-Q86R1b.js} +1 -1
- package/dashboard/dist/assets/use-reduced-motion-D7NNqavo.js +1 -0
- package/dashboard/dist/assets/{use-session-efficiency-pref-DBmd-MqH.js → use-session-efficiency-pref-CrNz45y7.js} +1 -1
- package/dashboard/dist/assets/{use-transform-Bp5XrwaQ.js → use-transform-CoGM21px.js} +1 -1
- package/dashboard/dist/assets/{use-usage-limits-BmqRcyhH.js → use-usage-limits-C_6L1sO5.js} +1 -1
- package/dashboard/dist/assets/{useCurrency-B0YsRDj-.js → useCurrency-CgCfDktb.js} +1 -1
- package/dashboard/dist/assets/{useTokenFormat-PP3D0Ket.js → useTokenFormat-QKtzCKTL.js} +1 -1
- package/dashboard/dist/assets/{zap-BVOm1aBH.js → zap-CTIobzgU.js} +1 -1
- package/dashboard/dist/brand-logos/commandcode.svg +1 -0
- package/dashboard/dist/index.html +5 -5
- package/dashboard/dist/ip-check.html +2 -2
- package/dashboard/dist/leaderboard.html +2 -2
- package/dashboard/dist/share.html +2 -2
- package/package.json +1 -1
- package/src/commands/status.js +4 -4
- package/src/commands/sync.js +5 -3
- package/src/lib/ark-agent-plan-limits.js +4 -3
- package/src/lib/ark-coding-plan-limits.js +6 -8
- package/src/lib/codex-rollout-parser.js +2 -2
- package/src/lib/command-runner.js +13 -0
- package/src/lib/commandcode-limits.js +317 -0
- package/src/lib/local-api.js +3 -0
- package/src/lib/pricing/curated-overrides.json +11 -0
- package/src/lib/pricing/index.js +6 -7
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +183 -11
- package/src/lib/session-analytics.js +2 -2
- package/src/lib/usage-limits.js +153 -14
- package/dashboard/dist/assets/DashboardPage-BjYZLmqQ.js +0 -1
- package/dashboard/dist/assets/DialogDescription-KY7X94CG.js +0 -1
- package/dashboard/dist/assets/LimitsPage-CAwff24b.js +0 -6
- package/dashboard/dist/assets/SettingsPage-DLOHHB4f.js +0 -2
- package/dashboard/dist/assets/__vite-browser-external-4IGm4Djn.js +0 -45
- package/dashboard/dist/assets/__vite-browser-external-CCMdjCX2.css +0 -1
- package/dashboard/dist/assets/limits-providers-jn7Yln_V.js +0 -1
- package/dashboard/dist/assets/use-reduced-motion-D_kUnDs4.js +0 -1
package/src/lib/rollout.js
CHANGED
|
@@ -4458,6 +4458,9 @@ function claudeMessageDedupKey(obj) {
|
|
|
4458
4458
|
function normalizeClaudeUsage(u) {
|
|
4459
4459
|
const inputTokens = toNonNegativeInt(u?.input_tokens);
|
|
4460
4460
|
const outputTokens = toNonNegativeInt(u?.output_tokens);
|
|
4461
|
+
const reasoningTokens = Math.min(outputTokens, toNonNegativeInt(
|
|
4462
|
+
u?.output_tokens_details?.thinking_tokens ?? u?.output_tokens_details?.reasoning_tokens,
|
|
4463
|
+
));
|
|
4461
4464
|
const cacheCreation = toNonNegativeInt(u?.cache_creation_input_tokens);
|
|
4462
4465
|
const cacheRead = toNonNegativeInt(u?.cache_read_input_tokens);
|
|
4463
4466
|
const totalTokens = inputTokens + outputTokens + cacheCreation + cacheRead;
|
|
@@ -4465,8 +4468,9 @@ function normalizeClaudeUsage(u) {
|
|
|
4465
4468
|
input_tokens: inputTokens,
|
|
4466
4469
|
cached_input_tokens: cacheRead,
|
|
4467
4470
|
cache_creation_input_tokens: cacheCreation,
|
|
4468
|
-
output_tokens
|
|
4469
|
-
|
|
4471
|
+
// Claude rows price reasoning separately; it is already included in usage.output_tokens.
|
|
4472
|
+
output_tokens: outputTokens - reasoningTokens,
|
|
4473
|
+
reasoning_output_tokens: reasoningTokens,
|
|
4470
4474
|
total_tokens: totalTokens,
|
|
4471
4475
|
};
|
|
4472
4476
|
}
|
|
@@ -5841,17 +5845,21 @@ function resolveQoderCnProjectsDir({ home = os.homedir(), env = process.env, pla
|
|
|
5841
5845
|
? path.resolve(env.QODER_CN_PROJECTS_DIR.trim())
|
|
5842
5846
|
: null;
|
|
5843
5847
|
if (override) return override;
|
|
5844
|
-
//
|
|
5845
|
-
//
|
|
5848
|
+
// The new CN app (com.qodercn.app.stable, 2026-08+) keeps its sessions in
|
|
5849
|
+
// ~/.qoder-cn/projects — a sibling of the international ~/.qoder, not a
|
|
5850
|
+
// shared directory. Pointing CN at ~/.qoder/projects made the "CN dir
|
|
5851
|
+
// diverges from international" guards in sync.js/status.js always false,
|
|
5852
|
+
// so new-version CN JSONL usage was silently never parsed (and on
|
|
5853
|
+
// international-only installs would have double-counted under qoder-cn).
|
|
5846
5854
|
if (platform === "win32" && !env.QODER_CN_PROJECTS_DIR) {
|
|
5847
5855
|
const discoverWslHome = deps.discoverWslHome || wsl.discoverWslHome;
|
|
5848
|
-
const wslRoot = wsl.shouldProbeWsl(env) ? discoverWslHome(".qoder", { ...deps, env }) : null;
|
|
5856
|
+
const wslRoot = wsl.shouldProbeWsl(env) ? discoverWslHome(".qoder-cn", { ...deps, env }) : null;
|
|
5849
5857
|
if (wslRoot) {
|
|
5850
5858
|
const wslProjects = path.join(wslRoot, "projects");
|
|
5851
5859
|
if ((deps.existsSync || fssync.existsSync)(wslProjects)) return wslProjects;
|
|
5852
5860
|
}
|
|
5853
5861
|
}
|
|
5854
|
-
return path.join(home, ".qoder", "projects");
|
|
5862
|
+
return path.join(home, ".qoder-cn", "projects");
|
|
5855
5863
|
}
|
|
5856
5864
|
|
|
5857
5865
|
async function listQoderNewSessionFiles(projectsDir) {
|
|
@@ -5876,7 +5884,15 @@ async function listQoderNewSessionFiles(projectsDir) {
|
|
|
5876
5884
|
function qoderNewModelFromRecord(record) {
|
|
5877
5885
|
const msgModel = record?.message?.model;
|
|
5878
5886
|
const direct = typeof msgModel === "string" ? msgModel.trim() : "";
|
|
5879
|
-
|
|
5887
|
+
// CN BYOK routes embed an install-local provider UUID in the model id
|
|
5888
|
+
// ("qoder-custom-<uuid>/glm-5.3-flash"). Keep the bare model id so bucket
|
|
5889
|
+
// keys stay stable across reinstalls and don't fragment per user; official
|
|
5890
|
+
// ids (e.g. "qmodel_38max") have no prefix and pass through unchanged.
|
|
5891
|
+
const stripped = direct.replace(
|
|
5892
|
+
/^qoder-custom-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\//i,
|
|
5893
|
+
"",
|
|
5894
|
+
);
|
|
5895
|
+
return normalizeModelInput(stripped) || "qoder-agent";
|
|
5880
5896
|
}
|
|
5881
5897
|
|
|
5882
5898
|
function qoderNewMessageKey(record, filePath, lineIndex = 0) {
|
|
@@ -18654,6 +18670,9 @@ async function parseAntigravityIncremental({
|
|
|
18654
18670
|
const initialContextTokens = sameFile ? Number(prev.contextTokens || 0) : 0;
|
|
18655
18671
|
const initialPrevContext = sameFile ? Number(prev.previousContextTokens || 0) : 0;
|
|
18656
18672
|
const initialModel = sameFile && typeof prev.currentModel === "string" ? prev.currentModel : null;
|
|
18673
|
+
const initialLastPlannerModel =
|
|
18674
|
+
sameFile && typeof prev.lastPlannerModel === "string" ? prev.lastPlannerModel : null;
|
|
18675
|
+
const initialUsageSource = sameFile && typeof prev.usageSource === "string" ? prev.usageSource : null;
|
|
18657
18676
|
|
|
18658
18677
|
const projectContext = projectEnabled
|
|
18659
18678
|
? await resolveProjectContextForFile({
|
|
@@ -18673,6 +18692,8 @@ async function parseAntigravityIncremental({
|
|
|
18673
18692
|
initialContextTokens,
|
|
18674
18693
|
initialPrevContext,
|
|
18675
18694
|
initialModel,
|
|
18695
|
+
initialLastPlannerModel,
|
|
18696
|
+
initialUsageSource,
|
|
18676
18697
|
hourlyState,
|
|
18677
18698
|
touchedBuckets,
|
|
18678
18699
|
source: fileSource,
|
|
@@ -18690,6 +18711,8 @@ async function parseAntigravityIncremental({
|
|
|
18690
18711
|
contextTokens: result.contextTokens,
|
|
18691
18712
|
previousContextTokens: result.previousContextTokens,
|
|
18692
18713
|
currentModel: result.currentModel,
|
|
18714
|
+
lastPlannerModel: result.lastPlannerModel,
|
|
18715
|
+
usageSource: result.usageSource,
|
|
18693
18716
|
updatedAt: new Date().toISOString(),
|
|
18694
18717
|
};
|
|
18695
18718
|
|
|
@@ -18722,12 +18745,121 @@ async function parseAntigravityIncremental({
|
|
|
18722
18745
|
return { filesProcessed, eventsAggregated, bucketsQueued, projectBucketsQueued };
|
|
18723
18746
|
}
|
|
18724
18747
|
|
|
18748
|
+
function decodeAntigravityVarint(buf, offset) {
|
|
18749
|
+
let res = 0;
|
|
18750
|
+
let shift = 0;
|
|
18751
|
+
while (offset < buf.length) {
|
|
18752
|
+
const b = buf[offset++];
|
|
18753
|
+
res += (b & 0x7f) * 2 ** shift;
|
|
18754
|
+
if (!(b & 0x80)) break;
|
|
18755
|
+
shift += 7;
|
|
18756
|
+
}
|
|
18757
|
+
return [res, offset];
|
|
18758
|
+
}
|
|
18759
|
+
|
|
18760
|
+
function findAntigravityProtoFields(buf) {
|
|
18761
|
+
const fields = [];
|
|
18762
|
+
let offset = 0;
|
|
18763
|
+
while (offset < buf.length) {
|
|
18764
|
+
const [tag, next] = decodeAntigravityVarint(buf, offset);
|
|
18765
|
+
offset = next;
|
|
18766
|
+
const fieldNum = tag >> 3;
|
|
18767
|
+
const wireType = tag & 7;
|
|
18768
|
+
if (wireType === 0) {
|
|
18769
|
+
const [val, vNext] = decodeAntigravityVarint(buf, offset);
|
|
18770
|
+
offset = vNext;
|
|
18771
|
+
fields.push({ num: fieldNum, val });
|
|
18772
|
+
} else if (wireType === 2) {
|
|
18773
|
+
const [len, lNext] = decodeAntigravityVarint(buf, offset);
|
|
18774
|
+
offset = lNext;
|
|
18775
|
+
fields.push({ num: fieldNum, val: buf.subarray(offset, offset + len) });
|
|
18776
|
+
offset += len;
|
|
18777
|
+
} else if (wireType === 1) {
|
|
18778
|
+
offset += 8;
|
|
18779
|
+
} else if (wireType === 5) {
|
|
18780
|
+
offset += 4;
|
|
18781
|
+
} else {
|
|
18782
|
+
break;
|
|
18783
|
+
}
|
|
18784
|
+
}
|
|
18785
|
+
return fields;
|
|
18786
|
+
}
|
|
18787
|
+
|
|
18788
|
+
function extractAntigravityGenInfo(buf) {
|
|
18789
|
+
const root = findAntigravityProtoFields(buf);
|
|
18790
|
+
const f1 = root.find((f) => f.num === 1)?.val;
|
|
18791
|
+
if (!f1) return null;
|
|
18792
|
+
|
|
18793
|
+
const inner = findAntigravityProtoFields(f1);
|
|
18794
|
+
let model = null;
|
|
18795
|
+
const f19 = inner.find((f) => f.num === 19)?.val;
|
|
18796
|
+
if (f19) model = Buffer.from(f19).toString("utf8").trim();
|
|
18797
|
+
|
|
18798
|
+
let contextTokens = 0;
|
|
18799
|
+
const f9 = inner.find((f) => f.num === 9)?.val;
|
|
18800
|
+
if (f9) {
|
|
18801
|
+
const f10 = findAntigravityProtoFields(f9).find((f) => f.num === 10)?.val;
|
|
18802
|
+
if (f10) {
|
|
18803
|
+
const tok = findAntigravityProtoFields(f10).find((f) => f.num === 1)?.val;
|
|
18804
|
+
if (Number.isFinite(tok)) contextTokens = tok;
|
|
18805
|
+
}
|
|
18806
|
+
}
|
|
18807
|
+
|
|
18808
|
+
let lastStepIndex = null;
|
|
18809
|
+
for (const f of inner) {
|
|
18810
|
+
if (f.num !== 20 || !f.val) continue;
|
|
18811
|
+
const kv = findAntigravityProtoFields(f.val);
|
|
18812
|
+
const k = kv.find((x) => x.num === 1)?.val;
|
|
18813
|
+
const v = kv.find((x) => x.num === 2)?.val;
|
|
18814
|
+
if (k && Buffer.from(k).toString("utf8") === "last_step_index" && v) {
|
|
18815
|
+
const parsed = parseInt(Buffer.from(v).toString("utf8"), 10);
|
|
18816
|
+
if (Number.isFinite(parsed)) lastStepIndex = parsed;
|
|
18817
|
+
}
|
|
18818
|
+
}
|
|
18819
|
+
|
|
18820
|
+
return { model, contextTokens, lastStepIndex };
|
|
18821
|
+
}
|
|
18822
|
+
|
|
18823
|
+
function resolveAntigravityDbPath(transcriptPath) {
|
|
18824
|
+
if (!transcriptPath || typeof transcriptPath !== "string") return null;
|
|
18825
|
+
const m = transcriptPath.match(/^(.*)[/\\]brain[/\\]([^/\\]+)[/\\]\.system_generated[/\\]logs[/\\]transcript.*\.jsonl$/);
|
|
18826
|
+
if (!m) return null;
|
|
18827
|
+
return path.join(m[1], "conversations", `${m[2]}.db`);
|
|
18828
|
+
}
|
|
18829
|
+
|
|
18830
|
+
function readAntigravityConversationDb(dbPath) {
|
|
18831
|
+
if (!dbPath) return null;
|
|
18832
|
+
try {
|
|
18833
|
+
const rows = readSqliteJsonRows(
|
|
18834
|
+
dbPath,
|
|
18835
|
+
"SELECT idx, quote(data) as hex FROM gen_metadata ORDER BY idx",
|
|
18836
|
+
{ readOnly: true },
|
|
18837
|
+
);
|
|
18838
|
+
if (!Array.isArray(rows) || rows.length === 0) return null;
|
|
18839
|
+
|
|
18840
|
+
const stepMap = new Map();
|
|
18841
|
+
for (const r of rows) {
|
|
18842
|
+
if (!r || typeof r.hex !== "string" || !r.hex.startsWith("X'")) continue;
|
|
18843
|
+
const buf = Buffer.from(r.hex.slice(2, -1), "hex");
|
|
18844
|
+
const info = extractAntigravityGenInfo(buf);
|
|
18845
|
+
if (info && info.lastStepIndex != null && info.contextTokens > 0) {
|
|
18846
|
+
stepMap.set(info.lastStepIndex + 1, info);
|
|
18847
|
+
}
|
|
18848
|
+
}
|
|
18849
|
+
return stepMap.size > 0 ? stepMap : null;
|
|
18850
|
+
} catch (_) {
|
|
18851
|
+
return null;
|
|
18852
|
+
}
|
|
18853
|
+
}
|
|
18854
|
+
|
|
18725
18855
|
async function parseAntigravityFile({
|
|
18726
18856
|
filePath,
|
|
18727
18857
|
lastLine,
|
|
18728
18858
|
initialContextTokens,
|
|
18729
18859
|
initialPrevContext,
|
|
18730
18860
|
initialModel,
|
|
18861
|
+
initialLastPlannerModel,
|
|
18862
|
+
initialUsageSource,
|
|
18731
18863
|
hourlyState,
|
|
18732
18864
|
touchedBuckets,
|
|
18733
18865
|
source,
|
|
@@ -18744,6 +18876,8 @@ async function parseAntigravityFile({
|
|
|
18744
18876
|
contextTokens: 0,
|
|
18745
18877
|
previousContextTokens: 0,
|
|
18746
18878
|
currentModel: null,
|
|
18879
|
+
lastPlannerModel: null,
|
|
18880
|
+
usageSource: "estimated",
|
|
18747
18881
|
};
|
|
18748
18882
|
}
|
|
18749
18883
|
|
|
@@ -18752,6 +18886,8 @@ async function parseAntigravityFile({
|
|
|
18752
18886
|
.map((line) => line.trim())
|
|
18753
18887
|
.filter(Boolean);
|
|
18754
18888
|
let eventsAggregated = 0;
|
|
18889
|
+
const dbPath = resolveAntigravityDbPath(filePath);
|
|
18890
|
+
const stepMap = dbPath ? readAntigravityConversationDb(dbPath) : null;
|
|
18755
18891
|
// Resume cached context-token total + model so historical lines (i < lastLine)
|
|
18756
18892
|
// don't need to be re-tokenized on every sync. Falls back to a full re-walk
|
|
18757
18893
|
// when the cached state is missing (legacy cursor) or the file rotated.
|
|
@@ -18760,7 +18896,9 @@ async function parseAntigravityFile({
|
|
|
18760
18896
|
const cachedTokens = Number.isFinite(initialContextTokens) ? initialContextTokens : 0;
|
|
18761
18897
|
const cachedPrev = Number.isFinite(initialPrevContext) ? initialPrevContext : 0;
|
|
18762
18898
|
const cachedModel = typeof initialModel === "string" ? initialModel : null;
|
|
18763
|
-
const
|
|
18899
|
+
const sqliteCursor = initialUsageSource === "sqlite";
|
|
18900
|
+
const resumed =
|
|
18901
|
+
canResume && (cachedTokens > 0 || cachedModel !== null) && (!stepMap || sqliteCursor);
|
|
18764
18902
|
const scanStart = resumed ? lastLine : 0;
|
|
18765
18903
|
let currentModel = resumed ? cachedModel : null;
|
|
18766
18904
|
if (!currentModel) {
|
|
@@ -18771,6 +18909,11 @@ async function parseAntigravityFile({
|
|
|
18771
18909
|
// tokens accumulated AFTER that point count as new input on the next planner
|
|
18772
18910
|
// call — prevents O(N²) double-counting of the full history every turn.
|
|
18773
18911
|
let previousContextTokens = resumed ? cachedPrev : 0;
|
|
18912
|
+
let lastPlannerModel = null;
|
|
18913
|
+
if (resumed) {
|
|
18914
|
+
lastPlannerModel =
|
|
18915
|
+
typeof initialLastPlannerModel === "string" ? initialLastPlannerModel : cachedModel;
|
|
18916
|
+
}
|
|
18774
18917
|
let lastCompletedLine = Math.min(Number.isFinite(lastLine) ? lastLine : 0, lines.length);
|
|
18775
18918
|
|
|
18776
18919
|
for (let i = scanStart; i < lines.length; i++) {
|
|
@@ -18793,9 +18936,27 @@ async function parseAntigravityFile({
|
|
|
18793
18936
|
}
|
|
18794
18937
|
|
|
18795
18938
|
const eventContextTokens = antigravityContextTokens(parsed);
|
|
18939
|
+
const dbTurn =
|
|
18940
|
+
parsed.type === "PLANNER_RESPONSE" && stepMap && Number.isFinite(parsed.step_index)
|
|
18941
|
+
? stepMap.get(parsed.step_index)
|
|
18942
|
+
: null;
|
|
18943
|
+
const dbContextTokens = dbTurn && dbTurn.contextTokens > 0 ? dbTurn.contextTokens : 0;
|
|
18944
|
+
if (dbTurn && dbTurn.model) {
|
|
18945
|
+
const norm = normalizeAntigravityTranscriptModel(dbTurn.model);
|
|
18946
|
+
if (norm) currentModel = norm;
|
|
18947
|
+
}
|
|
18796
18948
|
|
|
18797
18949
|
if (!isNewEvent) {
|
|
18798
|
-
|
|
18950
|
+
if (parsed.type === "PLANNER_RESPONSE") {
|
|
18951
|
+
if (dbContextTokens > 0) {
|
|
18952
|
+
contextTokens = dbContextTokens;
|
|
18953
|
+
}
|
|
18954
|
+
previousContextTokens = contextTokens;
|
|
18955
|
+
lastPlannerModel = currentModel;
|
|
18956
|
+
contextTokens += eventContextTokens;
|
|
18957
|
+
} else {
|
|
18958
|
+
contextTokens += eventContextTokens;
|
|
18959
|
+
}
|
|
18799
18960
|
lastCompletedLine = i + 1;
|
|
18800
18961
|
continue;
|
|
18801
18962
|
}
|
|
@@ -18822,7 +18983,14 @@ async function parseAntigravityFile({
|
|
|
18822
18983
|
const content = typeof parsed.content === "string" ? parsed.content : "";
|
|
18823
18984
|
const thinking = typeof parsed.thinking === "string" ? parsed.thinking : "";
|
|
18824
18985
|
|
|
18986
|
+
if (dbContextTokens > 0) {
|
|
18987
|
+
contextTokens = dbContextTokens;
|
|
18988
|
+
}
|
|
18989
|
+
if (lastPlannerModel && model !== lastPlannerModel) {
|
|
18990
|
+
previousContextTokens = 0;
|
|
18991
|
+
}
|
|
18825
18992
|
const inputDelta = Math.max(0, contextTokens - previousContextTokens);
|
|
18993
|
+
|
|
18826
18994
|
const outputTokens =
|
|
18827
18995
|
antigravityValueTokens(content) + antigravityValueTokens(parsed.tool_calls);
|
|
18828
18996
|
const reasoningTokens = antigravityValueTokens(thinking);
|
|
@@ -18830,8 +18998,6 @@ async function parseAntigravityFile({
|
|
|
18830
18998
|
delta.input_tokens = inputDelta;
|
|
18831
18999
|
delta.output_tokens = outputTokens;
|
|
18832
19000
|
delta.reasoning_output_tokens = reasoningTokens;
|
|
18833
|
-
// Match the mainstream convention (Codebuddy / Kilocode / OMP / Hermes):
|
|
18834
|
-
// total_tokens = sum of every token column. No cache columns here.
|
|
18835
19001
|
delta.total_tokens = inputDelta + outputTokens + reasoningTokens;
|
|
18836
19002
|
delta.billable_total_tokens = delta.total_tokens;
|
|
18837
19003
|
delta.conversation_count = 1;
|
|
@@ -18865,6 +19031,7 @@ async function parseAntigravityFile({
|
|
|
18865
19031
|
// so they MUST be billed as input on the next planner — don't fold them into
|
|
18866
19032
|
// previousContextTokens or that history vanishes from the totals.
|
|
18867
19033
|
previousContextTokens = contextTokens;
|
|
19034
|
+
lastPlannerModel = model;
|
|
18868
19035
|
contextTokens += eventContextTokens;
|
|
18869
19036
|
lastCompletedLine = i + 1;
|
|
18870
19037
|
}
|
|
@@ -18875,6 +19042,8 @@ async function parseAntigravityFile({
|
|
|
18875
19042
|
contextTokens,
|
|
18876
19043
|
previousContextTokens,
|
|
18877
19044
|
currentModel,
|
|
19045
|
+
lastPlannerModel,
|
|
19046
|
+
usageSource: stepMap ? "sqlite" : "estimated",
|
|
18878
19047
|
};
|
|
18879
19048
|
}
|
|
18880
19049
|
|
|
@@ -20457,6 +20626,9 @@ module.exports = {
|
|
|
20457
20626
|
parseAntigravityIncremental,
|
|
20458
20627
|
estimateAntigravityTokens,
|
|
20459
20628
|
isCjkCodePoint,
|
|
20629
|
+
resolveAntigravityDbPath,
|
|
20630
|
+
extractAntigravityGenInfo,
|
|
20631
|
+
readAntigravityConversationDb,
|
|
20460
20632
|
|
|
20461
20633
|
// Trae SOLO (ByteDance AI IDE)
|
|
20462
20634
|
resolveTraePath,
|
|
@@ -190,8 +190,8 @@ function normalizeModelUsageRows(rows) {
|
|
|
190
190
|
// selected_models re-seeds from `model`, model_attribution is derived from
|
|
191
191
|
// rerouted_usage_events, and cost_usd is always recomputed by
|
|
192
192
|
// repriceSessionRecord(). Worth ~19% of the file on a 6.8k-session history,
|
|
193
|
-
// most of it the long_context_* counters
|
|
194
|
-
// OPENAI_LONG_CONTEXT_INPUT_THRESHOLD in src/lib/pricing/index.js
|
|
193
|
+
// most of it the long_context_* counters for sessions with no requests over
|
|
194
|
+
// OPENAI_LONG_CONTEXT_INPUT_THRESHOLD in src/lib/pricing/index.js.
|
|
195
195
|
function serializeModelUsageRow(row) {
|
|
196
196
|
const out = { model: row.model };
|
|
197
197
|
for (const field of MODEL_USAGE_SUM_FIELDS) {
|
package/src/lib/usage-limits.js
CHANGED
|
@@ -30,6 +30,7 @@ const {
|
|
|
30
30
|
const { fetchGrokLimits } = require("./grok-limits");
|
|
31
31
|
const { fetchZcodeLimits } = require("./zcode-limits");
|
|
32
32
|
const { fetchOpencodeGoLimits } = require("./opencode-go-limits");
|
|
33
|
+
const { fetchCommandcodeLimits } = require("./commandcode-limits");
|
|
33
34
|
const { fetchQoderLimits, fetchQoderCnLimits } = require("./qoder-limits");
|
|
34
35
|
const { fetchArkCodingPlanLimits } = require("./ark-coding-plan-limits");
|
|
35
36
|
const { fetchArkAgentPlanLimits } = require("./ark-agent-plan-limits");
|
|
@@ -2167,10 +2168,19 @@ async function detectAntigravityProcess({
|
|
|
2167
2168
|
);
|
|
2168
2169
|
processes = parseWindowsProcesses(result?.stdout);
|
|
2169
2170
|
} else {
|
|
2170
|
-
|
|
2171
|
+
let result = await runCommand(commandRunner, "/bin/ps", ["-ax", "-o", "pid=,command="], {
|
|
2171
2172
|
timeout: timeoutMs,
|
|
2172
2173
|
signal,
|
|
2173
2174
|
});
|
|
2175
|
+
const isSpawnFailure = result?.error
|
|
2176
|
+
&& result.error.code !== "ETIMEDOUT"
|
|
2177
|
+
&& result.error.name !== "AbortError";
|
|
2178
|
+
if (isSpawnFailure && !result?.stdout) {
|
|
2179
|
+
result = await runCommand(commandRunner, "ps", ["-ax", "-o", "pid=,command="], {
|
|
2180
|
+
timeout: timeoutMs,
|
|
2181
|
+
signal,
|
|
2182
|
+
});
|
|
2183
|
+
}
|
|
2174
2184
|
processes = String(result?.stdout || "")
|
|
2175
2185
|
.split("\n")
|
|
2176
2186
|
.map(parseProcessLine)
|
|
@@ -2633,10 +2643,70 @@ function parseWindowsListeningPorts(output, pid) {
|
|
|
2633
2643
|
return Array.from(ports).sort((a, b) => a - b);
|
|
2634
2644
|
}
|
|
2635
2645
|
|
|
2646
|
+
function parseLinuxProcListeningPorts(pid, { procRoot = "/proc" } = {}) {
|
|
2647
|
+
const numPid = Number(pid);
|
|
2648
|
+
if (!Number.isFinite(numPid) || numPid <= 0) return [];
|
|
2649
|
+
const inodes = new Set();
|
|
2650
|
+
try {
|
|
2651
|
+
const fds = fs.readdirSync(path.join(procRoot, String(numPid), "fd"));
|
|
2652
|
+
for (const fd of fds) {
|
|
2653
|
+
try {
|
|
2654
|
+
const link = fs.readlinkSync(path.join(procRoot, String(numPid), "fd", fd));
|
|
2655
|
+
const m = link.match(/^socket:\[(\d+)\]$/);
|
|
2656
|
+
if (m) inodes.add(m[1]);
|
|
2657
|
+
} catch {}
|
|
2658
|
+
}
|
|
2659
|
+
} catch {
|
|
2660
|
+
return [];
|
|
2661
|
+
}
|
|
2662
|
+
if (inodes.size === 0) return [];
|
|
2663
|
+
|
|
2664
|
+
const ports = new Set();
|
|
2665
|
+
for (const table of [path.join(procRoot, "net", "tcp"), path.join(procRoot, "net", "tcp6")]) {
|
|
2666
|
+
try {
|
|
2667
|
+
const content = fs.readFileSync(table, "utf8");
|
|
2668
|
+
for (const line of content.split("\n")) {
|
|
2669
|
+
const parts = line.trim().split(/\s+/);
|
|
2670
|
+
if (parts.length > 9 && parts[3] === "0A") {
|
|
2671
|
+
const inode = parts[9];
|
|
2672
|
+
if (inodes.has(inode)) {
|
|
2673
|
+
const portHex = parts[1]?.split(":")[1];
|
|
2674
|
+
if (portHex) {
|
|
2675
|
+
const port = parseInt(portHex, 16);
|
|
2676
|
+
if (Number.isInteger(port) && port > 0 && port <= 65535) {
|
|
2677
|
+
ports.add(port);
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
} catch {}
|
|
2684
|
+
}
|
|
2685
|
+
return Array.from(ports).sort((a, b) => a - b);
|
|
2686
|
+
}
|
|
2687
|
+
|
|
2688
|
+
function parseSsListeningPorts(output, pid) {
|
|
2689
|
+
const ports = new Set();
|
|
2690
|
+
const pidPattern = pid ? new RegExp(`\\bpid=${pid}\\b`) : null;
|
|
2691
|
+
for (const line of String(output || "").split("\n")) {
|
|
2692
|
+
if (!line.includes("LISTEN")) continue;
|
|
2693
|
+
if (pidPattern && !pidPattern.test(line)) continue;
|
|
2694
|
+
const match = line.match(/:(\d+)\s+/);
|
|
2695
|
+
if (match) {
|
|
2696
|
+
const port = Number(match[1]);
|
|
2697
|
+
if (Number.isInteger(port) && port > 0 && port <= 65535) {
|
|
2698
|
+
ports.add(port);
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
return Array.from(ports).sort((a, b) => a - b);
|
|
2703
|
+
}
|
|
2704
|
+
|
|
2636
2705
|
async function listAntigravityPorts(pid, {
|
|
2637
2706
|
commandRunner,
|
|
2638
2707
|
platform = process.platform,
|
|
2639
2708
|
timeoutMs = ANTIGRAVITY_PROCESS_SCAN_TIMEOUT_MS,
|
|
2709
|
+
procRoot = "/proc",
|
|
2640
2710
|
signal,
|
|
2641
2711
|
} = {}) {
|
|
2642
2712
|
if (platform === "win32") {
|
|
@@ -2652,21 +2722,48 @@ async function listAntigravityPorts(pid, {
|
|
|
2652
2722
|
}
|
|
2653
2723
|
return ports;
|
|
2654
2724
|
}
|
|
2725
|
+
|
|
2726
|
+
// On Linux, try procfs first when no mock command runner is provided (zero-spawn, no dependencies).
|
|
2727
|
+
if (platform === "linux" && !commandRunner) {
|
|
2728
|
+
const procPorts = parseLinuxProcListeningPorts(pid, { procRoot });
|
|
2729
|
+
if (procPorts.length > 0) return procPorts;
|
|
2730
|
+
}
|
|
2731
|
+
|
|
2655
2732
|
const lsof = await resolveLsofBinary({ commandRunner });
|
|
2656
|
-
if (
|
|
2657
|
-
|
|
2733
|
+
if (lsof) {
|
|
2734
|
+
const result = await runCommand(
|
|
2735
|
+
commandRunner,
|
|
2736
|
+
lsof,
|
|
2737
|
+
["-nP", "-iTCP", "-sTCP:LISTEN", "-a", "-p", String(pid)],
|
|
2738
|
+
{ timeout: timeoutMs, signal },
|
|
2739
|
+
);
|
|
2740
|
+
const ports = parseListeningPorts(result?.stdout);
|
|
2741
|
+
if (ports.length > 0) return ports;
|
|
2658
2742
|
}
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2743
|
+
|
|
2744
|
+
// On Linux, fall back to procfs (honoring procRoot) or ss if lsof is absent or yielded no ports.
|
|
2745
|
+
if (platform === "linux") {
|
|
2746
|
+
const procPorts = parseLinuxProcListeningPorts(pid, { procRoot });
|
|
2747
|
+
if (procPorts.length > 0) return procPorts;
|
|
2748
|
+
|
|
2749
|
+
const ss = await whichBinary("ss", { commandRunner });
|
|
2750
|
+
if (ss) {
|
|
2751
|
+
const result = await runCommand(
|
|
2752
|
+
commandRunner,
|
|
2753
|
+
ss,
|
|
2754
|
+
["-H", "-tlpn"],
|
|
2755
|
+
{ timeout: timeoutMs, signal },
|
|
2756
|
+
);
|
|
2757
|
+
const ssPorts = parseSsListeningPorts(result?.stdout, pid);
|
|
2758
|
+
if (ssPorts.length > 0) return ssPorts;
|
|
2759
|
+
}
|
|
2668
2760
|
}
|
|
2669
|
-
|
|
2761
|
+
|
|
2762
|
+
if (!lsof && platform !== "linux") {
|
|
2763
|
+
throw new Error("Antigravity port detection needs lsof. Install it, then retry.");
|
|
2764
|
+
}
|
|
2765
|
+
|
|
2766
|
+
throw new Error("Antigravity is running but not exposing ports yet. Try again in a few seconds.");
|
|
2670
2767
|
}
|
|
2671
2768
|
|
|
2672
2769
|
function antigravityDefaultBody() {
|
|
@@ -3620,7 +3717,7 @@ async function fetchUsageLimitsUncached({
|
|
|
3620
3717
|
: null;
|
|
3621
3718
|
|
|
3622
3719
|
const providerFetch = withFetchTimeout(fetchImpl, providerTimeoutMs);
|
|
3623
|
-
const [claudeResult, codexResult, cursor, kimi, gemini, kiro, antigravity, copilot, grok, zcode, opencodeGoRaw, qoder, qoderCn, codingPlan, agentPlan, claudeServiceStatus] = await Promise.all([
|
|
3720
|
+
const [claudeResult, codexResult, cursor, kimi, gemini, kiro, antigravity, copilot, grok, zcode, opencodeGoRaw, qoder, qoderCn, codingPlan, agentPlan, commandCodeRaw, claudeServiceStatus] = await Promise.all([
|
|
3624
3721
|
claudeToken && !freshClaudeCache && !claudeRetryAtMs
|
|
3625
3722
|
? withProviderTimeout(fetchClaudeUsageLimits(claudeToken, { fetchImpl: providerFetch, maxAttempts: 1 }), "Claude", providerTimeoutMs).then(
|
|
3626
3723
|
(value) => ({ status: "fulfilled", value }),
|
|
@@ -3721,6 +3818,19 @@ async function fetchUsageLimitsUncached({
|
|
|
3721
3818
|
"Ark Agent Plan",
|
|
3722
3819
|
providerTimeoutMs,
|
|
3723
3820
|
).catch((reason) => ({ configured: true, error: reason?.message || "Unknown error" })),
|
|
3821
|
+
// CommandCode (commandcode.ai): official subscription windows (5h + weekly)
|
|
3822
|
+
// from the CLI's own alpha endpoints, keyed by the apiKey the CLI stores in
|
|
3823
|
+
// ~/.commandcode/auth.json (or COMMAND_CODE_API_KEY). No local fallback —
|
|
3824
|
+
// window state lives server-side. fetchCommandcodeLimits throws on auth
|
|
3825
|
+
// expiry so the assemble step below can flag auth_action_required. The
|
|
3826
|
+
// outer race bounds the whole slot: without it three sequential per-request
|
|
3827
|
+
// timeouts (whoami, then credits+subscriptions) could hold the aggregate
|
|
3828
|
+
// ~2x longer than any sibling provider.
|
|
3829
|
+
withProviderTimeout(fetchCommandcodeLimits({ home, env, fetchImpl: providerFetch }), "CommandCode", providerTimeoutMs)
|
|
3830
|
+
.then(
|
|
3831
|
+
(value) => ({ status: "fulfilled", value }),
|
|
3832
|
+
(reason) => ({ status: "rejected", reason }),
|
|
3833
|
+
),
|
|
3724
3834
|
// Public status-page probe (fail-soft, own 5-min cache in provider-status.js).
|
|
3725
3835
|
// Only probed for configured accounts — without a token the Claude section
|
|
3726
3836
|
// never renders, so the reading would have nowhere to go.
|
|
@@ -3897,6 +4007,28 @@ async function fetchUsageLimitsUncached({
|
|
|
3897
4007
|
}
|
|
3898
4008
|
}
|
|
3899
4009
|
|
|
4010
|
+
// CommandCode: official windows straight from the API — nothing to cache on
|
|
4011
|
+
// disk beyond the shared 2-minute in-memory cache, so keep the assembly
|
|
4012
|
+
// simple. A fulfilled `configured: false` means no apiKey found; a rejected
|
|
4013
|
+
// fetch surfaced an auth-expired error the panel should act on.
|
|
4014
|
+
let commandCodeObj;
|
|
4015
|
+
if (commandCodeRaw?.status === "fulfilled") {
|
|
4016
|
+
const value = commandCodeRaw.value;
|
|
4017
|
+
commandCodeObj = value && value.configured === false
|
|
4018
|
+
? value
|
|
4019
|
+
: { ...value, stale: false, cached_at: new Date(nowMs).toISOString() };
|
|
4020
|
+
} else {
|
|
4021
|
+
const reason = commandCodeRaw?.reason || null;
|
|
4022
|
+
const authExpired = Boolean(
|
|
4023
|
+
reason &&
|
|
4024
|
+
(reason?.code === "AUTH_EXPIRED" ||
|
|
4025
|
+
/token expired|run `cmd login`|Not authenticated/i.test(reason?.message || "")),
|
|
4026
|
+
);
|
|
4027
|
+
commandCodeObj = authExpired
|
|
4028
|
+
? { configured: true, error: reason?.message || "Unknown error", auth_action_required: "reauth" }
|
|
4029
|
+
: { configured: true, error: reason?.message || "Unknown error" };
|
|
4030
|
+
}
|
|
4031
|
+
|
|
3900
4032
|
const data = {
|
|
3901
4033
|
fetched_at: new Date(nowMs).toISOString(),
|
|
3902
4034
|
claude: withPlanLabel(claude, claudePlanType, "Claude"),
|
|
@@ -3914,6 +4046,10 @@ async function fetchUsageLimitsUncached({
|
|
|
3914
4046
|
grok: withPlanLabel(grok, null, "Grok"),
|
|
3915
4047
|
zcode: withPlanLabel(zcode, zcode.plan_label, "ZCode"),
|
|
3916
4048
|
opencodeGo: withPlanLabel(opencodeGo, opencodeGo?.plan_label, "OpenCode Go"),
|
|
4049
|
+
// CommandCode tiers are acronym brands (GOAT/Pro/Max) — the fetcher already
|
|
4050
|
+
// maps plan ids to the CLI's exact display strings, so skip the shared
|
|
4051
|
+
// Title-Case normalization ("Goat") and surface them as-is.
|
|
4052
|
+
commandCode: commandCodeObj,
|
|
3917
4053
|
qoder: withPlanLabel(qoder, qoder?.plan_label, "Qoder"),
|
|
3918
4054
|
qoderCn: withPlanLabel(qoderCn, qoderCn?.plan_label, "Qoder CN"),
|
|
3919
4055
|
codingPlan: withPlanLabel(codingPlan, codingPlan?.plan_label, "Ark Coding Plan"),
|
|
@@ -3969,6 +4105,8 @@ module.exports = {
|
|
|
3969
4105
|
loadAntigravityCredentials,
|
|
3970
4106
|
parseListeningPorts,
|
|
3971
4107
|
parseWindowsListeningPorts,
|
|
4108
|
+
parseLinuxProcListeningPorts,
|
|
4109
|
+
parseSsListeningPorts,
|
|
3972
4110
|
listAntigravityPorts,
|
|
3973
4111
|
detectAntigravityProcess,
|
|
3974
4112
|
fetchAntigravityLimits,
|
|
@@ -3982,6 +4120,7 @@ module.exports = {
|
|
|
3982
4120
|
fetchGrokLimits,
|
|
3983
4121
|
fetchZcodeLimits,
|
|
3984
4122
|
fetchOpencodeGoLimits,
|
|
4123
|
+
fetchCommandcodeLimits,
|
|
3985
4124
|
fetchQoderLimits,
|
|
3986
4125
|
fetchQoderCnLimits,
|
|
3987
4126
|
};
|