@usagefleet/cli 1.2.176 → 1.2.178

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,18 @@ export function activeJcodeToken(authPath) {
46
46
  return null;
47
47
  }
48
48
  }
49
+ /** pi's Anthropic OAuth access token from its `auth.json` (`{ anthropic: { type, access, expires } }`),
50
+ * or null when missing or expired; pi refreshes it only when it runs. */
51
+ export function piClaudeToken(authPath) {
52
+ try {
53
+ const { anthropic } = JSON.parse(readFileSync(authPath, 'utf-8'));
54
+ const fresh = anthropic?.type === 'oauth' && typeof anthropic.expires === 'number' && anthropic.expires > Date.now();
55
+ return fresh && typeof anthropic.access === 'string' && anthropic.access !== '' ? anthropic.access : null;
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ }
49
61
  /** Every Claude subscription login saved in the agent CLI's `accounts.json` whose access
50
62
  * token has not expired; the agent refreshes a token only when it uses that account. */
51
63
  export function agentClaudeLogins(accountsPath) {
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, agentClaudeLogins, detectClaudeAccount, tokenOwner } from './claude-account.js';
4
+ import { activeJcodeToken, agentClaudeLogins, detectClaudeAccount, piClaudeToken, 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,22 +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 every other account jcode, pj or the agent CLI is signed in to. */
327
+ /** Report the Claude Code login's limits, then those of every other account jcode, pj, pi or the agent CLI is signed in to. */
328
328
  export async function reportLimitsOnce(cfg, log = () => {
329
329
  /* empty */
330
330
  }) {
331
- const report = await reportClaudeCodeLimits(cfg, log);
332
- await reportOtherLogins(cfg, report?.account?.extId, log);
331
+ const others = await otherLogins(cfg);
332
+ const report = await reportClaudeCodeLimits(cfg, others.length > 0, log);
333
+ await reportOtherLogins(cfg, others, report?.account?.extId, log);
333
334
  return report;
334
335
  }
335
336
  /**
336
- * jcode, pj and the agent CLI keep their own Anthropic logins, so the account they use
337
+ * jcode, pj, pi and the agent CLI keep their own Anthropic logins, so the account they use
337
338
  * can differ from Claude Code's; with no reading of its own that account's limits go
338
339
  * stale on the server and its group stops blocking.
339
340
  */
340
- async function reportOtherLogins(cfg, reportedExtId, log) {
341
+ async function reportOtherLogins(cfg, logins, reportedExtId, log) {
341
342
  const reported = new Set(reportedExtId ? [reportedExtId] : []);
342
- for (const { extId, label, token } of await otherLogins(cfg)) {
343
+ for (const { extId, label, token } of logins) {
343
344
  if (reported.has(extId)) {
344
345
  continue;
345
346
  }
@@ -358,7 +359,7 @@ async function reportOtherLogins(cfg, reportedExtId, log) {
358
359
  }
359
360
  }
360
361
  }
361
- // Never refreshed here: rotating a refresh token would sign jcode, pj or the agent out.
362
+ // Never refreshed here: rotating a refresh token would sign jcode, pj, pi or the agent out.
362
363
  async function otherLogins(cfg) {
363
364
  const logins = [];
364
365
  for (const sessionsDir of [cfg.jcodeDir, cfg.pjDir]) {
@@ -371,6 +372,13 @@ async function otherLogins(cfg) {
371
372
  logins.push({ extId, label: tilde(dirname(sessionsDir)), token });
372
373
  }
373
374
  }
375
+ for (const piDir of new Set(cfg.piDirs.map(dir => dirname(dir)))) {
376
+ const token = piClaudeToken(join(piDir, 'auth.json'));
377
+ const extId = token ? await tokenOwner(token) : null;
378
+ if (token && extId) {
379
+ logins.push({ extId, label: tilde(piDir), token });
380
+ }
381
+ }
374
382
  if (cfg.agentDir) {
375
383
  const accountsPath = join(dirname(cfg.agentDir), 'accounts.json');
376
384
  for (const login of agentClaudeLogins(accountsPath)) {
@@ -385,9 +393,13 @@ async function otherLogins(cfg) {
385
393
  * report it to the server. Best-effort — returns null (and logs) when no login
386
394
  * is found or the request fails.
387
395
  */
388
- async function reportClaudeCodeLimits(cfg, log) {
396
+ async function reportClaudeCodeLimits(cfg, hasOtherLogin, log) {
389
397
  const creds = await detectClaudeCreds();
390
398
  if (!creds) {
399
+ // A machine running only jcode, pj, pi or the agent has no Claude Code login to fix.
400
+ if (hasOtherLogin) {
401
+ return null;
402
+ }
391
403
  if (process.platform === 'darwin' && macKeychainDenied()) {
392
404
  // "Works by hand, broken as a service" signature: a launchd agent can be
393
405
  // denied the login-Keychain read. Make it diagnosable instead of silent.
package/dist/release.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by .github/workflows/release.yml.
2
- export const RELEASE_VERSION = "1.2.176";
2
+ export const RELEASE_VERSION = "1.2.178";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usagefleet/cli",
3
- "version": "1.2.176",
3
+ "version": "1.2.178",
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",