{"record":{"id":"893a2949a0f0c4ec","repo":"thedotmack/claude-mem","slug":"plugin-scripts-bun-runner-js-uses-optional-chainin","errorCode":null,"errorMessage":"plugin/scripts/bun-runner.js uses optional chaining (?.) or nullish coalescing (??) — this launcher must parse on pre-ES2020 Node (issue #2791). Rewrite with explicit guards.","messagePattern":"plugin/scripts/bun-runner\\.js uses optional chaining \\(\\?\\.\\) or nullish coalescing \\(\\?\\?\\) — this launcher must parse on pre-ES2020 Node \\(issue #2791\\)\\. Rewrite with explicit guards\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"scripts/build-hooks.js","lineNumber":239,"sourceCode":"    }\n  }\n\n  // Rule C safety net (bun-runner.js fixBrokenScriptPath) must stay documented.\n  const bunRunner = fs.readFileSync('plugin/scripts/bun-runner.js', 'utf-8');\n  if (!bunRunner.includes('function fixBrokenScriptPath')) {\n    throw new Error(\n      'plugin/scripts/bun-runner.js is missing fixBrokenScriptPath — it is the Rule C runtime safety net behind Rule A. Do not remove it.'\n    );\n  }\n\n  // Parser-compat guard (issue #2791): bun-runner.js is invoked by hosts that\n  // may run a pre-ES2020 Node whose ESM loader throws on optional chaining.\n  // Strip comments, then forbid `?.` / `??` in executable code.\n  const bunRunnerCode = bunRunner\n    .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n    .replace(/(^|[^:])\\/\\/.*$/gm, '$1');\n  if (/\\?\\.|\\?\\?/.test(bunRunnerCode)) {\n    throw new Error(\n      'plugin/scripts/bun-runner.js uses optional chaining (?.) or nullish coalescing (??) — ' +\n      'this launcher must parse on pre-ES2020 Node (issue #2791). Rewrite with explicit guards.'\n    );\n  }\n\n  console.log('✓ Rule A shell templates match the canonical generator');\n}\n\nasync function buildHooks() {\n  console.log('🔨 Building claude-mem hooks and worker service...\\n');\n\n  try {\n    const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf-8'));\n    const version = packageJson.version;\n    console.log(`📌 Version: ${version}`);\n\n    console.log('\\n📦 Preparing output directories...');\n    const hooksDir = 'plugin/scripts';","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/scripts/build-hooks.js#L221-L257","documentation":"A parser-compatibility guard for plugin/scripts/bun-runner.js (issue #2791). Some hosts invoke the launcher under a pre-ES2020 Node whose ES module loader throws on optional chaining (?.) and nullish coalescing (??). The build strips comments from bun-runner.js, then regex-scans the remaining executable code; any ?. or ?? triggers this error so the launcher stays parseable on old Node.","triggerScenarios":"Editing plugin/scripts/bun-runner.js and introducing a `?.` or `??` operator. A dependency inlined into bun-runner.js that uses these operators. Note the comment-stripping regex means operators inside comments are fine, but ones in live code fail.","commonSituations":"Modernising bun-runner.js style (e.g. `process?.env?.X ?? 'default'`). Copying a snippet from a newer module that uses optional chaining. A bundler/prettier reformat that introduces nullish coalescing.","solutions":["Rewrite the offending expression with explicit guards: `x?.y` → `(x && x.y)`; `a ?? b` → `(a !== null && a !== undefined ? a : b)`.","Move the logic into a separately-bundled file that targets modern Node if the operator is genuinely required, leaving bun-runner.js as a thin pre-ES2020 launcher.","Re-run node scripts/build-hooks.js; the guard passes once no ?. or ?? survives in executable code.","Keep the comment-stripping behaviour in mind: do not 'hide' the operator in a comment to defeat the guard — it would still fail on old Node at runtime."],"exampleFix":"// before (bun-runner.js)\nconst port = process.env?.CLAUDE_MEM_WORKER_PORT ?? defaultPort;\n\n// after — explicit guards parse on pre-ES2020 Node\nconst envPort = process.env && process.env.CLAUDE_MEM_WORKER_PORT;\nconst port = (envPort !== null && envPort !== undefined) ? envPort : defaultPort;","handlingStrategy":"validation","validationCode":"// Mirror the build guard locally before pushing bun-runner.js changes:\nconst code = fs.readFileSync('plugin/scripts/bun-runner.js','utf8')\n  .replace(/\\/\\*[\\s\\S]*?\\*\\//g,'')\n  .replace(/(^|[^:])\\/\\/.*$/gm,'$1');\nif (/\\?\\.|\\?\\?/.test(code)) throw new Error('optional chaining/nullish coalescing forbidden in bun-runner.js');","typeGuard":null,"tryCatchPattern":"// Build-time only. Rewrite offending expressions with explicit guards\n// (see exampleFix). Do not disable the guard — old-Node hosts will fail at runtime.","preventionTips":["Configure your editor to flag ?. and ?? in plugin/scripts/bun-runner.js (eslint no-optional-chaining / no-nullish-coalescing-operator scoped to this file).","Keep bun-runner.js minimal — push real logic into separately-bundled modules that may target modern Node.","Run the build under the oldest supported Node in CI to catch parser issues early."],"tags":["build","verification","compatibility","node","parser","issue-2791"],"backgroundTag":null,"analyzedSha":"d768ba364302d12b76e69e4f021f0bb1d2d50ed6","analyzedAt":"2026-08-12T23:52:55.241Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}