rho-coding-agent 1.10.0

A lightweight agent harness inspired by Pi
Documentation
use {
    rho_providers::auth::login_dispatch::{
        AuthenticationMethod, OAuthMode, OAuthUserAction, ProviderAuthentication,
    },
    rho_providers::credentials::OsCredentialStore,
    rho_providers::model::catalog,
};

pub(super) async fn run(provider: &str, device_auth: bool) -> anyhow::Result<()> {
    let Some(target) = catalog::login_target_for_provider(provider) else {
        anyhow::bail!(
            "unsupported login provider '{provider}'. Use one of: {}",
            catalog::implemented_providers().join(", ")
        );
    };
    if let AuthenticationMethod::ApiKey { entry_label } =
        ProviderAuthentication::method(&target.provider)?
    {
        anyhow::bail!(
            "{entry_label} login is only supported in the interactive TUI; run `/login {provider}`"
        );
    }

    let mode = if device_auth {
        OAuthMode::Device
    } else {
        OAuthMode::Browser
    };
    let login = ProviderAuthentication::start_oauth(&target.provider, mode).await?;
    match &login.user_action {
        OAuthUserAction::BrowserOpened => {
            eprintln!(
                "Opening browser for {} login. On a remote or headless session, use `rho login {} --device-auth` instead.",
                login.provider_label, target.provider
            );
        }
        OAuthUserAction::DeviceCode {
            verification_uri,
            user_code,
            verification_uri_complete,
        } => {
            eprintln!(
                "{} login: visit {verification_uri} and enter code {user_code}",
                login.provider_label
            );
            if let Some(uri) = verification_uri_complete {
                eprintln!("Or open this URL to continue: {uri}");
            }
        }
    }

    login.completion.await?.save(&OsCredentialStore)?;
    eprintln!("Successfully logged in to {}", target.provider);
    Ok(())
}