From 5ac68b8ec0b860fbd90de661d9e0e1c0c3a7edd7 Mon Sep 17 00:00:00 2001 From: MichielMAnalytics <135761097+MichielMAnalytics@users.noreply.github.com> Date: Wed, 6 May 2026 19:36:34 +0200 Subject: [PATCH] fix(opencode): strip directory query when proxying to remote workspace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SDK rewrites x-opencode-directory header to a ?directory= query for GET/HEAD requests. When proxied to a remote workspace, the local path leaks through, the remote can't resolve it, falls back to worktree="/", and corrupts sessionListQuery's path.relative() — which empties the TUI's session list and renders a black screen. Add the directory strip alongside the existing workspace strip so the adapter's target.headers["x-opencode-directory"] wins. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../opencode/src/server/shared/workspace-routing.ts | 9 +++++++++ .../opencode/test/server/workspace-routing.test.ts | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/packages/opencode/src/server/shared/workspace-routing.ts b/packages/opencode/src/server/shared/workspace-routing.ts index 366c455dd6bb..c57e392c2191 100644 --- a/packages/opencode/src/server/shared/workspace-routing.ts +++ b/packages/opencode/src/server/shared/workspace-routing.ts @@ -32,5 +32,14 @@ export function workspaceProxyURL(target: string | URL, requestURL: URL) { proxyURL.search = requestURL.search proxyURL.hash = requestURL.hash proxyURL.searchParams.delete("workspace") + // The SDK rewrites the client's `x-opencode-directory` header into a + // `?directory=` query before sending. When the request is then proxied + // to a remote workspace, that local-machine path leaks through and the + // remote falls back to `worktree="/"` because the path doesn't exist on + // its filesystem — which corrupts downstream `path.relative()` callers + // (notably `sessionListQuery`) and wipes the TUI's session list. + // Strip it so the workspace adapter's `target.headers["x-opencode-directory"]` + // (the workspace's directory on the remote) wins. + proxyURL.searchParams.delete("directory") return proxyURL } diff --git a/packages/opencode/test/server/workspace-routing.test.ts b/packages/opencode/test/server/workspace-routing.test.ts index a921ae2774c5..f851fc00087e 100644 --- a/packages/opencode/test/server/workspace-routing.test.ts +++ b/packages/opencode/test/server/workspace-routing.test.ts @@ -75,6 +75,18 @@ describe("workspaceProxyURL", () => { expect(result.searchParams.get("keep")).toBe("yes") }) + test("strips directory query so the remote uses its own working directory", () => { + // The SDK rewrites the client's `x-opencode-directory` header into a + // `?directory=` query before sending. Forwarding that local-machine + // path to a remote workspace makes the remote fall back to + // `worktree="/"` (the path doesn't exist on its filesystem) and + // corrupts downstream `path.relative()` callers. + const url = new URL("http://localhost/path?workspace=ws_123&directory=%2FUsers%2Falice%2Fproj") + const result = workspaceProxyURL("http://remote:8080", url) + expect(result.searchParams.get("workspace")).toBeNull() + expect(result.searchParams.get("directory")).toBeNull() + }) + test("preserves hash from request", () => { const url = new URL("http://localhost/page#section") const result = workspaceProxyURL("http://remote:8080", url)