Skip to main content

ai_agent/utils/plugins/
schemas.rs

1// Source: ~/claudecode/openclaudecode/src/utils/plugins/schemas.ts
2#![allow(dead_code)]
3
4use once_cell::sync::Lazy;
5use std::collections::HashSet;
6
7// Re-export types that are defined in types.rs to avoid duplicate definitions
8pub use super::types::{
9    KnownMarketplace, KnownMarketplacesFile, PluginMarketplaceEntry, PluginSource,
10};
11
12/// Official marketplace names that are reserved for Anthropic/Claude official use.
13pub fn allowed_official_marketplace_names() -> &'static HashSet<&'static str> {
14    static NAMES: Lazy<HashSet<&'static str>> = Lazy::new(|| {
15        HashSet::from([
16            "claude-code-marketplace",
17            "claude-code-plugins",
18            "claude-plugins-official",
19            "anthropic-marketplace",
20            "anthropic-plugins",
21            "agent-skills",
22            "life-sciences",
23            "knowledge-work-plugins",
24        ])
25    });
26    &NAMES
27}
28
29/// Official marketplaces that should NOT auto-update by default.
30fn no_auto_update_official_marketplaces() -> &'static HashSet<&'static str> {
31    static NAMES: Lazy<HashSet<&'static str>> =
32        Lazy::new(|| HashSet::from(["knowledge-work-plugins"]));
33    &NAMES
34}
35
36/// Check if auto-update is enabled for a marketplace.
37pub fn is_marketplace_auto_update(marketplace_name: &str, _entry: &serde_json::Value) -> bool {
38    let normalized = marketplace_name.to_lowercase();
39    allowed_official_marketplace_names().contains(normalized.as_str())
40        && !no_auto_update_official_marketplaces().contains(normalized.as_str())
41}
42
43/// Check if a source is a local plugin source.
44pub fn is_local_plugin_source(source: &PluginSource) -> bool {
45    matches!(source, PluginSource::Relative(_))
46}
47
48/// Marketplace source types.
49#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
50#[serde(tag = "source")]
51pub enum MarketplaceSource {
52    #[serde(rename = "github")]
53    Github {
54        repo: String,
55        #[serde(rename = "ref", skip_serializing_if = "Option::is_none")]
56        ref_: Option<String>,
57        #[serde(skip_serializing_if = "Option::is_none")]
58        path: Option<String>,
59    },
60    #[serde(rename = "url")]
61    Url { url: String },
62    #[serde(rename = "git")]
63    Git {
64        url: String,
65        #[serde(rename = "ref", skip_serializing_if = "Option::is_none")]
66        ref_: Option<String>,
67        #[serde(skip_serializing_if = "Option::is_none")]
68        path: Option<String>,
69    },
70    #[serde(rename = "directory")]
71    Directory { path: String },
72    #[serde(rename = "file")]
73    File { path: String },
74    #[serde(rename = "settings")]
75    Settings { name: String, plugins: Vec<String> },
76    #[serde(rename = "git-subdir")]
77    GitSubdir {
78        url: String,
79        path: String,
80        #[serde(rename = "ref", skip_serializing_if = "Option::is_none")]
81        ref_: Option<String>,
82    },
83}
84
85/// Check if a marketplace source is a local marketplace source.
86pub fn is_local_marketplace_source(source: &MarketplaceSource) -> bool {
87    matches!(
88        source,
89        MarketplaceSource::Directory { .. } | MarketplaceSource::File { .. }
90    )
91}
92
93/// Plugin manifest (from plugin.json).
94#[derive(Debug, Clone, serde::Deserialize)]
95pub struct PluginManifest {
96    pub name: String,
97    pub version: Option<String>,
98    pub description: Option<String>,
99    pub author: Option<PluginAuthor>,
100    pub dependencies: Option<Vec<String>>,
101    #[serde(rename = "userConfig")]
102    pub user_config: Option<serde_json::Value>,
103}
104
105#[derive(Debug, Clone, serde::Deserialize)]
106pub struct PluginAuthor {
107    pub name: String,
108    pub email: Option<String>,
109    pub url: Option<String>,
110}
111
112/// Plugin installation scope.
113#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
114pub enum PluginScope {
115    #[serde(rename = "user")]
116    User,
117    #[serde(rename = "managed")]
118    Managed,
119    #[serde(rename = "project")]
120    Project,
121    #[serde(rename = "local")]
122    Local,
123}
124
125/// Plugin installation entry.
126#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
127pub struct PluginInstallationEntry {
128    pub scope: PluginScope,
129    #[serde(rename = "installPath")]
130    pub install_path: String,
131    pub version: Option<String>,
132    #[serde(rename = "installedAt")]
133    pub installed_at: String,
134    #[serde(rename = "lastUpdated")]
135    pub last_updated: String,
136    #[serde(rename = "gitCommitSha", skip_serializing_if = "Option::is_none")]
137    pub git_commit_sha: Option<String>,
138    #[serde(rename = "projectPath", skip_serializing_if = "Option::is_none")]
139    pub project_path: Option<String>,
140}