feat(tui,cli): provider → auth-method login chooser + profile-picker fixes (cursor-reset, hover shows provider/weekly-left)#362
Merged
Conversation
…fixes Add a two-level, data-driven login chooser (provider → login method) reachable from both auth-profile entry points, and fix two profile-picker bugs. - Capability model in codex-login as the single source of truth (no hardcoded provider/method lists): AuthProfileSubscriptionProvider::ALL, description(), AuthProfileLoginMethod, supported_login_methods(). This alone restores Claude.ai, which the old hardcoded chooser dropped. - /profile -> "Log in new profile" now shows a provider chooser (every provider), then a per-provider method chooser listing only supported methods (filtered by forced_login_method); single-method providers skip the extra step. Methods route to existing flows: browser OAuth in-session; device-code and API-key hand off to the `codewith login` CLI so secrets never pass through the TUI. - `codewith --auth-profile <missing>` no longer dead-ends in a login screen: it falls back to the default login and opens the provider chooser to create the named profile (gated by codex-login::auth_profile_exists). - Fix profile-picker cursor reset (Bug B): the in-place popup refresh opts into a new SelectionViewParams.prefer_initial_over_current so a background usage-heartbeat rebuild keeps the user's cursor instead of snapping back to the active-profile row. - Profile-picker highlighted-row detail shows the subscription provider + weekly usage remaining (loading placeholder until fetched), never the account email (Bug C). Tests cover the capability model, auth_profile_exists, cursor preservation, the provider+weekly detail, and the missing-profile routing decision; flow tests and insta snapshots updated. Full codex-login + codex-tui suites pass on Blacksmith.
andrei-hasna
force-pushed
the
feat/auth-login-provider-method-chooser
branch
from
July 22, 2026 09:01
ef4f2dc to
bd554ba
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
The "login with another profile" flow dead-ended into a single login page from both entry points, and the profile picker had two UX bugs. This adds a consistent two-level, data-driven chooser — provider → login method (only the methods that provider supports) — and fixes the picker.
The two entry points, fixed
1.
codewith --auth-profile <name>for a profile that doesn't exist.Previously the app scoped auth to the empty profile dir →
NotAuthenticated→ dropped you into the generic onboarding login with no provider choice (and silently created the profile). Now:codex-login::auth_profile_existsgates it; a missing profile falls back to your default login (no dead-end) and auto-opens the provider chooser to create the named profile. The--auth-profileselection resolution/env-scoping decision is a small pure function (auth_profile_env_decision) with unit tests.2.
/profile→ "Log in new profile".Previously showed a hardcoded ChatGPT/Cursor/Grok list (Claude.ai was dropped) and, for ChatGPT, jumped straight to browser OAuth with no method choice. Now it's a two-step selector:
then, for the chosen provider, only its supported methods:
Single-method providers (Claude.ai/Cursor/Grok today) skip the method step.
Data-driven (no hardcoded provider/method lists)
The chooser derives everything from a new capability model in
codex-login— the single source of truth:AuthProfileSubscriptionProvider::ALL,description()AuthProfileLoginMethod+supported_login_methods()Iterating
ALLis what restores Claude.ai automatically. The TUI filters methods byforced_login_method. Method selection routes to the existing login flows: browser OAuth runs in-session; device-code and API-key hand off to thecodewith loginCLI so a credential never passes through the TUI (the composer prompt has no masking — deliberately not capturing secrets on-screen).Bug B — cursor reset while navigating
/profileA background usage/rate-limit heartbeat rebuilt the popup mid-navigation and snapped the highlight back to the active profile (the
is_currentauto-select beat the passed cursor index). Fix: a new opt-inSelectionViewParams.prefer_initial_over_current; the in-place refresh sets it so the rebuild honors the user's cursor. First-open and every other popup keep the historicis_currentbehavior (scoped, zero blast radius).Bug C — hover/detail showed the email
The highlighted profile's detail now shows the subscription provider + weekly usage remaining, never the account email. When weekly usage isn't loaded yet it shows a placeholder (provider is always visible):
Weekly-left is read from the
/usagerate-limit data (weekly window identified viausage_profile_health::WEEKLY_LIMIT_LABEL); the email was removed from the always-visible row description too.Tests
New/updated: capability model + exhaustiveness (
codex-login),auth_profile_exists, cursor-preservation-across-refresh, provider+weekly-detail, the missing-profile routing decision, two-step chooser flow, and the API-only/duplicate/external-provider paths. Insta snapshots regenerated for the provider chooser, the new method chooser, and the three picker screens (reviewed — no secrets).Blacksmith result
Clean checkout of this commit on a Blacksmith 16-vCPU box:
cargo nextest run -p codex-login -p codex-tui→ 3607 passed, 0 failed, 4 skipped. Nightlycargo fmt --check --config imports_granularity=Itemclean. Staged secrets scan clean.Deferred follow-ups