use clap::{Parser, Subcommand};
use std::path::PathBuf;
#[derive(clap::Args, Debug, Clone, Copy, Default)]
pub struct Verbosity {
#[arg(
long,
short = 'v',
action = clap::ArgAction::Count,
global = true,
help = "Increase logging verbosity",
long_help = None,
)]
pub verbose: u8,
#[arg(
long,
short = 'q',
action = clap::ArgAction::Count,
global = true,
help = "Decrease logging verbosity",
long_help = None,
conflicts_with = "verbose",
)]
pub quiet: u8,
}
#[derive(Debug, Parser)]
#[command(author, version)]
pub struct Options {
#[clap(
short = 'c',
long = "config",
help = "path to config file",
global = true
)]
pub config_path: Option<PathBuf>,
#[arg(long = "strict", env = "MICROMUX_STRICT", help = "enable strict mode")]
pub strict: Option<bool>,
#[arg(
long = "color",
env = "MICROMUX_COLOR",
help = "enable or disable color"
)]
pub color_choice: Option<termcolor::ColorChoice>,
#[command(flatten)]
pub verbosity: Verbosity,
#[arg(
long = "log",
env = "MICROMUX_LOG_LEVEL",
aliases = ["log-level"],
help = "Log level. When using a more sophisticated logging setup using RUST_LOG environment variable, this option is overwritten."
)]
pub log_level: Option<tracing::metadata::Level>,
#[arg(long = "log-file", env = "MICROMUX_LOG_FILE", help = "Log file")]
pub log_file: Option<PathBuf>,
#[arg(
long = "no-pretty-json-logs",
env = "MICROMUX_NO_PRETTY_JSON_LOGS",
help = "show structured JSON logs as raw JSON in the TUI (also configurable via `ui: { pretty_json_logs: false }`)"
)]
pub no_pretty_json_logs: bool,
#[arg(
long = "no-control",
env = "MICROMUX_NO_CONTROL",
help = "disable the agent control plane (also configurable via `control: { enabled: false }`)"
)]
pub no_control: bool,
#[command(subcommand)]
pub command: Option<Command>,
}
#[derive(Debug, Subcommand)]
pub enum Command {
Attach {
#[arg(long)]
session: Option<String>,
},
Ctl {
#[command(subcommand)]
action: CtlAction,
},
#[cfg(feature = "mcp")]
Mcp,
Serve,
}
#[cfg(test)]
mod tests {
use super::{Command, Options};
use clap::Parser;
use similar_asserts::assert_eq;
#[test]
fn attach_accepts_optional_selector_and_global_config_override() -> Result<(), clap::Error> {
let current = Options::try_parse_from(["micromux", "attach"]);
assert!(matches!(
current.map(|options| options.command),
Ok(Some(Command::Attach { session: None }))
));
let options = Options::try_parse_from([
"micromux",
"attach",
"--session",
"name:api",
"--config",
"other.yaml",
])?;
assert_eq!(
options.config_path.as_deref(),
Some(std::path::Path::new("other.yaml"))
);
assert!(matches!(
options.command,
Some(Command::Attach { session: Some(session) }) if session == "name:api"
));
Ok(())
}
}
#[derive(Debug, Subcommand)]
pub enum CtlAction {
Ls,
Logs {
service: String,
#[arg(long)]
run_generation: Option<u64>,
#[arg(long)]
tail: Option<usize>,
},
LogRuns {
service: String,
},
Restart {
service: String,
},
RestartAll,
Enable {
service: String,
},
Disable {
service: String,
},
StopDynamic {
service: String,
},
Reconcile {
#[arg(long)]
dry_run: bool,
},
Health {
service: String,
#[arg(long)]
history: bool,
},
Describe,
Stop,
}