feat(login): /login opens the provider picker with green connected badges

/login previously fired the resolved method's flow immediately — there was
no way to see providers or their status. It now lands on the provider
picker; already-connected providers show a green 'connected' badge in the
key column.

Shell: initialize() probes stored credentials once (primary session flag,
auth.json oauth/<provider> scopes, resolved platform keys env>auth.json>
config) and stamps _meta.connected on each advertised method
(connected_method_ids + stamp_connected_meta, pure and unit-tested).
Display state only — never an authorization input.

TUI:
- PendingMenuItem::connected() reads the badge from method meta; the
  picker renders it green (accent_success), replacing the shortcut hint.
- New Action::OpenLoginPicker: /login shows the picker; mid-session it
  stashes the view like dispatch_login, and starts no flow by itself.
- Mid-session picker: last row reads 'Cancel' and dispatches CancelLogin
  (clicking it must not exit the app); Esc also returns to the session.
- After a successful login, the just-authenticated method is stamped
  connected in the TUI's advertised-methods copy (auth_in_flight_method →
  AuthComplete), so a later /login shows the badge without re-initialize.

Verified: kigi-shell 5256 + kigi-tui 6870 tests green, clippy clean.
This commit is contained in:
ZacharyZhang-NY committed 2026-07-22 16:14:42 -04:00
1 parent 1e57cd9225
commit fc7c2a1b9b
11 files changed
+384 -15

No files matched your search

@@ -1,4 +1,4 @@
//! `/login` -- log in or re-authenticate with your account.
//! `/login` -- pick a provider to log in or re-authenticate with.
use crate::app::actions::Action;
use crate::slash::command::{CommandExecCtx, CommandResult, SlashCommand};
@@ -11,14 +11,17 @@ impl SlashCommand for LoginCommand {
}
fn description(&self) -> &str {
"Log in or re-authenticate with your account"
"Pick a provider to log in with (connected ones are marked)"
}
fn usage(&self) -> &str {
"/login"
}
/// Opens the provider picker rather than auto-starting a flow: the user
/// chooses a row there, and already-connected providers show a green
/// "connected" badge.
fn run(&self, _ctx: &mut CommandExecCtx, _args: &str) -> CommandResult {
CommandResult::Action(Action::Login)
CommandResult::Action(Action::OpenLoginPicker)
}
}