// Which account the agent is logged in as (novox/hq ADR 0183): not in the token, but in the agent's // own state file beside the home, `~/.claude.json` → `oauthAccount`. Read to attribute a login; written, // three keys and nothing else, when a licence is switched, so the file Claude Code shows the account from // names the account whose token it now holds (as the predecessor learned: two files that disagree make // a later login look like the wrong account). import { readFileSync, renameSync, writeFileSync } from "node:fs"; export interface Identity { readonly accountUuid: string; readonly emailAddress?: string; readonly organizationUuid?: string; } export function readIdentity(stateFile: string): Identity | null { try { const raw = JSON.parse(readFileSync(stateFile, "utf8")) as { oauthAccount?: Record }; const a = raw.oauthAccount; if (!a || typeof a.accountUuid !== "string") return null; return { accountUuid: a.accountUuid, emailAddress: typeof a.emailAddress === "string" ? a.emailAddress : undefined, organizationUuid: typeof a.organizationUuid === "string" ? a.organizationUuid : undefined, }; } catch { return null; } } /** * Point the state file's account at `id`, keeping every other key as found. Returns whether the file * changed; a file that cannot be read as an object is left alone rather than replaced. */ export function writeIdentity(stateFile: string, id: Identity): boolean { let raw: Record; try { raw = JSON.parse(readFileSync(stateFile, "utf8")) as Record; if (!raw || typeof raw !== "object") return false; } catch { raw = {}; } const current = (raw.oauthAccount ?? {}) as Record; if (current.accountUuid === id.accountUuid && current.emailAddress === id.emailAddress && current.organizationUuid === id.organizationUuid) return false; raw.oauthAccount = { ...current, accountUuid: id.accountUuid, emailAddress: id.emailAddress, organizationUuid: id.organizationUuid }; const tmp = `${stateFile}.mesh-tmp`; writeFileSync(tmp, JSON.stringify(raw, null, 2), { mode: 0o600 }); renameSync(tmp, stateFile); return true; }