Skip to main content

systemprompt_cli/runner/args/
mod.rs

1//! Top-level clap argument definitions and the command tree.
2//!
3//! Defines the global option groups, the [`Cli`] parser, and the [`Commands`]
4//! subcommand tree, along with the mapping from each command to its bootstrap
5//! [`CommandDescriptor`] and the argument-reconstruction used when forwarding
6//! to a remote tenant.
7//!
8//! Copyright (c) systemprompt.io — Business Source License 1.1.
9//! See <https://systemprompt.io> for licensing details.
10
11use 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(
68        long,
69        global = true,
70        env = "SYSTEMPROMPT_DATABASE_URL",
71        hide_env_values = true,
72        help = "Direct database URL (bypasses profile)"
73    )]
74    pub database_url: Option<String>,
75}
76
77#[derive(Debug, clap::Args)]
78pub struct ProfileOpts {
79    #[arg(
80        long,
81        global = true,
82        help = "Profile name to use (overrides active session)"
83    )]
84    pub profile: Option<String>,
85}
86
87#[derive(Debug, Parser)]
88#[command(name = "systemprompt")]
89#[command(about = "Agent orchestration and AI operations.")]
90#[command(version = env!("CARGO_PKG_VERSION"))]
91#[command(
92    before_help = "\x1b[38;5;208m</\x1b[1;37mSYSTEMPROMPT\x1b[38;5;208m.\x1b[0;37mio\x1b[38;5;\
93                   208m>\x1b[0m"
94)]
95#[command(after_help = "\
96GETTING STARTED:
97  systemprompt core skills list                 List all skills
98
99GLOBAL OPTIONS (apply to all commands):
100  -v, --verbose         Increase verbosity
101  -q, --quiet           Suppress output
102      --debug           Debug logging
103      --json            JSON output
104      --yaml            YAML output
105      --no-color        Disable colors
106      --non-interactive Non-interactive mode
107      --database-url    Direct database URL (bypasses profile)
108      --profile         Profile name to use (overrides active session)")]
109pub struct Cli {
110    #[command(flatten)]
111    pub verbosity: VerbosityOpts,
112
113    #[command(flatten)]
114    pub output: OutputOpts,
115
116    #[command(flatten)]
117    pub display: DisplayOpts,
118
119    #[command(flatten)]
120    pub database: DatabaseOpts,
121
122    #[command(flatten)]
123    pub profile_opts: ProfileOpts,
124
125    #[command(subcommand)]
126    pub command: Option<Commands>,
127}
128
129#[derive(Debug, Subcommand)]
130pub enum Commands {
131    #[command(
132        subcommand,
133        about = "Core operations: skills, content, files, contexts"
134    )]
135    Core(core::CoreCommands),
136
137    #[command(
138        subcommand,
139        about = "Infrastructure management (services, db, jobs, logs, system)"
140    )]
141    Infra(infrastructure::InfraCommands),
142
143    #[command(
144        subcommand,
145        about = "Administration (users, agents, config, setup, session)"
146    )]
147    Admin(admin::AdminCommands),
148
149    #[command(subcommand, about = "Cloud deployment, backup, and setup")]
150    Cloud(cloud::CloudCommands),
151
152    #[command(subcommand, about = "Analytics and metrics reporting")]
153    Analytics(analytics::AnalyticsCommands),
154
155    #[command(subcommand, about = "Web service configuration management")]
156    Web(web::WebCommands),
157
158    #[command(subcommand, about = "Plugins, extensions, and MCP server management")]
159    Plugins(plugins::PluginsCommands),
160
161    #[command(subcommand, about = "Build MCP extensions")]
162    Build(build::BuildCommands),
163}
164
165impl DescribeCommand for Commands {
166    fn descriptor(&self) -> CommandDescriptor {
167        match self {
168            Self::Cloud(cmd) => cmd.descriptor(),
169            Self::Plugins(cmd) => cmd.descriptor(),
170            Self::Admin(admin::AdminCommands::Setup(_)) => CommandDescriptor::NONE,
171            Self::Admin(admin::AdminCommands::Session(cmd)) => cmd.descriptor(),
172            Self::Admin(admin::AdminCommands::Config(admin::config::ConfigCommands::Secret(_)))
173            | Self::Build(_) => CommandDescriptor::PROFILE_ONLY,
174            Self::Admin(admin::AdminCommands::Config(_))
175            | Self::Web(_)
176            | Self::Core(
177                core::CoreCommands::Hooks(_)
178                | core::CoreCommands::Plugins(_)
179                | core::CoreCommands::Skills(
180                    core::skills::SkillsCommands::List(_) | core::skills::SkillsCommands::Show(_),
181                ),
182            ) => CommandDescriptor::PROFILE_SECRETS_AND_PATHS,
183            Self::Infra(infrastructure::InfraCommands::Services(_)) => {
184                CommandDescriptor::PROFILE_SECRETS_AND_PATHS
185            },
186            Self::Infra(infrastructure::InfraCommands::Jobs(
187                infrastructure::jobs::JobsCommands::Run(_)
188                | infrastructure::jobs::JobsCommands::List,
189            )) => CommandDescriptor::FULL.with_skip_validation(),
190            // Why: reads. They may fall back to local data with a warning rather
191            // than refusing when a cloud profile cannot route remotely.
192            Self::Analytics(_) => CommandDescriptor::FULL
193                .with_skip_validation()
194                .with_read_only(),
195            Self::Infra(infrastructure::InfraCommands::Logs(_)) => {
196                CommandDescriptor::FULL.with_read_only()
197            },
198            _ => CommandDescriptor::FULL,
199        }
200    }
201}
202
203mod assemble;
204
205pub use assemble::{
206    build_cli_config, has_local_export_flag, has_local_export_flag_in, reconstruct_args,
207    reconstruct_args_from,
208};