Skip to main content

progit_plugin_sdk/
lib.rs

1// SPDX-License-Identifier: LSL-1.0
2// Copyright (c) 2025 Markus Maiwald
3
4//! # ProGit Plugin SDK
5//!
6//! LSL-1.0 licensed SDK for building ProGit plugins in Lua or WASM.
7//!
8//! ## Architecture
9//!
10//! The SDK is the single contract between the ProGit TUI core (LCL-1.0)
11//! and community / commercial plugins. The SDK itself is LSL-1.0 (file-level
12//! copyleft + explicit patent grant) so corporations can ship closed plugins
13//! without license contagion. Modifications to SDK files stay open.
14//!
15//! ## Plugin Types
16//!
17//! - **Lua Plugins** — lightweight scripting via LuaJIT, sandboxed by default.
18//! - **WASM Plugins** — high-performance compiled plugins, available behind
19//!   the `wasm` feature flag. Off by default to keep the binary lean.
20//!
21//! ## v0.2 Highlights
22//!
23//! - One canonical [`event::PluginEvent`] enum (host no longer redefines it).
24//! - LuaJIT runtime is sandboxed: dangerous stdlib (`os.execute`, `io.popen`,
25//!   `package.loadlib`, `debug`) is dropped by default.
26//! - Per-plugin memory limits and instruction caps via [`lua::LuaPluginOptions`].
27//! - Injected `log` and `storage` globals so plugins do not have to invent
28//!   their own logging or persistence.
29//! - Per-plugin failure isolation with quarantine after N consecutive errors.
30//! - SDK API versioning + capability declarations on the plugin metadata.
31//!
32//! ## Example
33//!
34//! ```rust,ignore
35//! use progit_plugin_sdk::prelude::*;
36//!
37//! let mut plugin = LuaPlugin::load("plugins/my-plugin.lua")?;
38//! let context = PluginContext {
39//!     repo_path: "/path/to/repo".into(),
40//!     user: Some("developer".into()),
41//!     env: Default::default(),
42//!     config: Default::default(),
43//! };
44//! plugin.init(&context)?;
45//!
46//! if plugin.supports_hook(&PluginHook::OnIssueCreated) {
47//!     let data = serde_json::json!({"id": "123", "title": "Bug fix"});
48//!     plugin.execute_hook(&PluginHook::OnIssueCreated, &data)?;
49//! }
50//! # Ok::<(), anyhow::Error>(())
51//! ```
52
53pub mod contributions;
54pub mod event;
55pub mod lua;
56pub mod manifest;
57pub mod render;
58pub mod storage;
59pub mod traits;
60
61#[cfg(feature = "wasm")]
62pub mod wasm;
63
64pub mod prelude {
65    //! Convenience re-exports for plugin development.
66
67    pub use crate::contributions::{
68        CommandArgs, CommandContribution, CommandOutputMode, CommandTuiContribution,
69        PluginContributionManifest, PluginContributions,
70    };
71    pub use crate::event::{PipelineJob, PipelineState, PipelineStatus, PluginEvent};
72    pub use crate::lua::{
73        LuaPlugin, LuaPluginOptions, SoberHost, SoberInvocation, SoberInvocationResult,
74    };
75    pub use crate::manifest::{Capabilities, PluginManifest, SdkVersion};
76    pub use crate::render::{HighlightRequest, HighlightResponse, Rgb, TokenSpan};
77    pub use crate::storage::{JsonFileStorage, PluginStorage, SyncState};
78    pub use crate::traits::*;
79
80    #[cfg(feature = "wasm")]
81    pub use crate::wasm::WasmPlugin;
82}
83
84/// Plugin SDK semantic version (taken from `Cargo.toml` at build time).
85pub const VERSION: &str = env!("CARGO_PKG_VERSION");
86
87/// SDK API contract version. Plugins declare a compatible version in their
88/// metadata; the loader rejects plugins with a mismatched major.
89///
90/// Bump the **major** when an existing API method signature or hook payload
91/// shape changes in a breaking way. Bump the **minor** when adding new
92/// hooks, events, or stdlib globals.
93pub const SDK_API_VERSION: &str = "0.4";
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    #[test]
100    fn version_constants_are_set() {
101        assert!(!VERSION.is_empty());
102        assert!(SDK_API_VERSION.starts_with("0."));
103    }
104}