tokentracker-cli 0.96.1 → 0.96.3
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 +34 -25
- package/README.ja.md +38 -27
- package/README.ko.md +39 -28
- package/README.md +36 -28
- package/README.zh-CN.md +36 -25
- package/dashboard/dist/assets/{AchievementBadge-DKyElm0T.js → AchievementBadge-BX4iBBYM.js} +1 -1
- package/dashboard/dist/assets/{AchievementsPage-BvCx3wND.js → AchievementsPage-DRYRuCbh.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-DN69LzXX.js → AchievementsSection-BM_JWWhJ.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-DGiKdZfz.js → BadgeDetailModal-DxoxXst2.js} +1 -1
- package/dashboard/dist/assets/{BotAnimated-zN8rH7_K.js → BotAnimated-BVpFxG8u.js} +1 -1
- package/dashboard/dist/assets/{Card-COWo-ClV.js → Card-BJJs701t.js} +1 -1
- package/dashboard/dist/assets/{ClawdAnimated-BWsB7Eat.js → ClawdAnimated-46wPZ_Tc.js} +2 -2
- package/dashboard/dist/assets/{CommandPalette-BfvIwuoJ.js → CommandPalette-B_zkc7IU.js} +1 -1
- package/dashboard/dist/assets/{CommunityStatsModal-BQWg7R_y.js → CommunityStatsModal-M2k5rIf1.js} +1 -1
- package/dashboard/dist/assets/{ConfirmModal-C7ABSI-O.js → ConfirmModal-DBvOTcAQ.js} +1 -1
- package/dashboard/dist/assets/{Controls-vMzEZzej.js → Controls-BCkjPMSH.js} +1 -1
- package/dashboard/dist/assets/DashboardPage-3bHhou09.js +1 -0
- package/dashboard/dist/assets/{DevicePage-3ejUBLWM.js → DevicePage-DFBUce8C.js} +1 -1
- package/dashboard/dist/assets/DialogClose-kvDd8h3V.js +1 -0
- package/dashboard/dist/assets/DialogDescription-BMyOicfz.js +1 -0
- package/dashboard/dist/assets/DialogTitle-DL5nvD31.js +1 -0
- package/dashboard/dist/assets/{FadeIn-D7Jcfz1N.js → FadeIn-B-Bg6SEy.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-D--Rx5BS.js → HeaderGithubStar-BExz0hh4.js} +1 -1
- package/dashboard/dist/assets/{HoverTooltip-n1W0z3Wr.js → HoverTooltip-Dj5zemYT.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-D202tl9B.js → IpCheckPage-DN7FuJ_v.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-D6yL2EZo.js → LandingPage-9dKgSBRy.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardAvatar-ChFg2mtA.js → LeaderboardAvatar-00V95XIg.js} +1 -1
- package/dashboard/dist/assets/{LeaderboardPage-BXHwGs8r.js → LeaderboardPage-DkKfUt0Z.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardProfileModal-B5LoOpCk.js → LeaderboardProfileModal-C9sIHBgN.js} +4 -4
- package/dashboard/dist/assets/{LeaderboardProfilePage-jsukhRz8.js → LeaderboardProfilePage-BAiLMsEb.js} +1 -1
- package/dashboard/dist/assets/LimitsPage-BuenTaHa.js +8 -0
- package/dashboard/dist/assets/{LocalOnlyNotice-Du0lz657.js → LocalOnlyNotice-CKhY27Lr.js} +1 -1
- package/dashboard/dist/assets/{LoginCard-BFEX9x7-.js → LoginCard-BbvoBx5N.js} +1 -1
- package/dashboard/dist/assets/{LoginModal-DqC7_d35.js → LoginModal-P7zIkBhO.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-Dzx8N7HE.js → LoginPage-Bo0bR26x.js} +1 -1
- package/dashboard/dist/assets/PetPage-C6i9bSSl.js +1 -0
- package/dashboard/dist/assets/PopoverPopup-h0gf36vg.js +1 -0
- package/dashboard/dist/assets/ProviderIcon-Dm8fwPdj.js +1 -0
- package/dashboard/dist/assets/{ResetPasswordPage-x_GR79sR.js → ResetPasswordPage-DvSJ8kg0.js} +1 -1
- package/dashboard/dist/assets/{SegmentedControl-BxDiDV4R.js → SegmentedControl-CP7oiGZE.js} +1 -1
- package/dashboard/dist/assets/Select-iwP92x9C.js +1 -0
- package/dashboard/dist/assets/SelectItemText-DzljA15_.js +1 -0
- package/dashboard/dist/assets/{ServiceStatusPage-BVQuVdjg.js → ServiceStatusPage-uD4D0Tid.js} +1 -1
- package/dashboard/dist/assets/{SessionsPage-DE39wNIO.js → SessionsPage-Cmb1ssNP.js} +2 -2
- package/dashboard/dist/assets/SettingsPage-D8ryg1Pv.js +2 -0
- package/dashboard/dist/assets/SkillsPage-eXI09q03.js +1 -0
- package/dashboard/dist/assets/{TokenGalaxy-BPM779Wb.js → TokenGalaxy-f2djrlUv.js} +1 -1
- package/dashboard/dist/assets/ToolbarRootContext-CDxCPYLv.js +1 -0
- package/dashboard/dist/assets/{TrendMonitor-BkNy-o1D.js → TrendMonitor-C419X22G.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-Bpg6H-ZB.js → WidgetsPage-AYq__pOO.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-C6-NM-RO.js → WrappedPage-Bsm9k5XI.js} +1 -1
- package/dashboard/dist/assets/{__vite-browser-external-CvMMIjhi.css → __vite-browser-external-5P7me0Qq.css} +1 -1
- package/dashboard/dist/assets/__vite-browser-external-BDkeh90N.js +45 -0
- package/dashboard/dist/assets/{agent-logos-DpbkRqXT.js → agent-logos-B6Vg-4_1.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-BjOtWUVs.js → arrow-up-right-DIQXwaOD.js} +1 -1
- package/dashboard/dist/assets/{check-BlxnX5jZ.js → check-CgD_bV39.js} +1 -1
- package/dashboard/dist/assets/composite-BIgEqWZD.js +1 -0
- package/dashboard/dist/assets/{copy-CIsWjLY5.js → copy-DlM1BHdp.js} +1 -1
- package/dashboard/dist/assets/{download-QDaQbQdd.js → download-CQFG-VIY.js} +1 -1
- package/dashboard/dist/assets/{external-link-DPV4VU3m.js → external-link-BQyDqGxz.js} +1 -1
- package/dashboard/dist/assets/{flame-B_X-7VNp.js → flame-BamzyXzF.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-DEx2TJj8.js → format-tokens-C4G-_xYt.js} +1 -1
- package/dashboard/dist/assets/{icons-983RyGSl.js → icons-Ntscvl1a.js} +1 -1
- package/dashboard/dist/assets/{index-qtonw_x4.js → index-CUrcPqgp.js} +1 -1
- package/dashboard/dist/assets/{index-BONYA8HZ.js → index-DGxgsNoQ.js} +1 -1
- package/dashboard/dist/assets/{index-Cjs5stC0.js → index-FRIt5mlv.js} +1 -1
- package/dashboard/dist/assets/{info-DpVOhXZI.js → info-CXytWcZi.js} +1 -1
- package/dashboard/dist/assets/{link-2-CBro-upz.js → link-2-Dexoo_jO.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-wYFdSyOd.js → loader-circle-Cn0JHc8t.js} +1 -1
- package/dashboard/dist/assets/{maximize-2-DhTyQ4ly.js → maximize-2-DLh7gYuP.js} +1 -1
- package/dashboard/dist/assets/{modifiers.esm-CPljwVhN.js → modifiers.esm-DOh_xtyt.js} +1 -1
- package/dashboard/dist/assets/module-DUSXqJtA.js +3 -0
- package/dashboard/dist/assets/{monitor-smartphone-D_wr-HOR.js → monitor-smartphone-CpqS9Ior.js} +1 -1
- package/dashboard/dist/assets/{plus-BNjfkBEF.js → plus-bfQV7nyv.js} +1 -1
- package/dashboard/dist/assets/provider-display-Bf9pW06U.js +42 -0
- package/dashboard/dist/assets/{react-yHv9MTUA.js → react-BmFZKA_b.js} +1 -1
- package/dashboard/dist/assets/{search-Dfak92ZA.js → search-l3jJ2fzC.js} +1 -1
- package/dashboard/dist/assets/{skills-api-By2PdNa1.js → skills-api-CWmLnaxn.js} +1 -1
- package/dashboard/dist/assets/{sortable.esm-B9xy66_v.js → sortable.esm-DLgyXLHM.js} +1 -1
- package/dashboard/dist/assets/store-JM-a8ElZ.js +1 -0
- package/dashboard/dist/assets/{terminal-pbXWBmZM.js → terminal-6aY2Sn8P.js} +1 -1
- package/dashboard/dist/assets/{trash-2-CboDPwbW.js → trash-D5oon5pT.js} +1 -1
- package/dashboard/dist/assets/{use-community-stats-D6HTdnHq.js → use-community-stats-ZWUMFwzc.js} +1 -1
- package/dashboard/dist/assets/{use-latest-request-guard-hwSr9Cam.js → use-latest-request-guard-BDaXr4gK.js} +1 -1
- package/dashboard/dist/assets/use-limits-display-prefs-yXXToNIc.js +1 -0
- package/dashboard/dist/assets/{use-ordered-list-OtfOqrNb.js → use-ordered-list-C6RG8N6c.js} +1 -1
- package/dashboard/dist/assets/use-reduced-motion-BqDKim_3.js +1 -0
- package/dashboard/dist/assets/{use-session-efficiency-pref-BScvtS8F.js → use-session-efficiency-pref-DpgZO_Lx.js} +1 -1
- package/dashboard/dist/assets/{use-transform-Cy1ykjEs.js → use-transform-D42P7jkd.js} +1 -1
- package/dashboard/dist/assets/use-usage-limits-CV6puFwq.js +1 -0
- package/dashboard/dist/assets/{useCurrency-VqF3cy1C.js → useCurrency-GWBmOrCR.js} +1 -1
- package/dashboard/dist/assets/{useTokenFormat-Cgub4MXu.js → useTokenFormat-Beybkb0v.js} +1 -1
- package/dashboard/dist/assets/{zap-DStzvQJI.js → zap-CEq2616W.js} +1 -1
- package/dashboard/dist/brand-logos/acode-dark.png +0 -0
- package/dashboard/dist/brand-logos/acode.png +0 -0
- package/dashboard/dist/brand-logos/commandcode.svg +1 -0
- package/dashboard/dist/brand-logos/devin.svg +6 -0
- package/dashboard/dist/index.html +20 -16
- package/dashboard/dist/ip-check.html +2 -2
- package/dashboard/dist/leaderboard.html +2 -2
- package/dashboard/dist/llms.txt +4 -2
- package/dashboard/dist/share.html +2 -2
- package/package.json +2 -2
- package/src/commands/init.js +114 -4
- package/src/commands/status.js +37 -0
- package/src/commands/sync.js +92 -10
- package/src/commands/uninstall.js +23 -0
- package/src/lib/codex-config.js +42 -0
- package/src/lib/codex-rollout-parser.js +2 -2
- package/src/lib/commandcode-limits.js +317 -0
- package/src/lib/devin-limits.js +249 -0
- package/src/lib/devin-usage.js +212 -0
- package/src/lib/local-api.js +14 -0
- package/src/lib/passive-mode.js +13 -1
- package/src/lib/pricing/curated-overrides.json +78 -1
- package/src/lib/pricing/index.js +11 -9
- package/src/lib/pricing/matcher.js +28 -0
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +1473 -147
- package/src/lib/session-analytics.js +2 -2
- package/src/lib/skills-manager.js +5 -0
- package/src/lib/subscriptions.js +70 -16
- package/src/lib/usage-limits.js +240 -49
- package/dashboard/dist/assets/DashboardPage-QBhbCMZF.js +0 -1
- package/dashboard/dist/assets/DialogClose-D_dvtfGV.js +0 -1
- package/dashboard/dist/assets/DialogDescription-ryGYdQjX.js +0 -1
- package/dashboard/dist/assets/DialogTitle-_ahf0z8b.js +0 -1
- package/dashboard/dist/assets/LimitsPage-PvqkOOwp.js +0 -6
- package/dashboard/dist/assets/PetPage-CNlWHF4z.js +0 -1
- package/dashboard/dist/assets/PopoverPopup-D9jadD3j.js +0 -1
- package/dashboard/dist/assets/ProviderIcon-Caz5PuAm.js +0 -1
- package/dashboard/dist/assets/Select-B5o-1sEl.js +0 -1
- package/dashboard/dist/assets/SelectItemText-CiA6L7Wk.js +0 -1
- package/dashboard/dist/assets/SettingsPage-DJrb_fsK.js +0 -2
- package/dashboard/dist/assets/SkillsPage-COk-YQQ5.js +0 -1
- package/dashboard/dist/assets/ToolbarRootContext-CozJT6Vs.js +0 -1
- package/dashboard/dist/assets/__vite-browser-external-BGnq8Ebm.js +0 -45
- package/dashboard/dist/assets/composite-Dxmivlk4.js +0 -1
- package/dashboard/dist/assets/limits-providers-BUoquSA-.js +0 -1
- package/dashboard/dist/assets/module-xpSFyNBK.js +0 -3
- package/dashboard/dist/assets/provider-display-BOBtUyFi.js +0 -42
- package/dashboard/dist/assets/store-oQZR4d9M.js +0 -1
- package/dashboard/dist/assets/use-limits-display-prefs-B-pbwUS8.js +0 -1
- package/dashboard/dist/assets/use-reduced-motion-DGXcZBX3.js +0 -1
- package/dashboard/dist/assets/use-usage-limits-CSMb2zYW.js +0 -1
|
@@ -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) {
|
|
@@ -15,6 +15,7 @@ const DEFAULT_REPOS = [
|
|
|
15
15
|
const TARGETS = {
|
|
16
16
|
claude: { id: "claude", label: "Claude", dir: () => path.join(os.homedir(), ".claude", "skills") },
|
|
17
17
|
codex: { id: "codex", label: "Codex", dir: () => path.join(resolveCodexHome(), "skills") },
|
|
18
|
+
acode: { id: "acode", label: "AStudio", dir: () => path.join(resolveAcodeHome(), "skills") },
|
|
18
19
|
grok: { id: "grok", label: "Grok", dir: () => path.join(resolveGrokHome(process.env), "skills") },
|
|
19
20
|
antigravity: { id: "antigravity", label: "Antigravity", dirs: () => resolveAntigravitySkillDirs(process.env) },
|
|
20
21
|
gemini: { id: "gemini", label: "Gemini", dir: () => path.join(os.homedir(), ".gemini", "skills") },
|
|
@@ -32,6 +33,10 @@ function resolveCodexHome() {
|
|
|
32
33
|
return String(process.env.CODEX_HOME || "").trim() || path.join(os.homedir(), ".codex");
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
function resolveAcodeHome() {
|
|
37
|
+
return String(process.env.TOKENTRACKER_ACODE_HOME || "").trim() || path.join(os.homedir(), ".acode");
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
function resolveZcodeHome() {
|
|
36
41
|
return String(process.env.ZCODE_HOME || "").trim() || path.join(os.homedir(), ".zcode");
|
|
37
42
|
}
|
package/src/lib/subscriptions.js
CHANGED
|
@@ -19,6 +19,9 @@ const CLAUDE_CODE_CREDENTIALS_FILE = ".credentials.json";
|
|
|
19
19
|
// Platforms where Claude Code stores credentials in the plain JSON file above
|
|
20
20
|
// rather than the macOS Keychain.
|
|
21
21
|
const CLAUDE_CODE_CREDENTIALS_FILE_PLATFORMS = new Set(["linux", "win32"]);
|
|
22
|
+
// Refresh slightly before wall-clock expiry so Limits does not spend a request
|
|
23
|
+
// that Anthropic answers with 429 for a real-but-expired Claude Code token.
|
|
24
|
+
const CLAUDE_TOKEN_EXPIRY_SKEW_MS = 60_000;
|
|
22
25
|
|
|
23
26
|
function usesClaudeCodeCredentialsFile(platform) {
|
|
24
27
|
return CLAUDE_CODE_CREDENTIALS_FILE_PLATFORMS.has(platform);
|
|
@@ -164,14 +167,23 @@ async function detectOpencodeChatgptSubscription({ home, env }) {
|
|
|
164
167
|
};
|
|
165
168
|
}
|
|
166
169
|
|
|
167
|
-
|
|
170
|
+
// Match Claude Code 2.1.267's account derivation. A service-only lookup may
|
|
171
|
+
// select credentials from an older installation before the current account.
|
|
172
|
+
function resolveClaudeKeychainAccount({ env = process.env, userInfo = os.userInfo } = {}) {
|
|
173
|
+
let account;
|
|
174
|
+
try { account = env.USER || userInfo().username; } catch (_error) { return "claude-code-user"; }
|
|
175
|
+
return typeof account === "string" && /^[a-zA-Z0-9._-]+$/.test(account)
|
|
176
|
+
? account : "claude-code-user";
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function probeMacosKeychainGenericPassword({ service, securityRunner, timeoutMs, env } = {}) {
|
|
168
180
|
const svc = normalizeString(service);
|
|
169
181
|
if (!svc) return false;
|
|
170
182
|
|
|
171
183
|
const runner = typeof securityRunner === "function" ? securityRunner : cp.spawnSync;
|
|
172
184
|
if (runner === cp.spawnSync && !fs.existsSync(MACOS_SECURITY_BIN)) return false;
|
|
173
185
|
|
|
174
|
-
const result = runner(MACOS_SECURITY_BIN, ["find-generic-password", "-s", svc], {
|
|
186
|
+
const result = runner(MACOS_SECURITY_BIN, ["find-generic-password", "-s", svc, "-a", resolveClaudeKeychainAccount({ env })], {
|
|
175
187
|
stdio: "ignore",
|
|
176
188
|
timeout: Number.isFinite(timeoutMs) ? timeoutMs : 2000,
|
|
177
189
|
});
|
|
@@ -180,14 +192,14 @@ function probeMacosKeychainGenericPassword({ service, securityRunner, timeoutMs
|
|
|
180
192
|
return result.status === 0;
|
|
181
193
|
}
|
|
182
194
|
|
|
183
|
-
function readMacosKeychainPassword({ service, securityRunner, timeoutMs } = {}) {
|
|
195
|
+
function readMacosKeychainPassword({ service, securityRunner, timeoutMs, env } = {}) {
|
|
184
196
|
const svc = normalizeString(service);
|
|
185
197
|
if (!svc) return null;
|
|
186
198
|
|
|
187
199
|
const runner = typeof securityRunner === "function" ? securityRunner : cp.spawnSync;
|
|
188
200
|
if (runner === cp.spawnSync && !fs.existsSync(MACOS_SECURITY_BIN)) return null;
|
|
189
201
|
|
|
190
|
-
const result = runner(MACOS_SECURITY_BIN, ["find-generic-password", "-s", svc, "-w"], {
|
|
202
|
+
const result = runner(MACOS_SECURITY_BIN, ["find-generic-password", "-s", svc, "-a", resolveClaudeKeychainAccount({ env }), "-w"], {
|
|
191
203
|
stdio: ["ignore", "pipe", "ignore"],
|
|
192
204
|
timeout: Number.isFinite(timeoutMs) ? timeoutMs : 2000,
|
|
193
205
|
encoding: "utf8",
|
|
@@ -217,12 +229,13 @@ function readClaudeCodeCredentialsFile({ home, fsReader } = {}) {
|
|
|
217
229
|
}
|
|
218
230
|
}
|
|
219
231
|
|
|
220
|
-
function detectClaudeCodeCredentialsPresence({ platform = process.platform, securityRunner, home, fsReader } = {}) {
|
|
232
|
+
function detectClaudeCodeCredentialsPresence({ platform = process.platform, securityRunner, home, fsReader, env } = {}) {
|
|
221
233
|
if (platform === "darwin") {
|
|
222
234
|
for (const service of CLAUDE_CODE_KEYCHAIN_SERVICES) {
|
|
223
235
|
const present = probeMacosKeychainGenericPassword({
|
|
224
236
|
service,
|
|
225
237
|
securityRunner,
|
|
238
|
+
env,
|
|
226
239
|
});
|
|
227
240
|
if (!present) continue;
|
|
228
241
|
|
|
@@ -260,6 +273,31 @@ function detectClaudeCodeCredentialsPresence({ platform = process.platform, secu
|
|
|
260
273
|
return null;
|
|
261
274
|
}
|
|
262
275
|
|
|
276
|
+
function parseClaudeOauthExpiryMs(value) {
|
|
277
|
+
if (typeof value === "number") {
|
|
278
|
+
if (!Number.isFinite(value)) return null;
|
|
279
|
+
if (value <= 0) return 0;
|
|
280
|
+
return value < 1e12 ? value * 1000 : value;
|
|
281
|
+
}
|
|
282
|
+
if (typeof value === "string") {
|
|
283
|
+
const trimmed = value.trim();
|
|
284
|
+
if (!trimmed) return null;
|
|
285
|
+
if (/^-?\d+(\.\d+)?$/.test(trimmed)) return parseClaudeOauthExpiryMs(Number(trimmed));
|
|
286
|
+
const ms = Date.parse(trimmed);
|
|
287
|
+
return Number.isFinite(ms) ? ms : null;
|
|
288
|
+
}
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function extractClaudeCodeOauth(payload, nowMs = Date.now()) {
|
|
293
|
+
const oauth = payload?.claudeAiOauth;
|
|
294
|
+
const accessToken = normalizeString(oauth?.accessToken);
|
|
295
|
+
if (!accessToken) return null;
|
|
296
|
+
const expiresAtMs = parseClaudeOauthExpiryMs(oauth?.expiresAt);
|
|
297
|
+
if (expiresAtMs != null && expiresAtMs <= nowMs + CLAUDE_TOKEN_EXPIRY_SKEW_MS) return null;
|
|
298
|
+
return { accessToken, expiresAtMs };
|
|
299
|
+
}
|
|
300
|
+
|
|
263
301
|
function extractClaudeKeychainSubscription(payload) {
|
|
264
302
|
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return null;
|
|
265
303
|
|
|
@@ -273,11 +311,11 @@ function extractClaudeKeychainSubscription(payload) {
|
|
|
273
311
|
return { subscriptionType, rateLimitTier };
|
|
274
312
|
}
|
|
275
313
|
|
|
276
|
-
function detectClaudeCodeSubscriptionDetails({ platform = process.platform, securityRunner, home, fsReader } = {}) {
|
|
314
|
+
function detectClaudeCodeSubscriptionDetails({ platform = process.platform, securityRunner, home, fsReader, env } = {}) {
|
|
277
315
|
const rawPayloads = [];
|
|
278
316
|
if (platform === "darwin") {
|
|
279
317
|
for (const service of CLAUDE_CODE_KEYCHAIN_SERVICES) {
|
|
280
|
-
const raw = readMacosKeychainPassword({ service, securityRunner });
|
|
318
|
+
const raw = readMacosKeychainPassword({ service, securityRunner, env });
|
|
281
319
|
if (raw) rawPayloads.push(raw);
|
|
282
320
|
}
|
|
283
321
|
} else if (usesClaudeCodeCredentialsFile(platform)) {
|
|
@@ -327,14 +365,14 @@ async function collectLocalSubscriptions({
|
|
|
327
365
|
if (opencode) out.push(opencode);
|
|
328
366
|
|
|
329
367
|
if (probeKeychainDetails) {
|
|
330
|
-
const claude = detectClaudeCodeSubscriptionDetails({ platform, securityRunner, home });
|
|
368
|
+
const claude = detectClaudeCodeSubscriptionDetails({ platform, securityRunner, home, env });
|
|
331
369
|
if (claude) out.push(claude);
|
|
332
370
|
else if (probeKeychain) {
|
|
333
|
-
const present = detectClaudeCodeCredentialsPresence({ platform, securityRunner, home });
|
|
371
|
+
const present = detectClaudeCodeCredentialsPresence({ platform, securityRunner, home, env });
|
|
334
372
|
if (present) out.push(present);
|
|
335
373
|
}
|
|
336
374
|
} else if (probeKeychain) {
|
|
337
|
-
const claude = detectClaudeCodeCredentialsPresence({ platform, securityRunner, home });
|
|
375
|
+
const claude = detectClaudeCodeCredentialsPresence({ platform, securityRunner, home, env });
|
|
338
376
|
if (claude) out.push(claude);
|
|
339
377
|
}
|
|
340
378
|
|
|
@@ -364,14 +402,25 @@ async function detectOpenclawSessionIntegration({ home, env }) {
|
|
|
364
402
|
};
|
|
365
403
|
}
|
|
366
404
|
|
|
367
|
-
|
|
405
|
+
// Returns the live OAuth token plus its expiry stamp. The expiry doubles as a
|
|
406
|
+
// rotation marker for the 429 cool-down: it changes on every refresh and, unlike
|
|
407
|
+
// the token itself, is not a secret, so nothing derived from a credential has to
|
|
408
|
+
// be written to disk.
|
|
409
|
+
function readClaudeCodeOauthToken({
|
|
410
|
+
platform = process.platform,
|
|
411
|
+
securityRunner,
|
|
412
|
+
home,
|
|
413
|
+
fsReader,
|
|
414
|
+
env,
|
|
415
|
+
nowMs = Date.now(),
|
|
416
|
+
} = {}) {
|
|
368
417
|
if (platform === "darwin") {
|
|
369
418
|
for (const service of CLAUDE_CODE_KEYCHAIN_SERVICES) {
|
|
370
419
|
try {
|
|
371
|
-
const raw = readMacosKeychainPassword({ service, securityRunner });
|
|
420
|
+
const raw = readMacosKeychainPassword({ service, securityRunner, env });
|
|
372
421
|
if (!raw) continue;
|
|
373
|
-
const
|
|
374
|
-
|
|
422
|
+
const oauth = extractClaudeCodeOauth(JSON.parse(raw), nowMs);
|
|
423
|
+
if (oauth) return oauth;
|
|
375
424
|
} catch (_e) {
|
|
376
425
|
continue;
|
|
377
426
|
}
|
|
@@ -386,13 +435,16 @@ function readClaudeCodeAccessToken({ platform = process.platform, securityRunner
|
|
|
386
435
|
const raw = readClaudeCodeCredentialsFile({ home, fsReader });
|
|
387
436
|
if (!raw) return null;
|
|
388
437
|
try {
|
|
389
|
-
|
|
390
|
-
return normalizeString(payload?.claudeAiOauth?.accessToken);
|
|
438
|
+
return extractClaudeCodeOauth(JSON.parse(raw), nowMs);
|
|
391
439
|
} catch (_e) {
|
|
392
440
|
return null;
|
|
393
441
|
}
|
|
394
442
|
}
|
|
395
443
|
|
|
444
|
+
function readClaudeCodeAccessToken(options = {}) {
|
|
445
|
+
return readClaudeCodeOauthToken(options)?.accessToken ?? null;
|
|
446
|
+
}
|
|
447
|
+
|
|
396
448
|
async function readCodexAccessToken({ home, env } = {}) {
|
|
397
449
|
try {
|
|
398
450
|
const codexHome = resolveCodexHome({ home, env });
|
|
@@ -445,10 +497,12 @@ async function readCodexAuthBundle({ home, env } = {}) {
|
|
|
445
497
|
}
|
|
446
498
|
|
|
447
499
|
module.exports = {
|
|
500
|
+
resolveClaudeKeychainAccount,
|
|
448
501
|
collectLocalSubscriptions,
|
|
449
502
|
detectClaudeCodeCredentialsPresence,
|
|
450
503
|
detectClaudeCodeSubscriptionDetails,
|
|
451
504
|
readClaudeCodeAccessToken,
|
|
505
|
+
readClaudeCodeOauthToken,
|
|
452
506
|
readCodexAccessToken,
|
|
453
507
|
readCodexAuthBundle,
|
|
454
508
|
};
|