thedotmack/claude-mem · critical · Error

plugin/scripts/bun-runner.js uses optional chaining (?.) or

Error message

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.

What it means

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.

Source

Thrown at scripts/build-hooks.js:239

    }
  }

  // Rule C safety net (bun-runner.js fixBrokenScriptPath) must stay documented.
  const bunRunner = fs.readFileSync('plugin/scripts/bun-runner.js', 'utf-8');
  if (!bunRunner.includes('function fixBrokenScriptPath')) {
    throw new Error(
      'plugin/scripts/bun-runner.js is missing fixBrokenScriptPath — it is the Rule C runtime safety net behind Rule A. Do not remove it.'
    );
  }

  // Parser-compat guard (issue #2791): bun-runner.js is invoked by hosts that
  // may run a pre-ES2020 Node whose ESM loader throws on optional chaining.
  // Strip comments, then forbid `?.` / `??` in executable code.
  const bunRunnerCode = bunRunner
    .replace(/\/\*[\s\S]*?\*\//g, '')
    .replace(/(^|[^:])\/\/.*$/gm, '$1');
  if (/\?\.|\?\?/.test(bunRunnerCode)) {
    throw new Error(
      '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.'
    );
  }

  console.log('✓ Rule A shell templates match the canonical generator');
}

async function buildHooks() {
  console.log('🔨 Building claude-mem hooks and worker service...\n');

  try {
    const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf-8'));
    const version = packageJson.version;
    console.log(`📌 Version: ${version}`);

    console.log('\n📦 Preparing output directories...');
    const hooksDir = 'plugin/scripts';

View on GitHub (pinned to d768ba3643)

Solutions

  1. Rewrite the offending expression with explicit guards: `x?.y` → `(x && x.y)`; `a ?? b` → `(a !== null && a !== undefined ? a : b)`.
  2. 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.
  3. Re-run node scripts/build-hooks.js; the guard passes once no ?. or ?? survives in executable code.
  4. 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.

Example fix

// before (bun-runner.js)
const port = process.env?.CLAUDE_MEM_WORKER_PORT ?? defaultPort;

// after — explicit guards parse on pre-ES2020 Node
const envPort = process.env && process.env.CLAUDE_MEM_WORKER_PORT;
const port = (envPort !== null && envPort !== undefined) ? envPort : defaultPort;
Defensive patterns

Strategy: validation

Validate before calling

// Mirror the build guard locally before pushing bun-runner.js changes:
const code = fs.readFileSync('plugin/scripts/bun-runner.js','utf8')
  .replace(/\/\*[\s\S]*?\*\//g,'')
  .replace(/(^|[^:])\/\/.*$/gm,'$1');
if (/\?\.|\?\?/.test(code)) throw new Error('optional chaining/nullish coalescing forbidden in bun-runner.js');

Try / catch

// Build-time only. Rewrite offending expressions with explicit guards
// (see exampleFix). Do not disable the guard — old-Node hosts will fail at runtime.

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12). Data as JSON: /api/errors/893a2949a0f0c4ec. Report an issue: GitHub.