use clap::{Args, Parser, Subcommand};
use crate::explain::Format;
use crate::pulse::HeartbeatOpts;
#[derive(Parser, Debug)]
#[command(
name = "ct-steer",
version,
about = "Steer ad-hoc shell commands to the ct tool that serves them; install the PreToolUse hook.",
long_about = "ct-steer recognises the shell idioms a ct tool serves better (find | xargs grep, \
sed -i, cat | head, for-loops, && / || chains) and, as a Claude Code PreToolUse \
hook, steers the agent to the ct equivalent instead. Also reachable as `ct steer`. \
Subcommands: `hook` is the runtime hook (reads a PreToolUse envelope on stdin); \
`install`/`uninstall` wire it into .claude/settings.json; `check` shows what the \
hook would decide for a command. See `ct-steer --explain` for agent docs."
)]
pub struct Cli {
#[command(subcommand)]
pub command: Option<Command>,
#[arg(long, global = true)]
pub json: bool,
#[arg(long, global = true)]
pub quiet: bool,
#[arg(long, value_name = "SECS", global = true)]
pub timeout: Option<f64>,
#[command(flatten)]
pub heartbeat: HeartbeatOpts,
#[arg(long, value_enum, num_args = 0..=1, default_missing_value = "md")]
pub explain: Option<Format>,
}
#[derive(Subcommand, Debug)]
pub enum Command {
Hook(HookArgs),
Install(InstallArgs),
Uninstall(InstallArgs),
Check(CheckArgs),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
pub enum Mode {
Deny,
Ask,
Warn,
}
impl Mode {
pub fn to_lib(self) -> crate::steer::Mode {
match self {
Mode::Deny => crate::steer::Mode::Deny,
Mode::Ask => crate::steer::Mode::Ask,
Mode::Warn => crate::steer::Mode::Warn,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
pub enum Scope {
Project,
Local,
User,
}
impl Scope {
pub fn to_lib(self) -> crate::steer::install::Scope {
match self {
Scope::Project => crate::steer::install::Scope::Project,
Scope::Local => crate::steer::install::Scope::Local,
Scope::User => crate::steer::install::Scope::User,
}
}
}
#[derive(Args, Debug)]
pub struct HookArgs {
#[arg(long, value_enum, default_value_t = Mode::Deny)]
pub mode: Mode,
}
#[derive(Args, Debug)]
pub struct InstallArgs {
#[arg(long, value_enum, default_value_t = Scope::Project)]
pub scope: Scope,
#[arg(long, value_enum, default_value_t = Mode::Deny)]
pub mode: Mode,
#[arg(long)]
pub dry_run: bool,
#[arg(long)]
pub print: bool,
}
#[derive(Args, Debug)]
pub struct CheckArgs {
#[arg(value_name = "COMMAND", required = true)]
pub command: String,
#[arg(long, value_enum, default_value_t = Mode::Deny)]
pub mode: Mode,
}