1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
//! sen-plugin-host: WASM plugin host runtime for sen-rs
//!
//! This crate provides the runtime for loading and executing WASM plugins.
//! It enables building plugin-extensible CLI applications with minimal effort.
//!
//! # Architecture
//!
//! ```text
//! ┌─────────────────────────────────────────────────────────────┐
//! │ Your Application │
//! ├─────────────────────────────────────────────────────────────┤
//! │ PluginRegistry │
//! │ ├─ load_plugin("./plugins/hello.wasm") │
//! │ ├─ execute("hello", &["World"]) │
//! │ └─ list_commands() │
//! ├─────────────────────────────────────────────────────────────┤
//! │ HotReloadWatcher (optional) │
//! │ └─ Watches directories, auto-loads/unloads plugins │
//! ├─────────────────────────────────────────────────────────────┤
//! │ PluginLoader │
//! │ ├─ Compiles WASM modules │
//! │ ├─ Validates API version │
//! │ └─ Creates sandboxed instances │
//! ├─────────────────────────────────────────────────────────────┤
//! │ wasmtime (sandboxed execution) │
//! │ ├─ CPU limits (fuel) │
//! │ ├─ Stack limits (1MB) │
//! │ └─ Memory isolation │
//! └─────────────────────────────────────────────────────────────┘
//! ```
//!
//! # Features
//!
//! - **Plugin Loading**: Load and execute WASM plugins with sandboxed execution
//! - **Hot Reload**: Automatically reload plugins when files change
//! - **Plugin Discovery**: Scan directories for plugin files
//! - **CPU Limits**: Prevent infinite loops with fuel-based execution limits
//! - **Stack Limits**: Prevent stack overflow attacks (1MB limit)
//! - `sen-integration`: Enable integration with sen-rs Router (adds `bridge` module)
//!
//! # Security
//!
//! Plugins run in a sandboxed WASM environment with multiple protections:
//!
//! | Protection | Description |
//! |------------|-------------|
//! | CPU Limit | 10M instructions per execution (fuel) |
//! | Stack Limit | 1MB maximum WASM stack |
//! | Memory Isolation | Each plugin has isolated linear memory |
//! | No System Access | No filesystem, network, or OS access |
//! | API Versioning | Rejects plugins with incompatible API versions |
//!
//! # Quick Start
//!
//! ## Building Plugins
//!
//! See the `sen-plugin-sdk` crate for detailed plugin development guide.
//!
//! ```bash
//! # Add the WASM target (one-time setup)
//! rustup target add wasm32-unknown-unknown
//!
//! # Build plugin
//! cargo build --release --target wasm32-unknown-unknown
//! ```
//!
//! ## Loading and Executing Plugins
//!
//! ### Direct Loading
//!
//! ```rust,ignore
//! use sen_plugin_host::PluginLoader;
//!
//! let loader = PluginLoader::new()?;
//! let wasm_bytes = std::fs::read("plugin.wasm")?;
//! let mut plugin = loader.load(&wasm_bytes)?;
//!
//! // Check plugin metadata
//! println!("Command: {}", plugin.manifest.command.name);
//! println!("Description: {}", plugin.manifest.command.about);
//!
//! // Execute
//! let result = plugin.instance.execute(&["World".to_string()])?;
//! match result {
//! ExecuteResult::Success(output) => println!("{}", output),
//! ExecuteResult::Error(err) => eprintln!("Error: {}", err.message),
//! }
//! ```
//!
//! ### Using Registry (Recommended)
//!
//! ```rust,ignore
//! use sen_plugin_host::PluginRegistry;
//!
//! let registry = PluginRegistry::new()?;
//!
//! // Load plugins
//! registry.load_plugin("./plugins/hello.wasm").await?;
//! registry.load_plugin("./plugins/greet.wasm").await?;
//!
//! // List available commands
//! for cmd in registry.list_commands().await {
//! println!(" {}", cmd);
//! }
//!
//! // Execute by command name
//! let result = registry.execute("hello", &["World".to_string()]).await?;
//! ```
//!
//! ## Hot Reload
//!
//! Automatically load/reload/unload plugins when files change:
//!
//! ```rust,ignore
//! use sen_plugin_host::{PluginRegistry, HotReloadWatcher, WatcherConfig};
//! use std::time::Duration;
//!
//! let registry = PluginRegistry::new()?;
//!
//! // Watch directory for plugin changes
//! let _watcher = HotReloadWatcher::new(
//! registry.clone(),
//! vec!["./plugins"],
//! WatcherConfig {
//! debounce: Duration::from_millis(300),
//! load_existing: true, // Load existing plugins on start
//! },
//! ).await?;
//!
//! // Plugins are now automatically managed:
//! // - New .wasm files are loaded
//! // - Modified .wasm files are reloaded
//! // - Deleted .wasm files are unloaded
//!
//! // Your application continues running...
//! loop {
//! let cmd = read_user_input();
//! if let Ok(result) = registry.execute(&cmd, &args).await {
//! // Handle result
//! }
//! }
//! ```
//!
//! ## Plugin Discovery
//!
//! Scan directories for plugins without hot reload:
//!
//! ```rust,ignore
//! use sen_plugin_host::PluginScanner;
//!
//! let scanner = PluginScanner::new()?;
//! let result = scanner.scan_directory("./plugins")?;
//!
//! println!("Found {} plugins", result.plugins.len());
//! for plugin in &result.plugins {
//! println!(" - {} ({})", plugin.manifest.command.name, plugin.manifest.command.about);
//! }
//!
//! if !result.failures.is_empty() {
//! eprintln!("Failed to load {} plugins:", result.failures.len());
//! for (path, error) in &result.failures {
//! eprintln!(" - {}: {}", path.display(), error);
//! }
//! }
//! ```
//!
//! # sen-rs Router Integration
//!
//! Enable the `sen-integration` feature to integrate plugins with sen-rs Router:
//!
//! ```toml
//! [dependencies]
//! sen-plugin-host = { version = "0.7", features = ["sen-integration"] }
//! ```
//!
//! ```rust,ignore
//! use sen::Router;
//! use sen_plugin_host::{PluginLoader, RouterPluginExt};
//!
//! let loader = PluginLoader::new()?;
//! let plugin = loader.load(&wasm_bytes)?;
//!
//! // Register plugin as a router command
//! let router = Router::new()
//! .plugin(plugin)
//! .with_state(MyState);
//!
//! // Plugin command is now available via the router
//! let response = router.execute_with(&["app", "hello", "World"]).await;
//! ```
//!
//! # Examples
//!
//! See `examples/wasm-cli/` for a complete example of a plugin-extensible CLI
//! with hot reload support.
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
// Permission system re-exports
pub use ;
pub use ;