From 43a8d1b1ae31155a65deb04fab3db4e145b24732 Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Thu, 13 Nov 2025 13:57:44 +1000 Subject: [PATCH] fix: Enable Windows builds and fix bun+pnpm install on Windows (#4273) --- packages/opencode/script/build.ts | 8 +-- packages/opencode/script/postinstall.mjs | 89 +++++++++++++++++++----- 2 files changed, 74 insertions(+), 23 deletions(-) diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts index 97631d90..2aaaaa2f 100755 --- a/packages/opencode/script/build.ts +++ b/packages/opencode/script/build.ts @@ -66,11 +66,11 @@ const allTargets: { avx2: false, }, { - os: "windows", + os: "win32", arch: "x64", }, { - os: "windows", + os: "win32", arch: "x64", avx2: false, }, @@ -115,7 +115,7 @@ for (const item of targets) { entrypoints: ["./src/index.ts", parserWorker, workerPath], define: { OPENCODE_VERSION: `'${Script.version}'`, - OTUI_TREE_SITTER_WORKER_PATH: "/$bunfs/root/" + path.relative(dir, parserWorker), + OTUI_TREE_SITTER_WORKER_PATH: "/$bunfs/root/" + path.relative(dir, parserWorker).replaceAll("\\", "/"), OPENCODE_WORKER_PATH: workerPath, OPENCODE_CHANNEL: `'${Script.channel}'`, }, @@ -127,7 +127,7 @@ for (const item of targets) { { name, version: Script.version, - os: [item.os === "windows" ? "win32" : item.os], + os: [item.os], cpu: [item.arch], }, null, diff --git a/packages/opencode/script/postinstall.mjs b/packages/opencode/script/postinstall.mjs index b875d158..89e67075 100644 --- a/packages/opencode/script/postinstall.mjs +++ b/packages/opencode/script/postinstall.mjs @@ -20,7 +20,7 @@ function detectPlatformAndArch() { platform = "linux" break case "win32": - platform = "windows" + platform = "win32" break default: platform = os.platform() @@ -50,24 +50,65 @@ function detectPlatformAndArch() { function findBinary() { const { platform, arch } = detectPlatformAndArch() const packageName = `opencode-${platform}-${arch}` - const binary = platform === "windows" ? "opencode.exe" : "opencode" + const binaryName = platform === "win32" ? "opencode.exe" : "opencode" try { // Use require.resolve to find the package const packageJsonPath = require.resolve(`${packageName}/package.json`) const packageDir = path.dirname(packageJsonPath) - const binaryPath = path.join(packageDir, "bin", binary) + const binaryPath = path.join(packageDir, "bin", binaryName) if (!fs.existsSync(binaryPath)) { throw new Error(`Binary not found at ${binaryPath}`) } - return binaryPath + return { binaryPath, binaryName } } catch (error) { throw new Error(`Could not find package ${packageName}: ${error.message}`) } } +function prepareBinDirectory(binaryName) { + const binDir = path.join(__dirname, "bin") + const targetPath = path.join(binDir, binaryName) + + // Ensure bin directory exists + if (!fs.existsSync(binDir)) { + fs.mkdirSync(binDir, { recursive: true }) + } + + // Remove existing binary/symlink if it exists + if (fs.existsSync(targetPath)) { + fs.unlinkSync(targetPath) + } + + return { binDir, targetPath } +} + +function copyBinary(sourcePath, binaryName) { + const { targetPath } = prepareBinDirectory(binaryName) + + fs.copyFileSync(sourcePath, targetPath) + console.log(`opencode binary installed: ${targetPath}`) + + // Verify the file exists after operation + if (!fs.existsSync(targetPath)) { + throw new Error(`Failed to copy binary to ${targetPath}`) + } +} + +function symlinkBinary(sourcePath, binaryName) { + const { targetPath } = prepareBinDirectory(binaryName) + + fs.symlinkSync(sourcePath, targetPath) + console.log(`opencode binary symlinked: ${targetPath} -> ${sourcePath}`) + + // Verify the file exists after operation + if (!fs.existsSync(targetPath)) { + throw new Error(`Failed to symlink binary to ${targetPath}`) + } +} + async function regenerateWindowsCmdWrappers() { console.log("Windows + npm detected: Forcing npm to rebuild bin links") @@ -102,27 +143,37 @@ async function main() { if (os.platform() === "win32") { // NPM eg format - npm/11.4.2 node/v24.4.1 win32 x64 // Bun eg format - bun/1.2.19 npm/? node/v24.3.0 win32 x64 - if (process.env.npm_config_user_agent.startsWith("npm")) { + // pnpm eg format - pnpm/8.10.0 npm/? node/v20.10.0 win32 x64 + const userAgent = process.env.npm_config_user_agent || "" + + if (userAgent.startsWith("npm")) { await regenerateWindowsCmdWrappers() - } else { - console.log("Windows detected but not npm, skipping postinstall") + return } + + if (userAgent.startsWith("bun")) { + console.log("Windows + bun detected: Setting up binary") + const { binaryPath, binaryName } = findBinary() + copyBinary(binaryPath, binaryName) + return + } + + if (userAgent.startsWith("pnpm")) { + console.log("Windows + pnpm detected: Setting up binary") + const { binaryPath, binaryName } = findBinary() + copyBinary(binaryPath, binaryName) + return + } + + // Unknown package manager on Windows + console.log("Windows detected but unknown package manager, skipping postinstall") return } - const binaryPath = findBinary() - const binScript = path.join(__dirname, "bin", "opencode") - - // Remove existing bin script if it exists - if (fs.existsSync(binScript)) { - fs.unlinkSync(binScript) - } - - // Create symlink to the actual binary - fs.symlinkSync(binaryPath, binScript) - console.log(`opencode binary symlinked: ${binScript} -> ${binaryPath}`) + const { binaryPath, binaryName } = findBinary() + symlinkBinary(binaryPath, binaryName) } catch (error) { - console.error("Failed to create opencode binary symlink:", error.message) + console.error("Failed to setup opencode binary:", error.message) process.exit(1) } }