From 420582984e5665475705ebe05572933599c7f40a Mon Sep 17 00:00:00 2001 From: Leonid <127580858+bashrusakh@users.noreply.github.com> Date: Sun, 12 Jul 2026 00:04:41 +1100 Subject: [PATCH] fix(sync): keep pending questions answerable after restart (#2005) Co-authored-by: bashrusakh --- packages/ui/src/stores/globalSessions.test.ts | 40 +++++++++++++++++++ packages/ui/src/sync/sync-context.tsx | 17 ++++---- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/packages/ui/src/stores/globalSessions.test.ts b/packages/ui/src/stores/globalSessions.test.ts index 9a164e41..73da61b2 100644 --- a/packages/ui/src/stores/globalSessions.test.ts +++ b/packages/ui/src/stores/globalSessions.test.ts @@ -55,4 +55,44 @@ describe('listGlobalSessionPages', () => { expect(session.revert).toEqual({ messageID: 'msg_1' }) expect(session.summary).toEqual({ additions: 5, deletions: 3, files: 2 }) }) + + test('paginates through all session-list pages', async () => { + const calls: Array> = [] + const apiClient = { + experimental: { + session: { + list: async (options: Record) => { + calls.push(options) + if (options.cursor === undefined) { + return { + data: [ + { id: 'ses_root', time: { updated: 20 } }, + { id: 'ses_child_1', time: { updated: 10 } }, + ], + response: { headers: new Headers({ 'x-next-cursor': '10' }) }, + } + } + return { + data: [ + { id: 'ses_child_2', time: { updated: 5 } }, + ], + response: { headers: new Headers() }, + } + }, + }, + }, + } as unknown as OpencodeClient + + const sessions = await listGlobalSessionPages(apiClient, { + directory: '/repo', + archived: false, + roots: false, + pageSize: 2, + }) + + expect(calls).toHaveLength(2) + expect(calls[0]).toEqual({ directory: '/repo', archived: false, roots: false, limit: 2 }) + expect(calls[1]).toEqual({ directory: '/repo', archived: false, roots: false, limit: 2, cursor: 10 }) + expect(sessions.map((session) => session.id)).toEqual(['ses_root', 'ses_child_1', 'ses_child_2']) + }) }) diff --git a/packages/ui/src/sync/sync-context.tsx b/packages/ui/src/sync/sync-context.tsx index 2207038a..f19c0a80 100644 --- a/packages/ui/src/sync/sync-context.tsx +++ b/packages/ui/src/sync/sync-context.tsx @@ -1738,21 +1738,18 @@ export function SyncProvider(props: { .filter((s) => !!s?.id) .sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)) - // Also load child sessions (sub-agent delegations) so they - // appear in the sidebar immediately instead of relying on - // the async global session store. + // Also load child sessions (sub-agent delegations) with pagination + // so pending questions can scope to them immediately after restart. let allSessions: typeof rootSessions = [] try { - const allResult = await props.sdk.session.list({ + allSessions = await listGlobalSessionPages(props.sdk, { directory: dir, - limit: 200, + archived: false, + roots: false, + pageSize: 500, }) - const allError = (allResult as { error?: unknown }).error - if (!allError) { - allSessions = ((allResult as { data?: unknown }).data ?? []) as typeof rootSessions - } } catch { - // Child load is best-effort; fall back to roots only + // Child load is best-effort; fall back to roots only. } // Merge: keep root sessions from the first query (for accurate