mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
feat: add optional persistent default mode setting
- Add setAsDefault parameter to handleModeSwitch() method - Add setAsDefaultMode() method to update global state - Add setDefaultMode message type and handler - Update tests to use new setAsDefault parameter - Maintain backward compatibility with existing behavior - Address concern about removing persistent default mode functionality This allows users to optionally set a mode as the global default while maintaining multi-window mode isolation.
This commit is contained in:
parent
48d24f0446
commit
e3fb12a8b3
5 changed files with 128 additions and 17 deletions
9
apps/web-evals/next.config.js
Normal file
9
apps/web-evals/next.config.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var nextConfig = {
|
||||
webpack: function (config) {
|
||||
config.resolve.extensionAlias = { ".js": [".ts", ".tsx", ".js", ".jsx"] };
|
||||
return config;
|
||||
},
|
||||
};
|
||||
exports.default = nextConfig;
|
||||
|
|
@ -802,8 +802,9 @@ export class ClineProvider
|
|||
/**
|
||||
* Handle switching to a new mode, including updating the associated API configuration
|
||||
* @param newMode The mode to switch to
|
||||
* @param setAsDefault Whether to set this mode as the global default for new windows
|
||||
*/
|
||||
public async handleModeSwitch(newMode: Mode) {
|
||||
public async handleModeSwitch(newMode: Mode, setAsDefault: boolean = false) {
|
||||
const cline = this.getCurrentCline()
|
||||
|
||||
if (cline) {
|
||||
|
|
@ -814,6 +815,11 @@ export class ClineProvider
|
|||
// Store mode in instance-specific storage to prevent cross-window interference
|
||||
this.instanceMode = newMode
|
||||
|
||||
// If user wants to set this as the default mode, update global state
|
||||
if (setAsDefault) {
|
||||
await this.setAsDefaultMode(newMode)
|
||||
}
|
||||
|
||||
// Load the saved API config for the new mode if it exists
|
||||
const savedConfigId = await this.providerSettingsManager.getModeConfigId(newMode)
|
||||
const listApiConfig = await this.providerSettingsManager.listConfig()
|
||||
|
|
@ -844,6 +850,14 @@ export class ClineProvider
|
|||
await this.postStateToWebview()
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a mode as the global default for new windows
|
||||
* @param mode The mode to set as default
|
||||
*/
|
||||
public async setAsDefaultMode(mode: Mode) {
|
||||
await this.updateGlobalState("mode", mode)
|
||||
}
|
||||
|
||||
// Provider Profile Management
|
||||
|
||||
getProviderProfileEntries(): ProviderSettingsEntry[] {
|
||||
|
|
@ -1416,6 +1430,7 @@ export class ClineProvider
|
|||
profileThresholds,
|
||||
alwaysAllowFollowupQuestions,
|
||||
followupAutoApproveTimeoutMs,
|
||||
modeApiConfigs,
|
||||
} = await this.getState()
|
||||
|
||||
const telemetryKey = process.env.POSTHOG_API_KEY
|
||||
|
|
@ -1529,6 +1544,7 @@ export class ClineProvider
|
|||
hasOpenedModeSelector: this.getGlobalState("hasOpenedModeSelector") ?? false,
|
||||
alwaysAllowFollowupQuestions: alwaysAllowFollowupQuestions ?? false,
|
||||
followupAutoApproveTimeoutMs: followupAutoApproveTimeoutMs ?? 60000,
|
||||
modeApiConfigs: modeApiConfigs ?? {},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -240,8 +240,8 @@ describe("ClineProvider - Multi-Window Mode Isolation", () => {
|
|||
expect(initialState1.mode).toBe("code")
|
||||
expect(initialState2.mode).toBe("code")
|
||||
|
||||
// Switch mode in provider1 to architect
|
||||
await provider1.handleModeSwitch("architect")
|
||||
// Switch mode in provider1 to architect (without setting as default)
|
||||
await provider1.handleModeSwitch("architect", false)
|
||||
|
||||
// Check states after mode switch
|
||||
const afterSwitchState1 = await provider1.getState()
|
||||
|
|
@ -257,11 +257,11 @@ describe("ClineProvider - Multi-Window Mode Isolation", () => {
|
|||
await provider1.resolveWebviewView(mockWebviewView1)
|
||||
await provider2.resolveWebviewView(mockWebviewView2)
|
||||
|
||||
// Switch provider1 to architect mode
|
||||
await provider1.handleModeSwitch("architect")
|
||||
// Switch provider1 to architect mode (without setting as default)
|
||||
await provider1.handleModeSwitch("architect", false)
|
||||
|
||||
// Switch provider2 to ask mode
|
||||
await provider2.handleModeSwitch("ask")
|
||||
// Switch provider2 to ask mode (without setting as default)
|
||||
await provider2.handleModeSwitch("ask", false)
|
||||
|
||||
// Check final states
|
||||
const finalState1 = await provider1.getState()
|
||||
|
|
@ -273,8 +273,8 @@ describe("ClineProvider - Multi-Window Mode Isolation", () => {
|
|||
})
|
||||
|
||||
test("new provider instances initialize with global mode, not instance-specific modes", async () => {
|
||||
// Switch provider1 to architect mode
|
||||
await provider1.handleModeSwitch("architect")
|
||||
// Switch provider1 to architect mode (without setting as default)
|
||||
await provider1.handleModeSwitch("architect", false)
|
||||
|
||||
// Create a new provider instance (simulating opening a new window)
|
||||
const contextProxy3 = new ContextProxy(mockContext1)
|
||||
|
|
@ -301,9 +301,9 @@ describe("ClineProvider - Multi-Window Mode Isolation", () => {
|
|||
await provider1.resolveWebviewView(mockWebviewView1)
|
||||
await provider2.resolveWebviewView(mockWebviewView2)
|
||||
|
||||
// Switch modes in both providers
|
||||
await provider1.handleModeSwitch("architect")
|
||||
await provider2.handleModeSwitch("ask")
|
||||
// Switch modes in both providers (without setting as default)
|
||||
await provider1.handleModeSwitch("architect", false)
|
||||
await provider2.handleModeSwitch("ask", false)
|
||||
|
||||
// Get webview states
|
||||
const webviewState1 = await provider1.getStateToPostToWebview()
|
||||
|
|
@ -348,8 +348,8 @@ describe("ClineProvider - Multi-Window Mode Isolation", () => {
|
|||
test("instance mode persists across state retrievals", async () => {
|
||||
await provider1.resolveWebviewView(mockWebviewView1)
|
||||
|
||||
// Switch to architect mode
|
||||
await provider1.handleModeSwitch("architect")
|
||||
// Switch to architect mode (without setting as default)
|
||||
await provider1.handleModeSwitch("architect", false)
|
||||
|
||||
// Get state multiple times
|
||||
const state1 = await provider1.getState()
|
||||
|
|
@ -369,8 +369,8 @@ describe("ClineProvider - Multi-Window Mode Isolation", () => {
|
|||
const initialGlobalMode = mockContext1.globalState.get("mode")
|
||||
expect(initialGlobalMode).toBe("code")
|
||||
|
||||
// Switch instance mode
|
||||
await provider1.handleModeSwitch("architect")
|
||||
// Switch instance mode (without setting as default)
|
||||
await provider1.handleModeSwitch("architect", false)
|
||||
|
||||
// Global mode should remain unchanged
|
||||
const finalGlobalMode = mockContext1.globalState.get("mode")
|
||||
|
|
@ -413,4 +413,83 @@ describe("ClineProvider - Multi-Window Mode Isolation", () => {
|
|||
// Should fallback to default mode
|
||||
expect(state.mode).toBe(defaultModeSlug)
|
||||
})
|
||||
|
||||
test("setting mode as default updates global state", async () => {
|
||||
await provider1.resolveWebviewView(mockWebviewView1)
|
||||
|
||||
// Get initial global mode
|
||||
const initialGlobalMode = mockContext1.globalState.get("mode")
|
||||
expect(initialGlobalMode).toBe("code")
|
||||
|
||||
// Switch mode and set as default
|
||||
await provider1.handleModeSwitch("architect", true)
|
||||
|
||||
// Global mode should be updated
|
||||
const finalGlobalMode = mockContext1.globalState.get("mode")
|
||||
expect(finalGlobalMode).toBe("architect")
|
||||
|
||||
// Instance should also have architect mode
|
||||
const instanceState = await provider1.getState()
|
||||
expect(instanceState.mode).toBe("architect")
|
||||
})
|
||||
|
||||
test("new windows initialize with updated default mode", async () => {
|
||||
await provider1.resolveWebviewView(mockWebviewView1)
|
||||
|
||||
// Switch mode and set as default in provider1
|
||||
await provider1.handleModeSwitch("architect", true)
|
||||
|
||||
// Create a new provider instance (simulating opening a new window)
|
||||
const contextProxy3 = new ContextProxy(mockContext1)
|
||||
await contextProxy3.initialize()
|
||||
const provider3 = new ClineProvider(mockContext1, mockOutputChannel, "sidebar", contextProxy3)
|
||||
provider3.getMcpHub = vi.fn().mockReturnValue({
|
||||
listTools: vi.fn().mockResolvedValue([]),
|
||||
callTool: vi.fn().mockResolvedValue({ content: [] }),
|
||||
listResources: vi.fn().mockResolvedValue([]),
|
||||
readResource: vi.fn().mockResolvedValue({ contents: [] }),
|
||||
getAllServers: vi.fn().mockReturnValue([]),
|
||||
})
|
||||
|
||||
// New provider should initialize with the new default mode (architect)
|
||||
const newProviderState = await provider3.getState()
|
||||
expect(newProviderState.mode).toBe("architect")
|
||||
})
|
||||
|
||||
test("setDefaultMode message handler updates global state", async () => {
|
||||
await provider1.resolveWebviewView(mockWebviewView1)
|
||||
|
||||
// Get initial global mode
|
||||
const initialGlobalMode = mockContext1.globalState.get("mode")
|
||||
expect(initialGlobalMode).toBe("code")
|
||||
|
||||
// Get message handler
|
||||
const messageHandler1 = (mockWebviewView1.webview.onDidReceiveMessage as any).mock.calls[0][0]
|
||||
|
||||
// Send setDefaultMode message
|
||||
await messageHandler1({ type: "setDefaultMode", mode: "architect" })
|
||||
|
||||
// Global mode should be updated
|
||||
const finalGlobalMode = mockContext1.globalState.get("mode")
|
||||
expect(finalGlobalMode).toBe("architect")
|
||||
})
|
||||
|
||||
test("mode switch without setAsDefault preserves global state", async () => {
|
||||
await provider1.resolveWebviewView(mockWebviewView1)
|
||||
|
||||
// Get initial global mode
|
||||
const initialGlobalMode = mockContext1.globalState.get("mode")
|
||||
expect(initialGlobalMode).toBe("code")
|
||||
|
||||
// Switch mode without setting as default
|
||||
await provider1.handleModeSwitch("architect", false)
|
||||
|
||||
// Global mode should remain unchanged
|
||||
const finalGlobalMode = mockContext1.globalState.get("mode")
|
||||
expect(finalGlobalMode).toBe("code")
|
||||
|
||||
// But instance should have architect mode
|
||||
const instanceState = await provider1.getState()
|
||||
expect(instanceState.mode).toBe("architect")
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1133,7 +1133,13 @@ export const webviewMessageHandler = async (
|
|||
}
|
||||
break
|
||||
case "mode":
|
||||
await provider.handleModeSwitch(message.text as Mode)
|
||||
await provider.handleModeSwitch(message.text as Mode, message.bool)
|
||||
break
|
||||
case "setDefaultMode":
|
||||
if (message.text) {
|
||||
await provider.setAsDefaultMode(message.text as Mode)
|
||||
await provider.postStateToWebview()
|
||||
}
|
||||
break
|
||||
case "updateSupportPrompt":
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ export interface WebviewMessage {
|
|||
| "requestDelaySeconds"
|
||||
| "setApiConfigPassword"
|
||||
| "mode"
|
||||
| "setDefaultMode"
|
||||
| "updatePrompt"
|
||||
| "updateSupportPrompt"
|
||||
| "getSystemPrompt"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue