{"record":{"id":"7b0d832c5f968127","repo":"thedotmack/claude-mem","slug":"plugin-mcp-json-mcp-search-launcher-must-include","errorCode":null,"errorMessage":"plugin/.mcp.json mcp-search launcher must include Codex cache fallback for hosts that do not inject PLUGIN_ROOT","messagePattern":"plugin/\\.mcp\\.json mcp-search launcher must include Codex cache fallback for hosts that do not inject PLUGIN_ROOT","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"scripts/build-hooks.js","lineNumber":746,"sourceCode":"    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`);\n    console.log(`   - Context Generator: context-generator.cjs`);\n    console.log(`   - Transcript Watcher: transcript-watcher.cjs`);\n    console.log(`   Output: ${npxCliOutDir}/`);\n    console.log(`   - NPX CLI: index.js`);\n    if (fs.existsSync('openclaw/dist/index.js')) {","sourceCodeStart":728,"sourceCodeEnd":764,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/scripts/build-hooks.js#L728-L764","documentation":"Loads plugin/.mcp.json, joins the mcp-search server's args, and asserts the resulting command contains the literal '.codex/plugins/cache/claude-mem-local/claude-mem'. This is the Codex cache fallback path used by hosts that don't inject PLUGIN_ROOT; without it the mcp-search launcher fails to locate the binary under Codex. The error names the missing fragment.","triggerScenarios":"Editing the mcp-search launcher in plugin/.mcp.json and dropping or rewriting the Codex cache fallback fragment. Regenerating shell templates with a buildShellCommand that omits the Codex cache branch.","commonSituations":"Simplifying the launcher to assume PLUGIN_ROOT is always set (it isn't, under Codex). Removing cache-fallback branches as 'dead code'. A generator change that drops the Codex path.","solutions":["Restore the '.codex/plugins/cache/claude-mem-local/claude-mem' fragment in the mcp-search launcher string in plugin/.mcp.json.","If the launcher is generator-produced, ensure src/build/hook-shell-template.ts still emits the Codex cache fallback branch, then run node scripts/build-hooks.js --write-shell-templates.","Re-run the build; the substring check at scripts/build-hooks.js:744-747 must pass."],"exampleFix":"// before: launcher lacks the Codex cache fallback\n\"args\": [\"...\", \"PLUGIN_ROOT=\"$PLUGIN_ROOT\" exec \\\"$PLUGIN_ROOT/mcp-search\\\"\"]\n\n// after: include the Codex cache path for hosts without PLUGIN_ROOT\n\"args\": [\"...\", \"... || exec \\\".codex/plugins/cache/claude-mem-local/claude-mem/mcp-search\\\"\"]","handlingStrategy":"validation","validationCode":"const mcp = JSON.parse(fs.readFileSync('plugin/.mcp.json','utf8'));\nconst cmd = (mcp.mcpServers?.['mcp-search']?.args ?? []).join(' ');\nif (!cmd.includes('.codex/plugins/cache/claude-mem-local/claude-mem')) {\n  throw new Error('mcp-search launcher missing Codex cache fallback');\n}","typeGuard":null,"tryCatchPattern":"// Build-time only. Restore the Codex cache-fallback fragment in the launcher,\n// or regenerate via --write-shell-templates after fixing the generator.","preventionTips":["Treat the mcp-search launcher as generator-owned; never hand-edit.","When modifying buildShellCommand, preserve both cache-fallback branches (Codex + Claude).","Add a CI assertion for both fallback substrings."],"tags":["build","verification","mcp","codex","plugin-root","cache-fallback"],"backgroundTag":null,"analyzedSha":"d768ba364302d12b76e69e4f021f0bb1d2d50ed6","analyzedAt":"2026-08-12T23:52:55.241Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}