import { copyFileSync, existsSync, unlinkSync } from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' import rcedit from 'rcedit' const PATCH_TARGETS = new Set(['launcher.exe']) const MAX_ATTEMPTS = 6 const BASE_DELAY_MS = 500 function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)) } async function patchExecutable(executablePath) { let lastError for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) { const tempPath = `${executablePath}.rcedit-${process.pid}-${attempt}.tmp` try { // Patch a copy then replace — avoids AV/indexer locks on the live PE. copyFileSync(executablePath, tempPath) await rcedit(tempPath, { 'requested-execution-level': 'asInvoker' }) copyFileSync(tempPath, executablePath) return } catch (error) { lastError = error const message = error instanceof Error ? error.message : String(error) console.warn( `patch-windows-binaries: attempt ${attempt}/${MAX_ATTEMPTS} failed for ${executablePath}: ${message}` ) if (attempt < MAX_ATTEMPTS) { await sleep(BASE_DELAY_MS * 2 ** (attempt - 1)) } } finally { try { unlinkSync(tempPath) } catch { // Ignore cleanup failures. } } } throw lastError } export async function patchWindowsBinaries(appDir) { if (process.platform !== 'win32') { return } const binDir = path.join(appDir, 'bin') if (!existsSync(binDir)) { throw new Error(`patch-windows-binaries: bin directory not found at ${binDir}`) } for (const executable of PATCH_TARGETS) { const executablePath = path.join(binDir, executable) if (!existsSync(executablePath)) { console.warn(`patch-windows-binaries: skipping missing ${executablePath}`) continue } try { await patchExecutable(executablePath) console.log(`patch-windows-binaries: set asInvoker on ${executablePath}`) } catch (error) { console.warn( `patch-windows-binaries: failed to patch ${executablePath}:`, error instanceof Error ? error.message : error ) } } } if (process.argv[1] === fileURLToPath(import.meta.url)) { const appDirArg = process.argv[2] if (!appDirArg) { console.error('Usage: bun scripts/patch-windows-binaries.mjs ') process.exit(1) } await patchWindowsBinaries(path.resolve(appDirArg)) }