#!/usr/bin/env node import fs from 'node:fs'; import path from 'node:path'; import { createRequire } from 'node:module'; const require = createRequire(import.meta.url); const targetFile = require.resolve('app-builder-lib/out/targets/nsis/NsisTarget.js'); const patchMarker = 'zn-ai patch: retry NSIS stub execution on Windows'; const helperSnippet = ` // ${patchMarker} function isRetryableWindowsSpawnError(error) { const code = error != null && typeof error.code === "string" ? error.code : ""; const message = error != null && typeof error.message === "string" ? error.message : ""; return (code === "EPERM" || code === "EACCES" || message.includes("spawn EPERM") || message.includes("spawn EACCES") || message.includes("used by another process")); } async function execWineWithRetry(file, file64 = null, appArgs = [], options = {}) { const maxAttempts = process.platform === "win32" ? 12 : 1; let attempt = 0; while (true) { attempt++; try { return await (0, wine_1.execWine)(file, file64, appArgs, options); } catch (error) { const shouldRetry = process.platform === "win32" && attempt < maxAttempts && isRetryableWindowsSpawnError(error); if (!shouldRetry) { throw error; } builder_util_1.log.warn({ attempt, maxAttempts, file, reason: error.message || String(error), }, "retrying NSIS stub execution after transient Windows spawn failure"); await new Promise(resolve => setTimeout(resolve, attempt * 1000)); } } } `; const originalCall = 'await (0, wine_1.execWine)(installerPath, null, [], { env: { __COMPAT_LAYER: "RunAsInvoker" } });'; const patchedCall = 'await execWineWithRetry(installerPath, null, [], { env: { __COMPAT_LAYER: "RunAsInvoker" } });'; const source = fs.readFileSync(targetFile, 'utf8'); if (source.includes(patchMarker)) { console.log(`[patch-electron-builder-nsis] already patched: ${targetFile}`); process.exit(0); } if (!source.includes(originalCall)) { console.error(`[patch-electron-builder-nsis] target call not found in ${targetFile}`); process.exit(1); } const classToken = 'class NsisTarget extends core_1.Target {'; if (!source.includes(classToken)) { console.error(`[patch-electron-builder-nsis] class token not found in ${targetFile}`); process.exit(1); } const patchedSource = source .replace(classToken, `${helperSnippet}\n${classToken}`) .replace(originalCall, patchedCall); fs.writeFileSync(targetFile, patchedSource, 'utf8'); console.log(`[patch-electron-builder-nsis] patched ${targetFile}`);