cc_plugin_validator/manifest/
mod.rs1use once_cell::sync::Lazy;
2use regex::Regex;
3use serde_json::Value;
4
5use crate::ValidationResult;
6
7mod channels_settings;
8mod commands;
9mod common;
10mod dependencies;
11mod hooks;
12mod lsp_servers;
13mod mcp_servers;
14mod metadata;
15mod path_fields;
16mod user_config;
17
18static PLUGIN_NAME_RE: Lazy<Regex> =
19 Lazy::new(|| Regex::new(r"^[a-z0-9][-a-z0-9._]*$").expect("valid plugin name regex"));
20static DEP_STR_RE: Lazy<Regex> = Lazy::new(|| {
21 Regex::new(r"^[a-z0-9][-a-z0-9._]*(?:@[a-z0-9][-a-z0-9._]*)?(?:@\^[^@]*)?$")
22 .expect("valid dependency regex")
23});
24static DEP_NAME_RE: Lazy<Regex> =
25 Lazy::new(|| Regex::new(r"^[a-z0-9][-a-z0-9._]*$").expect("valid dep name regex"));
26static USER_CONFIG_KEY_RE: Lazy<Regex> =
27 Lazy::new(|| Regex::new(r"^[A-Za-z_]\w*$").expect("valid user config key regex"));
28
29pub fn validate_plugin_manifest(input: Value) -> ValidationResult {
30 let mut issues = Vec::new();
31
32 let Some(root) = input.as_object() else {
33 common::push_issue(
34 &mut issues,
35 "",
36 "invalid_type",
37 "Manifest root must be a JSON object",
38 );
39 return ValidationResult::Failure { issues };
40 };
41
42 metadata::validate_required_name(root, &mut issues, &PLUGIN_NAME_RE);
43 metadata::validate_optional_metadata(root, &mut issues);
44 dependencies::validate_dependencies(root, &mut issues, &DEP_STR_RE, &DEP_NAME_RE);
45 hooks::validate_hooks_field(root, &mut issues);
46 commands::validate_commands_field(root, &mut issues);
47 path_fields::validate_agents_skills_output_styles(root, &mut issues);
48 mcp_servers::validate_mcp_servers_field(root, &mut issues);
49 lsp_servers::validate_lsp_servers_field(root, &mut issues);
50 user_config::validate_user_config(root, &mut issues, &USER_CONFIG_KEY_RE);
51 channels_settings::validate_channels(root, &mut issues);
52 channels_settings::validate_settings(root, &mut issues);
53
54 if issues.is_empty() {
55 ValidationResult::Success { data: input }
56 } else {
57 ValidationResult::Failure { issues }
58 }
59}