Grove/
lib.rs
1//! Grove - Rust/WASM Extension Host for VS Code
2//!
3//! Grove provides a secure, sandboxed environment for running VS Code
4//! extensions compiled to WebAssembly or native Rust. It complements Cocoon
5//! (Node.js) by offering a native extension host with full WASM support.
6//!
7//! # Architecture
8//!
9//! ```text
10//! +++++++++++++++++++++++++++++++++++++++++++
11//! + Extension Host +
12//! +++++++++++++++++++++++++++++++++++++++++++
13//! + Extension Manager → Activation Engine +
14//! + API Bridge → VS Code API +
15//! +++++++++++++++++++++++++++++++++++++++++++
16//! +
17//! ++++++++++++++++++++▼++++++++++++++++++++++
18//! + WASM Runtime (WASMtime) +
19//! + Module Loader → Host Bridge +
20//! +++++++++++++++++++++++++++++++++++++++++++
21//! +
22//! ++++++++++++++++++++▼++++++++++++++++++++++
23//! + Transport Layer +
24//! + gRPC | IPC | Direct WASM +
25//! +++++++++++++++++++++++++++++++++++++++++++
26//! ```
27//!
28//! # Features
29//!
30//! - **Standalone Operation**: Run independently or connect to Mountain via
31//! gRPC
32//! - **WASM Support**: Full WebAssembly runtime with WASMtime
33//! - **Multiple Transport**: gRPC, IPC, and direct WASM communication
34//! - **Secure Sandboxing**: WASMtime-based isolation for untrusted extensions
35//! - **Cocoon Compatible**: Shares API surface with Node.js host
36//!
37//! # Example: Standalone Usage
38//!
39//! ```rust,no_run
40//! use grove::{ExtensionHost, Transport};
41//!
42//! #[tokio::main]
43//! async fn main() -> anyhow::Result<()> {
44//! let host = ExtensionHost::new(Transport::default()).await?;
45//! host.load_extension("/path/to/extension").await?;
46//! host.activate().await?;
47//! Ok(())
48//! }
49//! ```
50//!
51//! # Module Organization
52//!
53//! - [`Host`] - Extension hosting core (ExtensionHost, ExtensionManager, etc.)
54//! - [`WASM`] - WebAssembly runtime integration
55//! - [`Transport`] - Communication strategies (gRPC, IPC, WASM)
56//! - [`API`] - VS Code API facade and types
57//! - [`Protocol`] - Protocol handling (Spine connection)
58//! - [`Services`] - Host services (configuration, etc.)
59//! - [`Common`] - Shared utilities and error types
60
61#![warn(missing_docs)]
62#![deny(unsafe_code)]
63#![warn(clippy::all)]
64#![allow(non_snake_case, non_camel_case_types, unexpected_cfgs)]
65
66// Public module declarations
67pub mod API;
68pub mod Binary;
69pub mod Common;
70pub mod Host;
71pub mod Protocol;
72pub mod Services;
73pub mod Transport;
74pub mod WASM;
75
76// Re-exports for convenience
77pub use API::{types, vscode};
78pub use Binary::{
79 Build::{RuntimeBuild, ServiceRegister},
80 Main::Entry::{BuildResult, Entry, ExtensionInfo, ValidationResult},
81};
82pub use Common::{
83 error::{GroveError, GroveResult},
84 traits::ExtensionContext,
85};
86// Transport module exports are already re-exported in Transport/mod.rs
87// Use grove::Transport::{Transport, TransportType, TransportStats, GrpcTransport, IPCTransportImpl,
88// WASMTransportImpl}
89pub use WASM::Runtime;
90// Note: ExtensionHost, ExtensionManager must be accessed via module prefix
91
92// Library version
93const VERSION:&str = env!("CARGO_PKG_VERSION");
94
95/// Grove library information
96#[derive(Debug, Clone)]
97pub struct GroveInfo {
98 /// Version string
99 pub version:&'static str,
100 /// Build timestamp
101 #[allow(dead_code)]
102 build_timestamp:String,
103}
104
105impl GroveInfo {
106 /// Create new GroveInfo with current build information
107 pub fn new() -> Self { Self { version:VERSION, build_timestamp:env!("VERGEN_BUILD_TIMESTAMP").to_string() } }
108
109 /// Get the Grove version
110 pub fn version(&self) -> &'static str { self.version }
111}
112
113impl Default for GroveInfo {
114 fn default() -> Self { Self::new() }
115}
116
117/// Initialize Grove library
118///
119/// This sets up logging and other global state.
120/// Call once at application startup.
121pub fn init() -> anyhow::Result<()> {
122 // Initialize tracing subscriber with environment-based filtering
123 let filter = tracing_subscriber::EnvFilter::from_default_env().add_directive(tracing::Level::INFO.into());
124
125 tracing_subscriber::fmt()
126 .with_env_filter(filter)
127 .with_target(false)
128 .try_init()
129 .map_err(|e| anyhow::anyhow!("Failed to initialize tracing: {}", e))?;
130
131 tracing::info!("Grove v{} initialized", VERSION);
132
133 Ok(())
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn test_version() {
142 assert!(!VERSION.is_empty());
143 assert!(VERSION.contains('.'));
144 }
145
146 #[test]
147 fn test_grove_info() {
148 let info = GroveInfo::new();
149 assert_eq!(info.version(), VERSION);
150 }
151}