mod dream; mod worker; use clap::{Parser, Subcommand}; #[derive(Parser)] #[command(name = "colony-agent", about = "Ape Colony Agent Runtime — autonomous agent lifecycle")] struct Cli { #[command(subcommand)] command: Commands, } #[derive(Subcommand)] enum Commands { /// Start the agent worker loop (pulse + react) Worker, /// Run one dream cycle (memory consolidation) Dream, /// Run one pulse cycle (check inbox, respond if needed) Pulse, /// Create a new agent on this VM Birth { name: String, #[arg(long)] instruction: String, }, /// Show agent status Status, } #[tokio::main] async fn main() { let cli = Cli::parse(); match cli.command { Commands::Worker => { worker::run_worker_loop(""); } Commands::Pulse => { worker::run_pulse(""); eprintln!("pulse complete"); } Commands::Dream => { dream::run_dream(); } Commands::Birth { name, instruction } => { // Birth delegates to the shell script for now let script = std::path::Path::new("scripts/birth.sh"); let script_path = if script.exists() { script.to_path_buf() } else { // Try relative to the apes repo let home = std::env::var("HOME").unwrap_or_default(); std::path::PathBuf::from(format!("{}/apes/scripts/birth.sh", home)) }; if !script_path.exists() { eprintln!("birth script not found at {} or scripts/birth.sh", script_path.display()); eprintln!("run from the apes repo root, or set HOME to the agent dir"); std::process::exit(1); } let status = std::process::Command::new("sudo") .args(["bash", &script_path.to_string_lossy(), &name, &instruction]) .status(); match status { Ok(s) if s.success() => eprintln!("agent {} born!", name), Ok(s) => { eprintln!("birth failed with status: {}", s); std::process::exit(1); } Err(e) => { eprintln!("failed to run birth script: {}", e); std::process::exit(1); } } } Commands::Status => { eprintln!("colony-agent: status not yet implemented"); std::process::exit(1); } } }