doum_cli/cli/
suggest.rs

1use crate::llm::client::LLMRequest;
2use crate::llm::{LLMMessage, PromptBuilder, create_client, parse_suggest};
3use crate::system::{get_system_info, load_config};
4use anyhow::Result;
5use arboard::Clipboard;
6use cliclack::{select, spinner};
7
8pub async fn handle_suggest_command(request: &str) -> Result<()> {
9    let config = load_config()?;
10    let client = create_client(&config.llm)?;
11    let system_info = get_system_info();
12    let builder = PromptBuilder::new(system_info.clone());
13
14    let sp = spinner();
15    sp.start("[SUGGEST MODE] Generating commands...");
16
17    let llm_request = LLMRequest {
18        system: builder.build_suggest(),
19        messages: vec![LLMMessage::user(request)],
20    };
21
22    let response = client.generate_with_parser(llm_request, parse_suggest).await?;
23
24    sp.stop("");
25
26    // Handle empty suggestions
27    if response.suggestions.is_empty() {
28        println!("\n⚠️  No commands to suggest.\n");
29        return Ok(());
30    }
31
32    // Format command items for selection
33    let items: Vec<_> = response
34        .suggestions
35        .iter()
36        .map(|s| (s, s.cmd.as_str(), s.description.as_str()))
37        .collect();
38
39    let selected = select("Select a command").items(&items).interact()?;
40
41    // Copy to clipboard
42    copy_to_clipboard(&selected.cmd)?;
43
44    cliclack::outro("✅ Command copied to clipboard, Ctrl+V to paste it!")?;
45
46    Ok(())
47}
48
49/// Copy text to clipboard using arboard
50fn copy_to_clipboard(text: &str) -> Result<()> {
51    let mut clipboard =
52        Clipboard::new().map_err(|e| anyhow::anyhow!("Failed to initialize clipboard: {}", e))?;
53
54    clipboard
55        .set_text(text)
56        .map_err(|e| anyhow::anyhow!("Failed to copy to clipboard: {}", e))?;
57
58    Ok(())
59}