xbp 0.5.4

XBP is a build pack and deployment management tool to deploy, rust, nextjs etc and manage the NGINX configs below it
Documentation
use tokio::process::Command;

pub async fn pm2_list(debug: bool) -> Result<(), String> {
    let mut cmd = Command::new("pm2");
    cmd.arg("list");
    let output = cmd.output().await.map_err(|e| format!("failed to run pm2 list: {}", e))?;
    if debug {
        println!(
            "[DEBUG] pm2 list status={:?} stdout='{}' stderr='{}'",
            output.status,
            String::from_utf8_lossy(&output.stdout),
            String::from_utf8_lossy(&output.stderr)
        );
    }
    if !output.status.success() {
        return Err(String::from_utf8_lossy(&output.stderr).to_string());
    }
    print!("{}", String::from_utf8_lossy(&output.stdout));
    Ok(())
}

pub async fn pm2_logs(project: Option<String>, debug: bool) -> Result<(), String> {
    let mut cmd = Command::new("pm2");
    cmd.arg("logs");
    if let Some(name) = project {
        cmd.arg(name);
    }
    let mut child = cmd
        .stdout(std::process::Stdio::inherit())
        .stderr(std::process::Stdio::inherit())
        .spawn()
        .map_err(|e| format!("failed to spawn pm2 logs: {}", e))?;
    if debug { println!("[DEBUG] spawned pm2 logs"); }
    let status = child.wait().await.map_err(|e| format!("pm2 logs wait failed: {}", e))?;
    if !status.success() { return Err(format!("pm2 logs exited with status: {}", status)); }
    Ok(())
}