refactor: derive Electron WSL paths from local server config

This commit is contained in:
LukeParkerDev
2026-04-16 14:17:55 +10:00
parent 9d4737fdc9
commit 1a215700c8
6 changed files with 33 additions and 16 deletions

View File

@@ -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`]

View File

@@ -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),

View File

@@ -31,7 +31,7 @@ type Deps = {
setDisplayBackend: (backend: string | null) => Promise<void> | void
parseMarkdown: (markdown: string) => Promise<string> | string
checkAppExists: (appName: string) => Promise<boolean> | boolean
wslPath: (path: string, mode: "windows" | "linux" | null) => Promise<string>
wslPath: (path: string, mode: "windows" | "linux" | null, distro?: string | null) => Promise<string>
resolveAppPath: (appName: string) => Promise<string | null>
loadingWindowComplete: () => void
runUpdater: (alertOnFail: boolean) => Promise<void> | 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())

View File

@@ -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),

View File

@@ -68,7 +68,7 @@ export type ElectronAPI = {
setDisplayBackend: (backend: LinuxDisplayBackend | null) => Promise<void>
parseMarkdownCommand: (markdown: string) => Promise<string>
checkAppExists: (appName: string) => Promise<boolean>
wslPath: (path: string, mode: "windows" | "linux" | null) => Promise<string>
wslPath: (path: string, mode: "windows" | "linux" | null, distro?: string | null) => Promise<string>
resolveAppPath: (appName: string) => Promise<string | null>
storeGet: (name: string, key: string) => Promise<string | null>
storeSet: (name: string, key: string, value: string) => Promise<void>

View File

@@ -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 <T extends string | string[]>(result: T | null): Promise<T | null> => {
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