unifier-cli 0.3.0

Filesystem postbox for inter-process communication via a Unix tree
Documentation
use clap::{Parser, Subcommand};

#[derive(Parser)]
#[command(name = "unifier")]
#[command(
    about = "Filesystem postbox: programs communicate by writing values to files in a Unix tree",
    version
)]
pub struct Cli {
    /// Override state root (default: $UNIFIER_HOME or ~/.local/unifier)
    #[arg(long, global = true, env = "UNIFIER_HOME")]
    pub home: Option<std::path::PathBuf>,

    /// Scope operations to chroots/<name>/ (only that subtree is visible)
    #[arg(long, global = true, env = "UNIFIER_CHROOT")]
    pub chroot: Option<String>,

    /// Force direct filesystem access even when a hot daemon is running
    #[arg(long, global = true)]
    pub no_daemon: bool,

    /// Prefix keys with this namespace (overrides a bound process namespace)
    #[arg(long, global = true, env = "UNIFIER_NAMESPACE")]
    pub namespace: Option<String>,

    #[command(subcommand)]
    pub cmd: Commands,
}

#[derive(Subcommand)]
pub enum Commands {
    /// Write a persistent key value under keys/
    Put {
        /// Key path (e.g. myapp/config/theme)
        key: String,
        /// Value to store
        value: String,
    },
    /// Read a key value
    Get { key: String },
    /// Delete a key
    Del { key: String },
    /// Drop a message into a recipient mailbox
    Send {
        /// Sender agent name (default: unifier)
        #[arg(long)]
        from: Option<String>,
        recipient: String,
        message: String,
    },
    /// Schedule a cron message (directory name: min_hour_dom_mon_dow, use * for any)
    Cron { schedule: String, message: String },
    /// Collect pending messages for a mailbox recipient
    Poll {
        recipient: String,
        /// Remove messages after printing
        #[arg(long)]
        ack: bool,
    },
    /// Collect cron messages whose schedule matches the current time
    PollCron {
        /// Remove messages after printing
        #[arg(long)]
        ack: bool,
    },
    /// List message files in a subtree (e.g. cron/0_0_*_*_*)
    List { path: String },
    /// Remove a message by UUID or relative path under the state root
    Ack { id_or_path: String },
    /// Print the effective state root path
    Root,
    /// Post a named JSON event for agent pickup
    Event {
        /// JSON payload (must include a name field or be a JSON object)
        payload: String,
    },
    /// Send a structured JSON message to an agent mailbox
    Message {
        #[arg(long)]
        from: String,
        recipient: String,
        payload: String,
    },
    /// ACID tick staging (read previous tick, write current, commit at end)
    #[command(subcommand)]
    Tick(TickCommands),
    /// Hot in-memory daemon (persists state in RAM, flushes to disk on demand)
    #[command(subcommand)]
    Daemon(DaemonCommands),
    /// Manage isolated chroot subtrees
    #[command(subcommand)]
    Chroot(ChrootCommands),
    /// Bind a key prefix to the calling process (and descendants)
    #[command(subcommand)]
    Namespace(NamespaceCommands),
}

#[derive(Subcommand)]
pub enum TickCommands {
    /// Begin a new tick (reads frozen snapshot of previous committed state)
    Start {
        #[arg(default_value = "default")]
        label: String,
    },
    /// Commit current tick to disk with versioning
    End,
    /// Show committed tick, active tick, queue depth, and locks
    Status,
    /// Lock a key for the duration of the active tick
    Lock { key: String },
    /// Release a tick lock
    Unlock { key: String },
}

#[derive(Subcommand)]
pub enum DaemonCommands {
    /// Start the hot daemon in the background
    Start,
    /// Run the daemon in the foreground (internal / debugging)
    Run,
    /// Stop the daemon (flushes dirty state first)
    Stop,
    /// Show whether the daemon is running
    Status,
    /// Flush in-memory dirty state to disk
    Flush,
    /// Print mailbox/event wakeup notices from the event socket (for Jan cron)
    Watch,
}

#[derive(Subcommand)]
pub enum ChrootCommands {
    /// Create chroots/<name>/ with keys/, mailbox/, and cron/
    Init { name: String },
    /// List chroot names under the global store
    List,
}

#[derive(Subcommand)]
pub enum NamespaceCommands {
    /// Bind a key prefix until this process exits or a new namespace is set
    Set { name: String },
    /// Print the effective namespace for this process
    #[command(visible_alias = "show")]
    Get,
    /// Remove this process's namespace binding
    Clear,
}