docs/gemini.md
Gemini uses the Gemini CLI OAuth credentials and private quota APIs. No browser cookies.
OAuth-backed quota API (only path used in fetch())
~/.gemini/settings.json.oauth-personal (or unknown → try OAuth creds).api-key, vertex-ai (hard error).Legacy CLI parsing (parser exists but not used in current fetch path)
GeminiStatusProbe.parse(text:) can parse /stats output.~/.gemini/oauth_creds.json.access_token, refresh_token (optional), id_token, expiry_date.GEMINI_OAUTH_CLIENT_ID + GEMINI_OAUTH_CLIENT_SECRET environment override.GEMINI_OAUTH2_JS_PATH pointing at a readable oauth2.js file.oauth2.js / bundle regex extraction).opt libexec package roots when the GUI cannot resolve
the gemini binary).gemini binary, then search for:
.../libexec/lib/node_modules/@google/gemini-cli/node_modules/@google/gemini-cli-core/dist/src/code_assist/oauth2.js/opt/homebrew/Cellar/gemini-cli/<version>/libexec/lib/node_modules/@google/gemini-cli/opt/homebrew/opt/gemini-cli/libexec/lib/node_modules/@google/gemini-cli/usr/local.../node_modules/@google/gemini-cli-core/dist/src/code_assist/oauth2.jsOAUTH_CLIENT_ID and OAUTH_CLIENT_SECRET from oauth2.js or Homebrew bundle chunks.POST https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuota{ "project": "<projectId>" } (or {} if unknown)Authorization: Bearer <access_token>cloudaicompanionProject from loadCodeAssist.GET https://cloudresourcemanager.googleapis.com/v1/projects
gen-lang-client* or label generative-language.POST https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist{ "metadata": { "ideType": "GEMINI_CLI", "pluginType": "GEMINI" } }POST https://oauth2.googleapis.com/tokenclient_id, client_secret, refresh_token, grant_type=refresh_token.remainingFraction, resetTime, modelId.remainingFraction wins.percentLeft = remainingFraction * 100.resetTime parsed as ISO-8601, formatted as "Resets in Xh Ym".loadCodeAssist:
paidTier.name → paid subscription label from Google, preferred whenever presentstandard-tier → "Paid" (fallback when paidTier.name is absent)free-tier + hd claim → "Workspace" (fallback when paidTier.name is absent)free-tier → "Free"legacy-tier → "Legacy"id_token JWT claims.loadCodeAssist, or token-refresh responses include Google's unsupported-client
migration signal (UNSUPPORTED_CLIENT, IneligibleTierError, or Antigravity migration copy),
CodexBar surfaces consumerTierDeprecated with guidance to use the Antigravity provider.loadCodeAssist body with no currentTier and the consumer tier
listed under ineligibleTiers[].reasonCode == "UNSUPPORTED_CLIENT"; the follow-up retrieveUserQuota
call then fails with HTTP 403 SUBSCRIPTION_REQUIRED and no migration wording. CodexBar reads the
200 body's ineligibleTiers directly, and maps that 403 to consumerTierDeprecated only when the same
fetch saw the unsupported-client flag and the account is not on standard-tier — a licensed
account's 403 stays HTTP 403.paidTier.name (authoritative even without currentTier) and an hd claim (Workspace/education, which
resolveAccountPlan reads as Workspace when paired with free-tier). Both would otherwise be pre-empted
by the earlier loadCodeAssist branch, which runs before the plan resolver.UsageStore.geminiMigrationObservation records which sentinel the last refresh produced
(none / localAntigravityHandoff / googleConsumerTierShutdown); a later local-tooling failure never
downgrades a shutdown already seen. geminiObservedConsumerTierDeprecation (either sentinel) drives the
settings action; the narrower geminiObservedGoogleConsumerTierShutdown drives the login guard. While
the narrow one is set for this session,
the Gemini login action stops clearing ~/.gemini/oauth_creds.json and launching Gemini CLI — whose
OAuth step fails with the same message — and shows the Antigravity guidance instead. The local
oauthCredentialsUnavailableWithAntigravity handoff deliberately does not guard login: there,
reinstalling or relaunching Gemini CLI is the fix, and Workspace accounts must keep that path.consumerTierDeprecated during a Gemini refresh (typed sentinel state, not user-facing text matching).notLoggedIn, and Antigravity setup errors remain unchanged. CodexBar does not
capture Terminal gemini OAuth output, so Terminal-only failures cannot activate the migration action.Sources/CodexBarCore/Providers/Gemini/GeminiStatusProbe.swift