Skip to main content

systemprompt_cli/commands/admin/
mod.rs

1//! `admin` command tree: privileged platform administration.
2//!
3//! [`AdminCommands`] groups user, agent, configuration, session, bridge,
4//! access-control, and signing-key management plus the setup and bootstrap
5//! flows. On a `--database-url` invocation only the user-management subgroup
6//! is served; the rest require a full profile context.
7
8pub mod access_control;
9pub mod agents;
10pub mod bootstrap;
11pub mod bridge;
12pub mod config;
13pub mod keys;
14pub mod session;
15pub mod setup;
16pub mod users;
17
18use anyhow::{Result, bail};
19use clap::Subcommand;
20
21use crate::context::CommandContext;
22use crate::shared::render_result;
23
24#[derive(Debug, Subcommand)]
25pub enum AdminCommands {
26    #[command(subcommand, about = "User management and IP banning")]
27    Users(users::UsersCommands),
28
29    #[command(subcommand, about = "Agent management")]
30    Agents(agents::AgentsCommands),
31
32    #[command(subcommand, about = "Configuration management and rate limits")]
33    Config(config::ConfigCommands),
34
35    #[command(about = "Interactive setup wizard for local development environment")]
36    Setup(setup::SetupArgs),
37
38    #[command(
39        about = "Idempotently ensure the platform admin user exists with the admin role. Required \
40                 by every install recipe before services start."
41    )]
42    Bootstrap(bootstrap::BootstrapArgs),
43
44    #[command(subcommand, about = "Manage CLI session and profile switching")]
45    Session(session::SessionCommands),
46
47    #[command(
48        subcommand,
49        about = "Bridge helper enrollment (device certs, exchange codes)"
50    )]
51    Bridge(bridge::BridgeCommands),
52
53    #[command(
54        subcommand,
55        name = "access-control",
56        about = "Access-control baseline operations (DB → YAML export)"
57    )]
58    AccessControl(access_control::AccessControlCommands),
59
60    #[command(
61        subcommand,
62        about = "RSA signing-key generation for the federated JWT plane"
63    )]
64    Keys(keys::KeysCommands),
65}
66
67pub async fn execute(cmd: AdminCommands, ctx: &CommandContext) -> Result<()> {
68    if ctx.is_database_scoped() && !matches!(cmd, AdminCommands::Users(_)) {
69        bail!("This command requires full profile context");
70    }
71
72    match cmd {
73        AdminCommands::Users(cmd) => users::execute(cmd, ctx).await,
74        AdminCommands::Agents(cmd) => agents::execute(cmd, ctx).await,
75        AdminCommands::Config(cmd) => config::execute(cmd, ctx).await,
76        AdminCommands::Setup(args) => {
77            let result = setup::execute(args, ctx).await?;
78            render_result(&result, &ctx.cli);
79            Ok(())
80        },
81        AdminCommands::Bootstrap(args) => {
82            let result = bootstrap::execute(args, &ctx.cli).await?;
83            render_result(&result, &ctx.cli);
84            Ok(())
85        },
86        AdminCommands::Session(cmd) => session::execute(cmd, ctx).await,
87        AdminCommands::Bridge(cmd) => bridge::execute(cmd, ctx).await,
88        AdminCommands::AccessControl(cmd) => access_control::execute(cmd, ctx).await,
89        AdminCommands::Keys(cmd) => keys::execute(cmd, ctx).await,
90    }
91}