Skip to content
Merged
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
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
This file provides guidance to agents when working with code in this repository.

- Settings View Pattern: When working on `SettingsView`, inputs must bind to the local `cachedState`, NOT the live `useExtensionState()`. The `cachedState` acts as a buffer for user edits, isolating them from the `ContextProxy` source-of-truth until the user explicitly clicks "Save". Wiring inputs directly to the live state causes race conditions.
- Changesets: Do NOT create `.changeset` files for each commit or code change. Changesets are managed separately by maintainers and should not be generated by agents during normal development.

## Test Placement Guidance

Expand Down
9 changes: 9 additions & 0 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2278,6 +2278,9 @@ export class ClineProvider
openRouterImageApiKey,
openRouterImageGenerationSelectedModel,
lockApiConfigAcrossModes,
autoCloseZooOpenedFiles,
autoCloseZooOpenedFilesAfterUserEdited,
autoCloseZooOpenedNewFiles,
} = await this.getState()

let cloudOrganizations: CloudOrganizationMembership[] = []
Expand Down Expand Up @@ -2457,6 +2460,9 @@ export class ClineProvider
imageGenerationProvider,
openRouterImageApiKey,
openRouterImageGenerationSelectedModel,
autoCloseZooOpenedFiles: autoCloseZooOpenedFiles ?? true,
autoCloseZooOpenedFilesAfterUserEdited: autoCloseZooOpenedFilesAfterUserEdited ?? false,
autoCloseZooOpenedNewFiles: autoCloseZooOpenedNewFiles ?? false,
openAiCodexIsAuthenticated: await (async () => {
try {
const { openAiCodexOAuthManager } = await import("../../integrations/openai-codex/oauth")
Expand Down Expand Up @@ -2657,6 +2663,9 @@ export class ClineProvider
imageGenerationProvider: stateValues.imageGenerationProvider,
openRouterImageApiKey: stateValues.openRouterImageApiKey,
openRouterImageGenerationSelectedModel: stateValues.openRouterImageGenerationSelectedModel,
autoCloseZooOpenedFiles: stateValues.autoCloseZooOpenedFiles,
autoCloseZooOpenedFilesAfterUserEdited: stateValues.autoCloseZooOpenedFilesAfterUserEdited,
autoCloseZooOpenedNewFiles: stateValues.autoCloseZooOpenedNewFiles,
}
}

Expand Down
50 changes: 50 additions & 0 deletions src/core/webview/__tests__/ClineProvider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,56 @@ describe("ClineProvider", () => {
expect(mockPostMessage).toHaveBeenCalled()
})

describe("auto-close settings are included in posted state", () => {
it("getStateToPostToWebview returns saved autoCloseZooOpenedFiles value", async () => {
await provider.resolveWebviewView(mockWebviewView)

// Simulate the updateSettings handler storing the value.
await provider.contextProxy.setValue("autoCloseZooOpenedFiles", false)
await provider.contextProxy.setValue("autoCloseZooOpenedFilesAfterUserEdited", true)
await provider.contextProxy.setValue("autoCloseZooOpenedNewFiles", true)

const state = await provider.getStateToPostToWebview()

// The saved values must be present in the state posted to the webview.
expect(state.autoCloseZooOpenedFiles).toBe(false)
expect(state.autoCloseZooOpenedFilesAfterUserEdited).toBe(true)
expect(state.autoCloseZooOpenedNewFiles).toBe(true)
})

it("getStateToPostToWebview defaults autoCloseZooOpenedFiles to true when unset", async () => {
await provider.resolveWebviewView(mockWebviewView)

// Ensure the settings are not set.
await provider.contextProxy.setValue("autoCloseZooOpenedFiles", undefined)
await provider.contextProxy.setValue("autoCloseZooOpenedFilesAfterUserEdited", undefined)
await provider.contextProxy.setValue("autoCloseZooOpenedNewFiles", undefined)

const state = await provider.getStateToPostToWebview()

// Unset values should default to their documented defaults.
expect(state.autoCloseZooOpenedFiles).toBe(true)
expect(state.autoCloseZooOpenedFilesAfterUserEdited).toBe(false)
expect(state.autoCloseZooOpenedNewFiles).toBe(false)
})

it("getState returns saved autoCloseZooOpenedFiles value for DiffViewProvider", async () => {
await provider.resolveWebviewView(mockWebviewView)

await provider.contextProxy.setValue("autoCloseZooOpenedFiles", false)
await provider.contextProxy.setValue("autoCloseZooOpenedFilesAfterUserEdited", true)
await provider.contextProxy.setValue("autoCloseZooOpenedNewFiles", true)

const state = await provider.getState()

// DiffViewProvider reads from getState(); all three fields must be present
// so a regression that drops any of them is caught.
expect(state.autoCloseZooOpenedFiles).toBe(false)
expect(state.autoCloseZooOpenedFilesAfterUserEdited).toBe(true)
expect(state.autoCloseZooOpenedNewFiles).toBe(true)
})
})

it("loads saved API config when switching modes", async () => {
await provider.resolveWebviewView(mockWebviewView)
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as any).mock.calls[0][0]
Expand Down
Loading