use clap::{Parser, Subcommand};
use std::ffi::OsString;
#[derive(Parser, Debug, Clone, PartialEq, Eq)]
#[command(
name = "git-claw",
bin_name = "git-claw",
version,
about = "Deterministic git worktree orchestration engine for developers and AI agents"
)]
pub struct Cli {
#[command(subcommand)]
pub command: Option<Commands>,
}
#[derive(Subcommand, Debug, Clone, PartialEq, Eq)]
pub enum Commands {
Feature {
#[command(subcommand)]
action: WorktreeAction,
},
Bugfix {
#[command(subcommand)]
action: WorktreeAction,
},
Hotfix {
#[command(subcommand)]
action: WorktreeAction,
},
Spike {
#[command(subcommand)]
action: SpikeAction,
},
Finish {
name: Option<String>,
#[arg(long)]
force: bool,
#[arg(long, short = 'k')]
keep_remote: bool,
},
Publish {
name: Option<String>,
#[arg(long)]
remote: Option<String>,
},
List,
Run {
name: Option<String>,
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
command: Vec<String>,
},
Open {
name: Option<String>,
},
Cd {
name: Option<String>,
},
Tag {
version: Option<String>,
},
Init {
#[arg(long, short = 'y')]
yes: bool,
},
#[command(name = "shell-hook")]
ShellHook {
#[arg(default_value = "bash")]
shell: String,
},
#[command(alias = "completions")]
Completion {
#[arg(value_enum)]
shell: clap_complete::Shell,
},
}
#[derive(Subcommand, Debug, Clone, PartialEq, Eq)]
pub enum WorktreeAction {
Start {
name: String,
#[arg(long)]
isolated: bool,
},
Publish {
name: Option<String>,
#[arg(long)]
remote: Option<String>,
},
}
#[derive(Subcommand, Debug, Clone, PartialEq, Eq)]
pub enum SpikeAction {
Start {
name: String,
#[arg(long)]
isolated: bool,
},
Drop {
name: String,
},
}
pub fn sanitize_args<I, T>(args: I) -> Vec<T>
where
I: IntoIterator<Item = T>,
T: AsRef<std::ffi::OsStr> + Clone,
{
let mut vec: Vec<T> = args.into_iter().collect();
if vec.len() > 1 && vec[1].as_ref() == "claw" {
vec.remove(1);
}
vec
}
impl Cli {
pub fn parse_from_env() -> Self {
let args = sanitize_args(std::env::args_os());
Self::parse_from(args)
}
#[allow(dead_code)]
pub fn try_parse_from_args<I, T>(args: I) -> Result<Self, clap::Error>
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
let raw: Vec<OsString> = args.into_iter().map(Into::into).collect();
let sanitized = sanitize_args(raw);
Self::try_parse_from(sanitized)
}
}