systemprompt_cli/commands/core/plugins/
show.rs1use anyhow::{Context, Result, anyhow};
7use clap::Args;
8use std::path::Path;
9
10use crate::CliConfig;
11use crate::shared::CommandOutput;
12
13use super::types::{PluginComponentRef, PluginDetailOutput};
14use systemprompt_identifiers::PluginId;
15use systemprompt_loader::ServicesRootBootstrap;
16
17#[derive(Debug, Clone, Args)]
18pub struct ShowArgs {
19 #[arg(help = "Plugin ID (directory name)", value_parser = crate::shared::parse_plugin_id)]
20 pub id: PluginId,
21}
22
23pub(super) fn execute(args: &ShowArgs, _config: &CliConfig) -> Result<CommandOutput> {
24 let plugins_path = get_plugins_path()?;
25 execute_with_path(args, &plugins_path)
26}
27
28pub fn execute_with_path(args: &ShowArgs, plugins_path: &Path) -> Result<CommandOutput> {
29 let plugin_dir = plugins_path.join(args.id.as_str());
30
31 if !plugin_dir.exists() {
32 return Err(anyhow!("Plugin '{}' not found", args.id));
33 }
34
35 let config_path = plugin_dir.join("config.yaml");
36 if !config_path.exists() {
37 return Err(anyhow!("Plugin '{}' has no config.yaml file", args.id));
38 }
39
40 let plugin_file = parse_plugin_config(&config_path)?;
41 let plugin = &plugin_file.plugin;
42
43 let output = PluginDetailOutput {
44 id: PluginId::new(plugin.id.clone()),
45 name: plugin.name.clone(),
46 description: plugin.description.clone(),
47 version: plugin.version.clone(),
48 enabled: plugin.enabled,
49 skills: PluginComponentRef {
50 source: plugin.skills.source,
51 filter: plugin.skills.filter,
52 include: plugin.skills.include.clone(),
53 exclude: plugin.skills.exclude.clone(),
54 },
55 agents: PluginComponentRef {
56 source: plugin.agents.source,
57 filter: plugin.agents.filter,
58 include: plugin.agents.include.clone(),
59 exclude: plugin.agents.exclude.clone(),
60 },
61 mcp_servers: plugin.mcp_servers.clone(),
62 scripts: plugin.scripts.iter().map(|s| s.name.clone()).collect(),
63 keywords: plugin.keywords.clone(),
64 category: plugin.category.clone(),
65 author: plugin.author.name.clone(),
66 };
67
68 Ok(CommandOutput::card_value(
69 format!("Plugin: {}", args.id),
70 &output,
71 ))
72}
73
74fn get_plugins_path() -> Result<std::path::PathBuf> {
75 let profile = systemprompt_config::ProfileBootstrap::get().context("Failed to get profile")?;
76 Ok(ServicesRootBootstrap::active_path_or(
77 &profile.paths.services,
78 "plugins",
79 ))
80}
81
82fn parse_plugin_config(config_path: &Path) -> Result<systemprompt_manifest::PluginConfigFile> {
83 let content = std::fs::read_to_string(config_path)
84 .with_context(|| format!("Failed to read {}", config_path.display()))?;
85 let plugin_file: systemprompt_manifest::PluginConfigFile = serde_yaml::from_str(&content)
86 .with_context(|| format!("Failed to parse {}", config_path.display()))?;
87 Ok(plugin_file)
88}