greppy/cli/
login.rs

1//! Login command implementation
2
3use crate::auth::{self, Provider};
4use crate::core::error::Result;
5use dialoguer::{theme::ColorfulTheme, Select};
6
7/// Run the login command - let user choose provider with arrow keys
8pub async fn run() -> Result<()> {
9    // Check if already logged in
10    let providers = auth::get_authenticated_providers();
11
12    if !providers.is_empty() {
13        println!("Already logged in with:");
14        for p in &providers {
15            match p {
16                Provider::Anthropic => println!("  - Claude (Anthropic)"),
17                Provider::Google => println!("  - Gemini (Google)"),
18            }
19        }
20        println!("\nTo switch providers, run 'greppy logout' first.");
21        return Ok(());
22    }
23
24    // Interactive selection - Claude first (most common)
25    let options = &["Claude (Anthropic) - OAuth", "Gemini (Google) - OAuth"];
26
27    let selection = Select::with_theme(&ColorfulTheme::default())
28        .with_prompt("Choose AI provider")
29        .items(options)
30        .default(0)
31        .interact()
32        .map_err(|e| crate::core::error::Error::DaemonError {
33            message: format!("Selection failed: {}", e),
34        })?;
35
36    match selection {
37        0 => {
38            println!("\nAuthenticating with Claude...\n");
39            auth::login_anthropic().await?;
40        }
41        1 => {
42            println!("\nAuthenticating with Google...\n");
43            auth::login_google().await?;
44        }
45        _ => unreachable!(),
46    }
47
48    println!("\nYou can now use semantic search:");
49    println!("  greppy search \"your query\"");
50
51    Ok(())
52}
53
54/// Run the logout command - remove all stored credentials
55pub fn logout() -> Result<()> {
56    let providers = auth::get_authenticated_providers();
57
58    if providers.is_empty() {
59        println!("Not logged in to any provider.");
60        return Ok(());
61    }
62
63    println!("Logging out from:");
64    for p in &providers {
65        match p {
66            Provider::Anthropic => println!("  - Claude (Anthropic)"),
67            Provider::Google => println!("  - Gemini (Google)"),
68        }
69    }
70
71    auth::logout()?;
72    println!("\nSuccessfully logged out.");
73    Ok(())
74}
75
76/// Check if user is authenticated with any provider
77pub fn is_authenticated() -> bool {
78    !auth::get_authenticated_providers().is_empty()
79}
80
81/// Get the preferred provider (Anthropic > Google)
82pub fn get_preferred_provider() -> Option<Provider> {
83    let providers = auth::get_authenticated_providers();
84    if providers.contains(&Provider::Anthropic) {
85        Some(Provider::Anthropic)
86    } else if providers.contains(&Provider::Google) {
87        Some(Provider::Google)
88    } else {
89        None
90    }
91}