-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalidate-plugins.sh
More file actions
executable file
·100 lines (88 loc) · 2.74 KB
/
validate-plugins.sh
File metadata and controls
executable file
·100 lines (88 loc) · 2.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#!/bin/bash
# Validate plugin structure against what Claude Code requires
# Run this before pushing to catch structural issues early
PLUGINS_DIR="$(cd "$(dirname "$0")/plugins" && pwd)"
errors=0
warnings=0
red() { printf '\033[0;31m%s\033[0m\n' "$1"; }
yellow() { printf '\033[0;33m%s\033[0m\n' "$1"; }
green() { printf '\033[0;32m%s\033[0m\n' "$1"; }
for plugin_dir in "$PLUGINS_DIR"/*/; do
plugin=$(basename "$plugin_dir")
pjson="$plugin_dir/.claude-plugin/plugin.json"
echo "--- $plugin"
# Check plugin.json exists
if [ ! -f "$pjson" ]; then
yellow " WARN: no .claude-plugin/plugin.json (may be a non-skill plugin)"
warnings=$((warnings + 1))
continue
fi
# Check plugin.json has required fields
for field in name description version; do
val=$(python3 -c "import json; print(json.load(open('$pjson')).get('$field', ''))" 2>/dev/null)
if [ -z "$val" ]; then
red " ERROR: plugin.json missing '$field'"
errors=$((errors + 1))
fi
done
# Check each skill
for skill_md in "$plugin_dir"/skills/*/SKILL.md; do
[ -f "$skill_md" ] || continue
skill_name=$(basename "$(dirname "$skill_md")")
# Check frontmatter has name
fm_name=$(python3 -c "
import re, sys
with open('$skill_md') as f:
text = f.read()
m = re.match(r'^---\n(.*?)\n---', text, re.DOTALL)
if not m:
sys.exit(0)
for line in m.group(1).split('\n'):
if line.startswith('name:'):
print(line.split(':', 1)[1].strip())
break
")
if [ -z "$fm_name" ]; then
red " ERROR: skills/$skill_name/SKILL.md frontmatter missing 'name'"
errors=$((errors + 1))
fi
# Check frontmatter has description
fm_desc=$(python3 -c "
import re, sys
with open('$skill_md') as f:
text = f.read()
m = re.match(r'^---\n(.*?)\n---', text, re.DOTALL)
if not m:
sys.exit(0)
for line in m.group(1).split('\n'):
if line.startswith('description:'):
print('yes')
break
")
if [ -z "$fm_desc" ]; then
red " ERROR: skills/$skill_name/SKILL.md frontmatter missing 'description'"
errors=$((errors + 1))
fi
# Check frontmatter exists at all
has_fm=$(head -1 "$skill_md")
if [ "$has_fm" != "---" ]; then
red " ERROR: skills/$skill_name/SKILL.md has no frontmatter"
errors=$((errors + 1))
fi
done
# Check at least one skill exists
skill_count=$(find "$plugin_dir/skills" -name "SKILL.md" 2>/dev/null | wc -l | tr -d ' ')
if [ "$skill_count" = "0" ] && [ -f "$pjson" ]; then
yellow " WARN: plugin has plugin.json but no skills"
warnings=$((warnings + 1))
fi
done
echo ""
echo "==============================="
if [ $errors -gt 0 ]; then
red "$errors error(s), $warnings warning(s)"
exit 1
else
green "All plugins valid. $warnings warning(s)."
exit 0
fi