diff --git a/packages/types/src/codebase-index.ts b/packages/types/src/codebase-index.ts index be7778f538..0d72f76c83 100644 --- a/packages/types/src/codebase-index.ts +++ b/packages/types/src/codebase-index.ts @@ -36,6 +36,15 @@ export const codebaseIndexConfigSchema = z.object({ // OpenAI Compatible specific fields codebaseIndexOpenAiCompatibleBaseUrl: z.string().optional(), codebaseIndexOpenAiCompatibleModelDimension: z.number().optional(), + // Per-workspace settings + codebaseIndexWorkspaceSettings: z + .record( + z.string(), + z.object({ + enabled: z.boolean(), + }), + ) + .optional(), }) export type CodebaseIndexConfig = z.infer diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index accb66f6e9..bd0a923a6f 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -25,6 +25,7 @@ import { changeLanguage, t } from "../../i18n" import { Package } from "../../shared/package" import { type RouterName, type ModelRecord, toRouterName } from "../../shared/api" import { MessageEnhancer } from "./messageEnhancer" +import { CodeIndexManager } from "../../services/code-index/manager" import { type WebviewMessage, @@ -2569,6 +2570,29 @@ export const webviewMessageHandler = async ( }) break } + case "setWorkspaceCodebaseIndexEnabled": { + const { workspacePath, enabled } = message + try { + const manager = CodeIndexManager.getInstance(provider.context, workspacePath) + if (manager && enabled !== undefined) { + await manager.setWorkspaceEnabled(enabled) + + // Send updated status back to webview + const status = manager.getCurrentStatus() + provider.postMessageToWebview({ + type: "indexingStatusUpdate", + values: { + ...status, + workspaceEnabled: manager.getWorkspaceEnabled(), + globalEnabled: manager.getGlobalEnabled(), + }, + }) + } + } catch (error) { + console.error("Failed to set workspace codebase index enabled state:", error) + } + break + } case "startIndexing": { try { const manager = provider.getCurrentWorkspaceCodeIndexManager() diff --git a/src/services/code-index/config-manager.ts b/src/services/code-index/config-manager.ts index 2c0e8bb5c9..bfcc2733f1 100644 --- a/src/services/code-index/config-manager.ts +++ b/src/services/code-index/config-manager.ts @@ -25,7 +25,15 @@ export class CodeIndexConfigManager { private searchMinScore?: number private searchMaxResults?: number - constructor(private readonly contextProxy: ContextProxy) { + // Per-workspace settings + private workspaceSettings: Record = {} + private currentWorkspacePath: string | undefined + + constructor( + private readonly contextProxy: ContextProxy, + workspacePath?: string, + ) { + this.currentWorkspacePath = workspacePath // Initialize with current configuration to avoid false restart triggers this._loadAndSetConfiguration() } @@ -61,6 +69,7 @@ export class CodeIndexConfigManager { codebaseIndexEmbedderModelId, codebaseIndexSearchMinScore, codebaseIndexSearchMaxResults, + codebaseIndexWorkspaceSettings, } = codebaseIndexConfig const openAiKey = this.contextProxy?.getSecret("codeIndexOpenAiKey") ?? "" @@ -72,8 +81,20 @@ export class CodeIndexConfigManager { const mistralApiKey = this.contextProxy?.getSecret("codebaseIndexMistralApiKey") ?? "" const vercelAiGatewayApiKey = this.contextProxy?.getSecret("codebaseIndexVercelAiGatewayApiKey") ?? "" + // Load workspace settings + this.workspaceSettings = codebaseIndexWorkspaceSettings ?? {} + + // Determine effective enabled state based on workspace override + const globalEnabled = codebaseIndexEnabled ?? true + let effectiveEnabled = globalEnabled + + if (this.currentWorkspacePath && this.workspaceSettings[this.currentWorkspacePath]) { + // Workspace setting takes precedence over global setting + effectiveEnabled = this.workspaceSettings[this.currentWorkspacePath].enabled + } + // Update instance variables with configuration - this.codebaseIndexEnabled = codebaseIndexEnabled ?? true + this.codebaseIndexEnabled = effectiveEnabled this.qdrantUrl = codebaseIndexQdrantUrl this.qdrantApiKey = qdrantApiKey ?? "" this.searchMinScore = codebaseIndexSearchMinScore @@ -409,6 +430,47 @@ export class CodeIndexConfigManager { return this.codebaseIndexEnabled } + /** + * Updates the enabled state for a specific workspace + */ + public async setWorkspaceEnabled(workspacePath: string, enabled: boolean): Promise { + if (!this.contextProxy) { + return + } + + // Get current config + const currentConfig = this.contextProxy.getGlobalState("codebaseIndexConfig") ?? {} + + // Update workspace settings + const workspaceSettings = currentConfig.codebaseIndexWorkspaceSettings ?? {} + workspaceSettings[workspacePath] = { enabled } + + // Save updated config + await this.contextProxy.updateGlobalState("codebaseIndexConfig", { + ...currentConfig, + codebaseIndexWorkspaceSettings: workspaceSettings, + }) + + // Reload configuration to apply changes + await this.loadConfiguration() + } + + /** + * Gets the enabled state for a specific workspace + */ + public getWorkspaceEnabled(workspacePath: string): boolean | undefined { + const config = this.contextProxy?.getGlobalState("codebaseIndexConfig") ?? {} + return config.codebaseIndexWorkspaceSettings?.[workspacePath]?.enabled + } + + /** + * Gets the global enabled state (without workspace override) + */ + public getGlobalEnabled(): boolean { + const config = this.contextProxy?.getGlobalState("codebaseIndexConfig") ?? {} + return config.codebaseIndexEnabled ?? true + } + /** * Gets whether the code indexing feature is properly configured */ diff --git a/src/services/code-index/manager.ts b/src/services/code-index/manager.ts index dd79a3f161..ccdca0df0c 100644 --- a/src/services/code-index/manager.ts +++ b/src/services/code-index/manager.ts @@ -118,7 +118,7 @@ export class CodeIndexManager { public async initialize(contextProxy: ContextProxy): Promise<{ requiresRestart: boolean }> { // 1. ConfigManager Initialization and Configuration Loading if (!this._configManager) { - this._configManager = new CodeIndexConfigManager(contextProxy) + this._configManager = new CodeIndexConfigManager(contextProxy, this.workspacePath) } // Load configuration once to get current state and restart requirements const { requiresRestart } = await this._configManager.loadConfiguration() @@ -419,4 +419,40 @@ export class CodeIndexManager { } } } + + /** + * Sets the enabled state for the current workspace + */ + public async setWorkspaceEnabled(enabled: boolean): Promise { + if (!this._configManager || !this.workspacePath) { + return + } + + await this._configManager.setWorkspaceEnabled(this.workspacePath, enabled) + + // Reload configuration to apply changes + await this.handleSettingsChange() + } + + /** + * Gets the enabled state for the current workspace + */ + public getWorkspaceEnabled(): boolean | undefined { + if (!this._configManager || !this.workspacePath) { + return undefined + } + + return this._configManager.getWorkspaceEnabled(this.workspacePath) + } + + /** + * Gets the global enabled state (without workspace override) + */ + public getGlobalEnabled(): boolean { + if (!this._configManager) { + return true + } + + return this._configManager.getGlobalEnabled() + } } diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index 93d0b9bc45..825f4ac1db 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -186,6 +186,7 @@ export interface WebviewMessage { | "requestIndexingStatus" | "startIndexing" | "clearIndexData" + | "setWorkspaceCodebaseIndexEnabled" | "indexingStatusUpdate" | "indexCleared" | "focusPanelRequest" @@ -272,6 +273,8 @@ export interface WebviewMessage { checkOnly?: boolean // For deleteCustomMode check upsellId?: string // For dismissUpsell list?: string[] // For dismissedUpsells response + workspacePath?: string // For setWorkspaceCodebaseIndexEnabled + enabled?: boolean // For setWorkspaceCodebaseIndexEnabled codeIndexSettings?: { // Global state settings codebaseIndexEnabled: boolean