Skip to content

Commit 605976b

Browse files
committed
fix(webview): route mode switches through view-local persistence
1 parent 0137651 commit 605976b

3 files changed

Lines changed: 43 additions & 15 deletions

File tree

src/core/webview/ClineProvider.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,8 +1633,7 @@ export class ClineProvider
16331633
}
16341634
}
16351635

1636-
await this.updateGlobalState("mode", newMode)
1637-
this._updateViewLocalStateFromMutation({ mode: newMode })
1636+
await this.saveViewState("mode", newMode)
16381637

16391638
this.emit(RooCodeEventName.ModeChanged, newMode)
16401639

src/core/webview/__tests__/ClineProvider.spec.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1718,8 +1718,13 @@ describe("ClineProvider", () => {
17181718
// Switch to architect mode
17191719
await provider.handleModeSwitch("architect")
17201720

1721-
// Verify mode was updated
1722-
expect(mockContext.globalState.update).toHaveBeenCalledWith("mode", "architect")
1721+
// Verify mode was updated in durable per-view state
1722+
expect(mockContext.globalState.update).toHaveBeenCalledWith(
1723+
"viewStates",
1724+
expect.objectContaining({
1725+
[provider.viewId]: expect.objectContaining({ mode: "architect" }),
1726+
}),
1727+
)
17231728

17241729
// Verify saved config was loaded
17251730
expect(provider.providerSettingsManager.getModeConfigId).toHaveBeenCalledWith("architect")
@@ -1750,8 +1755,13 @@ describe("ClineProvider", () => {
17501755
// Switch to architect mode
17511756
await provider.handleModeSwitch("architect")
17521757

1753-
// Verify mode was updated
1754-
expect(mockContext.globalState.update).toHaveBeenCalledWith("mode", "architect")
1758+
// Verify mode was updated in durable per-view state
1759+
expect(mockContext.globalState.update).toHaveBeenCalledWith(
1760+
"viewStates",
1761+
expect.objectContaining({
1762+
[provider.viewId]: expect.objectContaining({ mode: "architect" }),
1763+
}),
1764+
)
17551765

17561766
// Verify current config was saved as default for new mode
17571767
expect(provider.providerSettingsManager.setModeConfig).toHaveBeenCalledWith("architect", "current-id")

src/core/webview/__tests__/ClineProvider.sticky-mode.spec.ts

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -350,8 +350,13 @@ describe("ClineProvider - Sticky Mode", () => {
350350
// Switch mode
351351
await provider.handleModeSwitch("architect")
352352

353-
// Verify mode was updated in global state
354-
expect(mockContext.globalState.update).toHaveBeenCalledWith("mode", "architect")
353+
// Verify mode was updated in durable per-view state
354+
expect(mockContext.globalState.update).toHaveBeenCalledWith(
355+
"viewStates",
356+
expect.objectContaining({
357+
[provider.viewId]: expect.objectContaining({ mode: "architect" }),
358+
}),
359+
)
355360

356361
// Verify task history was updated with new mode
357362
expect(updateTaskHistorySpy).toHaveBeenCalledWith(
@@ -682,8 +687,13 @@ describe("ClineProvider - Sticky Mode", () => {
682687
// Switch mode - should not throw
683688
await expect(provider.handleModeSwitch("architect")).resolves.not.toThrow()
684689

685-
// Verify mode was still updated in global state
686-
expect(mockContext.globalState.update).toHaveBeenCalledWith("mode", "architect")
690+
// Verify mode was still updated in durable per-view state
691+
expect(mockContext.globalState.update).toHaveBeenCalledWith(
692+
"viewStates",
693+
expect.objectContaining({
694+
[provider.viewId]: expect.objectContaining({ mode: "architect" }),
695+
}),
696+
)
687697
})
688698

689699
it("should handle null/undefined mode gracefully", async () => {
@@ -859,12 +869,16 @@ describe("ClineProvider - Sticky Mode", () => {
859869

860870
await Promise.all(switches)
861871

862-
// Find the last mode update call
863-
const modeCalls = vi.mocked(mockContext.globalState.update).mock.calls.filter((call) => call[0] === "mode")
864-
const lastModeCall = modeCalls[modeCalls.length - 1]
872+
// Find the last durable view state update call
873+
const viewStateCalls = vi
874+
.mocked(mockContext.globalState.update)
875+
.mock.calls.filter((call) => call[0] === "viewStates")
876+
const lastViewStateCall = viewStateCalls[viewStateCalls.length - 1]
865877

866878
// Verify the last mode switch wins
867-
expect(lastModeCall).toEqual(["mode", "code"])
879+
expect(lastViewStateCall?.[1]).toMatchObject({
880+
[provider.viewId]: { mode: "code" },
881+
})
868882

869883
// Verify task history was updated with final mode
870884
const lastCall = updateTaskHistorySpy.mock.calls[updateTaskHistorySpy.mock.calls.length - 1]
@@ -955,7 +969,12 @@ describe("ClineProvider - Sticky Mode", () => {
955969
await provider.handleModeSwitch("invalid-mode" as any)
956970

957971
// The mode WILL be updated to invalid-mode (this is the actual behavior)
958-
expect(mockContext.globalState.update).toHaveBeenCalledWith("mode", "invalid-mode")
972+
expect(mockContext.globalState.update).toHaveBeenCalledWith(
973+
"viewStates",
974+
expect.objectContaining({
975+
[provider.viewId]: expect.objectContaining({ mode: "invalid-mode" }),
976+
}),
977+
)
959978
})
960979

961980
it("should handle errors during mode switch gracefully", async () => {

0 commit comments

Comments
 (0)