From 9a8f1359f3f82b462f3b667aec63985f81bfabae Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Wed, 18 Mar 2026 16:20:44 +0100 Subject: [PATCH] fix(vscode): use global.config.update for global marketplace changes For global-scope marketplace installs/removes, the extension was using global.dispose to reset the CLI's config cache. However, older CLI versions (pre-6d6e285bb) lack the Config.global.reset() call in the dispose handler, so the lazy-cached global config was never invalidated. Fix: use global.config.update with an empty config object to trigger Config.updateGlobal(), which always calls global.reset(). An empty merge is a no-op for the file content but properly resets the cache. This works on both old and new CLI binaries. --- packages/kilo-vscode/src/KiloProvider.ts | 47 ++++++++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index c3f8e66507c..f56e8c3cb7d 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -732,10 +732,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper const scope = message.mpInstallOptions?.target ?? "project" const result = await this.getMarketplace().install(message.mpItem, message.mpInstallOptions, workspace) if (result.success) { - await this.disposeCliInstance(scope) - this.cachedAgentsMessage = null - this.cachedConfigMessage = null - await Promise.all([this.fetchAndSendAgents(), this.fetchAndSendConfig()]) + await this.invalidateAfterMarketplaceChange(scope) } this.postMessage({ type: "marketplaceInstallResult", @@ -750,10 +747,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper const scope = message.mpInstallOptions?.target ?? "project" const result = await this.getMarketplace().remove(message.mpItem, scope, workspace) if (result.success) { - await this.disposeCliInstance(scope) - this.cachedAgentsMessage = null - this.cachedConfigMessage = null - await Promise.all([this.fetchAndSendAgents(), this.fetchAndSendConfig()]) + await this.invalidateAfterMarketplaceChange(scope) } this.postMessage({ type: "marketplaceRemoveResult", @@ -1373,6 +1367,43 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper }) } + /** + * Invalidate CLI caches and refresh the webview after a marketplace install/remove. + * + * For global scope: uses global.config.update with the freshly-written config file + * contents rather than global.dispose. This goes through Config.updateGlobal() which + * calls Config.global.reset() to invalidate the lazy-cached global config, ensuring + * the newly installed/removed MCP entry is visible on the next config.get call. + * (global.dispose alone is not sufficient on older CLI versions that lack the + * Config.global.reset() call in the dispose handler.) + * + * For project scope: instance.dispose is sufficient because the per-instance + * Config.state is cleared and re-reads all files (including global) on next access. + */ + private async invalidateAfterMarketplaceChange(scope: "project" | "global"): Promise { + if (!this.client) return + if (scope === "global") { + // Use global.config.update with an empty config to trigger Config.updateGlobal() + // which calls Config.global.reset(). This invalidates the lazy-cached global + // config in the CLI process so it re-reads kilo.json from disk. + // An empty object merge is a no-op for the file content but resets the cache. + // (global.dispose alone is insufficient on older CLI versions that lack + // the Config.global.reset() call in the dispose handler.) + await this.client.global.config.update({ config: {} }).catch((e: unknown) => { + console.warn("[Kilo New] global.config.update after marketplace change failed:", e) + }) + } + // Always dispose the per-project instance so it rebuilds state from + // the (possibly updated) global + project config on the next request. + const dir = this.getWorkspaceDirectory() + await this.client.instance.dispose({ directory: dir }).catch((e: unknown) => { + console.warn("[Kilo New] instance.dispose() after marketplace change failed:", e) + }) + this.cachedAgentsMessage = null + this.cachedConfigMessage = null + await Promise.all([this.fetchAndSendAgents(), this.fetchAndSendConfig()]) + } + /** * Fetch backend config and send to webview. */