use std::path::PathBuf; use anyhow::{Result, bail}; use clap::{Parser, Subcommand}; use hive_sh4re::{HostRequest, HostResponse}; mod client; mod lifecycle; mod server; #[derive(Parser)] #[command(name = "hive-c0re", about = "hyperhive coordinator daemon and CLI")] struct Cli { /// Path to the host admin socket. #[arg(long, global = true, default_value = "/run/hyperhive/host.sock")] socket: PathBuf, #[command(subcommand)] cmd: Cmd, } #[derive(Subcommand)] enum Cmd { /// Run the coordinator daemon. Serve { /// Flake reference for the agent base template. #[arg(long, default_value = "/etc/hyperhive#agent-base")] agent_flake: String, }, /// Spawn a new agent container (`hive-agent-`). Spawn { name: String }, /// Stop a managed container (graceful). Kill { name: String }, /// Apply pending config to a managed container. Rebuild { name: String }, /// List managed containers. List, } #[tokio::main] async fn main() -> Result<()> { tracing_subscriber::fmt() .with_env_filter( tracing_subscriber::EnvFilter::try_from_default_env() .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")), ) .init(); let cli = Cli::parse(); match cli.cmd { Cmd::Serve { agent_flake } => server::serve(&cli.socket, &agent_flake).await, Cmd::Spawn { name } => { render(client::request(&cli.socket, HostRequest::Spawn { name }).await?) } Cmd::Kill { name } => { render(client::request(&cli.socket, HostRequest::Kill { name }).await?) } Cmd::Rebuild { name } => { render(client::request(&cli.socket, HostRequest::Rebuild { name }).await?) } Cmd::List => render(client::request(&cli.socket, HostRequest::List).await?), } } fn render(resp: HostResponse) -> Result<()> { println!("{}", serde_json::to_string_pretty(&resp)?); if !resp.ok { bail!(resp.error.unwrap_or_else(|| "request failed".to_owned())); } Ok(()) }