From 71f4b292b637b2956cd79746fd89695527a2b065 Mon Sep 17 00:00:00 2001 From: Dusan Vystrcil Date: Mon, 23 Mar 2026 11:01:21 +0100 Subject: [PATCH] fix: restore marketplace.json validation and revert .gitignore changes Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/generate-agents.yml | 5 +-- .gitignore | 3 ++ scripts/generate_agents.py | 46 +++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/.github/workflows/generate-agents.yml b/.github/workflows/generate-agents.yml index 0d7cb0c..5530fde 100644 --- a/.github/workflows/generate-agents.yml +++ b/.github/workflows/generate-agents.yml @@ -1,4 +1,4 @@ -name: Check AGENTS.md +name: Check AGENTS.md and marketplace.json on: pull_request: @@ -7,6 +7,7 @@ on: - "scripts/generate_agents.py" - "**/SKILL.md" - "agents/AGENTS.md" + - ".claude-plugin/marketplace.json" jobs: validate: @@ -18,7 +19,7 @@ jobs: - name: Set up uv uses: astral-sh/setup-uv@v4 - - name: Generate AGENTS.md + - name: Generate AGENTS.md and validate marketplace.json run: uv run scripts/generate_agents.py - name: Ensure AGENTS.md is up to date diff --git a/.gitignore b/.gitignore index 9663ddc..2f157f1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,10 @@ # DEVELOPMENT .vscode .claude +context/ +CLAUDE.md PLAN.md PLAN-*.md .mcp.json +scripts/hooks/ .idea diff --git a/scripts/generate_agents.py b/scripts/generate_agents.py index 461ef4f..434c2fe 100644 --- a/scripts/generate_agents.py +++ b/scripts/generate_agents.py @@ -5,19 +5,24 @@ # /// """Generate AGENTS.md from AGENTS_TEMPLATE.md and SKILL.md frontmatter. +Also validates that marketplace.json is in sync with discovered skills. + Usage: uv run scripts/generate_agents.py """ from __future__ import annotations +import json import re +import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent TEMPLATE_PATH = ROOT / "scripts" / "AGENTS_TEMPLATE.md" OUTPUT_PATH = ROOT / "agents" / "AGENTS.md" +MARKETPLACE_PATH = ROOT / ".claude-plugin" / "marketplace.json" def load_template() -> str: @@ -76,6 +81,38 @@ def render(template: str, skills: list[dict[str, str]]) -> str: return content +def validate_marketplace(skills: list[dict[str, str]]) -> list[str]: + """Validate marketplace.json against discovered skills. Returns error messages.""" + if not MARKETPLACE_PATH.exists(): + return [f"marketplace.json not found at {MARKETPLACE_PATH}"] + + marketplace = json.loads(MARKETPLACE_PATH.read_text(encoding="utf-8")) + plugins = marketplace.get("plugins", []) + errors: list[str] = [] + + # Every plugin with skills should have at least one SKILL.md + for plugin in plugins: + source = plugin.get("source", "").lstrip("./") + plugin_skills = [s for s in skills if s["path"].startswith(source)] + if not plugin_skills: + errors.append( + f"Plugin '{plugin['name']}' at '{source}' has no SKILL.md files" + ) + + # Every discovered skill should be covered by a plugin + for skill in skills: + found = any( + skill["path"].startswith(p.get("source", "").lstrip("./")) + for p in plugins + ) + if not found: + errors.append( + f"Skill '{skill['name']}' at '{skill['path']}' is not covered by any plugin" + ) + + return errors + + def main() -> None: template = load_template() skills = collect_skills() @@ -84,6 +121,15 @@ def main() -> None: OUTPUT_PATH.write_text(output, encoding="utf-8") print(f"Wrote {OUTPUT_PATH} with {len(skills)} skills.") + # Validate marketplace.json + errors = validate_marketplace(skills) + if errors: + print("\nMarketplace.json validation errors:", file=sys.stderr) + for error in errors: + print(f" - {error}", file=sys.stderr) + sys.exit(1) + print("Marketplace.json validation passed.") + if __name__ == "__main__": main()