fix(desktop): load WSL shell environment
This commit is contained in:
parent
c9db6e9a1f
commit
11b14dff4d
3 changed files with 62 additions and 16 deletions
29
packages/desktop/src/main/wsl/sidecar-shell.test.ts
Normal file
29
packages/desktop/src/main/wsl/sidecar-shell.test.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { expect, test } from "bun:test"
|
||||||
|
import { chmod, mkdtemp, rm, writeFile } from "node:fs/promises"
|
||||||
|
import { tmpdir } from "node:os"
|
||||||
|
import { join } from "node:path"
|
||||||
|
import { wslSidecarShell } from "./sidecar-shell"
|
||||||
|
|
||||||
|
test("loads interactive WSL environment variables for the desktop server", async () => {
|
||||||
|
const home = await mkdtemp(join(tmpdir(), "opencode-wsl-env-"))
|
||||||
|
const opencode = join(home, "opencode")
|
||||||
|
await writeFile(join(home, ".profile"), 'source "$HOME/.bashrc"\n')
|
||||||
|
await writeFile(join(home, ".bashrc"), "export COMPANY_BASEURL=https://company.example\n")
|
||||||
|
await writeFile(opencode, '#!/usr/bin/env bash\nprintf "%s" "$COMPANY_BASEURL"\n')
|
||||||
|
await chmod(opencode, 0o755)
|
||||||
|
|
||||||
|
const shell = wslSidecarShell(opencode, 4096, "opencode", "secret", false)
|
||||||
|
const proc = Bun.spawn(shell.args, {
|
||||||
|
cwd: home,
|
||||||
|
env: { ...process.env, HOME: home },
|
||||||
|
stdin: new Blob([shell.script]),
|
||||||
|
stdout: "pipe",
|
||||||
|
stderr: "pipe",
|
||||||
|
})
|
||||||
|
const output = await new Response(proc.stdout).text()
|
||||||
|
await new Response(proc.stderr).text()
|
||||||
|
const code = await proc.exited
|
||||||
|
await rm(home, { recursive: true, force: true })
|
||||||
|
|
||||||
|
expect({ code, output }).toEqual({ code: 0, output: "https://company.example" })
|
||||||
|
})
|
||||||
28
packages/desktop/src/main/wsl/sidecar-shell.ts
Normal file
28
packages/desktop/src/main/wsl/sidecar-shell.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { shellEscape } from "./runtime"
|
||||||
|
|
||||||
|
export function wslSidecarShell(opencode: string, port: number, username: string, password: string, packaged: boolean) {
|
||||||
|
return {
|
||||||
|
// Explicit WSL commands skip login startup files. Load the same user environment
|
||||||
|
// as a terminal launch, then replace the interactive shell before reading stdin.
|
||||||
|
args: [
|
||||||
|
"bash",
|
||||||
|
"--noprofile",
|
||||||
|
"--norc",
|
||||||
|
"-ic",
|
||||||
|
'for file in "$HOME/.bash_profile" "$HOME/.bash_login" "$HOME/.profile"; do [[ ! -r "$file" ]] || { source "$file"; break; }; done; exec bash -se',
|
||||||
|
],
|
||||||
|
script: [
|
||||||
|
"set -euo pipefail",
|
||||||
|
'cd "$HOME" || cd /',
|
||||||
|
'PATH=$(awk -v RS=: -v ORS=: \'$0 !~ /^\\/mnt\\//\' <<<"$PATH" | sed "s/:$//")',
|
||||||
|
"export PATH",
|
||||||
|
"export WSLENV=",
|
||||||
|
"export OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER=true",
|
||||||
|
"export OPENCODE_CLIENT=desktop",
|
||||||
|
`export OPENCODE_SERVER_USERNAME=${shellEscape(username)}`,
|
||||||
|
`export OPENCODE_SERVER_PASSWORD=${shellEscape(password)}`,
|
||||||
|
'export XDG_STATE_HOME="$HOME/.local/state"',
|
||||||
|
`exec ${shellEscape(opencode)} --print-logs --log-level ${packaged ? "WARN" : "INFO"} serve --hostname 0.0.0.0 --port ${port}`,
|
||||||
|
].join("\n"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,8 @@ import { randomUUID } from "node:crypto"
|
||||||
import { createServer } from "node:net"
|
import { createServer } from "node:net"
|
||||||
import { app } from "electron"
|
import { app } from "electron"
|
||||||
import { checkHealth } from "../server"
|
import { checkHealth } from "../server"
|
||||||
import { type WslCommandLine, resolveWslOpencode, shellEscape, wslArgs } from "./runtime"
|
import { type WslCommandLine, resolveWslOpencode, wslArgs } from "./runtime"
|
||||||
|
import { wslSidecarShell } from "./sidecar-shell"
|
||||||
import { pollWslHealth } from "./startup"
|
import { pollWslHealth } from "./startup"
|
||||||
|
|
||||||
export type WslSidecar = {
|
export type WslSidecar = {
|
||||||
|
|
@ -23,24 +24,12 @@ export async function spawnWslSidecar(
|
||||||
const port = await allocatePort()
|
const port = await allocatePort()
|
||||||
const password = randomUUID()
|
const password = randomUUID()
|
||||||
const username = "opencode"
|
const username = "opencode"
|
||||||
const script = [
|
const shell = wslSidecarShell(opencode, port, username, password, app.isPackaged)
|
||||||
"set -euo pipefail",
|
const child = spawn("wsl", wslArgs(shell.args, distro), {
|
||||||
'cd "$HOME" || cd /',
|
|
||||||
'PATH=$(awk -v RS=: -v ORS=: \'$0 !~ /^\\/mnt\\//\' <<<"$PATH" | sed "s/:$//")',
|
|
||||||
"export PATH",
|
|
||||||
"export WSLENV=",
|
|
||||||
"export OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER=true",
|
|
||||||
"export OPENCODE_CLIENT=desktop",
|
|
||||||
`export OPENCODE_SERVER_USERNAME=${shellEscape(username)}`,
|
|
||||||
`export OPENCODE_SERVER_PASSWORD=${shellEscape(password)}`,
|
|
||||||
'export XDG_STATE_HOME="$HOME/.local/state"',
|
|
||||||
`exec ${shellEscape(opencode)} --print-logs --log-level ${app.isPackaged ? "WARN" : "INFO"} serve --hostname 0.0.0.0 --port ${port}`,
|
|
||||||
].join("\n")
|
|
||||||
const child = spawn("wsl", wslArgs(["bash", "-se"], distro), {
|
|
||||||
stdio: ["pipe", "pipe", "pipe"],
|
stdio: ["pipe", "pipe", "pipe"],
|
||||||
windowsHide: true,
|
windowsHide: true,
|
||||||
})
|
})
|
||||||
child.stdin.end(script)
|
child.stdin.end(shell.script)
|
||||||
|
|
||||||
const recentOutput: string[] = []
|
const recentOutput: string[] = []
|
||||||
const emit = (line: WslCommandLine) => {
|
const emit = (line: WslCommandLine) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue