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.
This commit is contained in:
Mark IJbema
2026-03-18 16:20:44 +01:00
parent 10f41f46f3
commit 9a8f1359f3
+39 -8
View File
@@ -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<void> {
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.
*/