use serde::{Deserialize, Serialize};
use crate::permissions::Permission;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PluginManifest {
pub id: String,
pub name: String,
pub version: String,
pub description: String,
#[serde(default)]
pub long_description: Option<String>,
pub author: String,
#[serde(default)]
pub author_url: Option<String>,
#[serde(default)]
pub homepage: Option<String>,
#[serde(default)]
pub license: Option<String>,
#[serde(default)]
pub keywords: Vec<String>,
#[serde(default)]
pub icon: Option<String>,
pub compatibility: CompatibilitySpec,
pub capability_levels: Vec<CapabilityLevel>,
#[serde(default)]
pub integration: IntegrationConfig,
#[serde(default)]
pub entry: EntryConfig,
#[serde(default)]
pub dependencies: Vec<PluginDependency>,
#[serde(default)]
pub permissions: Vec<Permission>,
#[serde(default)]
pub settings_schema: Option<serde_json::Value>,
#[serde(default)]
pub commands: Vec<CommandDeclaration>,
#[serde(default)]
pub checksum: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompatibilitySpec {
pub min_app_version: String,
#[serde(default)]
pub max_app_version: Option<String>,
#[serde(default = "all_platforms")]
pub platforms: Vec<String>,
}
fn all_platforms() -> Vec<String> {
vec!["windows".into(), "macos".into(), "linux".into()]
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(from = "u8", into = "u8")]
pub enum CapabilityLevel {
Module = 0,
ModuleFeature = 1,
UiExtension = 2,
AiAssistant = 3,
Service = 4,
}
impl From<u8> for CapabilityLevel {
fn from(v: u8) -> Self {
match v {
0 => Self::Module,
1 => Self::ModuleFeature,
2 => Self::UiExtension,
3 => Self::AiAssistant,
4 => Self::Service,
_ => Self::Service,
}
}
}
impl From<CapabilityLevel> for u8 {
fn from(l: CapabilityLevel) -> u8 {
l as u8
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct IntegrationConfig {
#[serde(default)]
pub level0: Option<Level0Config>,
#[serde(default)]
pub level1: Option<Level1Config>,
#[serde(default)]
pub level2: Option<Level2Config>,
#[serde(default)]
pub level3: Option<Level3Config>,
#[serde(default)]
pub level4: Option<Level4Config>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Level0Config {
pub module_id: String,
pub module_label: String,
pub module_icon: String,
#[serde(default = "default_sidebar_position")]
pub sidebar_position: String,
#[serde(default = "default_sidebar_order")]
pub sidebar_order: u32,
pub panel_entry: String,
}
fn default_sidebar_position() -> String { "main".into() }
fn default_sidebar_order() -> u32 { 100 }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Level1Config {
pub parent_module: String,
pub tab_id: String,
pub tab_label: String,
pub tab_icon: String,
#[serde(default)]
pub tab_position: Option<String>,
pub panel_entry: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Level2Config {
pub slots: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Level3Config {
pub assistant_id: String,
pub assistant_name: String,
#[serde(default)]
pub assistant_icon: Option<String>,
#[serde(default)]
pub assistant_description: Option<String>,
pub system_prompt_file: String,
#[serde(default)]
pub preferred_model: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Level4Config {
#[serde(default)]
pub workflow_step_types: Vec<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct EntryConfig {
#[serde(default)]
pub native: Option<NativeEntry>,
#[serde(default)]
pub frontend: Option<String>,
#[serde(default)]
pub frontend_styles: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct NativeEntry {
#[serde(default)]
pub macos_arm64: Option<String>,
#[serde(default)]
pub macos_x64: Option<String>,
#[serde(default)]
pub windows_x64: Option<String>,
#[serde(default)]
pub windows_arm64: Option<String>,
#[serde(default)]
pub linux_x64: Option<String>,
#[serde(default)]
pub linux_arm64: Option<String>,
}
impl NativeEntry {
pub fn for_current_platform(&self) -> Option<&str> {
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
return self.macos_arm64.as_deref();
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
return self.macos_x64.as_deref();
#[cfg(all(target_os = "windows", target_arch = "x86_64"))]
return self.windows_x64.as_deref();
#[cfg(all(target_os = "windows", target_arch = "aarch64"))]
return self.windows_arm64.as_deref();
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
return self.linux_x64.as_deref();
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
return self.linux_arm64.as_deref();
#[allow(unreachable_code)]
None
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PluginDependency {
pub id: String,
pub version: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CommandDeclaration {
pub id: String,
#[serde(default)]
pub description: Option<String>,
}