mirror of
https://github.com/anomalyco/opencode.git
synced 2026-09-09 13:04:43 +00:00
fix(app): refresh queued inputs when the connection returns (#47573)
This commit is contained in:
parent
33ef66746b
commit
99651b2d50
3 changed files with 56 additions and 17 deletions
|
|
@ -2,30 +2,54 @@ import { describe, expect, test } from "bun:test"
|
|||
import { createRoot } from "solid-js"
|
||||
import { createSessionResolution } from "./session-resolution"
|
||||
|
||||
function store() {
|
||||
const syncs = { session: 0, message: 0, pending: 0 }
|
||||
const sessions = {
|
||||
get: () => undefined,
|
||||
sync: () => {
|
||||
syncs.session++
|
||||
return Promise.resolve()
|
||||
},
|
||||
message: {
|
||||
sync: () => {
|
||||
syncs.message++
|
||||
return Promise.resolve()
|
||||
},
|
||||
},
|
||||
pending: {
|
||||
sync: () => {
|
||||
syncs.pending++
|
||||
return Promise.resolve()
|
||||
},
|
||||
},
|
||||
}
|
||||
return { syncs, sessions }
|
||||
}
|
||||
|
||||
describe("session resolution", () => {
|
||||
test("waits for a route session ID", () => {
|
||||
createRoot((dispose) => {
|
||||
const syncs = { session: 0, message: 0 }
|
||||
const sessions = {
|
||||
get: () => undefined,
|
||||
sync: () => {
|
||||
syncs.session++
|
||||
return Promise.resolve()
|
||||
},
|
||||
message: {
|
||||
sync: () => {
|
||||
syncs.message++
|
||||
return Promise.resolve()
|
||||
},
|
||||
},
|
||||
}
|
||||
const input = store()
|
||||
const session = createSessionResolution(
|
||||
() => undefined,
|
||||
() => sessions,
|
||||
() => input.sessions,
|
||||
)
|
||||
|
||||
expect(session()).toBeUndefined()
|
||||
expect(syncs).toEqual({ session: 0, message: 0 })
|
||||
expect(input.syncs).toEqual({ session: 0, message: 0, pending: 0 })
|
||||
dispose()
|
||||
})
|
||||
})
|
||||
|
||||
test("starts the transcript and queued input reads with metadata", () => {
|
||||
createRoot((dispose) => {
|
||||
const input = store()
|
||||
createSessionResolution(
|
||||
() => "ses_open",
|
||||
() => input.sessions,
|
||||
{ children: true },
|
||||
)
|
||||
expect(input.syncs).toEqual({ session: 1, message: 1, pending: 1 })
|
||||
dispose()
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ type SessionStore<T> = {
|
|||
message: {
|
||||
sync: (id: string) => Promise<unknown>
|
||||
}
|
||||
pending: {
|
||||
sync: (id: string) => Promise<unknown>
|
||||
}
|
||||
}
|
||||
|
||||
type Resolution<T> = { id: string; store: SessionStore<T> } & (
|
||||
|
|
@ -52,8 +55,11 @@ export function createSessionResolution<T>(
|
|||
onCleanup(() => {
|
||||
stale = true
|
||||
})
|
||||
// The timeline owns message errors; metadata resolution stays independent.
|
||||
// The timeline owns message errors; metadata resolution stays independent. Queued inputs
|
||||
// ride along so a reconnect refreshes them with the transcript instead of leaving the
|
||||
// pre-disconnect queue on screen.
|
||||
void store.message.sync(id).catch(() => undefined)
|
||||
void store.pending.sync(id).catch(() => undefined)
|
||||
if (cached() && !options?.children && !options?.connected) {
|
||||
setStatus({ id, store, state: "settled" })
|
||||
return
|
||||
|
|
|
|||
|
|
@ -17,9 +17,11 @@ function createFixture(initial: Record<string, Session> = {}) {
|
|||
const deferred = new Map<string, PromiseWithResolvers<unknown>>()
|
||||
const resolves: string[] = []
|
||||
const messages = { syncs: [] as string[], ...Promise.withResolvers<unknown>() }
|
||||
const pending = { syncs: [] as string[] }
|
||||
return {
|
||||
resolves,
|
||||
messages,
|
||||
pending,
|
||||
sessions: {
|
||||
get: (id: string) => cache()[id],
|
||||
sync: (id: string) => {
|
||||
|
|
@ -34,6 +36,12 @@ function createFixture(initial: Record<string, Session> = {}) {
|
|||
return messages.promise
|
||||
},
|
||||
},
|
||||
pending: {
|
||||
sync: (id: string) => {
|
||||
pending.syncs.push(id)
|
||||
return Promise.resolve()
|
||||
},
|
||||
},
|
||||
},
|
||||
settle(id: string, directory = `/dir/${id}`) {
|
||||
setCache({ ...cache(), [id]: { id, directory } })
|
||||
|
|
@ -86,6 +94,7 @@ test("refreshes the current session on reconnect while keeping cached content vi
|
|||
expect(fixture.resolves).toEqual(["ses_a", "ses_a"])
|
||||
expect(current()).toEqual(sessionOf("ses_a"))
|
||||
expect(fixture.messages.syncs).toEqual(["ses_a", "ses_a"])
|
||||
expect(fixture.pending.syncs).toEqual(["ses_a", "ses_a"])
|
||||
fixture.settle("ses_a", "/worktrees/moved")
|
||||
await flush()
|
||||
expect(current()?.directory).toBe("/worktrees/moved")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue