M1/F1: Kimi Code OAuth device-code flow
Replace the xAI OAuth stack with the Kimi device authorization grant:
- kimi_oauth.rs wire layer (device_authorization + token poll + refresh
against kigi_env::oauth_host(); client_id per PRD; retryable statuses
429/5xx with backoff; expired_token restarts authorization)
- X-Msh-Device-{Name,Model,Id} headers; device_id minted uuid4-hex at
~/.kigi/device_id (0600)
- Storage: system keyring service `kigi`, entry `oauth/kimi-code`
(macOS/Windows native backends), atomic-file fallback under ~/.kigi;
official client's keyring/~/.kimi never touched
- Refresh manager: 60s tick, threshold max(300, expires_in*0.5),
401-tombstone keyed by rejected refresh token with 300s cooldown and
rotation auto-clear, cross-process lock with sibling-adoption
triple-check, sleep/wake forced refresh
- Deleted xAI machinery: enterprise OIDC (PKCE/JWKS/teams), devbox login,
external auth provider, JWT tier gating + subscription paywall stack,
X-XAI-Token-Auth marker headers, ZDR gates, /user enrichment
- kigi login / TUI /login both drive the device flow; login-host display
now derives from kigi_env::oauth_host()
- 264 auth unit/wiremock tests; live contract probe of
auth.kimi.com/api/oauth/device_authorization matches the wire shapes
Gates: check/clippy --all-targets clean, fmt, deny ok, kigi-shell lib
5131 tests green.
This commit is contained in:
@@ -40,11 +40,11 @@ pub async fn run(args: SessionsArgs, agent_config: &AgentConfig) -> Result<()> {
|
||||
// for these setups), any cached credential will be used. Otherwise we still
|
||||
// proceed so the SessionRegistryClient can use the deployment_key when
|
||||
// talking to the custom proxy.
|
||||
let auth = try_ensure_fresh_auth(&agent_config.grok_com_config).await;
|
||||
let auth = try_ensure_fresh_auth(&agent_config.kimi_code_config).await;
|
||||
|
||||
let auth_manager = std::sync::Arc::new(AuthManager::new(
|
||||
&kigi_home(),
|
||||
agent_config.grok_com_config.clone(),
|
||||
agent_config.kimi_code_config.clone(),
|
||||
));
|
||||
|
||||
let client = kigi_shell::agent::session_registry_client::SessionRegistryClient::new(
|
||||
@@ -169,7 +169,7 @@ pub async fn run(args: SessionsArgs, agent_config: &AgentConfig) -> Result<()> {
|
||||
// backend delete is idempotent (a `404` is treated as success),
|
||||
// so this is safe for local-only sessions with no remote copy.
|
||||
// ZDR teams never upload, so there is nothing remote to delete.
|
||||
let needs_remote = auth.as_ref().is_some_and(|a| !a.is_zdr_team());
|
||||
let needs_remote = auth.is_some();
|
||||
|
||||
// Pass `cwd = None` so the session is found by id regardless of
|
||||
// which workspace it was created in; the local delete still uses
|
||||
|
||||
Reference in New Issue
Block a user