bd66e7e3fb
Hermes keeps its own copy of the Codex OAuth token per profile and at the top level, separate from the Codex CLI's ~/.codex/auth.json. OAuth refresh_tokens are single-use, so when the Codex CLI (or another Hermes process) rotates the shared token, the frozen copy's refresh_token goes stale and refresh_codex_oauth_pure fails with a relogin-required error (invalid_grant / refresh_token_reused / 401). Today that surfaces as a hard 401 on the turn — idle profiles and desktop sessions 401 "token_expired" until a manual re-auth — even though ~/.codex/auth.json holds a fresh token. _refresh_codex_auth_tokens now falls back to _import_codex_cli_tokens() (the canonical Codex CLI store) when the stored refresh_token is rejected, adopts and persists the fresh token, and lets the in-flight retry succeed. This complements PR #6525 (force relogin on 401/403): we attempt automatic recovery before surfacing a relogin prompt. Transient failures (e.g. 429 quota, relogin_required=False) are never self-healed — the stored token is still valid there — so they re-raise unchanged, and the happy path is untouched. Adds tests/hermes_cli/test_auth_codex_self_heal.py covering: self-heal on invalid_grant, no self-heal on 429 quota, re-raise when ~/.codex is absent, and happy-path-unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>