mod audit;
mod compose;
mod dashboard;
mod dashboard_write;
mod db;
mod db_dashboard;
mod profile;
mod read_model;
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.
#[command(
long_about = "Append an audit record (ADR 023). Use it for manual proof, corrections, recovery, and non-zynk-send events — for example recording a message delivered over a non-herdr transport, or correcting a chain. It is not for a message already sent with zynk send herdr --session-id: that send records its audit and corpus automatically, so auditing it again would double-record one message. (The audited-send integrity gap also prints a zynk audit … --payload-file … command; running that is the intended recovery path.)"
)]
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());
}