import { existsSync } from "node:fs"; import path from "node:path"; import { spawnSync } from "node:child_process"; import { fileURLToPath } from "node:url"; const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const WINDOWS_BIN_FILES = ["launcher.exe", "bun.exe"]; function ensureIconIco() { const iconPath = path.join(rootDir, "assets/icon.ico"); if (existsSync(iconPath)) { return iconPath; } const sources = [ path.join(rootDir, "assets/farmcontrolhosticon.png"), path.join(rootDir, "assets/icon.png"), ]; const source = sources.find((candidate) => existsSync(candidate)); if (!source) { throw new Error( "apply-windows-launcher-icon: assets/icon.ico not found and no source PNG to generate it", ); } console.log(`apply-windows-launcher-icon: generating icon.ico from ${source}`); const result = spawnSync( "bun", [path.join(rootDir, "scripts/prepare-app-icons.mjs"), source], { cwd: rootDir, stdio: "inherit", env: process.env }, ); if (result.status !== 0 || !existsSync(iconPath)) { throw new Error("apply-windows-launcher-icon: failed to generate assets/icon.ico"); } return iconPath; } /** * Embed the Farm Control icon into Windows launcher binaries. * Electrobun's built-in rcedit step often fails in CI (see electrobun#429). */ export async function applyWindowsLauncherIcon(appDir) { if (process.platform !== "win32") { console.log("apply-windows-launcher-icon: skipped (not Windows)"); return; } const iconPath = ensureIconIco(); const binDir = path.join(appDir, "bin"); if (!existsSync(binDir)) { throw new Error(`apply-windows-launcher-icon: bin directory not found: ${binDir}`); } const rcedit = (await import("rcedit")).default; let patched = 0; for (const fileName of WINDOWS_BIN_FILES) { const exePath = path.join(binDir, fileName); if (!existsSync(exePath)) { continue; } console.log(`apply-windows-launcher-icon: embedding icon into ${exePath}`); try { await rcedit(exePath, { icon: iconPath }); patched += 1; } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error( `apply-windows-launcher-icon: failed to embed icon into ${fileName}: ${message}`, ); } } if (patched === 0) { throw new Error( `apply-windows-launcher-icon: no launcher binaries found in ${binDir}`, ); } }