doum_cli/cli/
secret.rs

1use crate::core::{get_provider_config, save_secrets};
2use crate::llm::{Provider, load_presets, verify_config};
3use anyhow::{Context, Result};
4use cliclack::{input, password, select, spinner};
5use std::collections::HashMap;
6
7pub async fn handle_secret_command() -> Result<()> {
8    cliclack::intro("🔐 Configure LLM Provider Secret")?;
9
10    // Step 1: Select provider
11    let providers = Provider::all();
12    let provider_items: Vec<_> = providers
13        .iter()
14        .map(|p| (p.as_str(), p.as_str(), ""))
15        .collect();
16
17    let provider_str = select("Select provider to configure")
18        .items(&provider_items)
19        .interact()
20        .context("Selection failed")?;
21
22    let provider: Provider = provider_str.parse()?;
23
24    // Step 2: Prompt for secret fields
25    let config = get_provider_config(&provider)?;
26    let mut values = HashMap::new();
27    for field in &config.fields {
28        let value = if field.is_password {
29            password(&field.label)
30                .interact()
31                .context("Password input failed")?
32        } else {
33            // Optional field: allow empty input
34            let input_value: String = input(&field.label)
35                .placeholder("Press Enter to skip")
36                .required(false)
37                .interact()
38                .context("Input failed")?;
39            input_value
40        };
41        values.insert(field.name.clone(), value.trim().to_string());
42    }
43
44    // Save secrets
45    save_secrets(&provider, values)?;
46
47    // Get first model for verification
48    let first_model = load_presets(&provider)
49        .first()
50        .map(|m| m.id.clone())
51        .unwrap_or_else(|| "gpt-4".to_string());
52
53    // Verify with spinner
54    let sp = spinner();
55    sp.start("Verifying API key...");
56
57    match verify_config(provider.as_str(), &first_model).await {
58        Ok(true) => {
59            sp.stop(format!(
60                "✅ {} secrets saved and verified successfully",
61                provider_str.to_uppercase()
62            ));
63            cliclack::outro("Configuration complete!")?;
64            Ok(())
65        }
66        Ok(false) => {
67            sp.stop("⚠️  API key verification failed");
68            cliclack::outro("Secrets saved but verification failed. Please check your API key.")?;
69            Ok(())
70        }
71        Err(e) => {
72            sp.stop("❌ Verification error");
73            cliclack::outro(format!("Error: {}", e))?;
74            Err(e)
75        }
76    }
77}