Skip to main content

systemprompt_models/extension/
mod.rs

1//! `extension` module — see crate-level docs for context.
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use std::path::PathBuf;
6
7#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "lowercase")]
9pub enum ExtensionType {
10    Mcp,
11    Blog,
12    Cli,
13    #[default]
14    Other,
15}
16
17#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
18#[serde(rename_all = "lowercase")]
19pub enum BuildType {
20    #[default]
21    Workspace,
22    Submodule,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct ManifestRole {
27    pub display_name: String,
28    pub description: String,
29    #[serde(default)]
30    pub permissions: Vec<String>,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct CliCommand {
35    pub name: String,
36    #[serde(default)]
37    pub description: String,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct ExtensionManifest {
42    pub extension: Extension,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct Extension {
47    #[serde(rename = "type")]
48    pub type_: ExtensionType,
49
50    pub name: String,
51
52    #[serde(default, skip_serializing_if = "Option::is_none")]
53    pub binary: Option<String>,
54
55    #[serde(default)]
56    pub description: String,
57
58    #[serde(default, skip_serializing_if = "Option::is_none")]
59    pub port: Option<u16>,
60
61    #[serde(default)]
62    pub build_type: BuildType,
63
64    #[serde(default = "default_true")]
65    pub enabled: bool,
66
67    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
68    pub roles: HashMap<String, ManifestRole>,
69
70    #[serde(default, skip_serializing_if = "Vec::is_empty")]
71    pub commands: Vec<CliCommand>,
72
73    #[serde(default)]
74    pub supports_json_output: bool,
75}
76
77const fn default_true() -> bool {
78    true
79}
80
81#[derive(Debug, Clone)]
82pub struct DiscoveredExtension {
83    pub manifest: ExtensionManifest,
84    pub path: PathBuf,
85    pub manifest_path: PathBuf,
86}
87
88impl DiscoveredExtension {
89    pub const fn new(manifest: ExtensionManifest, path: PathBuf, manifest_path: PathBuf) -> Self {
90        Self {
91            manifest,
92            path,
93            manifest_path,
94        }
95    }
96
97    pub const fn extension_type(&self) -> ExtensionType {
98        self.manifest.extension.type_
99    }
100
101    pub fn binary_name(&self) -> Option<&str> {
102        self.manifest.extension.binary.as_deref()
103    }
104
105    pub const fn is_enabled(&self) -> bool {
106        self.manifest.extension.enabled
107    }
108
109    pub fn is_mcp(&self) -> bool {
110        self.manifest.extension.type_ == ExtensionType::Mcp
111    }
112
113    pub fn is_cli(&self) -> bool {
114        self.manifest.extension.type_ == ExtensionType::Cli
115    }
116
117    pub fn commands(&self) -> &[CliCommand] {
118        &self.manifest.extension.commands
119    }
120
121    pub const fn build_type(&self) -> BuildType {
122        self.manifest.extension.build_type
123    }
124
125    pub const fn supports_json_output(&self) -> bool {
126        self.manifest.extension.supports_json_output
127    }
128}