From 8d47e67595131ca7fe2db7220bbaebac5c5c8c4e Mon Sep 17 00:00:00 2001 From: KDR Date: Thu, 20 Aug 2026 17:19:05 -0700 Subject: [PATCH] ci: fail when plugin/marketplace/skill versions drift from package.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `.claude-plugin/plugin.json` and `.claude-plugin/marketplace.json` sat at 0.3.19 through both the 0.3.20 and 0.3.21 releases because nothing checked them — the drift was only caught by hand during the 0.3.22 release. The existing plugin-metadata job validated that these files parse, not that their versions mean anything. Adds two steps to that job: - Plugin + marketplace versions match package.json — covers plugin.json's version, marketplace.json's metadata.version, and every plugins[].version entry. The npm package version is the release version, so all of them must equal it. Prints a per-field ok/DRIFT table so a failure names the offending file immediately. - Skill manifest version matches package.json — pins tinycloud-skill.json's skill_version. Deliberately only skill_version: min_version/supported_range are the compatibility FLOOR, already diffed against preflight.sh by the next step, and may legitimately sit below the release version on a no-raise release (0.3.13 and 0.3.19 both did). Verified both directions locally: passes on the current tree (all four version fields 0.3.22), and re-injecting the exact historical drift (plugin.json → 0.3.19) fails with "Version drift against package.json (0.3.22): {'.claude-plugin/plugin.json': '0.3.19'}" and exit 1. --- .github/workflows/ci.yml | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a855ae..ccbc5ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,6 +47,50 @@ jobs: json.load(open(p)) print("OK", p) EOF + - name: Plugin + marketplace versions match package.json + # These three drifted apart once: plugin.json and marketplace.json sat + # at 0.3.19 through the 0.3.20 and 0.3.21 releases because nothing + # checked them. The npm package version is the release version, so + # every version field in the plugin metadata must equal it. + run: | + python3 - <<'EOF' + import json, sys + pkg = json.load(open("package.json"))["version"] + plugin = json.load(open(".claude-plugin/plugin.json"))["version"] + mkt = json.load(open(".claude-plugin/marketplace.json")) + found = { + "package.json": pkg, + ".claude-plugin/plugin.json": plugin, + ".claude-plugin/marketplace.json metadata.version": mkt["metadata"]["version"], + } + for entry in mkt["plugins"]: + found[f'.claude-plugin/marketplace.json plugins[{entry["name"]}].version'] = entry["version"] + bad = {k: v for k, v in found.items() if v != pkg} + for k, v in found.items(): + print(f'{"ok " if v == pkg else "DRIFT"} {k} = {v}') + if bad: + print(f"\nVersion drift against package.json ({pkg}): {bad}", file=sys.stderr) + sys.exit(1) + print(f"\nAll plugin metadata versions match package.json ({pkg}).") + EOF + + - name: Skill manifest version matches package.json + # tinycloud-skill.json's skill_version tracks the release too (the + # floor fields min_version/supported_range are checked separately + # against preflight.sh, and may legitimately sit below on a no-raise + # release -- so only skill_version is pinned here). + run: | + python3 - <<'EOF' + import json, sys + pkg = json.load(open("package.json"))["version"] + skill = json.load(open("skills/tinycloud/tinycloud-skill.json"))["skill_version"] + print(f"package.json={pkg} tinycloud-skill.json skill_version={skill}") + if skill != pkg: + print(f"skill_version {skill} != package.json {pkg}", file=sys.stderr) + sys.exit(1) + print("ok") + EOF + - name: Preflight requirements match tinycloud-skill.json run: | python3 - <<'EOF'