/** @jsxImportSource @opentui/solid */ import { describe, expect, test } from "bun:test" import { testRender } from "@opentui/solid" import { onMount } from "solid-js" import { Global } from "@opencode-ai/core/global" import { ArgsProvider } from "../../../../src/cli/cmd/tui/context/args" import { ExitProvider } from "../../../../src/cli/cmd/tui/context/exit" import { KVProvider, useKV } from "../../../../src/cli/cmd/tui/context/kv" import { ProjectProvider } from "../../../../src/cli/cmd/tui/context/project" import { SDKProvider, type EventSource } from "../../../../src/cli/cmd/tui/context/sdk" import { SyncProvider, useSync } from "../../../../src/cli/cmd/tui/context/sync" import { tmpdir } from "../../../fixture/fixture" const worktree = "/tmp/opencode" const directory = `${worktree}/packages/opencode` async function wait(fn: () => boolean, timeout = 2000) { const start = Date.now() while (!fn()) { if (Date.now() - start > timeout) throw new Error("timed out waiting for condition") await Bun.sleep(10) } } function json(data: unknown) { return new Response(JSON.stringify(data), { headers: { "content-type": "application/json" }, }) } function eventSource(): EventSource { return { subscribe: async () => () => {}, } } function createFetch() { const session = [] as URL[] const fetch = (async (input: RequestInfo | URL) => { const url = new URL(input instanceof Request ? input.url : String(input)) if (url.pathname === "/session") session.push(url) switch (url.pathname) { case "/agent": case "/command": case "/experimental/workspace": case "/experimental/workspace/status": case "/formatter": case "/lsp": return json([]) case "/config": case "/experimental/resource": case "/mcp": case "/provider/auth": case "/session/status": return json({}) case "/config/providers": return json({ providers: {}, default: {} }) case "/experimental/console": return json({ consoleManagedProviders: [], switchableOrgCount: 0 }) case "/path": return json({ home: "", state: "", config: "", worktree, directory }) case "/project/current": return json({ id: "proj_test" }) case "/provider": return json({ all: [], default: {}, connected: [] }) case "/session": return json([]) case "/vcs": return json({ branch: "main" }) } throw new Error(`unexpected request: ${url.pathname}`) }) as typeof globalThis.fetch return { fetch, session } } async function mount() { const calls = createFetch() let sync!: ReturnType let kv!: ReturnType let done!: () => void const ready = new Promise((resolve) => { done = resolve }) const app = await testRender(() => ( { sync = ctx.sync kv = ctx.kv done() }} /> )) await ready await wait(() => sync.status === "complete") return { app, kv, sync, session: calls.session } } function Probe(props: { onReady: (ctx: { kv: ReturnType; sync: ReturnType }) => void }) { const kv = useKV() const sync = useSync() onMount(() => { props.onReady({ kv, sync }) }) return } describe("tui sync", () => { test("refresh scopes sessions by default and lists project sessions when disabled", async () => { const previous = Global.Path.state await using tmp = await tmpdir() Global.Path.state = tmp.path await Bun.write(`${tmp.path}/kv.json`, "{}") const { app, kv, sync, session } = await mount() try { expect(kv.get("session_directory_filter_enabled", true)).toBe(true) expect(session.at(-1)?.searchParams.get("scope")).toBeNull() expect(session.at(-1)?.searchParams.get("path")).toBe("packages/opencode") kv.set("session_directory_filter_enabled", false) await sync.session.refresh() expect(session.at(-1)?.searchParams.get("scope")).toBe("project") expect(session.at(-1)?.searchParams.get("path")).toBeNull() } finally { app.renderer.destroy() Global.Path.state = previous } }) })