From d88ea71590a83d0d58cc2ddfffe17517b13007e2 Mon Sep 17 00:00:00 2001 From: Atharva Deopujari Date: Fri, 20 Mar 2026 11:25:19 +0530 Subject: [PATCH 1/2] fix: strip hardcoded __dirname/__filename from bundled CJS output esbuild inlines __dirname and __filename as static strings when converting ESM TypeScript source to CJS format. These build-time paths shadow the runtime's native __dirname (provided by Bun/Node CJS module wrapper), breaking path resolution for viewer UI, mode loading, and database initialization on end-user machines. Add a post-build step that removes the hardcoded var declarations from all bundled CJS outputs, allowing the runtime globals to work correctly. Fixes #1410 --- scripts/build-hooks.js | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/scripts/build-hooks.js b/scripts/build-hooks.js index 519d196e..2c62e188 100644 --- a/scripts/build-hooks.js +++ b/scripts/build-hooks.js @@ -27,6 +27,43 @@ const CONTEXT_GENERATOR = { source: 'src/services/context-generator.ts' }; +/** + * Strip hardcoded __dirname/__filename from bundled CJS output. + * + * When esbuild converts ESM TypeScript source to CJS format, it inlines + * __dirname and __filename as static strings based on the SOURCE file paths + * at build time. These `var __dirname = "/build/machine/path/..."` declarations + * shadow the runtime's native __dirname (provided by Bun/Node's CJS module + * wrapper), causing path resolution to fail on end-user machines. + * + * This post-build step removes those hardcoded assignments so the runtime + * globals are used instead. + * + * See: https://github.com/thedotmack/claude-mem/issues/1410 + */ +function stripHardcodedDirname(filePath) { + let content = fs.readFileSync(filePath, 'utf-8'); + const before = content.length; + + // Remove `var __dirname = "...", rest` → `var rest` + content = content.replace(/\bvar __dirname\s*=\s*"[^"]*",\s*/g, 'var '); + // Remove standalone `var __dirname = "...";` + content = content.replace(/\bvar __dirname\s*=\s*"[^"]*";\s*/g, ''); + // Remove `, __dirname = "..."` from mid/end of var declarations + content = content.replace(/,\s*__dirname\s*=\s*"[^"]*"/g, ''); + + // Same for __filename + content = content.replace(/\bvar __filename\s*=\s*"[^"]*",\s*/g, 'var '); + content = content.replace(/\bvar __filename\s*=\s*"[^"]*";\s*/g, ''); + content = content.replace(/,\s*__filename\s*=\s*"[^"]*"/g, ''); + + const removed = before - content.length; + if (removed > 0) { + fs.writeFileSync(filePath, content); + console.log(` ✓ Stripped hardcoded __dirname/__filename paths (${removed} bytes)`); + } +} + async function buildHooks() { console.log('🔨 Building claude-mem hooks and worker service...\n'); @@ -120,6 +157,9 @@ async function buildHooks() { } }); + // Fix hardcoded __dirname/__filename in bundled output (#1410) + stripHardcodedDirname(`${hooksDir}/${WORKER_SERVICE.name}.cjs`); + // Make worker service executable fs.chmodSync(`${hooksDir}/${WORKER_SERVICE.name}.cjs`, 0o755); const workerStats = fs.statSync(`${hooksDir}/${WORKER_SERVICE.name}.cjs`); @@ -157,6 +197,9 @@ async function buildHooks() { } }); + // Fix hardcoded __dirname/__filename in bundled output (#1410) + stripHardcodedDirname(`${hooksDir}/${MCP_SERVER.name}.cjs`); + // Make MCP server executable fs.chmodSync(`${hooksDir}/${MCP_SERVER.name}.cjs`, 0o755); const mcpServerStats = fs.statSync(`${hooksDir}/${MCP_SERVER.name}.cjs`); @@ -179,6 +222,9 @@ async function buildHooks() { } }); + // Fix hardcoded __dirname/__filename in bundled output (#1410) + stripHardcodedDirname(`${hooksDir}/${CONTEXT_GENERATOR.name}.cjs`); + const contextGenStats = fs.statSync(`${hooksDir}/${CONTEXT_GENERATOR.name}.cjs`); console.log(`✓ context-generator built (${(contextGenStats.size / 1024).toFixed(2)} KB)`); From abb5940788dbdeefb0e428d142112efd9ccb5dcc Mon Sep 17 00:00:00 2001 From: Atharva Deopujari Date: Fri, 20 Mar 2026 12:39:42 +0530 Subject: [PATCH 2/2] fix: handle single-quoted paths and dangling var; edge case Address review feedback: - Match both double-quoted and single-quoted string literals defensively - Clean up dangling `var ;` when __dirname is the sole declarator - Refactor into a loop over both identifiers to reduce duplication --- scripts/build-hooks.js | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/scripts/build-hooks.js b/scripts/build-hooks.js index 2c62e188..c5737851 100644 --- a/scripts/build-hooks.js +++ b/scripts/build-hooks.js @@ -45,17 +45,22 @@ function stripHardcodedDirname(filePath) { let content = fs.readFileSync(filePath, 'utf-8'); const before = content.length; - // Remove `var __dirname = "...", rest` → `var rest` - content = content.replace(/\bvar __dirname\s*=\s*"[^"]*",\s*/g, 'var '); - // Remove standalone `var __dirname = "...";` - content = content.replace(/\bvar __dirname\s*=\s*"[^"]*";\s*/g, ''); - // Remove `, __dirname = "..."` from mid/end of var declarations - content = content.replace(/,\s*__dirname\s*=\s*"[^"]*"/g, ''); + // Match both double-quoted and single-quoted string literals. + // esbuild currently emits double quotes, but single quotes are handled + // defensively in case future versions change quoting style. + const str = `(?:"[^"]*"|'[^']*')`; - // Same for __filename - content = content.replace(/\bvar __filename\s*=\s*"[^"]*",\s*/g, 'var '); - content = content.replace(/\bvar __filename\s*=\s*"[^"]*";\s*/g, ''); - content = content.replace(/,\s*__filename\s*=\s*"[^"]*"/g, ''); + for (const id of ['__dirname', '__filename']) { + // Remove `var = "...", rest` → `var rest` + content = content.replace(new RegExp(`\\bvar ${id}\\s*=\\s*${str},\\s*`, 'g'), 'var '); + // Remove standalone `var = "...";` + content = content.replace(new RegExp(`\\bvar ${id}\\s*=\\s*${str};\\s*`, 'g'), ''); + // Remove `, = "..."` from mid/end of var declarations + content = content.replace(new RegExp(`,\\s*${id}\\s*=\\s*${str}`, 'g'), ''); + } + + // Clean up dangling `var ;` left when __dirname was the sole declarator + content = content.replace(/\bvar\s*;/g, ''); const removed = before - content.length; if (removed > 0) {