ai_agent/utils/plugins/
schemas.rs1#![allow(dead_code)]
3
4use once_cell::sync::Lazy;
5use std::collections::HashSet;
6
7pub use super::types::{
9 KnownMarketplace, KnownMarketplacesFile, PluginMarketplaceEntry, PluginSource,
10};
11
12pub 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
29fn 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
36pub 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
43pub fn is_local_plugin_source(source: &PluginSource) -> bool {
45 matches!(source, PluginSource::Relative(_))
46}
47
48#[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
85pub fn is_local_marketplace_source(source: &MarketplaceSource) -> bool {
87 matches!(
88 source,
89 MarketplaceSource::Directory { .. } | MarketplaceSource::File { .. }
90 )
91}
92
93#[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#[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#[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}