diff --git a/apps/desktop/scripts/build-harness.mjs b/apps/desktop/scripts/build-harness.mjs index ca357bfa71..db970c175f 100644 --- a/apps/desktop/scripts/build-harness.mjs +++ b/apps/desktop/scripts/build-harness.mjs @@ -67,7 +67,11 @@ for (const [label, path] of [ } } -rmSync(out, { recursive: true, force: true }) +// Recursively removing the previous (multi-GB, symlink-heavy) harness can hit +// ENOTEMPTY/EBUSY transiently — on Windows especially, and on macOS under load. +// Retry so the rebuild is robust; maxRetries/retryDelay are Node's built-in +// answer to exactly these codes. +rmSync(out, { recursive: true, force: true, maxRetries: 10, retryDelay: 250 }) mkdirSync(join(out, 'apps'), { recursive: true }) mkdirSync(join(out, 'bin'), { recursive: true }) @@ -223,7 +227,28 @@ function pruneNodeModules(nmDir) { console.log(` [exclude] ${name} — removed top-level link (${fmtSize(sz)})`) } - // --- 5. Drop .bin shims that pointed into the removed store entries --- + // --- 5. Delete the flat .pnpm/node_modules/ copy. cpSync dereferences + // links while copying, so an excluded package lands here as a REAL directory + // (e.g. electron → 837 MB) that steps 2–4 never touch; it was shipping anyway. + // This shares the same safety check in step 2 — no kept package depends on it. + // Probe with lstatSync (not existsSync): it inspects the link itself rather + // than following the target, so a dangling symlink/junction (its .pnpm store + // entry already removed in step 3) is still found and removed on Windows. --- + const flat = join(pnpmDir, 'node_modules', ...name.split('/')) + let flatStat + try { + flatStat = lstatSync(flat) + } catch { + flatStat = null + } + if (flatStat) { + const sz = flatStat.isSymbolicLink() || flatStat.isFile() ? flatStat.size : dirSize(flat) + rmSync(flat, { recursive: true, force: true }) + totalFreed += sz + console.log(` [exclude] ${name} — removed flat .pnpm/node_modules copy (${fmtSize(sz)})`) + } + + // --- 6. Drop .bin shims that pointed into the removed store entries --- removeBinShims(join(nmDir, '.bin'), matching, pnpmDir) } diff --git a/apps/desktop/scripts/harness-excludes.json b/apps/desktop/scripts/harness-excludes.json index 19f29b1456..e3829f9975 100644 --- a/apps/desktop/scripts/harness-excludes.json +++ b/apps/desktop/scripts/harness-excludes.json @@ -58,6 +58,18 @@ { "name": "@electron/universal", "reason": "electron-builder toolchain (group): macOS universal binaries; build-time only." + }, + { + "name": "@electron/get", + "reason": "Orphan of the excluded electron toolchain: @electron/rebuild's download helper. No kept package imports it at runtime." + }, + { + "name": "@electron/rebuild", + "reason": "Orphan of the excluded electron toolchain: rebuilds native addons for the Electron ABI, which this app never needs (harness runs under system-Node)." + }, + { + "name": "@electron-internal/extract-zip", + "reason": "Orphan of the excluded electron-builder toolchain: internal zip extraction used only during packaging. Build-time only." } ] }