{"record":{"id":"deb8244ba8c7c9d9","repo":"thedotmack/claude-mem","slug":"agents-plugins-marketplace-json-must-point-claude","errorCode":null,"errorMessage":".agents/plugins/marketplace.json must point claude-mem source.path at ./plugin so Codex loads the bundled plugin root","messagePattern":"\\.agents/plugins/marketplace\\.json must point claude-mem source\\.path at \\./plugin so Codex loads the bundled plugin root","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"scripts/build-hooks.js","lineNumber":741,"sourceCode":"        throw new Error(`Missing required distribution file: ${filePath}`);\n      }\n    }\n    const codexHooks = JSON.parse(fs.readFileSync('plugin/hooks/codex-hooks.json', 'utf-8'));\n    const validCodexHookRootKeys = new Set(['hooks']);\n    for (const rootKey of Object.keys(codexHooks)) {\n      if (!validCodexHookRootKeys.has(rootKey)) {\n        throw new Error(`plugin/hooks/codex-hooks.json contains unsupported Codex root key: ${rootKey}`);\n      }\n    }\n    for (const eventName of Object.keys(codexHooks.hooks ?? {})) {\n      if (!validCodexHookEvents.has(eventName)) {\n        throw new Error(`plugin/hooks/codex-hooks.json contains unknown Codex hook event: ${eventName}`);\n      }\n    }\n    const codexMarketplace = JSON.parse(fs.readFileSync('.agents/plugins/marketplace.json', 'utf-8'));\n    const claudeMemMarketplaceEntry = (codexMarketplace.plugins ?? []).find((plugin) => plugin.name === 'claude-mem');\n    if (claudeMemMarketplaceEntry?.source?.path !== './plugin') {\n      throw new Error('.agents/plugins/marketplace.json must point claude-mem source.path at ./plugin so Codex loads the bundled plugin root');\n    }\n    const bundledMcp = JSON.parse(fs.readFileSync('plugin/.mcp.json', 'utf-8'));\n    const mcpSearchCommand = bundledMcp.mcpServers?.['mcp-search']?.args?.join(' ') ?? '';\n    if (!mcpSearchCommand.includes('.codex/plugins/cache/claude-mem-local/claude-mem')) {\n      throw new Error('plugin/.mcp.json mcp-search launcher must include Codex cache fallback for hosts that do not inject PLUGIN_ROOT');\n    }\n    if (!mcpSearchCommand.includes('plugins/cache/thedotmack/claude-mem')) {\n      throw new Error('plugin/.mcp.json mcp-search launcher must include Claude cache fallback for hosts that do not inject PLUGIN_ROOT');\n    }\n    console.log('✓ All required distribution files present');\n\n    await verifyShellTemplateCanonical();\n\n    console.log('\\n✅ All build targets compiled successfully!');\n    console.log(`   Output: ${hooksDir}/`);\n    console.log(`   - Worker: worker-service.cjs`);\n    console.log(`   - Server: server-service.cjs`);\n    console.log(`   - MCP Server: mcp-server.cjs`);","sourceCodeStart":723,"sourceCodeEnd":759,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/scripts/build-hooks.js#L723-L759","documentation":"Loads .agents/plugins/marketplace.json, finds the plugin whose name is 'claude-mem', and asserts its source.path equals './plugin'. Codex loads the bundled plugin root, so any other path (absolute, '../plugin', a cache path) would make Codex miss the bundled hooks/MCP server. The error explains the requirement.","triggerScenarios":"Editing .agents/plugins/marketplace.json and changing the claude-mem entry's source.path to a different value (absolute path, a cache dir, or a monorepo-relative path).","commonSituations":"Pointing source.path at a local dev checkout for testing and forgetting to revert. Automation that rewrites marketplace paths. A merge that brings in a different marketplace convention.","solutions":["Open .agents/plugins/marketplace.json and set the claude-mem entry's source.path back to './plugin'.","If you genuinely need a different path for local testing, do it in a copy of the file outside the repo or via an env override — the committed file must read './plugin'.","Re-run the build; the assertion at scripts/build-hooks.js:738-742 must pass."],"exampleFix":"// before: .agents/plugins/marketplace.json\n{ \"plugins\": [{ \"name\":\"claude-mem\", \"source\": { \"path\": \"/home/me/claude-mem/plugin\" } }] }\n\n// after\n{ \"plugins\": [{ \"name\":\"claude-mem\", \"source\": { \"path\": \"./plugin\" } }] }","handlingStrategy":"validation","validationCode":"const mp = JSON.parse(fs.readFileSync('.agents/plugins/marketplace.json','utf8'));\nconst entry = (mp.plugins ?? []).find(p => p.name === 'claude-mem');\nif (!entry || entry.source?.path !== './plugin') {\n  throw new Error('marketplace claude-mem source.path must be ./plugin');\n}","typeGuard":"function pointsAtBundledPlugin(entry): boolean {\n  return entry?.source?.path === './plugin';\n}","tryCatchPattern":"// Build-time only. Set source.path back to './plugin'. For local testing, use a\n// separate (non-committed) marketplace file. Do not suppress.","preventionTips":["Keep .agents/plugins/marketplace.json committed with source.path === './plugin'.","Do local testing via a copy or an env-driven override, not by editing the committed file.","CI should run the build so any drift fails the pipeline."],"tags":["build","verification","codex","marketplace","plugin-root"],"backgroundTag":null,"analyzedSha":"d768ba364302d12b76e69e4f021f0bb1d2d50ed6","analyzedAt":"2026-08-12T23:52:55.241Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}