diff --git a/packages/electron/README.md b/packages/electron/README.md index 04229790..f3418bad 100644 --- a/packages/electron/README.md +++ b/packages/electron/README.md @@ -64,7 +64,7 @@ That runs, in order: 2. `prepare:opencode-cli` to download/cache the pinned OpenCode CLI and copy it into `packages/electron/resources/opencode-cli`. 3. `bundle:main` to create `packages/electron/dist-bundle/main.mjs`. 4. `rebuild:native` to rebuild native modules for Electron. -5. `package.mjs` to run `electron-builder`. +5. `package.mjs` to run `electron-builder`; its `afterPack` hook stages the rebuilt `better-sqlite3` binary that Electron Builder's Bun dependency collector otherwise omits. Build output goes to `packages/electron/dist`. diff --git a/packages/electron/scripts/after-pack.cjs b/packages/electron/scripts/after-pack.cjs index c68f53fb..542ea614 100644 --- a/packages/electron/scripts/after-pack.cjs +++ b/packages/electron/scripts/after-pack.cjs @@ -2,11 +2,28 @@ const fs = require('node:fs'); const path = require('node:path'); module.exports = (context) => { + const resourcesPath = context.electronPlatformName === 'darwin' + ? path.join(context.appOutDir, `${context.packager.appInfo.productFilename}.app`, 'Contents', 'Resources') + : path.join(context.appOutDir, 'resources'); + const betterSqliteDir = path.dirname(require.resolve('better-sqlite3/package.json')); + const betterSqliteBinary = path.join(betterSqliteDir, 'build', 'Release', 'better_sqlite3.node'); + if (!fs.existsSync(betterSqliteBinary)) { + throw new Error(`Missing rebuilt better-sqlite3 binary at ${betterSqliteBinary}`); + } + const packagedBetterSqliteBinary = path.join( + resourcesPath, + 'app.asar.unpacked', + 'node_modules', + 'better-sqlite3', + 'build', + 'Release', + 'better_sqlite3.node', + ); + fs.mkdirSync(path.dirname(packagedBetterSqliteBinary), { recursive: true }); + fs.copyFileSync(betterSqliteBinary, packagedBetterSqliteBinary); + if (context.electronPlatformName !== 'darwin') return; - const appName = context.packager.appInfo.productFilename; - const appBundlePath = path.join(context.appOutDir, `${appName}.app`); - const resourcesPath = path.join(appBundlePath, 'Contents', 'Resources'); const sourceAssetsPath = path.join(__dirname, '..', 'resources', 'icons', 'Assets.car'); if (!fs.existsSync(sourceAssetsPath)) { diff --git a/packages/electron/scripts/rebuild-native.mjs b/packages/electron/scripts/rebuild-native.mjs index ed4d52b7..47039cc5 100644 --- a/packages/electron/scripts/rebuild-native.mjs +++ b/packages/electron/scripts/rebuild-native.mjs @@ -133,6 +133,19 @@ const ensureWindowsNodeAddonApiForNodePty = async (rebuildRootPath) => { console.log(`[electron] rebuilding native modules against Electron ${electronVersion}...`); +await rebuild({ + buildPath: electronDir, + electronVersion, + force: true, + arch: targetArchitecture.electronBuilder, + onlyModules: ['better-sqlite3'], +}); +const betterSqliteDir = path.dirname(require.resolve('better-sqlite3/package.json')); +const betterSqliteBinary = path.join(betterSqliteDir, 'build', 'Release', 'better_sqlite3.node'); +if (!existsSync(betterSqliteBinary)) { + throw new Error(`better-sqlite3 rebuild did not produce ${betterSqliteBinary}`); +} + // Rebuild against the hoisted root node_modules (bun workspace layout). // force=true re-links regardless of cached state; prebuild-install lookup is // bypassed by @electron/rebuild in favor of direct node-gyp builds. @@ -145,7 +158,7 @@ try { electronVersion, force: true, arch: targetArchitecture.electronBuilder, - onlyModules: ['better-sqlite3', 'node-pty', 'bun-pty'], + onlyModules: ['node-pty', 'bun-pty'], }); } finally { try {