diff --git a/.cursor/skills/verify-marketplace/SKILL.md b/.cursor/skills/verify-marketplace/SKILL.md index cd170ee..c155f55 100644 --- a/.cursor/skills/verify-marketplace/SKILL.md +++ b/.cursor/skills/verify-marketplace/SKILL.md @@ -2,16 +2,16 @@ name: verify-marketplace description: >- Drive the duyet/codex-claude-plugins marketplace pack via control-marketplace: - marketplace JSON, Claude/Codex/Antigravity manifests, and documented install - paths. Use when verifying plugin catalog changes, install docs, or - scripts/validate-plugins.sh. There is no hosted web UI. + marketplace JSON, Claude/Codex/Antigravity/Grok manifests, local plugin logos, + and documented install paths. Use when verifying plugin catalog changes, + install docs, or scripts/validate-plugins.sh. There is no hosted web UI. --- # Verify marketplace Drive this checkout as a **plugin marketplace pack**, not a web app. Users add a -marketplace and install plugins in Claude Code or Codex. The lever is -`control-marketplace.mjs`. `--help` is canonical. +marketplace and install plugins in Claude Code, Codex, Grok Build, or Grok Bot. +The lever is `control-marketplace.mjs`. `--help` is canonical. ```bash node .cursor/skills/verify-marketplace/control-marketplace.mjs --help @@ -21,16 +21,19 @@ node .cursor/skills/verify-marketplace/control-marketplace.mjs --help - **Primary:** catalogs and manifests on disk (`marketplace.json`, `.claude-plugin/marketplace.json`, - `.agents/plugins/marketplace.json`, per-plugin `.claude-plugin/plugin.json` - and `.codex-plugin/plugin.json`). + `.agents/plugins/marketplace.json`, `.grok-plugin/marketplace.json`, + per-plugin `.claude-plugin/plugin.json`, `.codex-plugin/plugin.json`, + `.grok-plugin/plugin.json`, and `.grok-build-plugin/plugin.json`). - **Install docs:** root `README.md`, `CLAUDE.md`, `CONTRIBUTING.md`. +- **Logos:** each plugin's `assets/logo.svg`, plus marketplace `logo` paths + relative to the plugin source directory. - **Existing harness:** `bash scripts/validate-plugins.sh` (same script CI runs). - **Also present:** `scripts/install-antigravity.sh` for the one plugin that ships `.antigravity-plugin/plugin.json`. -- **Not present:** hosted UI, Grok Build catalog, Grok Bot pack. Do not open a - browser against this repo. Do not invent a Grok driver; use - `check-install --surface grok` which is an expected skip. +- **Not present:** hosted UI. Do not open a browser against this repo. Drive + Grok Build and Grok Bot with `check-install --surface grok`. Skip is a + failure. ## Launch @@ -53,11 +56,12 @@ node .cursor/skills/verify-marketplace/control-marketplace.mjs doctor node .cursor/skills/verify-marketplace/control-marketplace.mjs doctor --json ``` -Doctor answers "is this instance worth driving?": marketplace JSON parses, -`scripts/validate-plugins.sh` exists, plugin directories are visible, python3 -works. Catalog drift (for example a plugin missing from the Codex marketplace) -is **not** a doctor failure; `validate` and `check-install --surface codex` -report that. +Doctor answers "is this instance worth driving?": marketplace JSON parses +(including `.grok-plugin/marketplace.json`), `scripts/validate-plugins.sh` +exists, plugin directories are visible, python3 works. Catalog drift (for +example a plugin missing from the Codex or Grok marketplace) is **not** a +doctor failure; `validate` and `check-install --surface codex|grok` report +that. ## Drive @@ -80,6 +84,9 @@ node .cursor/skills/verify-marketplace/control-marketplace.mjs check-install --s node .cursor/skills/verify-marketplace/control-marketplace.mjs check-install --surface codex --json node .cursor/skills/verify-marketplace/control-marketplace.mjs check-install --surface grok --json +# Grok Bot + Grok Build proven drive (skip is a failure) +node .cursor/skills/verify-marketplace/control-marketplace.mjs prove --feature grok-build-and-bot --json + # destructive Antigravity symlink plan only node .cursor/skills/verify-marketplace/control-marketplace.mjs install-antigravity --dry-run --json ``` @@ -109,6 +116,7 @@ Record a drive: ```bash node .cursor/skills/verify-marketplace/control-marketplace.mjs prove --feature marketplace-catalog --json +node .cursor/skills/verify-marketplace/control-marketplace.mjs prove --feature grok-build-and-bot --json ``` ## Cleanup diff --git a/.cursor/skills/verify-marketplace/control-marketplace.mjs b/.cursor/skills/verify-marketplace/control-marketplace.mjs index 77bb139..0b7f8e1 100755 --- a/.cursor/skills/verify-marketplace/control-marketplace.mjs +++ b/.cursor/skills/verify-marketplace/control-marketplace.mjs @@ -1,9 +1,4 @@ #!/usr/bin/env node -/** - * Drive the duyet/codex-claude-plugins marketplace pack. - * There is no hosted web UI; the user-facing product is plugin catalogs, - * manifests, and documented install paths for Claude Code and Codex. - */ import { spawnSync } from "node:child_process"; import fs from "node:fs"; @@ -21,6 +16,7 @@ const MARKETPLACE_FILES = { root: "marketplace.json", claude: path.join(".claude-plugin", "marketplace.json"), codex: path.join(".agents", "plugins", "marketplace.json"), + grok: path.join(".grok-plugin", "marketplace.json"), }; const CLAUDE_INSTALL_NEEDLES = [ @@ -59,6 +55,34 @@ const CODEX_INSTALL_NEEDLES = [ }, ]; +const GROK_INSTALL_NEEDLES = [ + { + id: "readme-grok-marketplace-add", + file: "README.md", + needle: "grok plugin marketplace add duyet/codex-claude-plugins", + }, + { + id: "readme-grok-plugin-install", + file: "README.md", + needle: "grok plugin install ", + }, + { + id: "readme-grok-marketplace-file", + file: "README.md", + needle: ".grok-plugin/marketplace.json", + }, + { + id: "readme-grok-logo", + file: "README.md", + needle: "assets/logo.svg", + }, + { + id: "contributing-grok-marketplace", + file: "CONTRIBUTING.md", + needle: ".grok-plugin/marketplace.json", + }, +]; + const DOCS_NEEDLES = [ { id: "contributing-validate", @@ -80,6 +104,21 @@ const DOCS_NEEDLES = [ file: "CLAUDE.md", needle: ".codex-plugin/plugin.json", }, + { + id: "claude-md-grok-manifest", + file: "CLAUDE.md", + needle: ".grok-plugin/plugin.json", + }, + { + id: "claude-md-grok-build-manifest", + file: "CLAUDE.md", + needle: ".grok-build-plugin/plugin.json", + }, + { + id: "claude-md-grok-marketplace", + file: "CLAUDE.md", + needle: ".grok-plugin/marketplace.json", + }, ]; const COMMANDS = [ @@ -103,7 +142,7 @@ function main(argv) { writeOutput(parsed, { ok: true, command: "version", - version: "1.0.0", + version: "1.1.0", skill: "verify-marketplace", }); return OK_EXIT; @@ -197,7 +236,10 @@ function parseArgs(argv) { "force", "missingReadme", "missingCodex", + "missingGrok", "hasAntigravity", + "hasGrok", + "hasGrokBuild", ]); if (booleanFlags.has(key)) { flags[key] = true; @@ -297,7 +339,19 @@ function pluginDirectories(repoRoot) { .filter((name) => { const claude = path.join(repoRoot, name, ".claude-plugin", "plugin.json"); const codex = path.join(repoRoot, name, ".codex-plugin", "plugin.json"); - return fs.existsSync(claude) || fs.existsSync(codex); + const grok = path.join(repoRoot, name, ".grok-plugin", "plugin.json"); + const grokBuild = path.join( + repoRoot, + name, + ".grok-build-plugin", + "plugin.json", + ); + return ( + fs.existsSync(claude) || + fs.existsSync(codex) || + fs.existsSync(grok) || + fs.existsSync(grokBuild) + ); }) .sort(); } @@ -307,27 +361,47 @@ function pluginRecord(repoRoot, name) { const claudePath = path.join(dir, ".claude-plugin", "plugin.json"); const codexPath = path.join(dir, ".codex-plugin", "plugin.json"); const antigravityPath = path.join(dir, ".antigravity-plugin", "plugin.json"); + const grokPath = path.join(dir, ".grok-plugin", "plugin.json"); + const grokBuildPath = path.join(dir, ".grok-build-plugin", "plugin.json"); const claude = fs.existsSync(claudePath) ? loadJson(claudePath) : null; const codex = fs.existsSync(codexPath) ? loadJson(codexPath) : null; const antigravity = fs.existsSync(antigravityPath) ? loadJson(antigravityPath) : null; + const grok = fs.existsSync(grokPath) ? loadJson(grokPath) : null; + const grokBuild = fs.existsSync(grokBuildPath) + ? loadJson(grokBuildPath) + : null; const readme = fs.existsSync(path.join(dir, "README.md")); const claudeMd = fs.existsSync(path.join(dir, "CLAUDE.md")); return { name, dir, - version: claude?.version ?? codex?.version ?? null, - description: claude?.description ?? codex?.description ?? null, + version: + claude?.version ?? + codex?.version ?? + grok?.version ?? + grokBuild?.version ?? + null, + description: + claude?.description ?? + codex?.description ?? + grok?.description ?? + grokBuild?.description ?? + null, claude: Boolean(claude), codex: Boolean(codex), antigravity: Boolean(antigravity), + grok: Boolean(grok), + grokBuild: Boolean(grokBuild), readme, claudeMd, manifests: { claude: claude ? rel(repoRoot, claudePath) : null, codex: codex ? rel(repoRoot, codexPath) : null, antigravity: antigravity ? rel(repoRoot, antigravityPath) : null, + grok: grok ? rel(repoRoot, grokPath) : null, + grokBuild: grokBuild ? rel(repoRoot, grokBuildPath) : null, }, }; } @@ -337,6 +411,54 @@ function marketplaceNames(data) { return plugins.map((plugin) => plugin?.name).filter(Boolean); } +function grokSource(plugin) { + const source = plugin?.source; + if (typeof source === "string" && source.startsWith("./")) { + return { ok: true, path: source }; + } + if (source && typeof source === "object") { + const pathValue = source.path; + const local = source.type === "local" || source.source === "local"; + return { + ok: + local && + typeof pathValue === "string" && + pathValue.startsWith("./"), + path: typeof pathValue === "string" ? pathValue : null, + }; + } + return { ok: false, path: null }; +} + +function grokLogoCheck(repoRoot, plugin) { + const name = plugin?.name ?? "unknown"; + const logo = plugin?.logo; + const source = grokSource(plugin); + if (typeof logo !== "string" || !logo.trim()) { + return { + ok: false, + detail: `${name}: Grok marketplace logo missing`, + }; + } + if (logo.startsWith("http://") || logo.startsWith("https://")) { + return { ok: true, detail: `${name} remote logo ${logo}` }; + } + if (!source.path) { + return { + ok: false, + detail: `${name}: Grok logo ${JSON.stringify(logo)} has no source path`, + }; + } + const filePath = path.normalize(path.join(repoRoot, source.path, logo)); + const exists = fs.existsSync(filePath) && fs.statSync(filePath).isFile(); + return { + ok: exists, + detail: exists + ? `${name} logo ${rel(repoRoot, filePath)}` + : `${name}: Grok logo missing: ${JSON.stringify(logo)}`, + }; +} + function rel(repoRoot, filePath) { return path.relative(repoRoot, filePath) || "."; } @@ -410,7 +532,7 @@ function runDoctor(parsed) { checks.push({ id: "plugin-dirs", ok: plugins.length > 0, - detail: `${plugins.length} plugin directories with Claude or Codex manifests`, + detail: `${plugins.length} plugin directories with Claude, Codex, or Grok manifests`, }); const skillCli = path.join(SKILL_DIR, "control-marketplace.mjs"); checks.push({ @@ -439,7 +561,11 @@ function runInfo(parsed) { pluginRecord(repoRoot, name), ); const payload = { - ok: marketplaces.root.ok && marketplaces.claude.ok && marketplaces.codex.ok, + ok: + marketplaces.root.ok && + marketplaces.claude.ok && + marketplaces.codex.ok && + marketplaces.grok.ok, command: "info", repoRoot, marketplaceName: marketplaces.root.value?.name ?? null, @@ -448,6 +574,9 @@ function runInfo(parsed) { rootMarketplace: marketplaces.root.names.length, claudeMarketplace: marketplaces.claude.names.length, codexMarketplace: marketplaces.codex.names.length, + grokMarketplace: marketplaces.grok.names.length, + grok: plugins.filter((plugin) => plugin.grok).length, + grokBuild: plugins.filter((plugin) => plugin.grokBuild).length, antigravity: plugins.filter((plugin) => plugin.antigravity).length, missingReadme: plugins.filter((plugin) => !plugin.readme).length, }, @@ -455,8 +584,9 @@ function runInfo(parsed) { claudeCode: true, codex: true, antigravity: plugins.some((plugin) => plugin.antigravity), - grokBuild: false, - grokBot: false, + grokBuild: + marketplaces.grok.ok && plugins.some((plugin) => plugin.grokBuild), + grokBot: marketplaces.grok.ok && plugins.some((plugin) => plugin.grok), }, gaps: { missingFromCodex: sortedDiff( @@ -467,6 +597,14 @@ function runInfo(parsed) { marketplaces.codex.names, plugins.map((plugin) => plugin.name), ), + missingFromGrok: sortedDiff( + plugins.map((plugin) => plugin.name), + marketplaces.grok.names, + ), + extraInGrok: sortedDiff( + marketplaces.grok.names, + plugins.map((plugin) => plugin.name), + ), }, hostedUi: false, }; @@ -485,9 +623,18 @@ function runList(parsed) { if (parsed.flags.missingCodex) { plugins = plugins.filter((plugin) => !plugin.codex); } + if (parsed.flags.missingGrok) { + plugins = plugins.filter((plugin) => !plugin.grok || !plugin.grokBuild); + } if (parsed.flags.hasAntigravity) { plugins = plugins.filter((plugin) => plugin.antigravity); } + if (parsed.flags.hasGrok) { + plugins = plugins.filter((plugin) => plugin.grok); + } + if (parsed.flags.hasGrokBuild) { + plugins = plugins.filter((plugin) => plugin.grokBuild); + } const payload = { ok: true, command: "list", @@ -572,6 +719,7 @@ function runCheckDocs(parsed) { for (const spec of [ ...CLAUDE_INSTALL_NEEDLES, ...CODEX_INSTALL_NEEDLES, + ...GROK_INSTALL_NEEDLES, ...DOCS_NEEDLES, ]) { const found = fileContains(repoRoot, spec.file, spec.needle); @@ -719,31 +867,76 @@ function runCheckInstall(parsed) { } if (want("grok")) { - const grokMarkers = [ - ".grok-plugin/marketplace.json", - ".grok/plugins/marketplace.json", - "grok-marketplace.json", - ]; - const found = grokMarkers.filter((relative) => - fs.existsSync(path.join(repoRoot, relative)), - ); + checks.push({ + id: "grok-marketplace-parses", + ok: marketplaces.grok.ok, + detail: marketplaces.grok.ok + ? MARKETPLACE_FILES.grok + : marketplaces.grok.error, + }); + const records = plugins.map((name) => pluginRecord(repoRoot, name)); + const missingGrokBot = records + .filter((plugin) => !plugin.grok) + .map((plugin) => plugin.name); + const missingGrokBuild = records + .filter((plugin) => !plugin.grokBuild) + .map((plugin) => plugin.name); + checks.push({ + id: "grok-bot", + ok: marketplaces.grok.ok && missingGrokBot.length === 0, + available: marketplaces.grok.ok, + detail: + marketplaces.grok.ok && missingGrokBot.length === 0 + ? `${MARKETPLACE_FILES.grok} and .grok-plugin/plugin.json on every plugin` + : `Grok Bot missing: marketplaceOk=${marketplaces.grok.ok} missingManifests=${JSON.stringify(missingGrokBot)}`, + }); checks.push({ id: "grok-build", - ok: true, - severity: "skip", + ok: missingGrokBuild.length === 0, + available: missingGrokBuild.length === 0, detail: - found.length === 0 - ? "no Grok Build marketplace file in-tree; do not invent a driver" - : `unexpected Grok markers: ${found.join(", ")}`, - available: found.length > 0, + missingGrokBuild.length === 0 + ? ".grok-build-plugin/plugin.json on every plugin" + : `missing Grok Build manifests: ${JSON.stringify(missingGrokBuild)}`, }); + const missingFromGrok = sortedDiff(plugins, marketplaces.grok.names); + const extraInGrok = sortedDiff(marketplaces.grok.names, plugins); checks.push({ - id: "grok-bot", - ok: true, - severity: "skip", - detail: "no Grok Bot pack surface in-tree; leave room in the feature map", - available: false, + id: "grok-marketplace-names", + ok: missingFromGrok.length === 0 && extraInGrok.length === 0, + detail: + missingFromGrok.length === 0 && extraInGrok.length === 0 + ? "Grok marketplace names match plugin directories" + : `missingFromGrok=${JSON.stringify(missingFromGrok)} extraInGrok=${JSON.stringify(extraInGrok)}`, + missingFromGrok, + extraInGrok, }); + const grokPlugins = marketplaces.grok.value?.plugins ?? []; + for (const plugin of grokPlugins) { + const source = grokSource(plugin); + const absSource = + source.path && source.path.startsWith("./") + ? path.join(repoRoot, source.path) + : null; + const sourceOk = source.ok && Boolean(absSource) && fs.existsSync(absSource); + checks.push({ + id: `grok-source-${plugin?.name ?? "unknown"}`, + ok: sourceOk, + detail: sourceOk + ? `${plugin.name} source ${source.path}` + : `${plugin?.name}: Grok source missing or invalid: ${JSON.stringify(plugin?.source)}`, + }); + const logo = grokLogoCheck(repoRoot, plugin); + checks.push({ + id: `grok-logo-${plugin?.name ?? "unknown"}`, + ok: logo.ok, + detail: logo.detail, + }); + } + for (const spec of GROK_INSTALL_NEEDLES) { + const found = fileContains(repoRoot, spec.file, spec.needle); + checks.push({ id: spec.id, ok: found.ok, detail: found.detail }); + } } return finishChecks(parsed, "check-install", checks, { @@ -854,6 +1047,18 @@ function runProve(parsed) { stderr: result.stderr, }); } + let skipFailure = null; + if (feature === "grok-build-and-bot") { + const grokStep = results.find((step) => step.id === "check-install-grok"); + const skipIds = grokSkipCheckIds(grokStep, repoRoot); + if (skipIds === null || skipIds.length > 0) { + ok = false; + skipFailure = skipIds ?? ["unparseable-check-install-grok"]; + if (grokStep) { + grokStep.ok = false; + } + } + } const proof = { ok, command: "prove", @@ -869,7 +1074,8 @@ function runProve(parsed) { invocation: portableInvocation(step.args, repoRoot), })), hostedUi: false, - note: "This pack has no hosted web UI. Proof is catalog parse, plugin inventory, and Claude marketplace source resolution.", + note: proofNote(feature), + ...(skipFailure ? { skipFailure } : {}), }; const jsonPath = path.join(outDir, "drive.json"); const mdPath = path.join(outDir, "drive.md"); @@ -939,6 +1145,8 @@ function proveSteps(feature) { case "grok-build-and-bot": return [ { id: "doctor", args: ["doctor", "--json"] }, + { id: "info", args: ["info", "--json"] }, + { id: "list", args: ["list", "--json"] }, { id: "check-install-grok", args: ["check-install", "--surface", "grok", "--json"], @@ -951,6 +1159,40 @@ function proveSteps(feature) { } } +function proofNote(feature) { + if (feature === "grok-build-and-bot") { + return "This pack has no hosted web UI. Proof is Grok marketplace parse, per-plugin Grok Bot and Grok Build manifests, local source paths, and marketplace logo files."; + } + return "This pack has no hosted web UI. Proof is catalog parse, plugin inventory, and Claude marketplace source resolution."; +} + +function proofWhatProved(proof, catalogSummary) { + if (proof.feature === "marketplace-catalog") { + return `The checkout is a marketplace plugin pack. Marketplace JSON parses, plugin directories are listable, and every Claude marketplace \`source\` resolves to a real folder. There is no web app to click; Claude Code install needles in README match files that exist on disk.${catalogSummary}`; + } + if (proof.feature === "grok-build-and-bot") { + return `The checkout ships Grok Bot and Grok Build. \`.grok-plugin/marketplace.json\` parses, every plugin directory has \`.grok-plugin/plugin.json\` and \`.grok-build-plugin/plugin.json\`, marketplace sources resolve, and each marketplace logo path exists on disk. \`check-install --surface grok\` does not report skip.${catalogSummary}`; + } + return `Drove feature \`${proof.feature}\` through control-marketplace.${catalogSummary}`; +} + +function grokSkipCheckIds(step, repoRoot) { + if (!step?.stdout) { + return null; + } + try { + const payload = JSON.parse(portableText(step.stdout, repoRoot)); + if (!Array.isArray(payload.checks)) { + return null; + } + return payload.checks + .filter((check) => check.severity === "skip") + .map((check) => check.id); + } catch { + return null; + } +} + function portableInvocation(childArgs, repoRoot) { const args = []; for (let i = 0; i < childArgs.length; i += 1) { @@ -978,7 +1220,7 @@ function renderProofMarkdown(proof, results, repoRoot) { try { const info = JSON.parse(portableText(infoStep.stdout, repoRoot)); const missing = info.gaps?.missingFromCodex ?? []; - catalogSummary = ` Inventory from \`info\`: ${info.counts?.pluginDirs} plugin directories, root/Claude catalogs ${info.counts?.rootMarketplace}/${info.counts?.claudeMarketplace}, Codex ${info.counts?.codexMarketplace}${missing.length ? ` (missing ${missing.join(", ")}; not a Claude-catalog failure)` : ""}.`; + catalogSummary = ` Inventory from \`info\`: ${info.counts?.pluginDirs} plugin directories, root/Claude catalogs ${info.counts?.rootMarketplace}/${info.counts?.claudeMarketplace}, Codex ${info.counts?.codexMarketplace}, Grok ${info.counts?.grokMarketplace}${missing.length ? ` (missing ${missing.join(", ")}; not a Claude-catalog failure)` : ""}.`; } catch { catalogSummary = ""; } @@ -995,9 +1237,7 @@ function renderProofMarkdown(proof, results, repoRoot) { "", "## What this proved", "", - proof.feature === "marketplace-catalog" - ? `The checkout is a marketplace plugin pack. Marketplace JSON parses, plugin directories are listable, and every Claude marketplace \`source\` resolves to a real folder. There is no web app to click; Claude Code install needles in README match files that exist on disk.${catalogSummary}` - : `Drove feature \`${proof.feature}\` through control-marketplace.${catalogSummary}`, + proofWhatProved(proof, catalogSummary), "", "## Steps", "", @@ -1012,7 +1252,6 @@ function renderProofMarkdown(proof, results, repoRoot) { lines.push( "- `drive.md` — what the drive proved (committed). `drive.transcript.txt` is local-only.", ); - lines.push(""); return `${lines.join("\n")}\n`; } @@ -1104,9 +1343,8 @@ USAGE node .cursor/skills/verify-marketplace/control-marketplace.mjs [flags] This repo is a plugin marketplace, not a hosted web app. The lever validates -marketplace JSON, plugin manifests, and documented Claude Code / Codex install -paths. Grok Build and Grok Bot have no in-tree surface yet; check-install ---surface grok reports that skip instead of inventing a driver. +marketplace JSON, plugin manifests, and documented Claude Code, Codex, Grok +Build, and Grok Bot install paths. GLOBAL FLAGS --json Machine-readable stdout (also --format json) @@ -1159,20 +1397,21 @@ USAGE Reports python3, node, validate-plugins.sh, marketplace JSON parse, plugin directory count, and that this lever plus the feature map are present. -Does not fail on Codex catalog drift; that is validate / check-install --surface codex.`, +Does not fail on Codex or Grok catalog name drift; that is validate / +check-install --surface codex|grok.`, info: `info — pack identity USAGE control-marketplace.mjs info [--json] [--repo ] Prints marketplace name, plugin counts per catalog, Antigravity count, -Grok surface flags (currently false), and Codex name gaps.`, +Grok Bot / Grok Build surface flags, and Codex or Grok name gaps.`, list: `list — plugin inventory USAGE - control-marketplace.mjs list [--json] [--missing-readme] [--missing-codex] [--has-antigravity] + control-marketplace.mjs list [--json] [--missing-readme] [--missing-codex] [--missing-grok] [--has-antigravity] [--has-grok] [--has-grok-build] -Each row includes claude/codex/antigravity booleans, README/CLAUDE.md, and version.`, +Each row includes claude/codex/antigravity/grok/grokBuild booleans, README/CLAUDE.md, and version.`, inspect: `inspect — one plugin USAGE @@ -1201,7 +1440,7 @@ USAGE claude Claude marketplace sources exist; root ids are name@marketplace codex Codex marketplace names match plugin dirs; local sources exist antigravity Lists .antigravity-plugin packs and the install script -grok Expected skip until a Grok Build / Grok Bot catalog exists`, +grok Grok marketplace names, local sources, per-plugin logos, and Grok Bot / Grok Build manifests. Skip is a failure.`, "install-antigravity": `install-antigravity — symlink Antigravity plugins USAGE @@ -1292,6 +1531,8 @@ function renderText(payload) { plugin.claude ? "claude" : null, plugin.codex ? "codex" : null, plugin.antigravity ? "antigravity" : null, + plugin.grok ? "grok" : null, + plugin.grokBuild ? "grok-build" : null, plugin.readme ? "readme" : "NO-README", ] .filter(Boolean) @@ -1309,7 +1550,7 @@ function renderText(payload) { lines.push(`marketplace: ${payload.marketplaceName}`); lines.push(`pluginDirs: ${payload.counts.pluginDirs}`); lines.push( - `catalogs: root=${payload.counts.rootMarketplace} claude=${payload.counts.claudeMarketplace} codex=${payload.counts.codexMarketplace}`, + `catalogs: root=${payload.counts.rootMarketplace} claude=${payload.counts.claudeMarketplace} codex=${payload.counts.codexMarketplace} grok=${payload.counts.grokMarketplace}`, ); lines.push( `surfaces: claudeCode=${payload.surfaces.claudeCode} codex=${payload.surfaces.codex} antigravity=${payload.surfaces.antigravity} grokBuild=${payload.surfaces.grokBuild} grokBot=${payload.surfaces.grokBot}`, @@ -1319,6 +1560,11 @@ function renderText(payload) { `codex gap: missing ${payload.gaps.missingFromCodex.join(", ")}`, ); } + if (payload.gaps?.missingFromGrok?.length) { + lines.push( + `grok gap: missing ${payload.gaps.missingFromGrok.join(", ")}`, + ); + } } if (payload.command === "prove" && payload.steps) { for (const step of payload.steps) { diff --git a/.cursor/skills/verify-marketplace/proof/README.md b/.cursor/skills/verify-marketplace/proof/README.md index 308af93..45fc940 100644 --- a/.cursor/skills/verify-marketplace/proof/README.md +++ b/.cursor/skills/verify-marketplace/proof/README.md @@ -7,8 +7,15 @@ Generate (or refresh) a drive with: ```bash node .cursor/skills/verify-marketplace/control-marketplace.mjs prove --feature marketplace-catalog --json +node .cursor/skills/verify-marketplace/control-marketplace.mjs prove --feature grok-build-and-bot --json +node .cursor/skills/verify-marketplace/control-marketplace.mjs prove --feature codex-install --json ``` +`prove` writes one drive at a time into this directory. Claude and Codex +recipes stay in `proveSteps`. The Grok drive is the required proof after the +Grok marketplace shipped. Skip from `check-install --surface grok` fails the +Grok drive. + Expected files after a successful drive: - `drive.json` — machine-readable summary (`ok`, feature id, step exits) diff --git a/.cursor/skills/verify-marketplace/proof/drive.json b/.cursor/skills/verify-marketplace/proof/drive.json index 75a5f64..78265c6 100644 --- a/.cursor/skills/verify-marketplace/proof/drive.json +++ b/.cursor/skills/verify-marketplace/proof/drive.json @@ -1,9 +1,9 @@ { "ok": true, "command": "prove", - "feature": "marketplace-catalog", - "startedAt": "2026-09-02T18:23:37.757Z", - "finishedAt": "2026-09-02T18:23:37.859Z", + "feature": "grok-build-and-bot", + "startedAt": "2026-09-02T18:59:00.819Z", + "finishedAt": "2026-09-02T18:59:00.931Z", "repoRoot": ".", "outDir": ".cursor/skills/verify-marketplace/proof", "steps": [ @@ -26,12 +26,12 @@ "invocation": "node .cursor/skills/verify-marketplace/control-marketplace.mjs list --json" }, { - "id": "check-install-claude", + "id": "check-install-grok", "ok": true, "exitCode": 0, - "invocation": "node .cursor/skills/verify-marketplace/control-marketplace.mjs check-install --surface claude --json" + "invocation": "node .cursor/skills/verify-marketplace/control-marketplace.mjs check-install --surface grok --json" } ], "hostedUi": false, - "note": "This pack has no hosted web UI. Proof is catalog parse, plugin inventory, and Claude marketplace source resolution." + "note": "This pack has no hosted web UI. Proof is Grok marketplace parse, per-plugin Grok Bot and Grok Build manifests, local source paths, and marketplace logo files." } diff --git a/.cursor/skills/verify-marketplace/proof/drive.md b/.cursor/skills/verify-marketplace/proof/drive.md index 92bd427..977d55a 100644 --- a/.cursor/skills/verify-marketplace/proof/drive.md +++ b/.cursor/skills/verify-marketplace/proof/drive.md @@ -1,22 +1,22 @@ -# Proven drive: marketplace-catalog +# Proven drive: grok-build-and-bot Result: **pass** -- Started: 2026-09-02T18:23:37.757Z -- Finished: 2026-09-02T18:23:37.859Z +- Started: 2026-09-02T18:59:00.819Z +- Finished: 2026-09-02T18:59:00.931Z - Repo: checkout root (paths in this file are repo-relative) - Hosted UI: no ## What this proved -The checkout is a marketplace plugin pack. Marketplace JSON parses, plugin directories are listable, and every Claude marketplace `source` resolves to a real folder. There is no web app to click; Claude Code install needles in README match files that exist on disk. Inventory from `info`: 24 plugin directories, root/Claude catalogs 24/24, Codex 23 (missing command-code; not a Claude-catalog failure). +The checkout ships Grok Bot and Grok Build. `.grok-plugin/marketplace.json` parses, every plugin directory has `.grok-plugin/plugin.json` and `.grok-build-plugin/plugin.json`, marketplace sources resolve, and each marketplace logo path exists on disk. `check-install --surface grok` does not report skip. Inventory from `info`: 24 plugin directories, root/Claude catalogs 24/24, Codex 24, Grok 24. ## Steps - `doctor`: pass (exit 0) — `node .cursor/skills/verify-marketplace/control-marketplace.mjs doctor --json` - `info`: pass (exit 0) — `node .cursor/skills/verify-marketplace/control-marketplace.mjs info --json` - `list`: pass (exit 0) — `node .cursor/skills/verify-marketplace/control-marketplace.mjs list --json` -- `check-install-claude`: pass (exit 0) — `node .cursor/skills/verify-marketplace/control-marketplace.mjs check-install --surface claude --json` +- `check-install-grok`: pass (exit 0) — `node .cursor/skills/verify-marketplace/control-marketplace.mjs check-install --surface grok --json` ## Artifacts diff --git a/.cursor/skills/verify-marketplace/references/features/README.md b/.cursor/skills/verify-marketplace/references/features/README.md index a9c870d..92e5fa7 100644 --- a/.cursor/skills/verify-marketplace/references/features/README.md +++ b/.cursor/skills/verify-marketplace/references/features/README.md @@ -2,7 +2,8 @@ Behavior-level inventory of **duyet/codex-claude-plugins**. Agents use this map to decide what to drive and what evidence counts. This checkout is a plugin -marketplace pack (Claude Code + Codex). It is not a hosted web app. +marketplace pack (Claude Code, Codex, Grok Build, Grok Bot). It is not a hosted +web app. ## Baseline preconditions @@ -12,9 +13,9 @@ marketplace pack (Claude Code + Codex). It is not a hosted web app. - `python3` is on `PATH` (needed by `scripts/validate-plugins.sh`). - Read-only commands are safe to run concurrently. - Do not `install-antigravity --apply` against `$HOME` during verification. -- Grok Build / Grok Bot have no in-tree catalog. Drive - [grok-build-and-bot.md](./grok-build-and-bot.md) as an expected skip, not a - failure. +- Grok Build and Grok Bot are real slots. Drive + [grok-build-and-bot.md](./grok-build-and-bot.md). A skip from + `check-install --surface grok` is a failed drive. ## Driving conventions @@ -22,28 +23,31 @@ marketplace pack (Claude Code + Codex). It is not a hosted web app. - Treat commands in feature files as literal. - Use `--json` when asserting fields. - `validate` wraps the production script; do not reimplement it ad hoc. -- Report unreachable paths (Claude Code / Codex CLIs not installed here) as - skipped with the closest on-disk proof that remains. +- Report unreachable paths (Claude Code / Codex / Grok CLIs not installed here) + as skipped with the closest on-disk proof that remains. ## Proof and skip reporting - Capture the command, exit code, and resulting catalog/docs state. - A marketplace `source` that does not exist on disk is a failed install path, even if JSON parses. +- A Grok marketplace `logo` that does not exist under the plugin source is a + failed install path. - Missing plugin `README.md` is a docs warning unless `--strict`. - Do not call a Codex gap verified via the Claude catalog. +- Do not call a Grok gap verified via the Claude or Codex catalog. ## Full sweep Walk this list top to bottom for a broad regression. Finish with -`grok-build-and-bot.md` (skip until a surface exists). +`grok-build-and-bot.md` as a real slot, not a skip. ## Catalog & manifests -- [marketplace-catalog](./marketplace-catalog.md): root, Claude, and Codex - marketplace JSON, plugin directory set, ids. +- [marketplace-catalog](./marketplace-catalog.md): root, Claude, Codex, and + Grok marketplace JSON, plugin directory set, ids. - [plugin-manifests](./plugin-manifests.md): per-plugin Claude / Codex / - Antigravity `plugin.json` and parity. + Antigravity / Grok Bot / Grok Build `plugin.json` and parity. ## Install @@ -51,6 +55,8 @@ Walk this list top to bottom for a broad regression. Finish with `/plugin install`, settings.json, Skills CLI. - [codex-install](./codex-install.md): local Codex marketplace import from `.agents/plugins/marketplace.json`. +- [grok-build-and-bot](./grok-build-and-bot.md): Grok marketplace add/install, + `.grok-plugin/` + `.grok-build-plugin/` manifests, local `assets/logo.svg`. ## Docs & harness @@ -59,11 +65,6 @@ Walk this list top to bottom for a broad regression. Finish with - [validation-harness](./validation-harness.md): `scripts/validate-plugins.sh` and CI. -## Later surfaces - -- [grok-build-and-bot](./grok-build-and-bot.md): placeholder for Grok Build / - Grok Bot. No driver yet. - ## Entry contract Every feature file uses the same four H2s: diff --git a/.cursor/skills/verify-marketplace/references/features/docs-and-readme.md b/.cursor/skills/verify-marketplace/references/features/docs-and-readme.md index 575044b..f5e5734 100644 --- a/.cursor/skills/verify-marketplace/references/features/docs-and-readme.md +++ b/.cursor/skills/verify-marketplace/references/features/docs-and-readme.md @@ -10,16 +10,22 @@ README.md files are the user-visible docs surface. settings.json, and skills CLI. - `docs-codex-install` README and CONTRIBUTING include `.agents/plugins/marketplace.json`. +- `docs-grok-install` README includes + `grok plugin marketplace add duyet/codex-claude-plugins` and + `.grok-plugin/marketplace.json`. CONTRIBUTING includes the Grok marketplace + path. - `docs-validate` CLAUDE.md and CONTRIBUTING tell contributors to run `scripts/validate-plugins.sh`. -- `docs-structure` CLAUDE.md names `.claude-plugin/plugin.json` and - `.codex-plugin/plugin.json`. +- `docs-structure` CLAUDE.md names `.claude-plugin/plugin.json`, + `.codex-plugin/plugin.json`, `.grok-plugin/plugin.json`, and + `.grok-build-plugin/plugin.json`. - `docs-plugin-readme` each plugin directory has `README.md` (warning unless `--strict`). ## How to get to it (user POV) -- Open `README.md` (Quick Install, Codex, Manual Installation). +- Open `README.md` (Quick Install, Codex, Grok Build, Grok Bot, Manual + Installation). - Open `CLAUDE.md` (plugin metadata and validate command). - Open `CONTRIBUTING.md` (new plugin checklist). - Open `/README.md` for plugin-specific usage. diff --git a/.cursor/skills/verify-marketplace/references/features/grok-build-and-bot.md b/.cursor/skills/verify-marketplace/references/features/grok-build-and-bot.md index 65ab3be..7c684aa 100644 --- a/.cursor/skills/verify-marketplace/references/features/grok-build-and-bot.md +++ b/.cursor/skills/verify-marketplace/references/features/grok-build-and-bot.md @@ -1,46 +1,80 @@ # Grok Build and Grok Bot -Room for future Grok surfaces. This pack does not yet ship a Grok Build -marketplace or a Grok Bot plugin catalog. Verification must report an -**expected skip**, not invent manifests, install commands, or a browser flow. +A Grok user adds this GitHub repo as a marketplace, then installs plugins with +`grok plugin install --trust`. Grok Bot and Grok Build share +`.grok-plugin/marketplace.json`. Each plugin ships `.grok-plugin/plugin.json` +and `.grok-build-plugin/plugin.json`, and listings render `assets/logo.svg`. ## Sub-features -- `grok-build-absent` no Grok Build marketplace file in the repo root layout. -- `grok-bot-absent` no Grok Bot pack metadata in-tree. -- `grok-check` `check-install --surface grok` returns `available: false` with - `severity: skip`. +- `grok-marketplace-parse` loads `.grok-plugin/marketplace.json` as JSON. +- `grok-marketplace-names` Grok marketplace names equal plugin directories. +- `grok-sources` every plugin `source.path` exists and `source.type` is + `local`. +- `grok-logos` every marketplace `logo` exists under the plugin source + (usually `assets/logo.svg`). +- `grok-bot-manifests` every plugin directory has `.grok-plugin/plugin.json`. +- `grok-build-manifests` every plugin directory has + `.grok-build-plugin/plugin.json`. +- `grok-docs` README and CONTRIBUTING document + `grok plugin marketplace add duyet/codex-claude-plugins` and + `.grok-plugin/marketplace.json`. +- `grok-check` `check-install --surface grok` returns `ok: true` with no + `severity: skip`. Skip is a failed drive. ## How to get to it (user POV) -- There is no user install path yet. Do not tell a user to run a Grok - marketplace add command. -- When a Grok surface lands, it should get its own marketplace file, install - docs in README, and new `control-marketplace` checks in the same shape as - Claude and Codex. +- Run `grok plugin marketplace add duyet/codex-claude-plugins`, then + `grok plugin install team-agents --trust` (or another name). +- In the Grok TUI, open `/marketplace` or `/plugin` and press `i` to install. +- In the Grok Bot app, open **Plugins** and add `duyet/codex-claude-plugins` + as a marketplace source if the CLI is not available. +- Open `/.grok-plugin/plugin.json` and + `/.grok-build-plugin/plugin.json`. +- Open `/assets/logo.svg`. ## Driving it with control-marketplace Preconditions: - `control-marketplace doctor` reports `ok`. +- Grok CLI may be absent. Do not fail the drive for a missing `grok` binary; + prove the files the commands would resolve. -- **Skip, do not fake.** Run - `node .cursor/skills/verify-marketplace/control-marketplace.mjs check-install --surface grok --json`. - Checks `grok-build` and `grok-bot` have `ok: true`, `severity: skip`, and - `available: false` (or a newly documented path if files appeared). -- **Surface flags.** Run +- **Surfaces.** Run `node .cursor/skills/verify-marketplace/control-marketplace.mjs info --json`. - `surfaces.grokBuild` and `surfaces.grokBot` are `false` until a catalog - exists. -- **Proof of absence.** The JSON above is the proof. Do not open Grok, X, or - a bot dashboard as a substitute. + `surfaces.grokBuild` and `surfaces.grokBot` are `true`. + `counts.grokMarketplace` equals `counts.pluginDirs`. +- **Inventory.** Run + `node .cursor/skills/verify-marketplace/control-marketplace.mjs list --json`. + Every plugin has `grok` and `grokBuild` true. `list --missing-grok --json` + returns `count: 0`. +- **Install resolvability.** Run + `node .cursor/skills/verify-marketplace/control-marketplace.mjs check-install --surface grok --json`. + `grok-marketplace-parses`, `grok-bot`, `grok-build`, and + `grok-marketplace-names` pass. Every `grok-source-*` and `grok-logo-*` + check passes. `readme-grok-marketplace-add` and + `readme-grok-marketplace-file` pass. No check has `severity: skip`. +- **Inspect one plugin.** Run + `node .cursor/skills/verify-marketplace/control-marketplace.mjs inspect anyrouter --json`. + `manifests.grok` and `manifests.grokBuild` are relative paths that exist. + `marketplaceRows.grok.source.path` is `./anyrouter` and `logo` is + `assets/logo.svg`. +- **Proof.** Run + `node .cursor/skills/verify-marketplace/control-marketplace.mjs prove --feature grok-build-and-bot --json`. + `proof/drive.json` has `ok: true`, no `skipFailure`, and step ids `doctor`, + `info`, `list`, `check-install-grok`. A screenshot of grok.x.ai is not this + feature. ## Gotchas -- Prompt-engineering docs mention Grok the model. That is not Grok Build / Grok - Bot install infrastructure. -- If someone adds `.grok-plugin/` or similar, this file is stale: extend - `check-install` and replace the skip with real source-path checks. -- `/maintain-verification-skill` should keep this entry until those hosts are - real. +- Prompt-engineering docs mention Grok the model. That is not Grok Build / + Grok Bot install infrastructure. +- Grok Bot and Grok Build share one marketplace file. Do not look for a + second catalog at `.grok-build-plugin/marketplace.json`. +- Marketplace `logo` is relative to the plugin source directory, not the repo + root. Root `assets/logo.svg` is not a substitute for + `/assets/logo.svg`. +- `info` can be `ok` while Grok still lags plugin directories. Use + `gaps.missingFromGrok`. +- Do not treat a passing Claude or Codex catalog as Grok coverage. diff --git a/.cursor/skills/verify-marketplace/references/features/marketplace-catalog.md b/.cursor/skills/verify-marketplace/references/features/marketplace-catalog.md index 2b95c4f..7dd0f02 100644 --- a/.cursor/skills/verify-marketplace/references/features/marketplace-catalog.md +++ b/.cursor/skills/verify-marketplace/references/features/marketplace-catalog.md @@ -1,26 +1,30 @@ # Marketplace catalog -The pack is three marketplace JSON files plus one directory per plugin. A user +The pack is four marketplace JSON files plus one directory per plugin. A user cannot install a plugin that is missing from the catalog they use, or whose `source` path does not exist. ## Sub-features - `catalog-parse` loads `marketplace.json`, `.claude-plugin/marketplace.json`, - and `.agents/plugins/marketplace.json` as JSON. -- `catalog-list` lists plugin directories that ship a Claude or Codex manifest. + `.agents/plugins/marketplace.json`, and `.grok-plugin/marketplace.json` as + JSON. +- `catalog-list` lists plugin directories that ship a Claude, Codex, or Grok + manifest. - `catalog-claude-sources` resolves every Claude marketplace `source` to a directory. - `catalog-root-ids` checks root marketplace `id` values are `@`. - `catalog-codex-names` checks Codex marketplace names match plugin directories. +- `catalog-grok-names` checks Grok marketplace names match plugin directories. ## How to get to it (user POV) - Open `marketplace.json` at the repo root (skills.sh / catalog metadata). - Open `.claude-plugin/marketplace.json` (Claude Code marketplace add). - Open `.agents/plugins/marketplace.json` (Codex local marketplace). +- Open `.grok-plugin/marketplace.json` (Grok Build and Grok Bot). - List first-level plugin folders that contain `.claude-plugin/plugin.json`. ## Driving it with control-marketplace @@ -34,8 +38,9 @@ Preconditions: - **Parse catalogs.** Run `node .cursor/skills/verify-marketplace/control-marketplace.mjs info --json`. `ok` is true, `marketplaceName` is `duyet-claude-plugins`, and - `counts.pluginDirs` equals `counts.rootMarketplace` and - `counts.claudeMarketplace`. + `counts.pluginDirs` equals `counts.rootMarketplace`, + `counts.claudeMarketplace`, and `counts.grokMarketplace`. + `surfaces.grokBuild` and `surfaces.grokBot` are true. - **List plugins.** Run `node .cursor/skills/verify-marketplace/control-marketplace.mjs list --json`. `plugins` is a non-empty array; each item has `name` and `claude: true`. @@ -58,5 +63,8 @@ Preconditions: schemas. Do not assert `source` on the root file. - `info` can be `ok` while Codex still lags plugin directories. Use `gaps.missingFromCodex`. -- Doctor does not fail on Codex drift. `validate` does. +- Doctor does not fail on Codex or Grok name drift. `validate` does. +- Grok install resolvability lives in + [grok-build-and-bot.md](./grok-build-and-bot.md). This feature only asserts + that the Grok catalog parses and the name set matches. - There is no web catalog to click. GitHub's repo page is not this feature. diff --git a/.cursor/skills/verify-marketplace/references/features/plugin-manifests.md b/.cursor/skills/verify-marketplace/references/features/plugin-manifests.md index 5ecd3c3..c7b4a28 100644 --- a/.cursor/skills/verify-marketplace/references/features/plugin-manifests.md +++ b/.cursor/skills/verify-marketplace/references/features/plugin-manifests.md @@ -1,9 +1,9 @@ # Plugin manifests Each plugin ships a Claude manifest and a Codex manifest with shared -`name`, `version`, `description`, and `author.name`. Some plugins also ship -Antigravity. Users and host tools read these files to load skills, commands, -and agents. +`name`, `version`, `description`, and `author.name`. Every plugin also ships +Grok Bot and Grok Build manifests. Some plugins also ship Antigravity. Users +and host tools read these files to load skills, commands, and agents. ## Sub-features @@ -13,15 +13,23 @@ and agents. relative `./` paths that exist. - `manifest-antigravity` requires `.antigravity-plugin/plugin.json` when that file is present (currently agent-loop). -- `manifest-parity` requires Claude/Codex/Antigravity shared fields to match. +- `manifest-grok` requires `.grok-plugin/plugin.json` with name, version, + description, author object, and `logo`. +- `manifest-grok-build` requires `.grok-build-plugin/plugin.json` plus + `interface` and a local `logo` / `interface.logo`. +- `manifest-parity` requires Claude/Codex/Grok/Antigravity shared fields to + match. - `manifest-inspect` shows one plugin's files and marketplace rows. ## How to get to it (user POV) - Open `/.claude-plugin/plugin.json`. - Open `/.codex-plugin/plugin.json`. +- Open `/.grok-plugin/plugin.json`. +- Open `/.grok-build-plugin/plugin.json`. - Open `/.antigravity-plugin/plugin.json` when the plugin supports Antigravity CLI. +- Open `/assets/logo.svg`. - Run `bash scripts/validate-plugins.sh` after editing either file. ## Driving it with control-marketplace @@ -32,16 +40,19 @@ Preconditions: - **Inventory manifests.** Run `node .cursor/skills/verify-marketplace/control-marketplace.mjs list --json`. - Every plugin has `claude` and `codex` true. `antigravity` is true only for - plugins that ship that manifest. + Every plugin has `claude`, `codex`, `grok`, and `grokBuild` true. + `antigravity` is true only for plugins that ship that manifest. + `list --missing-grok --json` is empty on a healthy pack. - **Inspect one plugin.** Run `node .cursor/skills/verify-marketplace/control-marketplace.mjs inspect commit --json`. `plugins[0].manifests.claude` and `manifests.codex` are relative paths that - exist. `marketplaceRows.claude` and `marketplaceRows.root` are non-null. + exist. `manifests.grok` and `manifests.grokBuild` exist. + `marketplaceRows.claude` and `marketplaceRows.root` are non-null. + `marketplaceRows.grok` is non-null. - **Production parity.** Run `node .cursor/skills/verify-marketplace/control-marketplace.mjs validate --json`. - Labels include `Claude/Codex/Antigravity manifest parity`. If that label is - in `failed`, manifests drifted. + Labels include `Claude/Codex/Grok/Antigravity manifest parity`. If that + label is in `failed`, manifests drifted. - **Proof for a single plugin change.** Re-run `inspect ` after the edit and confirm `version` matches in both manifests. @@ -51,6 +62,8 @@ Preconditions: arrays (arrays live under `codex.skills` when used). - `list --missing-codex` is empty on a healthy pack. A hit means a plugin is not installable in Codex. +- `list --missing-grok` is empty on a healthy pack. A hit means a plugin is + missing `.grok-plugin/plugin.json` or `.grok-build-plugin/plugin.json`. - Nested `plugin.json` under templates or `node_modules` is out of scope for `list` (first-level plugin dirs only). `validate-plugins.sh` uses `find` and may see more; treat a nested hit as a harness discrepancy and record it. diff --git a/.cursor/skills/verify-marketplace/references/features/validation-harness.md b/.cursor/skills/verify-marketplace/references/features/validation-harness.md index fd474f4..42e6812 100644 --- a/.cursor/skills/verify-marketplace/references/features/validation-harness.md +++ b/.cursor/skills/verify-marketplace/references/features/validation-harness.md @@ -1,9 +1,10 @@ # Validation harness `scripts/validate-plugins.sh` is the production check for manifests, Claude / -Codex / Antigravity parity, and marketplace files. GitHub Actions runs the same -script. Agents must use this script (via `control-marketplace validate`), not a -private reimplementation, as the source of pass/fail. +Codex / Antigravity / Grok Bot / Grok Build parity, and marketplace files. +GitHub Actions runs the same script. Agents must use this script (via +`control-marketplace validate`), not a private reimplementation, as the source +of pass/fail. ## Sub-features @@ -13,9 +14,12 @@ private reimplementation, as the source of pass/fail. - `harness-codex-manifests` validates every `.codex-plugin/plugin.json`. - `harness-antigravity-manifests` validates every `.antigravity-plugin/plugin.json`. +- `harness-grok-manifests` validates every `.grok-plugin/plugin.json`. +- `harness-grok-build-manifests` validates every + `.grok-build-plugin/plugin.json`. - `harness-parity` shared fields match across hosts. - `harness-marketplaces` marketplace files match plugin directories and - source paths. + source paths, including Grok logos under each plugin source. - `harness-ci` `.github/workflows/validate-plugins.yml` invokes the script. ## How to get to it (user POV)