zynk 0.2.2

Portable protocol and helper CLI for multi-agent collaboration.
mod audit;
mod compose;
mod dashboard;
mod db;
mod db_dashboard;
mod profile;
mod send_herdr;
mod status;
mod timestamp;

use clap::{Args, CommandFactory, Parser, Subcommand};

#[derive(Parser)]
#[command(
    name = "zynk",
    version,
    about = "Portable multi-agent collaboration helper CLI."
)]
struct Cli {
    #[command(subcommand)]
    command: Option<Commands>,
}

#[derive(Subcommand)]
#[allow(clippy::large_enum_variant)]
enum Commands {
    /// Compose a protocol message.
    Compose(compose::ComposeArgs),
    /// Send a composed protocol message.
    Send(SendCommand),
    /// Write an ADR 022 rolling status file.
    Status(status::StatusArgs),
    /// Append an ADR 023 audit record.
    Audit(audit::AuditArgs),
    /// Render an ADR 022 aggregate dashboard.
    Dashboard(dashboard::DashboardArgs),
    /// Manage the live-state SQLite database.
    Db(db::DbArgs),
}

#[derive(Args)]
struct SendCommand {
    #[command(subcommand)]
    transport: SendTransport,
}

#[derive(Subcommand)]
enum SendTransport {
    /// Send via herdr pane run.
    Herdr(send_herdr::SendHerdrArgs),
}

#[derive(Debug)]
pub struct CliError {
    code: i32,
    message: String,
}

impl CliError {
    pub fn usage(message: impl Into<String>) -> Self {
        Self {
            code: 2,
            message: message.into(),
        }
    }

    pub fn failure(message: impl Into<String>) -> Self {
        Self {
            code: 1,
            message: message.into(),
        }
    }

    pub fn with_code(code: i32, message: impl Into<String>) -> Self {
        Self {
            code,
            message: message.into(),
        }
    }
}

pub type CliResult<T> = Result<T, CliError>;

fn run() -> i32 {
    let cli = Cli::parse();
    let result = match cli.command {
        Some(Commands::Compose(args)) => compose::run(args),
        Some(Commands::Send(command)) => match command.transport {
            SendTransport::Herdr(args) => send_herdr::run(args),
        },
        Some(Commands::Status(args)) => status::run(args),
        Some(Commands::Audit(args)) => audit::run(args),
        Some(Commands::Dashboard(args)) => dashboard::run(args),
        Some(Commands::Db(args)) => db::run(args),
        None => {
            let mut command = Cli::command();
            let _ = command.print_help();
            println!();
            return 2;
        }
    };

    match result {
        Ok(()) => 0,
        Err(error) => {
            eprintln!("error: {}", error.message);
            error.code
        }
    }
}

fn main() {
    std::process::exit(run());
}