fix(tui): reconcile shells after reconnect
This commit is contained in:
parent
761f37370f
commit
9f279cafbc
2 changed files with 23 additions and 5 deletions
|
|
@ -50,6 +50,7 @@ type LocationData = {
|
|||
reference?: ReferenceInfo[]
|
||||
// Currently running shell commands for this location, keyed by shell id. Entries are removed
|
||||
// once the command exits or is deleted, so this only ever holds in-flight shells.
|
||||
shellLocation?: LocationRef
|
||||
shell?: Record<string, Shell>
|
||||
skill?: SkillInfo[]
|
||||
}
|
||||
|
|
@ -754,6 +755,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
case "shell.created":
|
||||
setStore("location", locationKey(event.location ?? defaultLocation()), (data) => ({
|
||||
...data,
|
||||
shellLocation: event.location ?? defaultLocation(),
|
||||
shell: { ...data?.shell, [event.data.info.id]: event.data.info },
|
||||
}))
|
||||
break
|
||||
|
|
@ -901,6 +903,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
const key = locationKey(result.location)
|
||||
setStore("location", key, {
|
||||
...store.location[key],
|
||||
shellLocation: { directory: result.location.directory, workspaceID: result.location.workspaceID },
|
||||
shell: Object.fromEntries(result.data.map((info) => [info.id, info])),
|
||||
})
|
||||
},
|
||||
|
|
@ -1066,12 +1069,19 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
|
|||
),
|
||||
)
|
||||
const refreshed = await Promise.allSettled(
|
||||
Array.from(locations)
|
||||
.filter(([location]) => location !== key)
|
||||
.map(([, location]) => result.session.form.refresh("global", location)),
|
||||
[
|
||||
...Array.from(locations)
|
||||
.filter(([location]) => location !== key)
|
||||
.map(([, location]) => result.session.form.refresh("global", location)),
|
||||
...Object.values(store.location).flatMap((data) =>
|
||||
data.shellLocation && data.shell && locationKey(data.shellLocation) !== key
|
||||
? [result.shell.refresh(data.shellLocation)]
|
||||
: [],
|
||||
),
|
||||
],
|
||||
)
|
||||
for (const failure of refreshed.filter((item) => item.status === "rejected"))
|
||||
console.error("Failed to refresh global forms", failure.reason)
|
||||
console.error("Failed to refresh location data", failure.reason)
|
||||
})
|
||||
.finally(() => {
|
||||
bootstrapping = undefined
|
||||
|
|
|
|||
|
|
@ -1315,15 +1315,18 @@ test("refreshes references after updates", async () => {
|
|||
test("keeps shell state scoped to location", async () => {
|
||||
const events = createEventStream()
|
||||
const other = "/tmp/opencode/other"
|
||||
let otherRequests = 0
|
||||
let otherRunning = true
|
||||
const calls = createFetch((url) => {
|
||||
if (url.pathname !== "/api/shell") return
|
||||
const requestDirectory = url.searchParams.get("location[directory]")
|
||||
if (requestDirectory === other) otherRequests++
|
||||
return json({
|
||||
location: {
|
||||
directory: requestDirectory ?? directory,
|
||||
project: { id: "proj_test", directory: requestDirectory ?? directory },
|
||||
},
|
||||
data: [
|
||||
data: requestDirectory === other && !otherRunning ? [] : [
|
||||
{
|
||||
id: requestDirectory === other ? "sh_other" : "sh_default",
|
||||
status: "running",
|
||||
|
|
@ -1383,6 +1386,11 @@ test("keeps shell state scoped to location", async () => {
|
|||
})
|
||||
await wait(() => data.shell.list({ directory: other }).some((shell) => shell.id === "sh_live_other"))
|
||||
expect(data.shell.list().map((shell) => shell.id)).toEqual(["sh_default"])
|
||||
|
||||
otherRunning = false
|
||||
events.disconnect()
|
||||
await wait(() => otherRequests === 2, 4000)
|
||||
await wait(() => data.shell.list({ directory: other }).length === 0)
|
||||
} finally {
|
||||
app.renderer.destroy()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue