diff --git a/scripts/validate-plugins.mjs b/scripts/validate-plugins.mjs index fda6c1361..eafc9c39a 100644 --- a/scripts/validate-plugins.mjs +++ b/scripts/validate-plugins.mjs @@ -31,6 +31,21 @@ function fail(message) { errors++; } +// The schema allows `source` to be a remote URL. Nothing here fetches it, so +// report the skip instead of resolving it as a path (which turns "https://x" +// into "/https:/x" and reports a missing directory). +function isRemoteSource(source) { + return typeof source === "string" && /^https?:\/\//i.test(source); +} + +function skipRemoteSource(entry) { + if (!isRemoteSource(entry.source)) return false; + console.log( + `INFO: Plugin "${entry.name}": remote source "${entry.source}" is not validated locally` + ); + return true; +} + // 1. Validate marketplace.json const marketplacePath = resolve(root, ".cursor-plugin/marketplace.json"); @@ -50,6 +65,8 @@ if (!validateMarketplace(marketplace)) { // 2. Validate each plugin for (const entry of marketplace.plugins ?? []) { + if (skipRemoteSource(entry)) continue; + const pluginDir = resolve(root, entry.source); const pluginJsonPath = resolve(pluginDir, ".cursor-plugin/plugin.json"); @@ -98,6 +115,8 @@ const claudeMarketplace = existsSync(claudeMarketplacePath) : { plugins: [] }; for (const entry of claudeMarketplace.plugins ?? []) { + if (skipRemoteSource(entry)) continue; + const pluginDir = resolve(root, entry.source); const pluginJsonPath = resolve(pluginDir, ".claude-plugin/plugin.json"); @@ -126,6 +145,7 @@ for (const entry of [ ...(marketplace.plugins ?? []), ...(claudeMarketplace.plugins ?? []), ]) { + if (isRemoteSource(entry.source)) continue; sources.set(resolve(root, entry.source), entry.name); }