package main // 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 report and attribute a login; // written, three keys and nothing else, when a licence is switched, so the account Claude Code shows is // the one whose token it now holds. import ( "bytes" "encoding/json" "os" ) // Identity is an account as the agent's state file names it. type Identity struct { AccountUUID string `json:"accountUuid"` EmailAddress string `json:"emailAddress,omitempty"` OrganizationUUID string `json:"organizationUuid,omitempty"` } func readState(path string) (map[string]any, bool) { raw, err := os.ReadFile(path) if err != nil { return nil, false } dec := json.NewDecoder(bytes.NewReader(raw)) dec.UseNumber() var m map[string]any if dec.Decode(&m) != nil || m == nil { return nil, false } return m, true } // ReadIdentity is the account the state file names, or nil — never a guess. func ReadIdentity(path string) *Identity { m, ok := readState(path) if !ok { return nil } a, _ := m["oauthAccount"].(map[string]any) uuid, _ := a["accountUuid"].(string) if uuid == "" { return nil } id := &Identity{AccountUUID: uuid} id.EmailAddress, _ = a["emailAddress"].(string) id.OrganizationUUID, _ = a["organizationUuid"].(string) return id } // WriteIdentity points the state file's account at id, keeping every other key as found; answers whether // the file changed. A file that is there and cannot be read as an object is left alone. func WriteIdentity(path string, id Identity) (bool, error) { m, ok := readState(path) if !ok { if _, err := os.Stat(path); err == nil { return false, nil } m = map[string]any{} } current, _ := m["oauthAccount"].(map[string]any) if current == nil { current = map[string]any{} } e, _ := current["emailAddress"].(string) o, _ := current["organizationUuid"].(string) if current["accountUuid"] == id.AccountUUID && e == id.EmailAddress && o == id.OrganizationUUID { return false, nil } current["accountUuid"] = id.AccountUUID current["emailAddress"] = id.EmailAddress current["organizationUuid"] = id.OrganizationUUID m["oauthAccount"] = current raw, err := indented(m) if err != nil { return false, err } tmp := path + ".mesh-tmp" if err := os.WriteFile(tmp, raw, 0o600); err != nil { return false, err } return true, os.Rename(tmp, path) }