Skip to main content

pleiades_agent_plugins/
registry.rs

1use std::collections::BTreeMap;
2
3use crate::hooks::HookRunner;
4use crate::manifest::{PluginError, PluginHooks};
5use crate::plugin::{Plugin, PluginDefinition, PluginKind, PluginMetadata, PluginTool};
6
7#[derive(Debug, Clone)]
8pub struct PluginEntry {
9    pub definition: PluginDefinition,
10    pub enabled: bool,
11}
12
13impl PluginEntry {
14    pub fn metadata(&self) -> &PluginMetadata {
15        self.definition.metadata()
16    }
17
18    pub fn hooks(&self) -> &PluginHooks {
19        self.definition.hooks()
20    }
21
22    pub fn tools(&self) -> &[PluginTool] {
23        self.definition.tools()
24    }
25}
26
27#[derive(Debug, Clone)]
28pub struct PluginRegistry {
29    plugins: Vec<PluginEntry>,
30}
31
32impl PluginRegistry {
33    pub fn new(plugins: Vec<PluginEntry>) -> Self {
34        Self { plugins }
35    }
36
37    pub fn plugins(&self) -> &[PluginEntry] {
38        &self.plugins
39    }
40
41    pub fn get(&self, plugin_id: &str) -> Option<&PluginEntry> {
42        self.plugins.iter().find(|p| p.metadata().id == plugin_id)
43    }
44
45    pub fn contains(&self, plugin_id: &str) -> bool {
46        self.get(plugin_id).is_some()
47    }
48
49    pub fn enabled_plugins(&self) -> impl Iterator<Item = &PluginEntry> {
50        self.plugins.iter().filter(|p| p.enabled)
51    }
52
53    pub fn aggregated_hooks(&self) -> PluginHooks {
54        self.enabled_plugins()
55            .map(|p| p.hooks())
56            .fold(PluginHooks::default(), |acc, hooks| acc.merged_with(hooks))
57    }
58
59    pub fn hook_runner(&self) -> HookRunner {
60        HookRunner::new(self.aggregated_hooks())
61    }
62
63    pub fn aggregated_tools(&self) -> Result<Vec<PluginTool>, PluginError> {
64        let mut tools = Vec::new();
65        let mut seen_names = BTreeMap::new();
66        for entry in self.enabled_plugins() {
67            for tool in entry.tools() {
68                if let Some(existing) = seen_names.insert(tool.name.clone(), tool.plugin_id.clone())
69                {
70                    return Err(PluginError::CommandFailed(format!(
71                        "tool `{}` is defined by both `{}` and `{}`",
72                        tool.name, existing, tool.plugin_id
73                    )));
74                }
75                tools.push(tool.clone());
76            }
77        }
78        Ok(tools)
79    }
80
81    pub fn summaries(&self) -> Vec<PluginSummary> {
82        self.plugins
83            .iter()
84            .map(|p| PluginSummary {
85                id: p.metadata().id.clone(),
86                name: p.metadata().name.clone(),
87                version: p.metadata().version.clone(),
88                description: p.metadata().description.clone(),
89                kind: p.metadata().kind,
90                enabled: p.enabled,
91                tool_count: p.tools().len(),
92                has_hooks: !p.hooks().is_empty(),
93            })
94            .collect()
95    }
96}
97
98impl Default for PluginRegistry {
99    fn default() -> Self {
100        Self::new(Vec::new())
101    }
102}
103
104#[derive(Debug, Clone)]
105pub struct PluginSummary {
106    pub id: String,
107    pub name: String,
108    pub version: String,
109    pub description: String,
110    pub kind: PluginKind,
111    pub enabled: bool,
112    pub tool_count: usize,
113    pub has_hooks: bool,
114}