diff --git a/packages/app/src/runtime/server/server-sync/connection.test.ts b/packages/app/src/runtime/server/server-sync/connection.test.ts index 1a0b5c4bc4d..653347c79e5 100644 --- a/packages/app/src/runtime/server/server-sync/connection.test.ts +++ b/packages/app/src/runtime/server/server-sync/connection.test.ts @@ -1,6 +1,6 @@ import { expect, test } from "bun:test" import { createRoot, createSignal } from "solid-js" -import { createConnectionSync } from "./connection" +import { createConnectionSync, reconnectOrder } from "./connection" test("invalidates disconnected data and synchronizes after the handshake", () => { const calls: string[] = [] @@ -19,3 +19,9 @@ test("invalidates disconnected data and synchronizes after the handshake", () => }) dispose() }) + +test("held directories refresh before the rest, otherwise keeping their order", () => { + const held = new Set(["/b", "/d"]) + expect(reconnectOrder(["/a", "/b", "/c", "/d"], (directory) => held.has(directory))).toEqual(["/b", "/d", "/a", "/c"]) + expect(reconnectOrder(["/a", "/c"], (directory) => held.has(directory))).toEqual(["/a", "/c"]) +}) diff --git a/packages/app/src/runtime/server/server-sync/connection.ts b/packages/app/src/runtime/server/server-sync/connection.ts index da04009a418..9c870e0bf1c 100644 --- a/packages/app/src/runtime/server/server-sync/connection.ts +++ b/packages/app/src/runtime/server/server-sync/connection.ts @@ -20,3 +20,8 @@ export function createConnectionSync(input: { return { handleEvent } } + +// Directories a mounted view holds refresh first; the rest keep their existing order behind them. +export function reconnectOrder(directories: string[], held: (directory: string) => boolean) { + return [...directories.filter(held), ...directories.filter((directory) => !held(directory))] +} diff --git a/packages/app/src/runtime/server/sync.tsx b/packages/app/src/runtime/server/sync.tsx index 1683bc9b313..eebc48dc2ee 100644 --- a/packages/app/src/runtime/server/sync.tsx +++ b/packages/app/src/runtime/server/sync.tsx @@ -17,7 +17,7 @@ import type { ServerScope } from "@/runtime/server/scope" import { persisted } from "@/runtime/persistence/storage" import type { ServerApi } from "@/runtime/server/api" import { toggleMcp } from "./global-sync/mcp" -import { createConnectionSync } from "./server-sync/connection" +import { createConnectionSync, reconnectOrder } from "./server-sync/connection" import { usePlatform } from "@/runtime/platform/platform" import type { Data } from "@opencode-ai/client/solid" import { createWorktreeInventory, withWorktreeInventory } from "@/workspaces/inventory" @@ -162,12 +162,11 @@ export function createServerSyncContextInner(serverSDK: ServerSDK, data: Data) { }, connected: (info) => { if (bootstrap.data !== undefined && !bootstrap.isFetching) void bootstrap.refetch() - Object.keys(children.children) - .filter(children.active) - .forEach((directory) => { - queue.push(directory) - void data.location.sync({ directory }).catch(() => undefined) - }) + // The refresh queue re-syncs two directories at a time, held ones first. Syncing every active + // directory here as well sent the whole catalog fan-out for all of them at once. + reconnectOrder(Object.keys(children.children).filter(children.active), children.pinned).forEach( + (directory) => queue.push(directory), + ) }, })