feat(accounts): surface Anthropic account/organization UUIDs through the full OAuth stack
Bundles three related changes that all revolve around the OAuth account record: capturing the new identity fields returned by the token-exchange endpoint, preventing stale CC credentials from clobbering a fresher locally persisted token, and making CC token refresh fall back to a still-valid cached credential when the claude binary is unavailable. UUID surfacing - src/oauth.ts: exchange() now picks up account.uuid and organization.uuid from the token response and returns them on the success variant. - src/storage.ts: AccountMetadata gains optional accountUuid and organizationUuid fields; validateAccount threads them through. - src/accounts.ts + src/accounts/matching.ts + src/accounts/persistence.ts: ManagedAccount and createManagedAccount accept and retain the UUIDs. updateManagedAccountFromStorage merges them in without losing previously set values. - src/commands/oauth-flow.ts: completeSlashOAuth copies both UUIDs into the managed account on add, update, and replace paths. - tests/unit/request/metadata.test.ts (new): pins the contract that getAccountIdentifier prefers accountUuid over the synthetic id when building metadata.user_id for downstream billing. Stale-token adoption rewrite - AccountManager.ensureOAuthAccountsFromCc now compares CC-credential recency against locally persisted auth recency before overwriting. Adopts the CC auth only when the local access token is missing, already expired, or the CC credential is at least as fresh. Refresh-token match still unconditionally adopts to avoid split-brain. - persistence.mergeAuthFallbackIntoAccounts accepts a preferredIndex and applies the auth fallback to the single account (or active index when there is ambiguity) only when the fallback looks fresh. - Exposes AccountManager.getManagedAccounts() so admin flows can mutate the live refs before persist. Token-refresh resilience - src/token-refresh.ts: introduces applyCCCredential and useCurrentAccountAccessIfStillValid helpers. refreshCCAccount now falls back to the cached credential when either the claude binary is missing, the execSync probe fails, or the post-probe read does not return a fresher token. refreshAccountToken downgrades the 'CC credential refresh failed' hard-throw to a debugLog, so callers automatically try the OAuth HTTP refresh path. Tests - tests/unit/oauth.test.ts: captures both UUIDs from a successful exchange response. - tests/unit/accounts.test.ts, matching.test.ts, persistence.test.ts: coverage for UUID plumbing and the fresher-token adoption rules. - tests/unit/token-refresh.test.ts: reworks the 'no claude binary' test into an HTTP-fallback assertion and adds coverage for the refresh-failure-but-cache-fresh path. Expected pre-existing bun-vs-vitest failures in these suites (vi.setSystemTime + mockFetch harness gaps) remain at 42 in the two largest files, unchanged by this commit.
V
Vacbo committed
1587d325ea3f97f8e8bdd5e168cc676bb537f56f
Parent: 22e9c71