Skip to content
Open
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
13 changes: 13 additions & 0 deletions src/core/config/ContextProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,19 @@ export class ContextProxy {
return this.originalContext.globalState.update(key, value)
}

/**
* Refresh a specific key from globalState and update the cache.
* This is useful for settings that may be edited across multiple VS Code windows,
* ensuring we read the latest value before making modifications.
* @param key The global state key to refresh
* @returns The fresh value from globalState
*/
refreshGlobalStateKey<K extends GlobalStateKey>(key: K): GlobalState[K] {
const value = this.originalContext.globalState.get<GlobalState[K]>(key)
this.stateCache[key] = value
return value as GlobalState[K]
}

private getAllGlobalState(): GlobalState {
return Object.fromEntries(GLOBAL_STATE_KEYS.map((key) => [key, this.getGlobalState(key)]))
}
Expand Down
51 changes: 51 additions & 0 deletions src/core/config/__tests__/ContextProxy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,57 @@ describe("ContextProxy", () => {
})
})

describe("refreshGlobalStateKey", () => {
it("should read fresh value from globalState and update cache", async () => {
// Set up initial cache value
await proxy.updateGlobalState("customSupportPrompts", { OLD: "old-prompt" })

// Simulate another window updating globalState directly (bypassing our cache)
const newValue = { OLD: "old-prompt", NEW: "new-prompt" }
mockGlobalState.get.mockReturnValue(newValue)

// Refresh the key
const result = proxy.refreshGlobalStateKey("customSupportPrompts")

// Should return the fresh value from globalState
expect(result).toEqual(newValue)

// Should have updated the cache (subsequent getGlobalState should return new value)
const cachedValue = proxy.getGlobalState("customSupportPrompts")
expect(cachedValue).toEqual(newValue)
})

it("should return undefined when globalState has no value", async () => {
// Set up initial cache value
await proxy.updateGlobalState("customModePrompts", { code: { roleDefinition: "test" } })

// Simulate globalState being cleared (e.g., by another window)
mockGlobalState.get.mockReturnValue(undefined)

// Refresh the key
const result = proxy.refreshGlobalStateKey("customModePrompts")

// Should return undefined
expect(result).toBeUndefined()

// Cache should also be updated to undefined
const cachedValue = proxy.getGlobalState("customModePrompts")
expect(cachedValue).toBeUndefined()
})

it("should call globalState.get with the correct key", async () => {
// Clear mock call history
mockGlobalState.get.mockClear()
mockGlobalState.get.mockReturnValue({ ENHANCE: "test-prompt" })

// Refresh a specific key
proxy.refreshGlobalStateKey("customSupportPrompts")

// Should have called get with the correct key
expect(mockGlobalState.get).toHaveBeenCalledWith("customSupportPrompts")
})
})

describe("getSecret", () => {
it("should return value from cache when it exists", async () => {
// Manually set a value in the cache
Expand Down
8 changes: 6 additions & 2 deletions src/core/webview/webviewMessageHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1485,7 +1485,9 @@ export const webviewMessageHandler = async (
break
case "updatePrompt":
if (message.promptMode && message.customPrompt !== undefined) {
const existingPrompts = getGlobalState("customModePrompts") ?? {}
// Use refreshGlobalStateKey to get the latest value from globalState,
// avoiding stale cache issues when multiple VS Code windows are open.
const existingPrompts = provider.contextProxy.refreshGlobalStateKey("customModePrompts") ?? {}
const updatedPrompts = { ...existingPrompts, [message.promptMode]: message.customPrompt }
await updateGlobalState("customModePrompts", updatedPrompts)
const currentState = await provider.getStateToPostToWebview()
Expand Down Expand Up @@ -1571,7 +1573,9 @@ export const webviewMessageHandler = async (
case "updateCondensingPrompt":
// Store the condensing prompt in customSupportPrompts["CONDENSE"]
// instead of customCondensingPrompt.
const currentSupportPrompts = getGlobalState("customSupportPrompts") ?? {}
// Use refreshGlobalStateKey to get the latest value from globalState,
// avoiding stale cache issues when multiple VS Code windows are open.
const currentSupportPrompts = provider.contextProxy.refreshGlobalStateKey("customSupportPrompts") ?? {}
const updatedSupportPrompts = { ...currentSupportPrompts, CONDENSE: message.text }
await updateGlobalState("customSupportPrompts", updatedSupportPrompts)
// Also update the old field for backward compatibility during migration.
Expand Down
Loading