systemprompt_cli/runner/args/
mod.rs1use clap::{Parser, Subcommand};
12
13use crate::commands::{admin, analytics, build, cloud, core, infrastructure, plugins, web};
14use crate::descriptor::{CommandDescriptor, DescribeCommand};
15
16#[derive(Debug, Clone, Copy, clap::Args)]
17pub struct VerbosityOpts {
18 #[arg(
19 long,
20 short = 'v',
21 global = true,
22 hide = true,
23 help = "Increase verbosity"
24 )]
25 pub verbose: bool,
26
27 #[arg(
28 long,
29 short = 'q',
30 global = true,
31 hide = true,
32 conflicts_with = "verbose",
33 help = "Suppress output"
34 )]
35 pub quiet: bool,
36
37 #[arg(long, global = true, hide = true, help = "Debug logging")]
38 pub debug: bool,
39}
40
41#[derive(Debug, Clone, Copy, clap::Args)]
42pub struct OutputOpts {
43 #[arg(long, global = true, hide = true, help = "JSON output")]
44 pub json: bool,
45
46 #[arg(
47 long,
48 global = true,
49 hide = true,
50 conflicts_with = "json",
51 help = "YAML output"
52 )]
53 pub yaml: bool,
54}
55
56#[derive(Debug, Clone, Copy, clap::Args)]
57pub struct DisplayOpts {
58 #[arg(long, global = true, hide = true, help = "Disable colors")]
59 pub no_color: bool,
60
61 #[arg(long, global = true, hide = true, help = "Non-interactive mode")]
62 pub non_interactive: bool,
63}
64
65#[derive(Debug, clap::Args)]
66pub struct DatabaseOpts {
67 #[arg(long, global = true, help = "Direct database URL (bypasses profile)")]
68 pub database_url: Option<String>,
69}
70
71#[derive(Debug, clap::Args)]
72pub struct ProfileOpts {
73 #[arg(
74 long,
75 global = true,
76 help = "Profile name to use (overrides active session)"
77 )]
78 pub profile: Option<String>,
79}
80
81#[derive(Debug, Parser)]
82#[command(name = "systemprompt")]
83#[command(about = "Agent orchestration and AI operations.")]
84#[command(version = env!("CARGO_PKG_VERSION"))]
85#[command(
86 before_help = "\x1b[38;5;208m</\x1b[1;37mSYSTEMPROMPT\x1b[38;5;208m.\x1b[0;37mio\x1b[38;5;\
87 208m>\x1b[0m"
88)]
89#[command(after_help = "\
90GETTING STARTED:
91 systemprompt core skills list List all skills
92
93GLOBAL OPTIONS (apply to all commands):
94 -v, --verbose Increase verbosity
95 -q, --quiet Suppress output
96 --debug Debug logging
97 --json JSON output
98 --yaml YAML output
99 --no-color Disable colors
100 --non-interactive Non-interactive mode
101 --database-url Direct database URL (bypasses profile)
102 --profile Profile name to use (overrides active session)")]
103pub struct Cli {
104 #[command(flatten)]
105 pub verbosity: VerbosityOpts,
106
107 #[command(flatten)]
108 pub output: OutputOpts,
109
110 #[command(flatten)]
111 pub display: DisplayOpts,
112
113 #[command(flatten)]
114 pub database: DatabaseOpts,
115
116 #[command(flatten)]
117 pub profile_opts: ProfileOpts,
118
119 #[command(subcommand)]
120 pub command: Option<Commands>,
121}
122
123#[derive(Debug, Subcommand)]
124pub enum Commands {
125 #[command(
126 subcommand,
127 about = "Core operations: skills, content, files, contexts"
128 )]
129 Core(core::CoreCommands),
130
131 #[command(
132 subcommand,
133 about = "Infrastructure management (services, db, jobs, logs, system)"
134 )]
135 Infra(infrastructure::InfraCommands),
136
137 #[command(
138 subcommand,
139 about = "Administration (users, agents, config, setup, session)"
140 )]
141 Admin(admin::AdminCommands),
142
143 #[command(subcommand, about = "Cloud deployment, backup, and setup")]
144 Cloud(cloud::CloudCommands),
145
146 #[command(subcommand, about = "Analytics and metrics reporting")]
147 Analytics(analytics::AnalyticsCommands),
148
149 #[command(subcommand, about = "Web service configuration management")]
150 Web(web::WebCommands),
151
152 #[command(subcommand, about = "Plugins, extensions, and MCP server management")]
153 Plugins(plugins::PluginsCommands),
154
155 #[command(subcommand, about = "Build MCP extensions")]
156 Build(build::BuildCommands),
157}
158
159impl DescribeCommand for Commands {
160 fn descriptor(&self) -> CommandDescriptor {
161 self.bootstrap_descriptor()
162 .with_data_impact(self.data_impact())
163 }
164}
165
166impl Commands {
167 #[must_use]
168 pub const fn serves_api(&self) -> bool {
169 match self {
170 Self::Infra(infrastructure::InfraCommands::Services(cmd)) => cmd.serves_api(),
171 _ => false,
172 }
173 }
174
175 fn bootstrap_descriptor(&self) -> CommandDescriptor {
176 match self {
177 Self::Cloud(cmd) => cmd.descriptor(),
178 Self::Plugins(cmd) => cmd.descriptor(),
179 Self::Admin(admin::AdminCommands::Session(cmd)) => cmd.descriptor(),
180 Self::Admin(admin::AdminCommands::Config(admin::config::ConfigCommands::Secret(_)))
181 | Self::Build(_) => CommandDescriptor::PROFILE_ONLY,
182 Self::Admin(admin::AdminCommands::Setup(_))
183 | Self::Core(
184 core::CoreCommands::Marketplace(core::marketplace::MarketplaceCommands::Import(_))
185 | core::CoreCommands::Services(
186 core::services::ServicesCommands::Validate(_)
187 | core::services::ServicesCommands::Bundle(_)
188 | core::services::ServicesCommands::Keygen(_),
189 ),
190 ) => CommandDescriptor::NONE,
191 Self::Core(core::CoreCommands::Services(
192 core::services::ServicesCommands::Publish(args),
193 )) => {
194 if args.auth_secret.is_some() {
195 CommandDescriptor::PROFILE_AND_SECRETS
196 } else {
197 CommandDescriptor::NONE
198 }
199 },
200 Self::Core(core::CoreCommands::Services(
201 core::services::ServicesCommands::Inspect(args),
202 )) => {
203 if args.active {
204 CommandDescriptor::PROFILE_SECRETS_AND_PATHS
205 } else {
206 CommandDescriptor::NONE
207 }
208 },
209 Self::Admin(admin::AdminCommands::Config(_))
210 | Self::Web(_)
211 | Self::Core(
212 core::CoreCommands::Hooks(_)
213 | core::CoreCommands::Plugins(_)
214 | core::CoreCommands::Skills(
215 core::skills::SkillsCommands::List(_) | core::skills::SkillsCommands::Show(_),
216 ),
217 ) => CommandDescriptor::PROFILE_SECRETS_AND_PATHS,
218 Self::Infra(cmd) => infra_descriptor(cmd),
219 Self::Analytics(_) => CommandDescriptor::FULL
220 .with_skip_validation()
221 .with_read_only(),
222 _ => CommandDescriptor::FULL,
223 }
224 }
225}
226
227const fn infra_descriptor(cmd: &infrastructure::InfraCommands) -> CommandDescriptor {
232 use infrastructure::InfraCommands;
233 use infrastructure::jobs::JobsCommands;
234 use infrastructure::logs::LogsCommands;
235 use infrastructure::services::ServicesCommands;
236
237 match cmd {
238 InfraCommands::Services(
239 ServicesCommands::Serve { .. } | ServicesCommands::Start { .. },
240 ) => CommandDescriptor::PROFILE_SECRETS_AND_PATHS.with_model_discovery(),
241 InfraCommands::Services(_) => CommandDescriptor::PROFILE_SECRETS_AND_PATHS,
242 InfraCommands::Jobs(JobsCommands::Run(_) | JobsCommands::List) => {
243 CommandDescriptor::FULL.with_skip_validation()
244 },
245 InfraCommands::Logs(LogsCommands::Delete(_) | LogsCommands::Cleanup(_)) => {
246 CommandDescriptor::FULL
247 },
248 InfraCommands::Logs(_) => CommandDescriptor::FULL.with_read_only(),
249 _ => CommandDescriptor::FULL,
250 }
251}
252
253mod assemble;
254mod impact;
255
256pub use assemble::{
257 build_cli_config, has_local_export_flag, has_local_export_flag_in, reconstruct_args,
258 reconstruct_args_from,
259};