1use std::path::PathBuf;
2
3use clap::{Args, Parser, Subcommand, ValueEnum};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Parser)]
7#[command(name = "git-hunk")]
8#[command(about = "Non-interactive hunk staging for AI agents")]
9pub struct Cli {
10 #[command(subcommand)]
11 pub command: Command,
12}
13
14impl Cli {
15 pub fn json(&self) -> bool {
16 match &self.command {
17 Command::Scan(args) => args.json,
18 Command::Show(args) => args.json,
19 Command::Resolve(args) => args.json,
20 Command::Stage(args) => args.json,
21 Command::Unstage(args) => args.json,
22 Command::Commit(args) => args.json,
23 }
24 }
25}
26
27#[derive(Debug, Subcommand)]
28pub enum Command {
29 Scan(ScanArgs),
30 Show(ShowArgs),
31 Resolve(ResolveArgs),
32 Stage(MutateArgs),
33 Unstage(MutateArgs),
34 Commit(CommitArgs),
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ValueEnum)]
38#[serde(rename_all = "snake_case")]
39pub enum Mode {
40 Stage,
41 Unstage,
42}
43
44impl Mode {
45 pub fn as_str(self) -> &'static str {
46 match self {
47 Mode::Stage => "stage",
48 Mode::Unstage => "unstage",
49 }
50 }
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ValueEnum)]
54#[serde(rename_all = "snake_case")]
55pub enum ResolveSide {
56 Auto,
57 Old,
58 New,
59}
60
61impl ResolveSide {
62 pub fn as_str(self) -> &'static str {
63 match self {
64 ResolveSide::Auto => "auto",
65 ResolveSide::Old => "old",
66 ResolveSide::New => "new",
67 }
68 }
69}
70
71#[derive(Debug, Args)]
72pub struct ScanArgs {
73 #[arg(long, value_enum)]
74 pub mode: Mode,
75 #[arg(long)]
76 pub compact: bool,
77 #[arg(long)]
78 pub json: bool,
79}
80
81#[derive(Debug, Args)]
82pub struct ShowArgs {
83 #[arg(long, value_enum)]
84 pub mode: Mode,
85 pub id: String,
86 #[arg(long)]
87 pub json: bool,
88}
89
90#[derive(Debug, Args)]
91pub struct ResolveArgs {
92 #[arg(long, value_enum)]
93 pub mode: Mode,
94 #[arg(long)]
95 pub snapshot: String,
96 #[arg(long)]
97 pub path: String,
98 #[arg(long)]
99 pub start: u32,
100 #[arg(long)]
101 pub end: Option<u32>,
102 #[arg(long, value_enum, default_value = "auto")]
103 pub side: ResolveSide,
104 #[arg(long)]
105 pub json: bool,
106}
107
108#[derive(Debug, Args)]
109pub struct MutateArgs {
110 #[arg(long)]
111 pub snapshot: Option<String>,
112 #[arg(long)]
113 pub plan: Option<PathBuf>,
114 #[arg(long = "hunk")]
115 pub hunks: Vec<String>,
116 #[arg(long = "change")]
117 pub changes: Vec<String>,
118 #[arg(long = "change-key")]
119 pub change_keys: Vec<String>,
120 #[arg(long)]
121 pub compact: bool,
122 #[arg(long)]
123 pub json: bool,
124}
125
126#[derive(Debug, Args)]
127pub struct CommitArgs {
128 #[arg(short = 'm', long = "message", required = true)]
129 pub messages: Vec<String>,
130 #[arg(long)]
131 pub snapshot: Option<String>,
132 #[arg(long)]
133 pub plan: Option<PathBuf>,
134 #[arg(long = "hunk")]
135 pub hunks: Vec<String>,
136 #[arg(long = "change")]
137 pub changes: Vec<String>,
138 #[arg(long = "change-key")]
139 pub change_keys: Vec<String>,
140 #[arg(long)]
141 pub allow_empty: bool,
142 #[arg(long)]
143 pub dry_run: bool,
144 #[arg(long)]
145 pub compact: bool,
146 #[arg(long)]
147 pub json: bool,
148}