From e8ea0316c4dba7b2d0c65b6f421543729e74d20d Mon Sep 17 00:00:00 2001 From: Dean Rie Date: Wed, 14 Oct 2026 16:10:54 +0300 Subject: [PATCH] validate: fail when a plugin directory is not listed in marketplace.json The validator walked marketplace.json entries only, so a directory with a .cursor-plugin/plugin.json that no entry references (forgotten listing, or a typo in source) passed CI and never reached the marketplace. Walk the repo root and third_party/ for plugin directories and fail for each one that is not a listed source. main has 102 listed and 0 unlisted today, so this is an error from the start. --- scripts/validate-plugins.mjs | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/scripts/validate-plugins.mjs b/scripts/validate-plugins.mjs index 6a7870854..672288211 100644 --- a/scripts/validate-plugins.mjs +++ b/scripts/validate-plugins.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { readFileSync, existsSync } from "fs"; +import { readFileSync, existsSync, readdirSync, statSync } from "fs"; import { resolve, dirname } from "path"; import { fileURLToPath } from "url"; import Ajv from "ajv"; @@ -92,7 +92,35 @@ for (const entry of marketplace.plugins ?? []) { } } -// 3. Report results +// 3. Every plugin directory in the repo must be listed in marketplace.json. +// A directory with a .cursor-plugin/plugin.json that marketplace.json does not +// reference is invisible to the marketplace and to the checks above, so a +// forgotten listing (or a typo in `source`) would otherwise pass silently. +const listedDirs = new Set( + (marketplace.plugins ?? []).map((entry) => resolve(root, entry.source)) +); + +function pluginDirsUnder(dir) { + if (!existsSync(dir)) return []; + return readdirSync(dir) + .filter((name) => !name.startsWith(".")) + .map((name) => resolve(dir, name)) + .filter( + (path) => + statSync(path).isDirectory() && + existsSync(resolve(path, ".cursor-plugin/plugin.json")) + ); +} + +for (const dir of [...pluginDirsUnder(root), ...pluginDirsUnder(resolve(root, "third_party"))]) { + if (!listedDirs.has(dir)) { + fail( + `Unlisted plugin: "${dir.slice(root.length + 1)}" has a .cursor-plugin/plugin.json but no entry in marketplace.json` + ); + } +} + +// 4. Report results if (errors > 0) { console.error(`\nValidation failed with ${errors} error(s).`); process.exit(1);