fix(plan): a Claude plan is the one Anthropic reports now, not the sign-in's

An account signed in on Pro and upgraded to Max 5x kept showing "Pro": the
plan was read only from .credentials.json / .claude.json, whose
subscriptionType and rate-limit tiers are written at sign-in. fetchOwner
already asks GET /api/oauth/profile for a token's owner; it now also reads
organization_type / rate_limit_tier / seat_tier into a plan
(planFromProfile), remembered per account uuid (rememberLivePlan). The live
row, saved profiles (identityOf) and pool accounts (poolStatus, whose quota
refresh now asks a login's owner too) show that plan when one was seen
(shownPlan), else planLabel of the files as before.
This commit is contained in:
2026-10-28 15:09:30 +07:00
parent 33d30f5e1f
commit 0841d3e5c8
12 changed files with 171 additions and 18 deletions
+9 -3
View File
@@ -165,7 +165,8 @@ async function fetchUsage(accessToken) {
const owners = new Map();
/**
* The account a token belongs to — `{uuid, email}` — or null when the profile
* The account a token belongs to — `{uuid, email, plan}` (`plan` as the
* profile endpoint reports it now, see cc-profiles.js `livePlans`) — or null when the profile
* endpoint does not say. A saved profile's label and its token come from two
* different files (`oauthAccount` and the credentials store), and a running
* Claude Code session can leave them naming different accounts, so the token's
@@ -179,9 +180,14 @@ async function fetchOwner(accessToken) {
signal: AbortSignal.timeout(TIMEOUT_MS),
});
if (!res.ok) return null;
const account = (await res.json())?.account;
const body = await res.json();
const account = body?.account;
if (!account?.uuid) return null;
const owner = { uuid: account.uuid, email: account.email || null };
// The plan as it is NOW (an upgrade since sign-in included): the stored
// files keep the plan the account had when it signed in.
const plan = profiles.planFromProfile(body.organization);
profiles.rememberLivePlan(account.uuid, plan);
const owner = { uuid: account.uuid, email: account.email || null, plan };
if (owners.size > 50) owners.clear(); // ponytail: crude cap; a few accounts per machine
owners.set(accessToken, owner);
return owner;