diff --git a/packages/tui/src/context/data.tsx b/packages/tui/src/context/data.tsx index c2f1beef12..d292926aa7 100644 --- a/packages/tui/src/context/data.tsx +++ b/packages/tui/src/context/data.tsx @@ -28,7 +28,7 @@ import { createSignal, onCleanup } from "solid-js" export type DataSessionStatus = "idle" | "running" -export type FormInfo = FormFormInfo | FormUrlInfo +export type FormInfo = (FormFormInfo | FormUrlInfo) & { readonly location?: LocationRef } type LocationData = { agent?: AgentV2Info[] @@ -577,7 +577,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ if (store.session.form[event.data.form.sessionID]?.some((form) => form.id === event.data.form.id)) break setStore("session", "form", event.data.form.sessionID, [ ...(store.session.form[event.data.form.sessionID] ?? []), - mutable(event.data.form), + mutable({ ...event.data.form, location: event.location }), ]) break case "form.replied": @@ -668,10 +668,15 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ registerSession(sessionID) }, async refreshChildren(sessionID: string) { - for (const session of mutable((await sdk.api.session.list({ parentID: sessionID, limit: 200 })).data)) { - setStore("session", "info", session.id, session) - registerSession(session.id) + const visit = async (parentID: string, seen: Set): Promise => { + const children = mutable((await sdk.api.session.list({ parentID, limit: 200 })).data).filter( + (session) => !seen.has(session.id), + ) + for (const session of children) setStore("session", "info", session.id, session) + for (const session of children) registerSession(session.id) + await Promise.all(children.map((session) => visit(session.id, new Set([...seen, session.id])))) } + await visit(sessionID, new Set([sessionID])) }, message: { ids(sessionID: string) { @@ -719,6 +724,23 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ return store.session.form[sessionID] }, async refresh(sessionID: string) { + if (sessionID === "global") { + const result = await sdk.api.form.listRequests({ location: locationQuery(defaultLocation()) }) + setStore( + "session", + "form", + sessionID, + mutable( + result.data + .filter((form) => form.sessionID === "global") + .map((form) => ({ + ...form, + location: { directory: result.location.directory, workspaceID: result.location.workspaceID }, + })), + ), + ) + return + } setStore("session", "form", sessionID, mutable(await sdk.api.form.list({ sessionID }))) }, }, diff --git a/packages/tui/src/routes/session/form.tsx b/packages/tui/src/routes/session/form.tsx index 7240765e0a..075dc35f40 100644 --- a/packages/tui/src/routes/session/form.tsx +++ b/packages/tui/src/routes/session/form.tsx @@ -83,6 +83,16 @@ function display(field: Field, value: FormValue | undefined) { return label(value) } +function requestOptions(form: FormInfo) { + if (!form.location) return undefined + return { + headers: { + "x-opencode-directory": encodeURIComponent(form.location.directory), + ...(form.location.workspaceID ? { "x-opencode-workspace": form.location.workspaceID } : {}), + }, + } +} + export function FormPrompt(props: { form: FormInfo }) { return props.form.mode === "url" ? : } @@ -107,7 +117,7 @@ function UrlPrompt(props: { form: FormInfo & { mode: "url" } }) { title: "Dismiss form", category: "Form", run() { - void sdk.api.form.cancel({ sessionID: props.form.sessionID, formID: props.form.id }) + void sdk.api.form.cancel({ sessionID: props.form.sessionID, formID: props.form.id }, requestOptions(props.form)) }, }, ], @@ -125,7 +135,7 @@ function UrlPrompt(props: { form: FormInfo & { mode: "url" } }) { desc: "Dismiss form", group: "Form", cmd: () => { - void sdk.api.form.cancel({ sessionID: props.form.sessionID, formID: props.form.id }) + void sdk.api.form.cancel({ sessionID: props.form.sessionID, formID: props.form.id }, requestOptions(props.form)) }, }, ], @@ -276,7 +286,7 @@ function FieldsPrompt(props: { form: FormInfo & { mode: "form" } }) { sessionID: props.form.sessionID, formID: props.form.id, answer: { [current.key]: value }, - }) + }, requestOptions(props.form)) .catch((error: unknown) => { setStore( "error", @@ -398,7 +408,7 @@ function FieldsPrompt(props: { form: FormInfo & { mode: "form" } }) { group: "Form", cmd: () => { if (textual()) { - void sdk.api.form.cancel({ sessionID: props.form.sessionID, formID: props.form.id }) + void sdk.api.form.cancel({ sessionID: props.form.sessionID, formID: props.form.id }, requestOptions(props.form)) return } setStore("editing", false) @@ -497,7 +507,7 @@ function FieldsPrompt(props: { form: FormInfo & { mode: "form" } }) { title: "Dismiss form", category: "Form", run() { - void sdk.api.form.cancel({ sessionID: props.form.sessionID, formID: props.form.id }) + void sdk.api.form.cancel({ sessionID: props.form.sessionID, formID: props.form.id }, requestOptions(props.form)) }, }, ], @@ -550,7 +560,7 @@ function FieldsPrompt(props: { form: FormInfo & { mode: "form" } }) { return value === undefined ? [] : [[field.key, value] as const] }), ), - }) + }, requestOptions(props.form)) .catch((error: unknown) => { setStore( "error", @@ -569,7 +579,7 @@ function FieldsPrompt(props: { form: FormInfo & { mode: "form" } }) { desc: "Dismiss form", group: "Form", cmd: () => { - void sdk.api.form.cancel({ sessionID: props.form.sessionID, formID: props.form.id }) + void sdk.api.form.cancel({ sessionID: props.form.sessionID, formID: props.form.id }, requestOptions(props.form)) }, }, { key: "up", desc: "Scroll review", group: "Form", cmd: () => review?.scrollBy(-1) }, @@ -608,7 +618,7 @@ function FieldsPrompt(props: { form: FormInfo & { mode: "form" } }) { desc: "Dismiss form", group: "Form", cmd: () => { - void sdk.api.form.cancel({ sessionID: props.form.sessionID, formID: props.form.id }) + void sdk.api.form.cancel({ sessionID: props.form.sessionID, formID: props.form.id }, requestOptions(props.form)) }, }, ...tuiConfig.keybinds.get("app.exit"), diff --git a/packages/tui/test/fixture/tui-sdk.ts b/packages/tui/test/fixture/tui-sdk.ts index cddc41055d..b8fc93c428 100644 --- a/packages/tui/test/fixture/tui-sdk.ts +++ b/packages/tui/test/fixture/tui-sdk.ts @@ -97,6 +97,7 @@ export function createFetch(override?: FetchHandler, events?: ReturnType