From f63baed573d9457d98c49ef228fe658b6fb0b3e5 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Mon, 14 Jul 2025 15:00:29 +0000 Subject: [PATCH] Replaced unzip with PowerShell on Windows Co-authored-by: thdxr --- packages/opencode/src/file/fzf.ts | 44 +++++++++++++++++++++------ packages/opencode/src/file/ripgrep.ts | 44 +++++++++++++++++++++------ packages/opencode/src/lsp/server.ts | 14 +++++++-- 3 files changed, 80 insertions(+), 22 deletions(-) diff --git a/packages/opencode/src/file/fzf.ts b/packages/opencode/src/file/fzf.ts index 1376af8cf..6069588f3 100644 --- a/packages/opencode/src/file/fzf.ts +++ b/packages/opencode/src/file/fzf.ts @@ -80,17 +80,41 @@ export namespace Fzf { }) } if (config.extension === "zip") { - const proc = Bun.spawn(["unzip", "-j", archivePath, "fzf.exe", "-d", Global.Path.bin], { - cwd: Global.Path.bin, - stderr: "pipe", - stdout: "ignore", - }) - await proc.exited - if (proc.exitCode !== 0) - throw new ExtractionFailedError({ - filepath: archivePath, - stderr: await Bun.readableStreamToText(proc.stderr), + if (process.platform === "win32") { + const powershellCommand = ` + Add-Type -AssemblyName System.IO.Compression.FileSystem; + $zip = [System.IO.Compression.ZipFile]::OpenRead('${archivePath.replace(/\\/g, '\\\\')}'); + $entry = $zip.Entries | Where-Object { $_.Name -eq 'fzf.exe' }; + if ($entry) { + [System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, '${path.join(Global.Path.bin, 'fzf.exe').replace(/\\/g, '\\\\')}', $true); + } + $zip.Dispose(); + `.trim() + + const proc = Bun.spawn(["powershell", "-Command", powershellCommand], { + cwd: Global.Path.bin, + stderr: "pipe", + stdout: "ignore", }) + await proc.exited + if (proc.exitCode !== 0) + throw new ExtractionFailedError({ + filepath: archivePath, + stderr: await Bun.readableStreamToText(proc.stderr), + }) + } else { + const proc = Bun.spawn(["unzip", "-j", archivePath, "fzf.exe", "-d", Global.Path.bin], { + cwd: Global.Path.bin, + stderr: "pipe", + stdout: "ignore", + }) + await proc.exited + if (proc.exitCode !== 0) + throw new ExtractionFailedError({ + filepath: archivePath, + stderr: await Bun.readableStreamToText(proc.stderr), + }) + } } await fs.unlink(archivePath) if (process.platform !== "win32") await fs.chmod(filepath, 0o755) diff --git a/packages/opencode/src/file/ripgrep.ts b/packages/opencode/src/file/ripgrep.ts index 05ebbe7d4..d69528ae6 100644 --- a/packages/opencode/src/file/ripgrep.ts +++ b/packages/opencode/src/file/ripgrep.ts @@ -161,17 +161,41 @@ export namespace Ripgrep { }) } if (config.extension === "zip") { - const proc = Bun.spawn(["unzip", "-j", archivePath, "*/rg.exe", "-d", Global.Path.bin], { - cwd: Global.Path.bin, - stderr: "pipe", - stdout: "ignore", - }) - await proc.exited - if (proc.exitCode !== 0) - throw new ExtractionFailedError({ - filepath: archivePath, - stderr: await Bun.readableStreamToText(proc.stderr), + if (process.platform === "win32") { + const powershellCommand = ` + Add-Type -AssemblyName System.IO.Compression.FileSystem; + $zip = [System.IO.Compression.ZipFile]::OpenRead('${archivePath.replace(/\\/g, '\\\\')}'); + $entry = $zip.Entries | Where-Object { $_.Name -eq 'rg.exe' }; + if ($entry) { + [System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, '${path.join(Global.Path.bin, 'rg.exe').replace(/\\/g, '\\\\')}', $true); + } + $zip.Dispose(); + `.trim() + + const proc = Bun.spawn(["powershell", "-Command", powershellCommand], { + cwd: Global.Path.bin, + stderr: "pipe", + stdout: "ignore", }) + await proc.exited + if (proc.exitCode !== 0) + throw new ExtractionFailedError({ + filepath: archivePath, + stderr: await Bun.readableStreamToText(proc.stderr), + }) + } else { + const proc = Bun.spawn(["unzip", "-j", archivePath, "*/rg.exe", "-d", Global.Path.bin], { + cwd: Global.Path.bin, + stderr: "pipe", + stdout: "ignore", + }) + await proc.exited + if (proc.exitCode !== 0) + throw new ExtractionFailedError({ + filepath: archivePath, + stderr: await Bun.readableStreamToText(proc.stderr), + }) + } } await fs.unlink(archivePath) if (!platformKey.endsWith("-win32")) await fs.chmod(filepath, 0o755) diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index 8c843fea1..16ea68c04 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -192,7 +192,12 @@ export namespace LSPServer { const zipPath = path.join(Global.Path.bin, "elixir-ls.zip") await Bun.file(zipPath).write(response) - await $`unzip -o -q ${zipPath}`.cwd(Global.Path.bin).nothrow() + if (process.platform === "win32") { + const powershellCommand = `Expand-Archive -Path '${zipPath.replace(/\\/g, '\\\\')}' -DestinationPath '${Global.Path.bin.replace(/\\/g, '\\\\')}' -Force` + await $`powershell -Command "${powershellCommand}"`.cwd(Global.Path.bin).nothrow() + } else { + await $`unzip -o -q ${zipPath}`.cwd(Global.Path.bin).nothrow() + } await fs.rm(zipPath, { force: true, @@ -294,7 +299,12 @@ export namespace LSPServer { await Bun.file(tempPath).write(downloadResponse) if (ext === "zip") { - await $`unzip -o -q ${tempPath}`.cwd(Global.Path.bin).nothrow() + if (process.platform === "win32") { + const powershellCommand = `Expand-Archive -Path '${tempPath.replace(/\\/g, '\\\\')}' -DestinationPath '${Global.Path.bin.replace(/\\/g, '\\\\')}' -Force` + await $`powershell -Command "${powershellCommand}"`.cwd(Global.Path.bin).nothrow() + } else { + await $`unzip -o -q ${tempPath}`.cwd(Global.Path.bin).nothrow() + } } else { await $`tar -xf ${tempPath}`.cwd(Global.Path.bin).nothrow() }