main
rs 283 lines 7.13 KB
Raw
1 //! The `si` command tree.
2
3 use {clap::Parser, sigit_si_api::Environment, std::str::FromStr};
4
5 #[derive(Parser)]
6 #[command(name = "si", version, about = "The sigit.si command line interface.")]
7 pub struct Cli {
8 /// Which sigit.si deployment to talk to. Overridden by SIGIT_HOST.
9 #[arg(short, long, global = true, env = "SIGIT_ENVIRONMENT", default_value = "production", value_parser = Environment::from_str)]
10 pub environment: Environment,
11
12 /// Print machine-readable JSON instead of formatted text, where supported.
13 #[arg(long, global = true)]
14 pub json: bool,
15
16 #[command(subcommand)]
17 pub command: Command,
18 }
19
20 #[derive(clap::Subcommand)]
21 pub enum Command {
22 /// Sign in, sign out, and inspect your session.
23 #[command(subcommand)]
24 Auth(AuthCommand),
25
26 /// Your sigit.si profile.
27 Me,
28
29 /// List, create, and inspect repositories.
30 #[command(subcommand)]
31 Repo(RepoCommand),
32
33 /// List, open, and comment on pull requests.
34 #[command(subcommand)]
35 Pr(PrCommand),
36
37 /// List, open, and comment on issues.
38 #[command(subcommand)]
39 Issue(IssueCommand),
40
41 /// Read files and search code in a repository.
42 #[command(subcommand)]
43 Code(CodeCommand),
44
45 /// Manage a repository's deploy webhooks.
46 #[command(subcommand)]
47 Hook(HookCommand),
48
49 /// Manage siGit Code Cloud Sessions.
50 #[command(subcommand)]
51 Session(SessionCommand),
52
53 /// Plan, usage, and the hosted billing portal.
54 #[command(subcommand)]
55 Billing(BillingCommand),
56
57 /// Open something on sigit.si in your browser.
58 Browse(BrowseArgs),
59
60 /// Call the sigit.si API directly. The escape hatch for anything without
61 /// a dedicated command.
62 Api(ApiArgs),
63
64 /// Serve these commands to an AI agent as MCP tools over stdio.
65 Mcp(McpArgs),
66 }
67
68 #[derive(clap::Subcommand)]
69 pub enum AuthCommand {
70 /// Sign in with your sigit.si email and password.
71 Login {
72 #[arg(long)]
73 email: Option<String>,
74 },
75 /// Sign out and remove the stored token.
76 Logout,
77 /// Show who is currently signed in.
78 Status,
79 }
80
81 #[derive(clap::Subcommand)]
82 pub enum RepoCommand {
83 /// List your repositories.
84 List,
85 /// Search all repositories you can see.
86 Search {
87 /// Case-insensitive substring of the owner or repo name.
88 query: Option<String>,
89 #[arg(long, default_value_t = 30)]
90 limit: u32,
91 },
92 /// Show a repository's details.
93 View {
94 /// OWNER/NAME. Defaults to the repo in the current directory.
95 repo: Option<String>,
96 },
97 /// Create a new (empty) repository to push to.
98 Create {
99 name: String,
100 #[arg(long)]
101 private: bool,
102 #[arg(long)]
103 description: Option<String>,
104 /// Skip the confirmation prompt.
105 #[arg(short, long)]
106 yes: bool,
107 },
108 /// Open a repository in your browser.
109 Browse { repo: Option<String> },
110 }
111
112 #[derive(clap::Subcommand)]
113 pub enum PrCommand {
114 /// List pull requests in a repository.
115 List {
116 repo: Option<String>,
117 #[arg(long, default_value = "open")]
118 state: String,
119 },
120 /// Show a pull request's details, comments, and diff.
121 View { number: i64, repo: Option<String> },
122 /// Print a pull request's unified diff.
123 Diff { number: i64, repo: Option<String> },
124 /// Open a pull request from one branch into another.
125 Create {
126 #[arg(long)]
127 title: String,
128 #[arg(long)]
129 head: Option<String>,
130 #[arg(long, default_value = "main")]
131 base: String,
132 #[arg(long)]
133 body: Option<String>,
134 repo: Option<String>,
135 },
136 /// Comment on a pull request.
137 Comment {
138 number: i64,
139 #[arg(long)]
140 body: String,
141 repo: Option<String>,
142 },
143 }
144
145 #[derive(clap::Subcommand)]
146 pub enum IssueCommand {
147 /// List issues in a repository.
148 List {
149 repo: Option<String>,
150 #[arg(long, default_value = "open")]
151 state: String,
152 #[arg(long)]
153 query: Option<String>,
154 },
155 /// Show an issue's details and comments.
156 View { number: i64, repo: Option<String> },
157 /// Open a new issue.
158 Create {
159 #[arg(long)]
160 title: String,
161 #[arg(long)]
162 body: Option<String>,
163 repo: Option<String>,
164 },
165 /// Comment on an issue.
166 Comment {
167 number: i64,
168 #[arg(long)]
169 body: String,
170 repo: Option<String>,
171 },
172 }
173
174 #[derive(clap::Subcommand)]
175 pub enum CodeCommand {
176 /// Print a file's contents at a ref.
177 View {
178 path: String,
179 #[arg(long)]
180 r#ref: Option<String>,
181 repo: Option<String>,
182 },
183 /// Search a repository's tracked files for a fixed string.
184 Search {
185 query: String,
186 #[arg(long)]
187 r#ref: Option<String>,
188 #[arg(long, default_value_t = 20)]
189 limit: u32,
190 repo: Option<String>,
191 },
192 }
193
194 #[derive(clap::Subcommand)]
195 pub enum HookCommand {
196 /// List a repository's webhooks.
197 List { repo: Option<String> },
198 /// Register a new webhook. Prints the signing secret once — it cannot be
199 /// retrieved again.
200 Create {
201 #[arg(long)]
202 url: String,
203 #[arg(long, value_delimiter = ',', default_value = "push")]
204 events: Vec<String>,
205 repo: Option<String>,
206 },
207 /// Remove a webhook.
208 Delete {
209 id: i64,
210 repo: Option<String>,
211 #[arg(short, long)]
212 yes: bool,
213 },
214 }
215
216 #[derive(clap::Subcommand)]
217 pub enum SessionCommand {
218 /// List your Cloud Sessions.
219 List,
220 /// Show a session and its transcript.
221 View { id: i64 },
222 /// Start a new session.
223 New {
224 #[arg(long)]
225 title: Option<String>,
226 #[arg(long)]
227 model: Option<String>,
228 },
229 /// Rename a session or change its model.
230 Update {
231 id: i64,
232 #[arg(long)]
233 title: Option<String>,
234 #[arg(long)]
235 model: Option<String>,
236 },
237 /// Delete a session.
238 Delete {
239 id: i64,
240 #[arg(short, long)]
241 yes: bool,
242 },
243 }
244
245 #[derive(clap::Subcommand)]
246 pub enum BillingCommand {
247 /// Show your current plan and cloud usage.
248 Show,
249 /// Open the hosted checkout to subscribe or change plans.
250 Checkout { plan: String },
251 /// Open the hosted billing portal.
252 Portal,
253 }
254
255 #[derive(clap::Args)]
256 pub struct BrowseArgs {
257 /// What to open: a repo, "OWNER/NAME/pull/N", "OWNER/NAME/issue/N", or
258 /// left blank for the current repository.
259 pub target: Option<String>,
260 }
261
262 #[derive(clap::Args)]
263 pub struct McpArgs {
264 /// Drop every tool that writes, leaving only the ones that read.
265 #[arg(long)]
266 pub read_only: bool,
267
268 /// Expose only these tool groups, comma-separated. Defaults to all of
269 /// them: account, repo, issue, pr, code, hook, session, billing.
270 #[arg(long, value_delimiter = ',', env = "SIGIT_TOOLSETS")]
271 pub toolsets: Vec<String>,
272 }
273
274 #[derive(clap::Args)]
275 pub struct ApiArgs {
276 /// Path under /api/v1, e.g. "repos" or "billing".
277 pub path: String,
278 #[arg(short = 'X', long, default_value = "GET")]
279 pub method: String,
280 /// Raw JSON request body.
281 #[arg(long)]
282 pub body: Option<String>,
283 }