fix(tui): preserve global form location

This commit is contained in:
Aiden Cline 2026-07-03 14:05:44 -05:00
commit 1a38f66825
3 changed files with 46 additions and 13 deletions

View file

@ -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<string>): Promise<void> => {
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 })))
},
},

View file

@ -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" ? <UrlPrompt form={props.form} /> : <FieldsPrompt form={props.form} />
}
@ -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"),

View file

@ -97,6 +97,7 @@ export function createFetch(override?: FetchHandler, events?: ReturnType<typeof
if (url.pathname === "/api/project/proj_test/directories") return json([{ directory: worktree }])
if (url.pathname === "/api/shell") return json({ location: { directory, project: { id: "proj_test", directory: worktree } }, data: [] })
if (url.pathname === "/api/mcp") return json({ location: { directory, project: { id: "proj_test", directory: worktree } }, data: [] })
if (url.pathname === "/api/form/request") return json({ location: { directory, project: { id: "proj_test", directory: worktree } }, data: [] })
if (url.pathname === "/api/session") return json({ data: [], cursor: {} })
if (url.pathname === "/api/session/active") return json({ data: {}, watermarks: {} })
if (/^\/api\/session\/[^/]+\/(permission|form)$/.test(url.pathname)) return json([])