diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index b86631ad398..ca185964cf1 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -24,6 +24,7 @@ import { } from "jsonc-parser" // kilocode_change end import { Instance } from "../project/instance" +import { State } from "../project/state" // kilocode_change import { LSPServer } from "../lsp/server" import { BunProc } from "@/bun" import { Installation } from "@/installation" @@ -1553,11 +1554,12 @@ export namespace Config { global.reset() - // kilocode_change start - only reset config cache, don't dispose all instances. - // Instance.disposeAll() was destroying all session state, MCP connections, and - // in-flight operations across every project whenever any global config changed - // (e.g. removing a mode). The cache reset above is sufficient — consumers will - // pick up the new config on their next read. + // kilocode_change start - reset all derived caches (Config.state, Agent.state, + // Provider.state, etc.) so they re-read the updated global config on next access. + // Only cache entries without dispose callbacks are cleared — side-effectful state + // like sessions, MCP connections, and file watchers are preserved. + State.resetCaches() + GlobalBus.emit("event", { directory: "global", payload: { diff --git a/packages/opencode/src/project/state.ts b/packages/opencode/src/project/state.ts index a9dce565b5e..dda791952a5 100644 --- a/packages/opencode/src/project/state.ts +++ b/packages/opencode/src/project/state.ts @@ -28,6 +28,21 @@ export namespace State { } } + /** + * Reset all cache-only entries (those without dispose callbacks) across all + * instances. This invalidates derived state like Config, Agent, Provider, + * etc. without tearing down side-effectful resources (MCP connections, + * sessions, file watchers, etc.). + */ + export function resetCaches() { + for (const entries of recordsByKey.values()) { + for (const [init, entry] of entries) { + if (entry.dispose) continue + entries.delete(init) + } + } + } + export async function dispose(key: string) { const entries = recordsByKey.get(key) if (!entries) return