summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorLuke Parker <[email protected]>2025-11-14 02:38:57 +1000
committerGitHub <[email protected]>2025-11-13 10:38:57 -0600
commit73443585e5e939522d306c601056dcdf609d67c3 (patch)
tree2c97adc740a40e56bf7dc687a01bf610d35cde6a
parent609ab069a99d6832c03c5b7b0b88c14b240ba4f8 (diff)
downloadopencode-73443585e5e939522d306c601056dcdf609d67c3.tar.gz
opencode-73443585e5e939522d306c601056dcdf609d67c3.zip
fix: resolve bun/pnpm global install failures on Windows (#4275)
Co-authored-by: Aiden Cline <[email protected]>
-rwxr-xr-xpackages/opencode/script/build.ts9
-rw-r--r--packages/opencode/script/postinstall.mjs70
-rwxr-xr-xpackages/opencode/script/publish.ts31
3 files changed, 36 insertions, 74 deletions
diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts
index 6731bea0b..502baed02 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,
},
@@ -88,7 +88,8 @@ await $`bun install --os="*" --cpu="*" @parcel/watcher@${pkg.dependencies["@parc
for (const item of targets) {
const name = [
pkg.name,
- item.os,
+ // changing to win32 flags npm for some reason
+ item.os === "win32" ? "windows" : item.os,
item.arch,
item.avx2 === false ? "baseline" : undefined,
item.abi === undefined ? undefined : item.abi,
@@ -127,7 +128,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 23a665175..78f022c9f 100644
--- a/packages/opencode/script/postinstall.mjs
+++ b/packages/opencode/script/postinstall.mjs
@@ -85,18 +85,6 @@ function prepareBinDirectory(binaryName) {
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)
@@ -109,64 +97,12 @@ function symlinkBinary(sourcePath, binaryName) {
}
}
-async function regenerateWindowsCmdWrappers() {
- console.log("Windows + npm detected: Forcing npm to rebuild bin links")
-
- try {
- const { execSync } = require("child_process")
- const pkgPath = path.join(__dirname, "..")
-
- // npm_config_global is string | undefined
- // if it exists, the value is true
- const isGlobal = process.env.npm_config_global === "true" || pkgPath.includes(path.join("npm", "node_modules"))
-
- // The npm rebuild command does 2 things - Execute lifecycle scripts and rebuild bin links
- // We want to skip lifecycle scripts to avoid infinite loops, so we use --ignore-scripts
- const cmd = `npm rebuild opencode-ai --ignore-scripts${isGlobal ? " -g" : ""}`
- const opts = {
- stdio: "inherit",
- shell: true,
- ...(isGlobal ? {} : { cwd: path.join(pkgPath, "..", "..") }), // For local, run from project root
- }
-
- console.log(`Running: ${cmd}`)
- execSync(cmd, opts)
- console.log("Successfully rebuilt npm bin links")
- } catch (error) {
- console.error("Error rebuilding npm links:", error.message)
- console.error("npm rebuild failed. You may need to manually run: npm rebuild opencode-ai --ignore-scripts")
- }
-}
-
async function main() {
try {
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
- // 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()
- 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")
+ // On Windows, the .exe is already included in the package and bin field points to it
+ // No postinstall setup needed
+ console.log("Windows detected: binary setup not needed (using packaged .exe)")
return
}
diff --git a/packages/opencode/script/publish.ts b/packages/opencode/script/publish.ts
index 3e989cc6a..ac2fce56b 100755
--- a/packages/opencode/script/publish.ts
+++ b/packages/opencode/script/publish.ts
@@ -2,8 +2,10 @@
import { $ } from "bun"
import pkg from "../package.json"
import { Script } from "@opencode-ai/script"
+import { fileURLToPath } from "url"
+import fs from "fs"
-const dir = new URL("..", import.meta.url).pathname
+const dir = fileURLToPath(new URL("..", import.meta.url))
process.chdir(dir)
const { binaries } = await import("./build.ts")
@@ -15,14 +17,29 @@ const { binaries } = await import("./build.ts")
await $`mkdir -p ./dist/${pkg.name}`
await $`cp -r ./bin ./dist/${pkg.name}/bin`
+
+// Copy Windows .exe if any Windows binaries were built
+let hasWindowsBinary = false
+for (const binaryName of Object.keys(binaries)) {
+ if (binaryName.includes("win32")) {
+ const winBinaryPath = `./dist/${binaryName}/bin/opencode.exe`
+ if (fs.existsSync(winBinaryPath)) {
+ await $`cp ${winBinaryPath} ./dist/${pkg.name}/bin/opencode.exe`
+ hasWindowsBinary = true
+ break
+ }
+ }
+}
+
await $`cp ./script/preinstall.mjs ./dist/${pkg.name}/preinstall.mjs`
await $`cp ./script/postinstall.mjs ./dist/${pkg.name}/postinstall.mjs`
+
await Bun.file(`./dist/${pkg.name}/package.json`).write(
JSON.stringify(
{
name: pkg.name + "-ai",
bin: {
- [pkg.name]: `./bin/${pkg.name}`,
+ [pkg.name]: hasWindowsBinary ? `./bin/${pkg.name}.exe` : `./bin/${pkg.name}`,
},
scripts: {
preinstall: "bun ./preinstall.mjs || node ./preinstall.mjs",
@@ -36,7 +53,15 @@ await Bun.file(`./dist/${pkg.name}/package.json`).write(
),
)
for (const [name] of Object.entries(binaries)) {
- await $`cd dist/${name} && chmod 777 -R . && bun publish --access public --tag ${Script.channel}`
+ try {
+ process.chdir(`./dist/${name}`)
+ if (process.platform !== "win32") {
+ await $`chmod 755 -R .`
+ }
+ await $`bun publish --access public --tag ${Script.channel}`
+ } finally {
+ process.chdir(dir)
+ }
}
await $`cd ./dist/${pkg.name} && bun publish --access public --tag ${Script.channel}`