diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 64140781..3b94eac0 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -27,7 +27,7 @@ "plugin", "marketplace" ], - "source": "." + "source": "./" } ] } diff --git a/.github/MAINTENANCE.md b/.github/MAINTENANCE.md index 886e0032..5f70613a 100644 --- a/.github/MAINTENANCE.md +++ b/.github/MAINTENANCE.md @@ -106,6 +106,34 @@ Before ANY commit that adds/modifies skills, run the chain: - **If the PR has merge conflicts:** Resolve them **on the PR branch** (you or the contributor: merge `main` into the PR branch, fix conflicts, drop derived registry files from the branch if they appear, push). For generated registry files, prefer keeping `main`'s side rather than hand-editing conflicts. Then use **"Squash and merge"** on GitHub. Full steps: [docs/maintainers/merging-prs.md](../docs/maintainers/merging-prs.md). - **Rare exception:** Only if merging via GitHub is not possible, you may integrate locally and close the PR; in that case you **must** add a Co-authored-by line to the commit and explain in a comment. Prefer to avoid this so PRs are always **Merged**. +**If CI is blocked on fork approval or stale PR metadata:** + +This happens regularly on community PRs from forks. The common symptoms are: + +- `gh pr checks` shows `no checks reported` even though Actions runs exist. +- `gh run list` shows `action_required` with `jobs: []` for `Skills Registry CI` or `Skill Review`. +- `pr-policy` fails with `PR body must include the Quality Bar Checklist from the template.` even after you corrected the PR body and hit rerun. + +Use this playbook: + +1. **Approve waiting fork runs** using the run id(s) from `gh run list`: + ```bash + gh api -X POST repos///actions/runs//approve + ``` +2. **Normalize the PR body** so it includes the repository template's `## Quality Bar Checklist ✅` section. If `gh pr edit` works, use it. If `gh pr edit` fails with the GraphQL `projectCards` / Projects Classic deprecation error, patch the PR body through the REST API instead: + ```bash + gh api repos///pulls/ -X PATCH --input <(jq -n --rawfile body /tmp/pr_body.md '{body:$body}') + ``` +3. **Do not trust a plain rerun** to pick up the updated PR body. In practice, `gh run rerun ` may re-use the original `pull_request` event payload, so `pr-policy` can keep reading the stale body and fail again. +4. **If the rerun still sees stale metadata, close and reopen the PR** to force a fresh `pull_request` event: + ```bash + gh pr close --comment "Maintainer workflow refresh: closing and reopening to retrigger pull_request checks against the updated PR body." + gh pr reopen + ``` +5. **Approve the newly created fork runs** after reopen. They will usually appear as a fresh pair of `action_required` runs for `Skills Registry CI` and `Skill Review`. +6. **Wait for the new checks only.** You may see older failed `pr-policy` runs in the rollup alongside newer green runs. Merge only after the fresh run set for the current PR state is fully green: `pr-policy`, `source-validation`, `artifact-preview`, and `review` when `SKILL.md` changed. +7. **If `gh pr merge` says `Base branch was modified`**, refresh the PR state and retry. This is normal when you are merging a batch and `main` moved between attempts. + **If a PR was closed after local integration (reopen and merge):** If a PR was integrated via local squash and then **closed** (so it shows "Closed" instead of "Merged"), you can still give the contributor credit by reopening it and merging it on GitHub. The merge can be effectively "empty" (no new diff vs `main`); what matters is that the PR ends up **Merged**. diff --git a/tools/scripts/tests/claude_plugin_marketplace.test.js b/tools/scripts/tests/claude_plugin_marketplace.test.js new file mode 100644 index 00000000..8ae90b2d --- /dev/null +++ b/tools/scripts/tests/claude_plugin_marketplace.test.js @@ -0,0 +1,25 @@ +const assert = require("assert"); +const fs = require("fs"); +const path = require("path"); +const { findProjectRoot } = require("../../lib/project-root"); + +const projectRoot = findProjectRoot(__dirname); +const marketplacePath = path.join(projectRoot, ".claude-plugin", "marketplace.json"); +const marketplace = JSON.parse(fs.readFileSync(marketplacePath, "utf8")); + +assert.ok(Array.isArray(marketplace.plugins), "marketplace.json must define a plugins array"); +assert.ok(marketplace.plugins.length > 0, "marketplace.json must contain at least one plugin"); + +for (const plugin of marketplace.plugins) { + assert.strictEqual( + typeof plugin.source, + "string", + `plugin ${plugin.name || ""} must define source as a string`, + ); + assert.ok( + plugin.source.startsWith("./"), + `plugin ${plugin.name || ""} source must be a relative path starting with ./`, + ); +} + +console.log("ok"); diff --git a/tools/scripts/tests/run-test-suite.js b/tools/scripts/tests/run-test-suite.js index ce3ca56c..cb883c4b 100644 --- a/tools/scripts/tests/run-test-suite.js +++ b/tools/scripts/tests/run-test-suite.js @@ -8,6 +8,7 @@ const ENABLED_VALUES = new Set(["1", "true", "yes", "on"]); const TOOL_SCRIPTS = path.join("tools", "scripts"); const TOOL_TESTS = path.join(TOOL_SCRIPTS, "tests"); const LOCAL_TEST_COMMANDS = [ + [path.join(TOOL_TESTS, "claude_plugin_marketplace.test.js")], [path.join(TOOL_TESTS, "jetski_gemini_loader.test.js")], [path.join(TOOL_TESTS, "npm_package_contents.test.js")], [path.join(TOOL_TESTS, "validate_skills_headings.test.js")], diff --git a/walkthrough.md b/walkthrough.md index 57587e00..b8bd8896 100644 --- a/walkthrough.md +++ b/walkthrough.md @@ -1,3 +1,12 @@ +# Maintenance Walkthrough - 2026-03-18 + +- Fixed issue `#344` by correcting `.claude-plugin/marketplace.json` so the marketplace plugin entry uses `source: "./"` instead of `"."`, matching Claude Code's relative-path schema requirement for marketplace entries. +- Added `tools/scripts/tests/claude_plugin_marketplace.test.js` and wired it into the local test suite so invalid marketplace `source` paths fail fast in CI/maintainer verification. +- Merged PRs `#333`, `#336`, `#338`, `#343`, `#340`, and `#334` via GitHub squash merge after maintainer refresh of forked workflows and PR metadata. +- Closed PR `#337` and PR `#342` as superseded by `#338`, then closed issue `#339` manually after confirming the accepted fix path; issue `#335` auto-closed from the merged PR body. +- Left issue `#344` open with a triage comment, and left PR `#341` open with a blocking review comment because the submitted skill content is corrupted even though CI is green. +- Documented a new maintainer edge case in `.github/MAINTENANCE.md`: forked runs in `action_required`, `pr-policy` failures caused by stale PR bodies, the REST API fallback when `gh pr edit` fails with the Projects Classic GraphQL error, and the need to `close`/`reopen` a PR when a plain rerun does not pick up updated metadata. + # Maintenance Walkthrough - 2026-03-17 - Synced `main` after the six merged community PRs and re-verified all forked PR workflows through GitHub before final release prep.