This commit is contained in:
LukeParkerDev
2026-04-28 08:13:09 +10:00
parent 81e907febe
commit 4f6caacde4
2 changed files with 15 additions and 32 deletions

View File

@@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto"
import { EventEmitter } from "node:events"
import { existsSync } from "node:fs"
import * as nodeHttp from "node:http"
import * as nodeHttps from "node:https"
import { homedir } from "node:os"
import { join } from "node:path"
import type { Event } from "electron"
@@ -344,7 +345,7 @@ function wireMenu() {
}
registerIpcHandlers({
httpFetch: (input) => bridgedHttpFetch(input, readyWslUrls()),
httpFetch: (input) => bridgedHttpFetch(input),
killSidecar: () => killSidecar(),
relaunch: () => relaunchApp(),
awaitInitialization: async (sendStep) => {
@@ -393,12 +394,6 @@ registerIpcHandlers({
setBackgroundColor: (color) => setBackgroundColor(color),
})
function readyWslUrls() {
return wslServers
.getState()
.servers.flatMap((item) => (item.runtime.kind === "ready" ? [item.runtime.url] : []))
}
function killSidecar() {
if (!server) return
server.stop()
@@ -414,7 +409,7 @@ function relaunchApp() {
app.exit(0)
}
// Uses node:http directly rather than global fetch (undici). On Windows,
// Uses node http clients directly rather than global fetch (undici). On Windows,
// undici pools keep-alive sockets across requests; the WSL2 port proxy
// silently drops idle loopback sockets, so reusing one hangs until timeout.
// `agent: false` + `Connection: close` forces a fresh TCP connection per
@@ -430,7 +425,6 @@ function bridgedHttpFetch(
body?: string
timeoutMs?: number
},
allowedUrls: string[],
): Promise<{
status: number
statusText: string
@@ -445,12 +439,8 @@ function bridgedHttpFetch(
reject(new Error(`httpFetch: invalid url ${input.url}: ${String(error)}`))
return
}
if (parsed.protocol !== "http:") {
reject(new Error(`httpFetch: only http: is supported (got ${parsed.protocol})`))
return
}
if (!allowedUrls.some((url) => sameOrigin(parsed, url))) {
reject(new Error("httpFetch: url is not an active WSL sidecar"))
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
reject(new Error(`httpFetch: only http: and https: are supported (got ${parsed.protocol})`))
return
}
const method = input.method.toUpperCase()
@@ -463,9 +453,9 @@ function bridgedHttpFetch(
return
}
const req = nodeHttp.request({
const req = (parsed.protocol === "https:" ? nodeHttps : nodeHttp).request({
host: parsed.hostname,
port: parsed.port ? Number(parsed.port) : 80,
port: parsed.port ? Number(parsed.port) : parsed.protocol === "https:" ? 443 : 80,
path: `${parsed.pathname}${parsed.search}`,
method,
headers: { ...input.headers, connection: "close" },
@@ -517,15 +507,6 @@ function bridgedHttpFetch(
})
}
function sameOrigin(input: URL, allowed: string) {
try {
const url = new URL(allowed)
return input.protocol === url.protocol && input.hostname === url.hostname && input.port === url.port
} catch {
return false
}
}
function ensureLoopbackNoProxy() {
const loopback = ["127.0.0.1", "localhost", "::1"]
const upsert = (key: string) => {

View File

@@ -306,10 +306,11 @@ export async function installWslDistro(name: string, opts?: RunWslOptions) {
}
export async function installWslOpencode(version: string, distro: string, opts?: RunWslOptions) {
return runWslBash(
`curl -fsSL https://opencode.ai/install | bash -s -- --version ${shellEscape(version)}`,
distro,
return runInteractiveCommand(
resolveSystem32Command("wsl.exe"),
wslArgs(["bash", "-lc", `curl -fsSL https://opencode.ai/install | bash -s -- --version ${shellEscape(version)}`], distro),
withTimeout(opts, DEFAULT_WSL_INSTALL_TIMEOUT_MS),
DEFAULT_WSL_INSTALL_TIMEOUT_MS,
)
}
@@ -421,10 +422,11 @@ export async function readWslCommandVersion(command: string, distro: string, opt
}
export async function upgradeWslOpencode(target: string, command: string, distro: string, opts?: RunWslOptions) {
return runWslBash(
`${shellEscape(command)} upgrade ${shellEscape(target)}`,
distro,
return runInteractiveCommand(
resolveSystem32Command("wsl.exe"),
wslArgs(["bash", "-lc", `${shellEscape(command)} upgrade ${shellEscape(target)}`], distro),
withTimeout(opts, DEFAULT_WSL_INSTALL_TIMEOUT_MS),
DEFAULT_WSL_INSTALL_TIMEOUT_MS,
)
}