Skip to main content

opendev_plugins/
models.rs

1//! Data models for the plugin system.
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::path::PathBuf;
7
8/// Source of a plugin installation.
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
10#[serde(rename_all = "snake_case")]
11pub enum PluginSource {
12    /// Installed from a git repository.
13    Git { url: String, branch: String },
14    /// Installed from a local directory.
15    Local { path: PathBuf },
16    /// Installed from a marketplace.
17    Marketplace { marketplace: String },
18}
19
20/// Status of a plugin.
21#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
22#[serde(rename_all = "snake_case")]
23pub enum PluginStatus {
24    /// Plugin is installed and active.
25    Installed,
26    /// Plugin is installed but disabled.
27    Disabled,
28    /// Plugin encountered an error.
29    Error(String),
30}
31
32/// Installation scope for plugins.
33#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
34#[serde(rename_all = "snake_case")]
35pub enum PluginScope {
36    /// User-global plugins (~/.opendev/plugins/).
37    User,
38    /// Project-local plugins (.opendev/plugins/).
39    Project,
40}
41
42/// A tool definition within a plugin manifest.
43#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
44pub struct ToolDefinition {
45    /// Tool name.
46    pub name: String,
47    /// Tool description.
48    #[serde(default)]
49    pub description: String,
50    /// JSON schema for tool parameters.
51    #[serde(default)]
52    pub parameters: serde_json::Value,
53}
54
55/// A prompt template within a plugin manifest.
56#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
57pub struct PromptTemplate {
58    /// Prompt name/identifier.
59    pub name: String,
60    /// Prompt description.
61    #[serde(default)]
62    pub description: String,
63    /// The template content.
64    #[serde(default)]
65    pub template: String,
66}
67
68/// Plugin manifest loaded from `manifest.json`.
69#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
70pub struct PluginManifest {
71    /// Plugin name.
72    pub name: String,
73    /// Plugin version (semver).
74    pub version: String,
75    /// Plugin description.
76    #[serde(default)]
77    pub description: String,
78    /// Plugin author.
79    #[serde(default)]
80    pub author: Option<String>,
81    /// Tool definitions provided by the plugin.
82    #[serde(default)]
83    pub tools: Vec<ToolDefinition>,
84    /// Prompt templates provided by the plugin.
85    #[serde(default)]
86    pub prompts: Vec<PromptTemplate>,
87    /// Plugin dependencies (other plugin names).
88    #[serde(default)]
89    pub dependencies: Vec<String>,
90    /// Skills provided by the plugin.
91    #[serde(default)]
92    pub skills: Vec<String>,
93    /// Source repository URL.
94    #[serde(default)]
95    pub repository: Option<String>,
96    /// License identifier.
97    #[serde(default)]
98    pub license: Option<String>,
99}
100
101/// Configuration for a single installed plugin.
102#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct PluginConfig {
104    /// Plugin name.
105    pub name: String,
106    /// Installed version.
107    pub version: String,
108    /// Installation source.
109    pub source: PluginSource,
110    /// Current status.
111    pub status: PluginStatus,
112    /// Installation scope.
113    pub scope: PluginScope,
114    /// Whether the plugin is enabled.
115    pub enabled: bool,
116    /// Path to the installed plugin directory.
117    pub path: PathBuf,
118    /// When the plugin was installed.
119    pub installed_at: DateTime<Utc>,
120    /// Marketplace this plugin came from (if applicable).
121    #[serde(default)]
122    pub marketplace: Option<String>,
123}
124
125/// Information about a registered marketplace.
126#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct MarketplaceInfo {
128    /// Unique name for this marketplace.
129    pub name: String,
130    /// Git URL of the marketplace repository.
131    pub url: String,
132    /// Git branch to track.
133    #[serde(default = "default_branch")]
134    pub branch: String,
135    /// When this marketplace was added.
136    pub added_at: DateTime<Utc>,
137    /// Last time marketplace was synced.
138    #[serde(default)]
139    pub last_updated: Option<DateTime<Utc>>,
140}
141
142fn default_branch() -> String {
143    "main".to_string()
144}
145
146/// Registry of known marketplaces.
147#[derive(Debug, Clone, Serialize, Deserialize, Default)]
148pub struct KnownMarketplaces {
149    /// Map of marketplace name to info.
150    #[serde(default)]
151    pub marketplaces: HashMap<String, MarketplaceInfo>,
152}
153
154/// Registry of installed plugins.
155#[derive(Debug, Clone, Serialize, Deserialize, Default)]
156pub struct InstalledPlugins {
157    /// Map of "marketplace:plugin" key to plugin config.
158    #[serde(default)]
159    pub plugins: HashMap<String, PluginConfig>,
160}
161
162impl InstalledPlugins {
163    /// Generate registry key for a plugin.
164    pub fn make_key(marketplace: &str, plugin: &str) -> String {
165        format!("{}:{}", marketplace, plugin)
166    }
167
168    /// Add a plugin to the registry.
169    pub fn add(&mut self, plugin: PluginConfig) {
170        let key = Self::make_key(
171            plugin.marketplace.as_deref().unwrap_or("local"),
172            &plugin.name,
173        );
174        self.plugins.insert(key, plugin);
175    }
176
177    /// Remove a plugin from the registry.
178    pub fn remove(&mut self, marketplace: &str, plugin: &str) -> Option<PluginConfig> {
179        let key = Self::make_key(marketplace, plugin);
180        self.plugins.remove(&key)
181    }
182
183    /// Get a plugin from the registry.
184    pub fn get(&self, marketplace: &str, plugin: &str) -> Option<&PluginConfig> {
185        let key = Self::make_key(marketplace, plugin);
186        self.plugins.get(&key)
187    }
188
189    /// Get a mutable reference to a plugin.
190    pub fn get_mut(&mut self, marketplace: &str, plugin: &str) -> Option<&mut PluginConfig> {
191        let key = Self::make_key(marketplace, plugin);
192        self.plugins.get_mut(&key)
193    }
194}
195
196/// Marketplace plugin catalog.
197#[derive(Debug, Clone, Serialize, Deserialize, Default)]
198pub struct MarketplaceCatalog {
199    /// List of plugin names available.
200    #[serde(default)]
201    pub plugins: Vec<String>,
202    /// Whether catalog was auto-discovered (no marketplace.json).
203    #[serde(default)]
204    pub auto_discovered: bool,
205}
206
207/// Plugin metadata from plugin.json or marketplace listing.
208#[derive(Debug, Clone, Serialize, Deserialize)]
209pub struct PluginMetadata {
210    /// Plugin name.
211    pub name: String,
212    /// Plugin version.
213    pub version: String,
214    /// Plugin description.
215    #[serde(default)]
216    pub description: String,
217    /// Plugin author.
218    #[serde(default)]
219    pub author: Option<String>,
220    /// Skills provided by the plugin.
221    #[serde(default)]
222    pub skills: Vec<String>,
223    /// Source repository URL.
224    #[serde(default)]
225    pub repository: Option<String>,
226    /// License identifier.
227    #[serde(default)]
228    pub license: Option<String>,
229}