Skip to main content

agent_procs/cli/
up.rs

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