Skip to content

Commit dfdf88f

Browse files
committed
fix(sdk): avoid implicit session directory filtering
Preserves project-scoped session listing when the SDK is configured with a working directory. This keeps TUI session resume working across worktrees while still honoring an explicit `directory` filter on `GET /session`. Closes: anomalyco#20238 Refs: anomalyco#20361
1 parent 6314f09 commit dfdf88f

File tree

2 files changed

+54
-1
lines changed

2 files changed

+54
-1
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { afterEach, describe, expect, test } from "bun:test"
2+
import { mkdir } from "fs/promises"
3+
import { createOpencodeClient } from "@opencode-ai/sdk/v2"
4+
import { Instance } from "../../src/project/instance"
5+
import { Server } from "../../src/server/server"
6+
import { Session } from "../../src/session"
7+
import { Log } from "../../src/util/log"
8+
import { tmpdir } from "../fixture/fixture"
9+
10+
Log.init({ print: false })
11+
12+
afterEach(async () => {
13+
await Instance.disposeAll()
14+
})
15+
16+
describe("session.list with sdk directory", () => {
17+
test("does not implicitly filter by current directory", async () => {
18+
await using tmp = await tmpdir({ git: true })
19+
const dir = `${tmp.path}/.dmux/worktrees/a`
20+
await mkdir(dir, { recursive: true })
21+
22+
const key = `worktree-${Date.now()}`
23+
const root = await Instance.provide({
24+
directory: tmp.path,
25+
fn: async () => Session.create({ title: `${key}-root` }),
26+
})
27+
const child = await Instance.provide({
28+
directory: dir,
29+
fn: async () => Session.create({ title: `${key}-child` }),
30+
})
31+
32+
const app = Server.Default()
33+
const fetcher = (async (input: RequestInfo | URL, init?: RequestInit) => {
34+
const req = new Request(input, init)
35+
return app.fetch(req)
36+
}) as typeof globalThis.fetch
37+
38+
const sdk = createOpencodeClient({
39+
baseUrl: "http://opencode.internal",
40+
directory: dir,
41+
fetch: fetcher,
42+
})
43+
const res = await sdk.session.list({ search: key })
44+
const ids = (res.data ?? []).map((item) => item.id)
45+
46+
expect(ids).toContain(root.id)
47+
expect(ids).toContain(child.id)
48+
})
49+
})

packages/sdk/js/src/v2/client.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,23 @@ function rewrite(request: Request, values: { directory?: string; workspace?: str
1717
if (request.method !== "GET" && request.method !== "HEAD") return request
1818

1919
const url = new URL(request.url)
20+
const session = /\/session\/?$/.test(url.pathname)
2021
let changed = false
2122

2223
for (const [name, key] of [
2324
["x-opencode-directory", "directory"],
2425
["x-opencode-workspace", "workspace"],
2526
] as const) {
27+
const has = url.searchParams.has(key)
28+
if (key === "directory" && session && !has) continue
29+
2630
const value = pick(
2731
request.headers.get(name),
2832
key === "directory" ? values.directory : values.workspace,
2933
key === "directory" ? encodeURIComponent : undefined,
3034
)
3135
if (!value) continue
32-
if (!url.searchParams.has(key)) {
36+
if (!has) {
3337
url.searchParams.set(key, value)
3438
}
3539
changed = true

0 commit comments

Comments
 (0)