vx_plugin/
types.rs

1//! Shared types and data structures for the plugin system
2//!
3//! This module contains all the common types used across the plugin system,
4//! including version information, package specifications, and execution contexts.
5
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::path::PathBuf;
9
10/// Information about a tool version
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub struct VersionInfo {
13    /// Version string (e.g., "1.2.3")
14    pub version: String,
15    /// Whether this is a prerelease version
16    pub prerelease: bool,
17    /// Release date in ISO format
18    pub release_date: Option<String>,
19    /// Release notes or description
20    pub release_notes: Option<String>,
21    /// Download URL for this version
22    pub download_url: Option<String>,
23    /// Checksum for verification
24    pub checksum: Option<String>,
25    /// File size in bytes
26    pub file_size: Option<u64>,
27    /// Additional metadata
28    pub metadata: HashMap<String, String>,
29}
30
31impl VersionInfo {
32    /// Create a new VersionInfo with minimal information
33    pub fn new(version: impl Into<String>) -> Self {
34        Self {
35            version: version.into(),
36            prerelease: false,
37            release_date: None,
38            release_notes: None,
39            download_url: None,
40            checksum: None,
41            file_size: None,
42            metadata: HashMap::new(),
43        }
44    }
45
46    /// Create a new VersionInfo with download URL
47    pub fn with_url(version: impl Into<String>, download_url: impl Into<String>) -> Self {
48        Self {
49            version: version.into(),
50            prerelease: false,
51            release_date: None,
52            release_notes: None,
53            download_url: Some(download_url.into()),
54            checksum: None,
55            file_size: None,
56            metadata: HashMap::new(),
57        }
58    }
59
60    /// Mark this version as a prerelease
61    pub fn as_prerelease(mut self) -> Self {
62        self.prerelease = true;
63        self
64    }
65
66    /// Set release date
67    pub fn with_release_date(mut self, date: impl Into<String>) -> Self {
68        self.release_date = Some(date.into());
69        self
70    }
71
72    /// Set release notes
73    pub fn with_release_notes(mut self, notes: impl Into<String>) -> Self {
74        self.release_notes = Some(notes.into());
75        self
76    }
77
78    /// Set checksum
79    pub fn with_checksum(mut self, checksum: impl Into<String>) -> Self {
80        self.checksum = Some(checksum.into());
81        self
82    }
83
84    /// Set file size
85    pub fn with_file_size(mut self, size: u64) -> Self {
86        self.file_size = Some(size);
87        self
88    }
89
90    /// Add metadata to this version
91    pub fn with_metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
92        self.metadata.insert(key.into(), value.into());
93        self
94    }
95}
96
97/// Package specification for installation
98#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
99pub struct PackageSpec {
100    /// Package name
101    pub name: String,
102    /// Optional version constraint
103    pub version: Option<String>,
104    /// Optional features or extras to enable
105    pub features: Vec<String>,
106    /// Whether this is a development dependency
107    pub dev_dependency: bool,
108    /// Additional options specific to the package manager
109    pub options: HashMap<String, String>,
110}
111
112impl PackageSpec {
113    /// Create a new package specification
114    pub fn new(name: impl Into<String>) -> Self {
115        Self {
116            name: name.into(),
117            version: None,
118            features: Vec::new(),
119            dev_dependency: false,
120            options: HashMap::new(),
121        }
122    }
123
124    /// Set version constraint
125    pub fn with_version(mut self, version: impl Into<String>) -> Self {
126        self.version = Some(version.into());
127        self
128    }
129
130    /// Add a feature
131    pub fn with_feature(mut self, feature: impl Into<String>) -> Self {
132        self.features.push(feature.into());
133        self
134    }
135
136    /// Mark as development dependency
137    pub fn as_dev_dependency(mut self) -> Self {
138        self.dev_dependency = true;
139        self
140    }
141}
142/// Information about an installed package
143#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
144pub struct PackageInfo {
145    /// Package name
146    pub name: String,
147    /// Installed version
148    pub version: String,
149    /// Package description
150    pub description: Option<String>,
151    /// Whether this is a development dependency
152    pub dev_dependency: bool,
153    /// Additional metadata
154    pub metadata: HashMap<String, String>,
155}
156
157/// Ecosystem that a tool or package manager belongs to
158#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
159pub enum Ecosystem {
160    /// Node.js ecosystem
161    Node,
162    /// Python ecosystem
163    Python,
164    /// Rust ecosystem
165    Rust,
166    /// Go ecosystem
167    Go,
168    /// Java ecosystem
169    Java,
170    /// .NET ecosystem
171    DotNet,
172    /// Ruby ecosystem
173    Ruby,
174    /// PHP ecosystem
175    Php,
176    /// Generic/cross-platform tools
177    Generic,
178}
179
180impl std::fmt::Display for Ecosystem {
181    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
182        match self {
183            Ecosystem::Node => write!(f, "node"),
184            Ecosystem::Python => write!(f, "python"),
185            Ecosystem::Rust => write!(f, "rust"),
186            Ecosystem::Go => write!(f, "go"),
187            Ecosystem::Java => write!(f, "java"),
188            Ecosystem::DotNet => write!(f, "dotnet"),
189            Ecosystem::Ruby => write!(f, "ruby"),
190            Ecosystem::Php => write!(f, "php"),
191            Ecosystem::Generic => write!(f, "generic"),
192        }
193    }
194}
195
196/// Context for tool execution
197#[derive(Debug, Clone, Default)]
198pub struct ToolContext {
199    /// Working directory for the tool
200    pub working_directory: Option<PathBuf>,
201    /// Environment variables to set
202    pub environment_variables: HashMap<String, String>,
203    /// Whether to use system PATH instead of vx-managed tools
204    pub use_system_path: bool,
205    /// Additional execution options
206    pub options: HashMap<String, String>,
207}
208
209impl ToolContext {
210    /// Create a new empty context
211    pub fn new() -> Self {
212        Self::default()
213    }
214
215    /// Set working directory
216    pub fn with_working_directory(mut self, dir: PathBuf) -> Self {
217        self.working_directory = Some(dir);
218        self
219    }
220
221    /// Add environment variable
222    pub fn with_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
223        self.environment_variables.insert(key.into(), value.into());
224        self
225    }
226
227    /// Use system PATH instead of vx-managed tools
228    pub fn with_system_path(mut self) -> Self {
229        self.use_system_path = true;
230        self
231    }
232}
233/// Result of tool execution
234#[derive(Debug, Clone, PartialEq, Eq)]
235pub struct ToolExecutionResult {
236    /// Exit code of the process
237    pub exit_code: i32,
238    /// Standard output (if captured)
239    pub stdout: Option<String>,
240    /// Standard error (if captured)
241    pub stderr: Option<String>,
242}
243
244impl ToolExecutionResult {
245    /// Create a successful execution result
246    pub fn success() -> Self {
247        Self {
248            exit_code: 0,
249            stdout: None,
250            stderr: None,
251        }
252    }
253
254    /// Create a failed execution result
255    pub fn failure(exit_code: i32) -> Self {
256        Self {
257            exit_code,
258            stdout: None,
259            stderr: None,
260        }
261    }
262
263    /// Check if the execution was successful
264    pub fn is_success(&self) -> bool {
265        self.exit_code == 0
266    }
267
268    /// Add stdout to the result
269    pub fn with_stdout(mut self, stdout: impl Into<String>) -> Self {
270        self.stdout = Some(stdout.into());
271        self
272    }
273
274    /// Add stderr to the result
275    pub fn with_stderr(mut self, stderr: impl Into<String>) -> Self {
276        self.stderr = Some(stderr.into());
277        self
278    }
279}
280
281/// Status information for a tool
282#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
283pub struct ToolStatus {
284    /// Whether the tool is installed
285    pub installed: bool,
286    /// Currently active version
287    pub current_version: Option<String>,
288    /// All installed versions
289    pub installed_versions: Vec<String>,
290}
291
292impl ToolStatus {
293    /// Create a new tool status
294    pub fn new() -> Self {
295        Self {
296            installed: false,
297            current_version: None,
298            installed_versions: Vec::new(),
299        }
300    }
301
302    /// Create status for an installed tool
303    pub fn installed_with_versions(versions: Vec<String>, current: Option<String>) -> Self {
304        Self {
305            installed: !versions.is_empty(),
306            current_version: current,
307            installed_versions: versions,
308        }
309    }
310}
311
312impl Default for ToolStatus {
313    fn default() -> Self {
314        Self::new()
315    }
316}
317
318/// Basic tool metadata for standard tools
319#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
320pub struct ToolMetadata {
321    /// Tool name
322    pub name: String,
323    /// Tool description
324    pub description: String,
325    /// Supported aliases
326    pub aliases: Vec<String>,
327    /// Supported platforms
328    pub platforms: Vec<String>,
329    /// Additional metadata
330    pub metadata: HashMap<String, String>,
331}
332
333impl ToolMetadata {
334    /// Create new tool metadata
335    pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
336        Self {
337            name: name.into(),
338            description: description.into(),
339            aliases: Vec::new(),
340            platforms: Vec::new(),
341            metadata: HashMap::new(),
342        }
343    }
344
345    /// Add an alias
346    pub fn with_alias(mut self, alias: impl Into<String>) -> Self {
347        self.aliases.push(alias.into());
348        self
349    }
350
351    /// Add a supported platform
352    pub fn with_platform(mut self, platform: impl Into<String>) -> Self {
353        self.platforms.push(platform.into());
354        self
355    }
356
357    /// Add metadata
358    pub fn with_metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
359        self.metadata.insert(key.into(), value.into());
360        self
361    }
362}
363
364/// Package manager configuration
365#[derive(Debug, Clone, Serialize, Deserialize)]
366pub struct PackageManagerConfig {
367    /// Package manager name
368    pub name: String,
369    /// Package manager version
370    pub version: Option<String>,
371    /// Path to the executable
372    pub executable_path: Option<PathBuf>,
373    /// Configuration files used by this package manager
374    pub config_files: Vec<PathBuf>,
375    /// Cache directory location
376    pub cache_directory: Option<PathBuf>,
377    /// Whether this package manager supports lock files
378    pub supports_lockfiles: bool,
379    /// Whether this package manager supports workspaces
380    pub supports_workspaces: bool,
381    /// Environment isolation level
382    pub isolation_level: IsolationLevel,
383}
384
385/// Environment isolation level
386#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
387pub enum IsolationLevel {
388    /// No isolation, global installation
389    Global,
390    /// User-level isolation
391    User,
392    /// Project-level isolation
393    #[default]
394    Project,
395    /// Complete sandboxing
396    Sandbox,
397}