1pub mod api;
23pub mod commands;
24pub mod config;
25pub mod context;
26pub mod engine;
27pub mod error;
28pub mod hooks;
29pub mod loader;
30
31pub use commands::CustomCommand;
33pub use config::{HookConfig, PluginConfig};
34pub use context::{BuildContext, PluginContext, TestContext};
35pub use engine::{PluginSystem, SteelEngine};
36pub use error::{PluginError, Result};
37pub use hooks::{HookEvent, HookResult};
38pub use loader::{DiscoveredPlugin, PluginPaths, discover_plugins, find_plugin};
39
40use std::path::Path;
41
42pub struct PluginManager {
44 engine: SteelEngine,
45 initialized: bool,
46}
47
48impl PluginManager {
49 pub fn new(config: PluginConfig) -> Result<Self> {
51 Ok(PluginManager {
52 engine: SteelEngine::new(config),
53 initialized: false,
54 })
55 }
56
57 pub fn with_defaults() -> Result<Self> {
59 Self::new(PluginConfig::new())
60 }
61
62 pub fn initialize(&mut self) -> Result<()> {
66 if self.initialized {
67 return Ok(());
68 }
69
70 self.engine.initialize()?;
71 self.initialized = true;
72 Ok(())
73 }
74
75 pub fn load_all(&mut self, project_root: &Path) -> Result<()> {
77 self.ensure_initialized()?;
78
79 let plugins = discover_plugins(self.engine.config(), project_root)?;
80
81 for plugin in plugins {
82 if let Err(e) = self.engine.load_plugin(&plugin.path) {
83 tracing::warn!("Failed to load plugin {}: {}", plugin.name, e);
85 }
86 }
87
88 Ok(())
89 }
90
91 pub fn load_plugin(&mut self, path: &Path) -> Result<()> {
93 self.ensure_initialized()?;
94 self.engine.load_plugin(path)
95 }
96
97 pub fn run_hook(&mut self, event: HookEvent, ctx: &PluginContext) -> Result<HookResult> {
99 self.ensure_initialized()?;
100 self.engine.run_hook(event, ctx)
101 }
102
103 pub fn run_command(&mut self, name: &str, args: &[String]) -> Result<i32> {
105 self.ensure_initialized()?;
106 self.engine.run_command(name, args)
107 }
108
109 pub fn commands(&self) -> &std::collections::HashMap<String, CustomCommand> {
111 self.engine.commands()
112 }
113
114 pub fn config(&self) -> &PluginConfig {
116 self.engine.config()
117 }
118
119 pub fn has_command(&self, name: &str) -> bool {
121 self.engine.commands().contains_key(name)
122 }
123
124 fn ensure_initialized(&mut self) -> Result<()> {
126 if !self.initialized {
127 self.initialize()?;
128 }
129 Ok(())
130 }
131}
132
133pub fn plugins_enabled(config: &PluginConfig) -> bool {
135 config.enabled
136}
137
138pub fn test_context(project_root: impl Into<std::path::PathBuf>, name: &str) -> PluginContext {
140 PluginContext::new(project_root.into(), name.to_string())
141}