pleiades_agent_plugins/
registry.rs1use 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}