From ac0546c0b00b7802dfbe183957b7da1b1e837a4c Mon Sep 17 00:00:00 2001 From: 7418 <7418@openclaw.ai> Date: Sat, 7 Feb 2026 13:31:54 +0800 Subject: [PATCH] fix: ensure better-sqlite3 in standalone uses Electron ABI Add afterPack hook that copies the @electron/rebuild-compiled better_sqlite3.node into the standalone resources directory. Previously the standalone copy retained the system Node ABI from next build, causing MODULE_VERSION mismatch at runtime. Co-Authored-By: Claude Opus 4.6 --- electron-builder.yml | 1 + scripts/after-pack.js | 70 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 scripts/after-pack.js diff --git a/electron-builder.yml b/electron-builder.yml index 5fd069d..327caf1 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -30,6 +30,7 @@ extraResources: - from: public/ to: standalone/public/ filter: ["**/*"] +afterPack: scripts/after-pack.js asarUnpack: - "**/*.node" - "**/better-sqlite3/**" diff --git a/scripts/after-pack.js b/scripts/after-pack.js new file mode 100644 index 0000000..ce174f3 --- /dev/null +++ b/scripts/after-pack.js @@ -0,0 +1,70 @@ +/** + * electron-builder afterPack hook. + * + * After @electron/rebuild recompiles native modules for Electron's ABI, + * copy the rebuilt better_sqlite3.node into the standalone resources + * (which still has the system-Node version from `next build`). + */ +const fs = require('fs'); +const path = require('path'); + +module.exports = async function afterPack(context) { + const appOutDir = context.appOutDir; + + // Source: the rebuilt .node file in the project's node_modules + const rebuiltSource = path.join( + process.cwd(), + 'node_modules', + 'better-sqlite3', + 'build', + 'Release', + 'better_sqlite3.node' + ); + + if (!fs.existsSync(rebuiltSource)) { + console.warn('[afterPack] Rebuilt better_sqlite3.node not found at', rebuiltSource); + return; + } + + // Find all better_sqlite3.node files inside the standalone resources + const resourcesDir = path.join(appOutDir, 'CodePilot.app', 'Contents', 'Resources'); + // On macOS the structure is: /CodePilot.app/Contents/Resources/standalone/... + // But appOutDir might already point to the .app parent, so try both + const searchRoots = [ + path.join(resourcesDir, 'standalone'), + path.join(appOutDir, 'Contents', 'Resources', 'standalone'), + ]; + + let replaced = 0; + + function walkAndReplace(dir) { + if (!fs.existsSync(dir)) return; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + walkAndReplace(fullPath); + } else if (entry.name === 'better_sqlite3.node') { + console.log(`[afterPack] Replacing ${fullPath}`); + fs.copyFileSync(rebuiltSource, fullPath); + replaced++; + } + } + } + + for (const root of searchRoots) { + walkAndReplace(root); + } + + if (replaced > 0) { + console.log(`[afterPack] Replaced ${replaced} better_sqlite3.node file(s) with Electron-compatible build`); + } else { + console.warn('[afterPack] No better_sqlite3.node files found in standalone resources'); + // List the resources dir for debugging + for (const root of searchRoots) { + if (fs.existsSync(root)) { + console.log(`[afterPack] Contents of ${root}:`, fs.readdirSync(root).slice(0, 20)); + } + } + } +};