diff --git a/packages/app/src/context/global-sync/bootstrap.test.ts b/packages/app/src/context/global-sync/bootstrap.test.ts index 71986dd3c40d..a95706a3dbe5 100644 --- a/packages/app/src/context/global-sync/bootstrap.test.ts +++ b/packages/app/src/context/global-sync/bootstrap.test.ts @@ -8,6 +8,7 @@ import { bootstrapDirectory, loadAgentsQuery, loadCommands, + loadGlobalConfigQuery, loadPathQuery, loadProjectsQuery, loadProvidersQuery, @@ -76,6 +77,7 @@ function directoryState() { describe("bootstrapDirectory", () => { test("uses legacy MCP endpoints while refreshing a v1 directory", async () => { + const legacyConfigReads: string[] = [] const mcpReads: string[] = [] const [store, setStore] = directoryState() @@ -91,7 +93,12 @@ describe("bootstrapDirectory", () => { }, sdk: { app: { agents: async () => ({ data: [{ name: "build", mode: "primary" }] }) }, - config: { get: async () => ({ data: {} }) }, + config: { + get: async () => { + legacyConfigReads.push("directory") + return { data: {} } + }, + }, session: { status: async () => ({ data: {} }) }, vcs: { get: async () => ({ data: undefined }) }, command: { @@ -134,8 +141,88 @@ describe("bootstrapDirectory", () => { await new Promise((resolve) => setTimeout(resolve, 80)) expect(store.status).toBe("complete") + expect(legacyConfigReads).toEqual(["directory"]) expect(mcpReads.sort()).toEqual(["command", "resource", "status"]) }) + + test("skips legacy config while refreshing a v2 directory", async () => { + const [store, setStore] = directoryState() + + await bootstrapDirectory({ + directory: "/project", + scope: ServerScope.local, + mcp: false, + global: { + config: {} satisfies Config, + path: { state: "", config: "", worktree: "/project", directory: "/project", home: "/home" }, + project: [{ id: "project", worktree: "/project" } as Project], + provider, + }, + sdk: { + config: { + get: async () => { + throw new Error("legacy directory config should not be called") + }, + }, + } as unknown as OpencodeClient, + api, + store, + setStore, + vcsCache: { setStore() {} } as unknown as VcsCache, + loadSessions() {}, + translate: (key) => key, + queryClient: new QueryClient(), + protocol: Promise.resolve("v2"), + }) + + expect(store.status).toBe("partial") + + await new Promise((resolve) => setTimeout(resolve, 80)) + + expect(store.status).toBe("complete") + }) +}) + +describe("config queries", () => { + test("skips legacy global config for v2 servers", async () => { + const sdk = { + global: { + config: { + get: async () => { + throw new Error("legacy global config should not be called") + }, + }, + }, + } as unknown as OpencodeClient + + const result = await new QueryClient().fetchQuery( + loadGlobalConfigQuery(ServerScope.local, sdk, Promise.resolve("v2")), + ) + + expect(result).toEqual({}) + }) + + test("loads legacy global config for v1 servers", async () => { + const calls: string[] = [] + const config = { shell: "zsh" } satisfies Config + const sdk = { + global: { + config: { + get: async () => { + calls.push("global") + return { data: config } + }, + }, + }, + } as unknown as OpencodeClient + + const result = await new QueryClient().fetchQuery( + loadGlobalConfigQuery(ServerScope.local, sdk, Promise.resolve("v1")), + ) + + expect(result).toEqual(config) + expect(calls).toEqual(["global"]) + }) }) describe("query keys", () => { diff --git a/packages/app/src/context/global-sync/bootstrap.ts b/packages/app/src/context/global-sync/bootstrap.ts index 39221d551fa6..5a11ce39b39c 100644 --- a/packages/app/src/context/global-sync/bootstrap.ts +++ b/packages/app/src/context/global-sync/bootstrap.ts @@ -105,10 +105,17 @@ function showErrors(input: { }) } -export const loadGlobalConfigQuery = (scope: ServerScope, sdk: OpencodeClient) => +export const loadGlobalConfigQuery = ( + scope: ServerScope, + sdk: OpencodeClient, + protocol?: Promise, +) => queryOptions({ queryKey: [scope, "config"], - queryFn: () => retry(() => sdk.global.config.get().then((x) => x.data!)), + queryFn: async () => { + if ((await protocol) !== "v1") return {} + return retry(() => sdk.global.config.get().then((x) => x.data!)) + }, }) type ProjectApi = { @@ -149,7 +156,7 @@ export async function bootstrapGlobal(input: { queryClient: QueryClient }) { const slow = [ - () => input.queryClient.fetchQuery(loadGlobalConfigQuery(input.scope, input.serverSDK)), + () => input.queryClient.fetchQuery(loadGlobalConfigQuery(input.scope, input.serverSDK, input.protocol)), () => input.queryClient.fetchQuery( loadProvidersQuery(input.scope, null, input.serverAPI, input.serverSDK, input.protocol), @@ -376,7 +383,10 @@ export async function bootstrapDirectory(input: { .ensureQueryData(loadAgentsQuery(input.scope, input.directory, input.api.agent, input.sdk, input.protocol)) .then((data) => input.setStore("agent", data)), () => - retry(() => input.sdk.config.get().then((x) => input.setStore("config", reconcile(x.data!, { merge: false })))), + retry(async () => { + if ((await input.protocol) !== "v1") return + return input.sdk.config.get().then((x) => input.setStore("config", reconcile(x.data!, { merge: false }))) + }), () => retry(() => (async () => { diff --git a/packages/app/src/context/server-sync.tsx b/packages/app/src/context/server-sync.tsx index 196cda84794e..13a0b74bc6f3 100644 --- a/packages/app/src/context/server-sync.tsx +++ b/packages/app/src/context/server-sync.tsx @@ -184,7 +184,7 @@ function makeQueryOptionsApi( protocol: Promise<"v1" | "v2">, ) { return { - globalConfig: () => loadGlobalConfigQuery(scope, serverSDK()), + globalConfig: () => loadGlobalConfigQuery(scope, serverSDK(), protocol), projects: () => loadProjectsQuery(scope, serverAPI.project), providers: (directory: PathKey | null) => loadProvidersQuery(scope, directory, serverAPI, directory ? sdkFor(directory) : serverSDK(), protocol),