@usagefleet/cli 1.2.171 → 1.2.172

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.
@@ -46,6 +46,34 @@ export function activeJcodeToken(authPath) {
46
46
  return null;
47
47
  }
48
48
  }
49
+ /** Every Claude subscription login saved in the agent CLI's `accounts.json` whose access
50
+ * token has not expired; the agent refreshes a token only when it uses that account. */
51
+ export function agentClaudeLogins(accountsPath) {
52
+ let accounts;
53
+ try {
54
+ accounts = JSON.parse(readFileSync(accountsPath, 'utf-8')).anthropic ?? [];
55
+ }
56
+ catch {
57
+ return [];
58
+ }
59
+ const logins = [];
60
+ for (const { type, name, access, accountId, expires } of accounts) {
61
+ if (type === 'oauth' &&
62
+ typeof access === 'string' &&
63
+ access !== '' &&
64
+ typeof accountId === 'string' &&
65
+ accountId !== '' &&
66
+ typeof expires === 'number' &&
67
+ expires > Date.now()) {
68
+ logins.push({
69
+ extId: accountId.slice(0, 100),
70
+ name: typeof name === 'string' ? name : accountId,
71
+ token: access,
72
+ });
73
+ }
74
+ }
75
+ return logins;
76
+ }
49
77
  /** The accountUuid Anthropic says owns this OAuth token, or null when it cannot
50
78
  * say. Null fails open to the file's identity: the endpoint is undocumented, and
51
79
  * losing it must not stop every collector from reporting limits. */
package/dist/collector.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { existsSync } from 'node:fs';
2
2
  import { hostname } from 'node:os';
3
3
  import { dirname, join, sep } from 'node:path';
4
- import { activeJcodeToken, detectClaudeAccount, tokenOwner } from './claude-account.js';
4
+ import { activeJcodeToken, agentClaudeLogins, detectClaudeAccount, tokenOwner } from './claude-account.js';
5
5
  import { detectClaudeCreds, macKeychainDenied } from './claude-creds.js';
6
6
  import { fetchLimits } from './claude-limits.js';
7
7
  import { ENDPOINT } from './config.js';
@@ -324,29 +324,23 @@ function pruneMissingFiles(state, scanned) {
324
324
  function planWall() {
325
325
  return `device outside your plan's device limit · free a slot or upgrade at ${ENDPOINT}/fleet · nothing is lost, uploads resume once it fits`;
326
326
  }
327
- /** Report the Claude Code login's limits, then those of any other account jcode or pj has active. */
327
+ /** Report the Claude Code login's limits, then those of every other account jcode, pj or the agent CLI is signed in to. */
328
328
  export async function reportLimitsOnce(cfg, log = () => {
329
329
  /* empty */
330
330
  }) {
331
331
  const report = await reportClaudeCodeLimits(cfg, log);
332
- await reportJcodeLimits(cfg, report?.account?.extId, log);
332
+ await reportOtherLogins(cfg, report?.account?.extId, log);
333
333
  return report;
334
334
  }
335
335
  /**
336
- * jcode and pj keep their own Anthropic logins, so the account one of them has active
336
+ * jcode, pj and the agent CLI keep their own Anthropic logins, so the account they use
337
337
  * can differ from Claude Code's; with no reading of its own that account's limits go
338
338
  * stale on the server and its group stops blocking.
339
339
  */
340
- async function reportJcodeLimits(cfg, reportedExtId, log) {
340
+ async function reportOtherLogins(cfg, reportedExtId, log) {
341
341
  const reported = new Set(reportedExtId ? [reportedExtId] : []);
342
- for (const sessionsDir of [cfg.jcodeDir, cfg.pjDir]) {
343
- if (!sessionsDir) {
344
- continue;
345
- }
346
- // Never refreshed here: rotating the refresh token would sign jcode or pj out.
347
- const token = activeJcodeToken(join(dirname(sessionsDir), 'auth.json'));
348
- const extId = token ? await tokenOwner(token) : null;
349
- if (!token || !extId || reported.has(extId)) {
342
+ for (const { extId, label, token } of await otherLogins(cfg)) {
343
+ if (reported.has(extId)) {
350
344
  continue;
351
345
  }
352
346
  reported.add(extId);
@@ -355,15 +349,36 @@ async function reportJcodeLimits(cfg, reportedExtId, log) {
355
349
  report = await fetchLimits({ source: 'sub', token });
356
350
  }
357
351
  catch (error) {
358
- log('warn', `limits fetch failed for the ${tilde(dirname(sessionsDir))} login · ${error.message}`);
352
+ log('warn', `limits fetch failed for the ${label} login · ${error.message}`);
359
353
  continue;
360
354
  }
361
355
  const outcome = await postLimits({ ...report, account: { email: null, extId, org: null } }, cfg);
362
356
  if (outcome !== 'ok') {
363
- log('warn', `limits upload failed for the ${tilde(dirname(sessionsDir))} login · ${outcome}`);
357
+ log('warn', `limits upload failed for the ${label} login · ${outcome}`);
364
358
  }
365
359
  }
366
360
  }
361
+ // Never refreshed here: rotating a refresh token would sign jcode, pj or the agent out.
362
+ async function otherLogins(cfg) {
363
+ const logins = [];
364
+ for (const sessionsDir of [cfg.jcodeDir, cfg.pjDir]) {
365
+ if (!sessionsDir) {
366
+ continue;
367
+ }
368
+ const token = activeJcodeToken(join(dirname(sessionsDir), 'auth.json'));
369
+ const extId = token ? await tokenOwner(token) : null;
370
+ if (token && extId) {
371
+ logins.push({ extId, label: tilde(dirname(sessionsDir)), token });
372
+ }
373
+ }
374
+ if (cfg.agentDir) {
375
+ const accountsPath = join(dirname(cfg.agentDir), 'accounts.json');
376
+ for (const login of agentClaudeLogins(accountsPath)) {
377
+ logins.push({ ...login, label: `${tilde(dirname(cfg.agentDir))} ${login.name}` });
378
+ }
379
+ }
380
+ return logins;
381
+ }
367
382
  /**
368
383
  * Auto-detect the local Claude login, read the real 5h/weekly utilization
369
384
  * (oauth/usage for subscription logins, rate-limit headers for API keys), and
@@ -448,5 +463,5 @@ async function reportClaudeCodeLimits(cfg, log) {
448
463
  ? report
449
464
  : { ...report, fiveHourPct: groupLimits.sessionPct, sevenDayPct: groupLimits.weeklyPct }, undefined, log);
450
465
  }
451
- return report;
466
+ return { ...report, account };
452
467
  }
package/dist/release.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by .github/workflows/release.yml.
2
- export const RELEASE_VERSION = "1.2.171";
2
+ export const RELEASE_VERSION = "1.2.172";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usagefleet/cli",
3
- "version": "1.2.171",
3
+ "version": "1.2.172",
4
4
  "description": "Tails Claude Code, Claude Desktop, and pi agent JSONL logs and reports token usage to a UsageFleet server.",
5
5
  "keywords": [
6
6
  "claude",