Skip to main content

systemprompt_cli/commands/plugins/
mod.rs

1//! `plugins` command group: discover and inspect compiled extensions.
2//!
3//! Covers listing and showing extensions, running CLI extension commands,
4//! validating dependencies and configuration, dumping config, summarising
5//! [`PluginsCommands::Capabilities`], and the [`mcp`] server-management
6//! subtree. [`types`] holds the shared serialisable output shapes.
7//!
8//! Copyright (c) systemprompt.io — Business Source License 1.1.
9//! See <https://systemprompt.io> for licensing details.
10
11pub mod types;
12
13pub mod capabilities;
14pub mod config;
15pub mod list;
16mod run;
17pub mod show;
18pub mod validate;
19
20pub mod mcp;
21
22use anyhow::{Context, Result, bail};
23use clap::Subcommand;
24use systemprompt_extension::ExtensionRegistry;
25
26use crate::context::CommandContext;
27use crate::descriptor::{CommandDescriptor, DescribeCommand};
28use crate::shared::render_result;
29
30fn discover_registry() -> ExtensionRegistry {
31    ExtensionRegistry::discover().unwrap_or_else(|e| {
32        tracing::error!(error = %e, "extension dependency cycle; using empty registry");
33        ExtensionRegistry::new()
34    })
35}
36
37#[derive(Debug, Subcommand)]
38pub enum PluginsCommands {
39    #[command(about = "List all discovered extensions")]
40    List(list::ListArgs),
41
42    #[command(about = "Show detailed extension information")]
43    Show(show::ShowArgs),
44
45    #[command(about = "Run a CLI extension command", trailing_var_arg = true)]
46    Run(run::RunArgs),
47
48    #[command(about = "Validate extension dependencies and configurations")]
49    Validate(validate::ValidateArgs),
50
51    #[command(about = "Show extension configuration")]
52    Config(config::ConfigArgs),
53
54    #[command(about = "List capabilities across all extensions")]
55    Capabilities(capabilities::CapabilitiesArgs),
56
57    #[command(subcommand, about = "MCP server management")]
58    Mcp(mcp::McpCommands),
59}
60
61impl DescribeCommand for PluginsCommands {
62    fn descriptor(&self) -> CommandDescriptor {
63        match self {
64            Self::Run(_) => CommandDescriptor::PROFILE_ONLY,
65            Self::Mcp(_) => CommandDescriptor::FULL,
66            _ => CommandDescriptor::PROFILE_ONLY.with_remote_eligible(),
67        }
68    }
69}
70
71pub async fn execute(cmd: PluginsCommands, ctx: &CommandContext) -> Result<()> {
72    match cmd {
73        PluginsCommands::List(args) => {
74            render_result(&list::execute(&args, &ctx.cli), &ctx.cli);
75            Ok(())
76        },
77        PluginsCommands::Show(args) => {
78            let result = show::execute(&args, &ctx.cli).context("Failed to show extension")?;
79            render_result(&result, &ctx.cli);
80            Ok(())
81        },
82        PluginsCommands::Run(args) => run::execute(args, ctx).await,
83        PluginsCommands::Validate(args) => {
84            let (output, valid) = validate::execute(&args, &ctx.cli);
85            render_result(&output, &ctx.cli);
86            if !valid {
87                bail!("Extension validation failed");
88            }
89            Ok(())
90        },
91        PluginsCommands::Config(args) => {
92            let result =
93                config::execute(&args, &ctx.cli).context("Failed to get extension config")?;
94            render_result(&result, &ctx.cli);
95            Ok(())
96        },
97        PluginsCommands::Capabilities(args) => {
98            capabilities::execute(args, &ctx.cli);
99            Ok(())
100        },
101        PluginsCommands::Mcp(cmd) => mcp::execute(cmd, ctx).await,
102    }
103}