Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 11 additions & 27 deletions packages/kilo-vscode/src/KiloProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,14 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
}
}

private async fetchAndSendMarketplaceData(): Promise<void> {
const workspace = this.getProjectDirectory(this.currentSession?.id)
const mp = this.getMarketplace()
const skills = await this.fetchCliSkills()
const data = await mp.fetchData(workspace, skills)
this.postMessage({ type: "marketplaceData", ...data })
}

private async fetchCliSkills(): Promise<Array<{ name: string; location: string }> | undefined> {
if (!this.client) return undefined
try {
Expand Down Expand Up @@ -1333,38 +1341,14 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
const stub = { id: name, type: "mode" as const, name, description: "", content: "" }
const project = await mp.remove(stub, "project", workspace)
const global = await mp.remove(stub, "global", workspace)
if (project.success || global.success) {
await this.disposeCliInstance("global")
removed = true
}
if (project.success || global.success) removed = true
}

if (!removed) {
console.error("[Kilo New] KiloProvider: Failed to remove mode:", name)
}

this.cachedAgentsMessage = null
await this.fetchAndSendAgents()
}

/**
* Dispose the CLI backend instance so it re-reads config from disk.
* Call after any marketplace install/remove that writes config files directly.
* Global-scope changes need global.dispose() to also reset the global config cache.
*/
private async disposeCliInstance(scope: "project" | "global"): Promise<void> {
if (!this.client) return
if (scope === "global") {
await this.client.global.dispose().catch((e: unknown) => {
console.warn("[Kilo New] global.dispose() 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)
})
await this.invalidateAfterMarketplaceChange("global")
}

/**
Expand Down Expand Up @@ -1401,7 +1385,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
})
this.cachedAgentsMessage = null
this.cachedConfigMessage = null
await Promise.all([this.fetchAndSendAgents(), this.fetchAndSendConfig()])
await Promise.all([this.fetchAndSendAgents(), this.fetchAndSendConfig(), this.fetchAndSendMarketplaceData()])
}

/**
Expand Down
8 changes: 8 additions & 0 deletions packages/opencode/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -1589,6 +1590,13 @@ export namespace Config {

global.reset()

// 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()
// kilocode_change end

GlobalBus.emit("event", {
directory: "global",
payload: {
Expand Down
15 changes: 15 additions & 0 deletions packages/opencode/src/project/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks dangerous

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
Expand Down
Loading