1use clap::{Parser, Subcommand};
2use std::path::PathBuf;
3
4#[derive(Parser, Debug)]
5#[command(
6 author,
7 version,
8 about = "Aperture: Dynamic CLI generator for OpenAPI specifications",
9 long_about = "Aperture dynamically generates commands from OpenAPI 3.x specifications.\n\
10 It serves as a bridge between autonomous AI agents and APIs by consuming\n\
11 OpenAPI specs and creating a rich command-line interface with built-in\n\
12 security, caching, and agent-friendly features.\n\n\
13 Examples:\n \
14 aperture config add myapi api-spec.yaml\n \
15 aperture api myapi users get-user --id 123\n \
16 aperture config list\n\n\
17 Agent-friendly features:\n \
18 aperture api myapi --describe-json # Get capability manifest\n \
19 aperture --json-errors api myapi ... # Structured error output\n \
20 aperture api myapi --dry-run ... # Show request without executing"
21)]
22pub struct Cli {
23 #[arg(long, global = true, help = "Output capability manifest as JSON")]
25 pub describe_json: bool,
26
27 #[arg(long, global = true, help = "Output errors in JSON format")]
29 pub json_errors: bool,
30
31 #[arg(long, global = true, help = "Show request details without executing")]
33 pub dry_run: bool,
34
35 #[arg(
37 long,
38 global = true,
39 value_name = "KEY",
40 help = "Set idempotency key header"
41 )]
42 pub idempotency_key: Option<String>,
43
44 #[command(subcommand)]
45 pub command: Commands,
46}
47
48#[derive(Subcommand, Debug)]
49pub enum Commands {
50 #[command(long_about = "Manage your collection of OpenAPI specifications.\n\n\
52 Add specifications to make their operations available as commands,\n\
53 list currently registered specs, remove unused ones, or edit\n\
54 existing specifications in your default editor.")]
55 Config {
56 #[command(subcommand)]
57 command: ConfigCommands,
58 },
59 #[command(
61 long_about = "Execute operations from a registered API specification.\n\n\
62 The context refers to the name you gave when adding the spec.\n\
63 Commands are dynamically generated based on the OpenAPI specification,\n\
64 organized by tags (e.g., 'users', 'posts', 'orders').\n\n\
65 Examples:\n \
66 aperture api myapi users get-user --id 123\n \
67 aperture api myapi posts create-post --body '{\"title\":\"Hello\"}'\n \
68 aperture api myapi --help # See available operations"
69 )]
70 Api {
71 context: String,
73 #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
75 args: Vec<String>,
76 },
77}
78
79#[derive(Subcommand, Debug)]
80pub enum ConfigCommands {
81 #[command(
83 long_about = "Add an OpenAPI 3.x specification to your configuration.\n\n\
84 This validates the specification, extracts operations, and creates\n\
85 a cached representation for fast command generation. The spec name\n\
86 becomes the context for executing API operations.\n\n\
87 Supported formats: YAML (.yaml, .yml)\n\
88 Supported auth: API Key, Bearer Token\n\n\
89 Example:\n \
90 aperture config add myapi ./openapi.yaml"
91 )]
92 Add {
93 name: String,
95 file: PathBuf,
97 #[arg(long, help = "Replace the specification if it already exists")]
99 force: bool,
100 },
101 #[command(
103 long_about = "Display all currently registered API specifications.\n\n\
104 Shows the names you can use as contexts with 'aperture api'.\n\
105 Use this to see what APIs are available for command generation."
106 )]
107 List {},
108 #[command(
110 long_about = "Remove a registered API specification and its cached data.\n\n\
111 This removes both the original specification file and the\n\
112 generated cache, making the API operations unavailable.\n\
113 Use 'aperture config list' to see available specifications."
114 )]
115 Remove {
116 name: String,
118 },
119 #[command(
121 long_about = "Open an API specification in your default text editor.\n\n\
122 Uses the $EDITOR environment variable to determine which editor\n\
123 to use. After editing, you may need to re-add the specification\n\
124 to update the cached representation.\n\n\
125 Example:\n \
126 export EDITOR=vim\n \
127 aperture config edit myapi"
128 )]
129 Edit {
130 name: String,
132 },
133 #[command(long_about = "Set the base URL for an API specification.\n\n\
135 This overrides the base URL from the OpenAPI spec and the\n\
136 APERTURE_BASE_URL environment variable. You can set a general\n\
137 override or environment-specific URLs.\n\n\
138 Examples:\n \
139 aperture config set-url myapi https://api.example.com\n \
140 aperture config set-url myapi --env staging https://staging.example.com\n \
141 aperture config set-url myapi --env prod https://prod.example.com")]
142 SetUrl {
143 name: String,
145 url: String,
147 #[arg(long, value_name = "ENV", help = "Set URL for specific environment")]
149 env: Option<String>,
150 },
151 #[command(
153 long_about = "Display the base URL configuration for an API specification.\n\n\
154 Shows the configured base URL override and any environment-specific\n\
155 URLs. Also displays what URL would be used based on current\n\
156 environment settings.\n\n\
157 Example:\n \
158 aperture config get-url myapi"
159 )]
160 GetUrl {
161 name: String,
163 },
164 #[command(
166 long_about = "Display all configured base URLs across all API specifications.\n\n\
167 Shows general overrides and environment-specific configurations\n\
168 for each registered API. Useful for reviewing your URL settings\n\
169 at a glance."
170 )]
171 ListUrls {},
172}