use clap::{Parser, Subcommand, ValueEnum};
use std::path::PathBuf;
#[derive(Parser)]
#[command(name = "claux")]
#[command(about = "claux — an open, hackable terminal AI coding assistant in Rust")]
pub struct Cli {
#[command(subcommand)]
pub command: Option<CliCommand>,
#[arg(short = 'p', long = "print")]
pub prompt: Option<String>,
#[arg(long)]
pub model: Option<String>,
#[arg(long)]
pub resume: Option<String>,
#[arg(long)]
pub permission_mode: Option<String>,
#[arg(long)]
pub trust_project: bool,
#[arg(short, long)]
pub verbose: bool,
#[arg(long)]
pub debug: bool,
#[arg(long)]
pub tui: bool,
}
#[derive(Subcommand)]
pub enum CliCommand {
Doctor {
#[arg(long)]
offline: bool,
},
Config {
#[command(subcommand)]
command: ConfigCommand,
},
#[command(name = "__sandbox-exec", hide = true)]
SandboxExec {
#[arg(long)]
workspace: PathBuf,
#[arg(long)]
command: String,
},
#[command(name = "__sandbox-probe", hide = true)]
SandboxProbe,
}
#[derive(Subcommand)]
pub enum ConfigCommand {
Init {
#[arg(long, value_enum, default_value_t = ConfigProvider::Anthropic)]
provider: ConfigProvider,
#[arg(long)]
model: Option<String>,
#[arg(long)]
force: bool,
},
}
#[derive(Clone, Copy, Debug, ValueEnum)]
pub enum ConfigProvider {
Anthropic,
Openai,
#[value(name = "openrouter")]
OpenRouter,
Ollama,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_doctor_offline() {
let cli = Cli::try_parse_from(["claux", "doctor", "--offline"]).unwrap();
assert!(matches!(
cli.command,
Some(CliCommand::Doctor { offline: true })
));
}
#[test]
fn parses_config_init_provider() {
let cli = Cli::try_parse_from([
"claux",
"config",
"init",
"--provider",
"ollama",
"--model",
"local-coder",
])
.unwrap();
assert!(matches!(
cli.command,
Some(CliCommand::Config {
command: ConfigCommand::Init {
provider: ConfigProvider::Ollama,
model: Some(ref model),
force: false,
},
}) if model == "local-coder"
));
}
#[test]
fn parses_openrouter_config_init() {
let cli = Cli::try_parse_from([
"claux",
"config",
"init",
"--provider",
"openrouter",
"--model",
"anthropic/claude-sonnet-5",
])
.unwrap();
assert!(matches!(
cli.command,
Some(CliCommand::Config {
command: ConfigCommand::Init {
provider: ConfigProvider::OpenRouter,
model: Some(ref model),
force: false,
},
}) if model == "anthropic/claude-sonnet-5"
));
}
}