doum_cli/cli/
secret.rs

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