diff --git a/packages/desktop-electron/src/main/apps.ts b/packages/desktop-electron/src/main/apps.ts index 174da94a5d..d0d4618c29 100644 --- a/packages/desktop-electron/src/main/apps.ts +++ b/packages/desktop-electron/src/main/apps.ts @@ -13,7 +13,7 @@ export function resolveAppPath(appName: string): string | null { return resolveWindowsAppPath(appName) } -export function wslPath(path: string, mode: "windows" | "linux" | null): string { +export function wslPath(path: string, mode: "windows" | "linux" | null, distro?: string | null): string { if (process.platform !== "win32") return path const flag = mode === "windows" ? "-w" : "-u" @@ -21,17 +21,22 @@ export function wslPath(path: string, mode: "windows" | "linux" | null): string if (path.startsWith("~")) { const suffix = path.slice(1) const cmd = `wslpath ${flag} "$HOME${suffix.replace(/"/g, '\\"')}"` - const output = execFileSync("wsl", ["-e", "sh", "-lc", cmd]) + const output = execFileSync("wsl", inDistro(["sh", "-lc", cmd], distro)) return output.toString().trim() } - const output = execFileSync("wsl", ["-e", "wslpath", flag, path]) + const output = execFileSync("wsl", inDistro(["wslpath", flag, path], distro)) return output.toString().trim() } catch (error) { throw new Error(`Failed to run wslpath: ${String(error)}`, { cause: error }) } } +function inDistro(args: string[], distro?: string | null) { + if (!distro) return ["-e", ...args] + return ["-d", distro, "--", ...args] +} + function checkMacosApp(appName: string) { const locations = [`/Applications/${appName}.app`, `/System/Applications/${appName}.app`] diff --git a/packages/desktop-electron/src/main/index.ts b/packages/desktop-electron/src/main/index.ts index d3b617f863..c9298e5546 100644 --- a/packages/desktop-electron/src/main/index.ts +++ b/packages/desktop-electron/src/main/index.ts @@ -260,7 +260,7 @@ registerIpcHandlers({ setDisplayBackend: async () => undefined, parseMarkdown: async (markdown) => parseMarkdown(markdown), checkAppExists: async (appName) => checkAppExists(appName), - wslPath: async (path, mode) => wslPath(path, mode), + wslPath: async (path, mode, distro) => wslPath(path, mode, distro), resolveAppPath: async (appName) => resolveAppPath(appName), loadingWindowComplete: () => loadingComplete.resolve(), runUpdater: async (alertOnFail) => checkForUpdates(alertOnFail), diff --git a/packages/desktop-electron/src/main/ipc.ts b/packages/desktop-electron/src/main/ipc.ts index c837551886..444fec5cbd 100644 --- a/packages/desktop-electron/src/main/ipc.ts +++ b/packages/desktop-electron/src/main/ipc.ts @@ -31,7 +31,7 @@ type Deps = { setDisplayBackend: (backend: string | null) => Promise | void parseMarkdown: (markdown: string) => Promise | string checkAppExists: (appName: string) => Promise | boolean - wslPath: (path: string, mode: "windows" | "linux" | null) => Promise + wslPath: (path: string, mode: "windows" | "linux" | null, distro?: string | null) => Promise resolveAppPath: (appName: string) => Promise loadingWindowComplete: () => void runUpdater: (alertOnFail: boolean) => Promise | void @@ -68,8 +68,10 @@ export function registerIpcHandlers(deps: Deps) { ) ipcMain.handle("parse-markdown", (_event: IpcMainInvokeEvent, markdown: string) => deps.parseMarkdown(markdown)) ipcMain.handle("check-app-exists", (_event: IpcMainInvokeEvent, appName: string) => deps.checkAppExists(appName)) - ipcMain.handle("wsl-path", (_event: IpcMainInvokeEvent, path: string, mode: "windows" | "linux" | null) => - deps.wslPath(path, mode), + ipcMain.handle( + "wsl-path", + (_event: IpcMainInvokeEvent, path: string, mode: "windows" | "linux" | null, distro?: string | null) => + deps.wslPath(path, mode, distro), ) ipcMain.handle("resolve-app-path", (_event: IpcMainInvokeEvent, appName: string) => deps.resolveAppPath(appName)) ipcMain.on("loading-window-complete", () => deps.loadingWindowComplete()) diff --git a/packages/desktop-electron/src/preload/index.ts b/packages/desktop-electron/src/preload/index.ts index d2e21509e5..d1d20efcce 100644 --- a/packages/desktop-electron/src/preload/index.ts +++ b/packages/desktop-electron/src/preload/index.ts @@ -26,7 +26,7 @@ const api: ElectronAPI = { setDisplayBackend: (backend) => ipcRenderer.invoke("set-display-backend", backend), parseMarkdownCommand: (markdown) => ipcRenderer.invoke("parse-markdown", markdown), checkAppExists: (appName) => ipcRenderer.invoke("check-app-exists", appName), - wslPath: (path, mode) => ipcRenderer.invoke("wsl-path", path, mode), + wslPath: (path, mode, distro) => ipcRenderer.invoke("wsl-path", path, mode, distro), resolveAppPath: (appName) => ipcRenderer.invoke("resolve-app-path", appName), storeGet: (name, key) => ipcRenderer.invoke("store-get", name, key), storeSet: (name, key, value) => ipcRenderer.invoke("store-set", name, key, value), diff --git a/packages/desktop-electron/src/preload/types.ts b/packages/desktop-electron/src/preload/types.ts index 6118f318ef..704125f34a 100644 --- a/packages/desktop-electron/src/preload/types.ts +++ b/packages/desktop-electron/src/preload/types.ts @@ -68,7 +68,7 @@ export type ElectronAPI = { setDisplayBackend: (backend: LinuxDisplayBackend | null) => Promise parseMarkdownCommand: (markdown: string) => Promise checkAppExists: (appName: string) => Promise - wslPath: (path: string, mode: "windows" | "linux" | null) => Promise + wslPath: (path: string, mode: "windows" | "linux" | null, distro?: string | null) => Promise resolveAppPath: (appName: string) => Promise storeGet: (name: string, key: string) => Promise storeSet: (name: string, key: string, value: string) => Promise diff --git a/packages/desktop-electron/src/renderer/index.tsx b/packages/desktop-electron/src/renderer/index.tsx index 39721307a9..9ce70e5a99 100644 --- a/packages/desktop-electron/src/renderer/index.tsx +++ b/packages/desktop-electron/src/renderer/index.tsx @@ -57,17 +57,26 @@ const createPlatform = (): Platform => { return undefined })() + const wslDistro = async () => { + if (os !== "windows") return + const state = await window.api.localServer.getState().catch(() => null) + if (state?.config.mode !== "wsl") return + return state.config.distro + } + const wslHome = async () => { - if (os !== "windows" || !window.__OPENCODE__?.wsl) return undefined - return window.api.wslPath("~", "windows").catch(() => undefined) + const distro = await wslDistro() + if (!distro) return undefined + return window.api.wslPath("~", "windows", distro).catch(() => undefined) } const handleWslPicker = async (result: T | null): Promise => { - if (!result || !window.__OPENCODE__?.wsl) return result + const distro = await wslDistro() + if (!result || !distro) return result if (Array.isArray(result)) { - return Promise.all(result.map((path) => window.api.wslPath(path, "linux").catch(() => path))) as any + return Promise.all(result.map((path) => window.api.wslPath(path, "linux", distro).catch(() => path))) as any } - return window.api.wslPath(result, "linux").catch(() => result) as any + return window.api.wslPath(result, "linux", distro).catch(() => result) as any } const storage = (() => { @@ -137,8 +146,9 @@ const createPlatform = (): Platform => { if (os === "windows") { const resolvedApp = app ? await window.api.resolveAppPath(app).catch(() => null) : null const resolvedPath = await (async () => { - if (window.__OPENCODE__?.wsl) { - const converted = await window.api.wslPath(path, "windows").catch(() => null) + const distro = await wslDistro() + if (distro) { + const converted = await window.api.wslPath(path, "windows", distro).catch(() => null) if (converted) return converted } return path