Procházet zdrojové kódy

fix: resolve bun/pnpm global install failures on Windows (#4275)

Co-authored-by: Aiden Cline <[email protected]>
Luke Parker před 4 měsíci
rodič
revize
73443585e5

+ 5 - 4
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,

+ 3 - 67
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
     }
 

+ 28 - 3
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}`