Skip to content

chore(claude-plugin): update marketplace.json source field #7

chore(claude-plugin): update marketplace.json source field

chore(claude-plugin): update marketplace.json source field #7

Workflow file for this run

name: Validate Skill
on:
pull_request:
paths:
- 'SKILL.md'
- 'references/**/*.md'
- '.claude-plugin/**'
push:
branches: [master, main]
paths:
- 'SKILL.md'
- 'references/**/*.md'
- '.claude-plugin/**'
workflow_dispatch:
jobs:
validate:
name: Validate Skill Files
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install Dependencies
run: pip install pyyaml
- name: Check SKILL.md Frontmatter
run: |
python3 << 'EOF'
import yaml
import sys
import re
print("🔍 Validating SKILL.md frontmatter...")
with open('SKILL.md', 'r') as f:
content = f.read()
if not content.startswith('---'):
print("❌ ERROR: No frontmatter found")
sys.exit(1)
parts = content.split('---', 2)
if len(parts) < 3:
print("❌ ERROR: Invalid frontmatter format")
sys.exit(1)
frontmatter = yaml.safe_load(parts[1])
if 'name' not in frontmatter or 'description' not in frontmatter:
print("❌ ERROR: Missing required fields")
sys.exit(1)
allowed = {'name', 'description'}
extra = set(frontmatter.keys()) - allowed
if extra:
print(f"❌ ERROR: Extra fields: {extra}")
print(" Only 'name' and 'description' allowed")
sys.exit(1)
name = frontmatter['name']
if not re.match(r'^[a-zA-Z0-9-]+$', name):
print(f"❌ ERROR: Invalid name: {name}")
sys.exit(1)
desc_len = len(frontmatter['description'])
if desc_len > 1024:
print(f"❌ ERROR: Description too long: {desc_len} chars")
sys.exit(1)
print(f"✅ Frontmatter valid ({desc_len} chars)")
EOF
- name: Check File Size
run: |
LINES=$(wc -l < SKILL.md)
WORDS=$(wc -w < SKILL.md)
echo "📊 SKILL.md: $LINES lines, $WORDS words"
if [ $LINES -gt 500 ]; then
echo "⚠️ WARNING: $LINES lines (guideline: <500)"
else
echo "✅ Size OK"
fi
- name: Validate marketplace.json
run: |
python3 << 'EOF'
import json
import sys
import re
print("🔍 Validating marketplace.json...")
with open('.claude-plugin/marketplace.json', 'r') as f:
marketplace = json.load(f)
# Validate marketplace-level fields
required_marketplace = ['name', 'owner', 'version', 'plugins']
missing = [f for f in required_marketplace if f not in marketplace]
if missing:
print(f"❌ ERROR: Missing marketplace fields: {missing}")
sys.exit(1)
# Validate owner structure
if 'name' not in marketplace['owner'] or 'email' not in marketplace['owner']:
print("❌ ERROR: owner must have 'name' and 'email'")
sys.exit(1)
# Validate version format
version = marketplace['version']
if not re.match(r'^\d+\.\d+\.\d+$', version):
print(f"❌ ERROR: Invalid marketplace version: {version}")
sys.exit(1)
# Validate plugins array
if not isinstance(marketplace['plugins'], list) or len(marketplace['plugins']) == 0:
print("❌ ERROR: 'plugins' must be a non-empty array")
sys.exit(1)
# Validate each plugin
for idx, plugin in enumerate(marketplace['plugins']):
required_plugin = ['name', 'version', 'description', 'source']
missing = [f for f in required_plugin if f not in plugin]
if missing:
print(f"❌ ERROR: Plugin {idx} missing fields: {missing}")
sys.exit(1)
# Validate plugin version
plugin_version = plugin['version']
if not re.match(r'^\d+\.\d+\.\d+$', plugin_version):
print(f"❌ ERROR: Invalid plugin version: {plugin_version}")
sys.exit(1)
# Validate source structure
source = plugin['source']
if 'type' not in source:
print(f"❌ ERROR: Plugin {idx} source missing 'type'")
sys.exit(1)
source_type = source['type']
if source_type == 'github':
if 'repo' not in source or 'ref' not in source:
print(f"❌ ERROR: GitHub source must have 'repo' and 'ref'")
sys.exit(1)
# Validate repo format (owner/repo)
if not re.match(r'^[^/]+/[^/]+$', source['repo']):
print(f"❌ ERROR: Invalid repo format: {source['repo']}")
sys.exit(1)
elif source_type == 'local':
if 'path' not in source:
print(f"❌ ERROR: Local source must have 'path'")
sys.exit(1)
else:
print(f"❌ ERROR: Unsupported source type: {source_type}")
sys.exit(1)
# Validate version sync
if plugin_version != version:
print(f"⚠️ WARNING: Plugin version {plugin_version} != marketplace version {version}")
# Validate ref sync (if github source)
if source_type == 'github':
expected_ref = f"v{version}"
if source['ref'] != expected_ref:
print(f"⚠️ WARNING: Source ref {source['ref']} != expected {expected_ref}")
print(f"✅ marketplace.json valid (v{version}, {len(marketplace['plugins'])} plugin(s))")
EOF
- name: Check for Broken Links
run: |
echo "🔍 Checking internal links..."
if grep -oP '\[.*?\]\(references/.*?\.md.*?\)' SKILL.md references/*.md 2>/dev/null | \
sed 's/.*(//' | sed 's/).*//' | sed 's/#.*//' | \
while read -r link; do
if [ ! -f "$link" ]; then
echo "❌ ERROR: Broken link: $link"
exit 1
fi
done
then
echo "✅ No broken links"
fi
- name: Lint Markdown
uses: DavidAnson/markdownlint-cli2-action@v16
with:
globs: |
SKILL.md
references/**/*.md
README.md
CONTRIBUTING.md
continue-on-error: true
- name: Summary
if: success()
run: |
echo "## ✅ Validation Passed" >> $GITHUB_STEP_SUMMARY
echo "All skill validation checks passed." >> $GITHUB_STEP_SUMMARY