Skip to main content

codetether_agent/cli/
run.rs

1//! Non-interactive run command
2
3use super::RunArgs;
4use crate::config::Config;
5use crate::session::Session;
6use anyhow::Result;
7
8pub async fn execute(args: RunArgs) -> Result<()> {
9    let message = args.message.trim();
10
11    if message.is_empty() {
12        anyhow::bail!("You must provide a message");
13    }
14
15    tracing::info!("Running with message: {}", message);
16
17    // Load configuration
18    let config = Config::load().await.unwrap_or_default();
19
20    // Create or continue session.
21    let mut session = if let Some(session_id) = args.session {
22        tracing::info!("Continuing session: {}", session_id);
23        if let Some(oc_id) = session_id.strip_prefix("opencode_") {
24            if let Some(storage) = crate::opencode::OpenCodeStorage::new() {
25                Session::from_opencode(oc_id, &storage).await?
26            } else {
27                anyhow::bail!("OpenCode storage not available")
28            }
29        } else {
30            Session::load(&session_id).await?
31        }
32    } else if args.continue_session {
33        let workspace_dir = std::env::current_dir().unwrap_or_default();
34        match Session::last_for_directory(Some(&workspace_dir)).await {
35            Ok(s) => {
36                tracing::info!(
37                    session_id = %s.id,
38                    workspace = %workspace_dir.display(),
39                    "Continuing last workspace session"
40                );
41                s
42            }
43            Err(_) => {
44                // Fallback: try to resume from OpenCode session
45                match Session::last_opencode_for_directory(&workspace_dir).await {
46                    Ok(s) => {
47                        tracing::info!(
48                            session_id = %s.id,
49                            workspace = %workspace_dir.display(),
50                            "Resuming from OpenCode session"
51                        );
52                        s
53                    }
54                    Err(_) => {
55                        let s = Session::new().await?;
56                        tracing::info!(
57                            session_id = %s.id,
58                            workspace = %workspace_dir.display(),
59                            "No workspace session found; created new session"
60                        );
61                        s
62                    }
63                }
64            }
65        }
66    } else {
67        let s = Session::new().await?;
68        tracing::info!("Created new session: {}", s.id);
69        s
70    };
71
72    // Set model: CLI arg > env var > config default
73    let model = args
74        .model
75        .or_else(|| std::env::var("CODETETHER_DEFAULT_MODEL").ok())
76        .or(config.default_model);
77
78    if let Some(model) = model {
79        tracing::info!("Using model: {}", model);
80        session.metadata.model = Some(model);
81    }
82
83    // Execute the prompt
84    let result = session.prompt(message).await?;
85
86    // Output based on format
87    match args.format.as_str() {
88        "json" => {
89            println!("{}", serde_json::to_string_pretty(&result)?);
90        }
91        _ => {
92            println!("{}", result.text);
93            // Show session ID for continuation
94            eprintln!(
95                "\n[Session: {} | Continue with: codetether run -c \"...\"]",
96                session.id
97            );
98        }
99    }
100
101    Ok(())
102}