Skip to main content

agent_procs/cli/
up.rs

1use crate::cli;
2use crate::config::{discover_config, ProjectConfig};
3use crate::protocol::{Request, Response};
4
5pub async fn execute(session: &str, only: Option<&str>, config_path: Option<&str>) -> i32 {
6    let path = match config_path {
7        Some(p) => std::path::PathBuf::from(p),
8        None => match discover_config(&std::env::current_dir().unwrap()) {
9            Some(p) => p,
10            None => { eprintln!("error: no agent-procs.yaml found"); return 1; }
11        },
12    };
13
14    let content = match std::fs::read_to_string(&path) {
15        Ok(c) => c,
16        Err(e) => { eprintln!("error: cannot read config: {}", e); return 1; }
17    };
18
19    let config: ProjectConfig = match serde_yaml::from_str(&content) {
20        Ok(c) => c,
21        Err(e) => { eprintln!("error: invalid config: {}", e); return 1; }
22    };
23
24    let only_set: Option<Vec<&str>> = only.map(|s| s.split(',').collect());
25
26    let groups = match config.startup_order() {
27        Ok(g) => g,
28        Err(e) => { eprintln!("error: {}", e); return 1; }
29    };
30
31    for group in &groups {
32        for name in group {
33            if let Some(ref only) = only_set {
34                if !only.contains(&name.as_str()) { continue; }
35            }
36
37            let def = &config.processes[name];
38
39            // Resolve cwd relative to config file directory
40            let resolved_cwd = def.cwd.as_ref().map(|c| {
41                let p = std::path::Path::new(c);
42                if p.is_relative() {
43                    path.parent().unwrap_or(std::path::Path::new(".")).join(p).to_string_lossy().to_string()
44                } else {
45                    c.clone()
46                }
47            });
48
49            // Pass env vars through the protocol (no shell escaping needed)
50            let env = if def.env.is_empty() { None } else { Some(def.env.clone()) };
51
52            // Start the process
53            let req = Request::Run {
54                command: def.cmd.clone(),
55                name: Some(name.clone()),
56                cwd: resolved_cwd,
57                env,
58            };
59            match cli::request(session, &req, true).await {
60                Ok(Response::RunOk { name, id, pid }) => {
61                    println!("started {} (id: {}, pid: {})", name, id, pid);
62                }
63                Ok(Response::Error { code, message }) => {
64                    eprintln!("error starting {}: {}", name, message);
65                    return code;
66                }
67                _ => return 1,
68            }
69
70            // Wait for ready pattern
71            if let Some(ref ready) = def.ready {
72                let req = Request::Wait {
73                    target: name.clone(), until: Some(ready.clone()),
74                    regex: false, exit: false, timeout_secs: Some(30),
75                };
76                match cli::request(session, &req, false).await {
77                    Ok(Response::WaitMatch { .. }) => println!("{} is ready", name),
78                    Ok(Response::WaitTimeout) => {
79                        eprintln!("warning: {} did not become ready within 30s", name);
80                    }
81                    Ok(Response::Error { message, .. }) => {
82                        eprintln!("error waiting for {}: {}", name, message);
83                        return 1;
84                    }
85                    _ => {}
86                }
87            }
88        }
89    }
90
91    println!("all processes started");
92    0
93}