diff --git a/packages/tui/src/context/data.tsx b/packages/tui/src/context/data.tsx index 04a81cb0b44..0a03f815495 100644 --- a/packages/tui/src/context/data.tsx +++ b/packages/tui/src/context/data.tsx @@ -1064,6 +1064,16 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ ) for (const session of response.data) registerSession(session.id) }), + sdk.api.permission.listRequests({ location: locationQuery(defaultLocation()) }).then((response) => { + const permissions = mutable(response.data).reduce>( + (result, request) => ({ + ...result, + [request.sessionID]: [...(result[request.sessionID] ?? []), request], + }), + {}, + ) + setStore("session", "permission", reconcile(permissions)) + }), result.location.refresh(), result.location.agent.refresh(), result.location.integration.refresh(), diff --git a/packages/tui/test/cli/tui/data.test.tsx b/packages/tui/test/cli/tui/data.test.tsx index 3d87dce6473..480dcbbec75 100644 --- a/packages/tui/test/cli/tui/data.test.tsx +++ b/packages/tui/test/cli/tui/data.test.tsx @@ -1521,6 +1521,52 @@ test("adds and dismisses permission requests from live events", async () => { } }) +test("reconciles all pending permission requests when the event stream reconnects", async () => { + const events = createEventStream() + let requests = [ + { id: "per_old", sessionID: "ses_old", action: "read", resources: ["old.txt"] }, + { id: "per_keep", sessionID: "ses_keep", action: "shell", resources: ["bun test"] }, + ] + let calls = 0 + const fetch = createFetch((url) => { + if (url.pathname !== "/api/permission/request") return + calls++ + return json({ location: { directory, project: { id: "proj_test", directory } }, data: requests }) + }, events) + let data!: ReturnType + + function Probe() { + data = useData() + return + } + + const app = await testRender(() => ( + + + + + + + + + + )) + + try { + await wait(() => data.session.permission.list("ses_old")?.[0]?.id === "per_old") + expect(data.session.permission.list("ses_keep")?.[0]?.id).toBe("per_keep") + + requests = [{ id: "per_new", sessionID: "ses_new", action: "edit", resources: ["new.txt"] }] + events.disconnect() + + await wait(() => calls === 2 && data.session.permission.list("ses_new")?.[0]?.id === "per_new") + expect(data.session.permission.list("ses_old")).toBeUndefined() + expect(data.session.permission.list("ses_keep")).toBeUndefined() + } finally { + app.renderer.destroy() + } +}) + test("adds, dismisses, and refreshes form requests", async () => { const events = createEventStream() const calls = createFetch((url) => { diff --git a/packages/tui/test/fixture/tui-sdk.ts b/packages/tui/test/fixture/tui-sdk.ts index 30c2abe6e25..57520099117 100644 --- a/packages/tui/test/fixture/tui-sdk.ts +++ b/packages/tui/test/fixture/tui-sdk.ts @@ -101,6 +101,8 @@ export function createFetch(override?: FetchHandler, events?: ReturnType