From b190b778d4860f20ffd7089a6fa398b9442baf78 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Sat, 22 Aug 2026 18:39:04 -0500 Subject: [PATCH] fix(tui): avoid premature environment sync (#44270) --- packages/client/src/solid/data.ts | 3 +++ packages/client/test/solid-data.test.ts | 33 ++++++++++++++++++++++++- packages/tui/src/app.tsx | 1 + 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/client/src/solid/data.ts b/packages/client/src/solid/data.ts index 0489f7ddc76..3ec0427071f 100644 --- a/packages/client/src/solid/data.ts +++ b/packages/client/src/solid/data.ts @@ -1101,6 +1101,9 @@ export function createData(config: CreateDataInput) { get(sessionID: string) { return store.session.info[sessionID] }, + creating(sessionID: string) { + return creating.has(sessionID) + }, remember(info: SessionInfo) { setStore("session", "info", info.id, reconcile(info)) sync.complete(`session:${info.id}`) diff --git a/packages/client/test/solid-data.test.ts b/packages/client/test/solid-data.test.ts index 9cc2c1c2a9e..c15d31578bf 100644 --- a/packages/client/test/solid-data.test.ts +++ b/packages/client/test/solid-data.test.ts @@ -1,4 +1,4 @@ -import { test } from "bun:test" +import { expect, test } from "bun:test" import { createRoot } from "solid-js" import { createData, type CreateDataInput } from "../src/solid" import { OpenCode, type OpenCodeEvent, type SessionInfo } from "../src/promise" @@ -72,6 +72,37 @@ test("revalidates after an event overtakes an active session read", async () => } }) +test("reports optimistic sessions as creating until the request settles", async () => { + const release = Promise.withResolvers() + const api = OpenCode.make({ + baseUrl: "http://opencode.local", + fetch: async (input, init) => { + const request = input instanceof Request ? input : new Request(input, init) + if (!request.url.endsWith("/api/session")) throw new Error(`Unexpected request: ${request.url}`) + await release.promise + return Response.json({ data: session(0) }) + }, + }) + const event: CreateDataInput["event"] = { + on: () => () => {}, + listen: () => () => {}, + } + const setup = createRoot((dispose) => ({ + data: createData({ api: () => api, directory: "/project", event, connection: { status: () => "connected" } }), + dispose, + })) + + try { + const created = setup.data.session.create({ id: "ses_refresh", location: { directory: "/project" } }) + expect(setup.data.session.creating(created.id)).toBe(true) + release.resolve() + await created.request + expect(setup.data.session.creating(created.id)).toBe(false) + } finally { + setup.dispose() + } +}) + async function wait(check: () => boolean) { const started = Date.now() while (!check()) { diff --git a/packages/tui/src/app.tsx b/packages/tui/src/app.tsx index daf1ad82e4b..64f3293e71e 100644 --- a/packages/tui/src/app.tsx +++ b/packages/tui/src/app.tsx @@ -486,6 +486,7 @@ function App(props: { pair?: DialogPairCredentials }) { if (route.data.type !== "session") return const session = data.session.get(route.data.sessionID) if (!session) return + if (data.session.creating(session.id)) return if (session.location.workspaceID !== undefined || terminalEnvironment.variables === undefined) return void client.api.session .environment({ sessionID: session.id, variables: terminalEnvironment.variables })