feat: add enable/disable toggle for code indexing (#5599)

This commit is contained in:
Daniel 2025-07-12 11:55:50 -05:00 committed by GitHub
parent cdacdfd54b
commit 5bffebde58
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 499 additions and 95 deletions

View file

@ -1536,12 +1536,12 @@ export class ClineProvider
condensingApiConfigId,
customCondensingPrompt,
codebaseIndexModels: codebaseIndexModels ?? EMBEDDING_MODEL_PROFILES,
codebaseIndexConfig: codebaseIndexConfig ?? {
codebaseIndexEnabled: true,
codebaseIndexQdrantUrl: "http://localhost:6333",
codebaseIndexEmbedderProvider: "openai",
codebaseIndexEmbedderBaseUrl: "",
codebaseIndexEmbedderModelId: "",
codebaseIndexConfig: {
codebaseIndexEnabled: codebaseIndexConfig?.codebaseIndexEnabled ?? true,
codebaseIndexQdrantUrl: codebaseIndexConfig?.codebaseIndexQdrantUrl ?? "http://localhost:6333",
codebaseIndexEmbedderProvider: codebaseIndexConfig?.codebaseIndexEmbedderProvider ?? "openai",
codebaseIndexEmbedderBaseUrl: codebaseIndexConfig?.codebaseIndexEmbedderBaseUrl ?? "",
codebaseIndexEmbedderModelId: codebaseIndexConfig?.codebaseIndexEmbedderModelId ?? "",
},
mdmCompliant: this.checkMdmCompliance(),
profileThresholds: profileThresholds ?? {},
@ -1695,12 +1695,14 @@ export class ClineProvider
condensingApiConfigId: stateValues.condensingApiConfigId,
customCondensingPrompt: stateValues.customCondensingPrompt,
codebaseIndexModels: stateValues.codebaseIndexModels ?? EMBEDDING_MODEL_PROFILES,
codebaseIndexConfig: stateValues.codebaseIndexConfig ?? {
codebaseIndexEnabled: true,
codebaseIndexQdrantUrl: "http://localhost:6333",
codebaseIndexEmbedderProvider: "openai",
codebaseIndexEmbedderBaseUrl: "",
codebaseIndexEmbedderModelId: "",
codebaseIndexConfig: {
codebaseIndexEnabled: stateValues.codebaseIndexConfig?.codebaseIndexEnabled ?? true,
codebaseIndexQdrantUrl:
stateValues.codebaseIndexConfig?.codebaseIndexQdrantUrl ?? "http://localhost:6333",
codebaseIndexEmbedderProvider:
stateValues.codebaseIndexConfig?.codebaseIndexEmbedderProvider ?? "openai",
codebaseIndexEmbedderBaseUrl: stateValues.codebaseIndexConfig?.codebaseIndexEmbedderBaseUrl ?? "",
codebaseIndexEmbedderModelId: stateValues.codebaseIndexConfig?.codebaseIndexEmbedderModelId ?? "",
},
profileThresholds: stateValues.profileThresholds ?? {},
}

View file

@ -1952,9 +1952,10 @@ export const webviewMessageHandler = async (
const embedderProviderChanged =
currentConfig.codebaseIndexEmbedderProvider !== settings.codebaseIndexEmbedderProvider
// Save global state settings atomically (without codebaseIndexEnabled which is now in global settings)
// Save global state settings atomically
const globalStateConfig = {
...currentConfig,
codebaseIndexEnabled: settings.codebaseIndexEnabled,
codebaseIndexQdrantUrl: settings.codebaseIndexQdrantUrl,
codebaseIndexEmbedderProvider: settings.codebaseIndexEmbedderProvider,
codebaseIndexEmbedderBaseUrl: settings.codebaseIndexEmbedderBaseUrl,

View file

@ -1,15 +1,27 @@
// npx vitest services/code-index/__tests__/config-manager.spec.ts
import { describe, it, expect, beforeEach, vi } from "vitest"
import { CodeIndexConfigManager } from "../config-manager"
import { ContextProxy } from "../../../core/config/ContextProxy"
import { PreviousConfigSnapshot } from "../interfaces/config"
// Mock ContextProxy
vi.mock("../../../core/config/ContextProxy")
describe("CodeIndexConfigManager", () => {
let mockContextProxy: any
let configManager: CodeIndexConfigManager
beforeEach(() => {
// Reset mocks
vi.clearAllMocks()
// Setup mock ContextProxy
mockContextProxy = {
getGlobalState: vitest.fn(),
getSecret: vitest.fn().mockReturnValue(undefined),
refreshSecrets: vitest.fn().mockResolvedValue(undefined),
getGlobalState: vi.fn(),
getSecret: vi.fn().mockReturnValue(undefined),
refreshSecrets: vi.fn().mockResolvedValue(undefined),
updateGlobalState: vi.fn(),
}
configManager = new CodeIndexConfigManager(mockContextProxy)
@ -37,6 +49,39 @@ describe("CodeIndexConfigManager", () => {
})
})
describe("isFeatureEnabled", () => {
it("should return false when codebaseIndexEnabled is false", async () => {
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: false,
})
mockContextProxy.getSecret.mockReturnValue(undefined)
// Re-create instance to load the configuration
configManager = new CodeIndexConfigManager(mockContextProxy)
expect(configManager.isFeatureEnabled).toBe(false)
})
it("should return true when codebaseIndexEnabled is true", async () => {
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: true,
})
mockContextProxy.getSecret.mockReturnValue(undefined)
// Re-create instance to load the configuration
configManager = new CodeIndexConfigManager(mockContextProxy)
expect(configManager.isFeatureEnabled).toBe(true)
})
it("should default to true when codebaseIndexEnabled is not set", async () => {
mockContextProxy.getGlobalState.mockReturnValue({})
mockContextProxy.getSecret.mockReturnValue(undefined)
// Re-create instance to load the configuration
configManager = new CodeIndexConfigManager(mockContextProxy)
expect(configManager.isFeatureEnabled).toBe(true)
})
})
describe("loadConfiguration", () => {
it("should load default configuration when no state exists", async () => {
mockContextProxy.getGlobalState.mockReturnValue(undefined)
@ -1300,4 +1345,294 @@ describe("CodeIndexConfigManager", () => {
expect(result.requiresRestart).toBe(false)
})
})
describe("doesConfigChangeRequireRestart", () => {
it("should return true when enabling the feature", async () => {
// Initial state: disabled
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: false,
codebaseIndexEmbedderProvider: "openai",
codebaseIndexQdrantUrl: "http://localhost:6333",
})
mockContextProxy.getSecret.mockReturnValue(undefined)
configManager = new CodeIndexConfigManager(mockContextProxy)
// Get the initial snapshot
const { configSnapshot: previousSnapshot } = await configManager.loadConfiguration()
// Update the internal state to enabled with proper configuration
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: true,
codebaseIndexEmbedderProvider: "openai",
codebaseIndexQdrantUrl: "http://localhost:6333",
})
mockContextProxy.getSecret.mockImplementation((key: string) => {
if (key === "codeIndexOpenAiKey") return "test-key"
return undefined
})
// Load the new configuration - this will internally call doesConfigChangeRequireRestart
const { requiresRestart } = await configManager.loadConfiguration()
expect(requiresRestart).toBe(true)
})
it("should return true when disabling the feature", async () => {
// Initial state: enabled and configured
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: true,
codebaseIndexEmbedderProvider: "openai",
codebaseIndexQdrantUrl: "http://localhost:6333",
})
mockContextProxy.getSecret.mockImplementation((key: string) => {
if (key === "codeIndexOpenAiKey") return "test-key"
return undefined
})
configManager = new CodeIndexConfigManager(mockContextProxy)
const previousSnapshot: PreviousConfigSnapshot = {
enabled: true,
configured: true,
embedderProvider: "openai",
openAiKey: "test-key",
qdrantUrl: "http://localhost:6333",
}
// Update to disabled
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: false,
codebaseIndexEmbedderProvider: "openai",
codebaseIndexQdrantUrl: "http://localhost:6333",
})
mockContextProxy.getSecret.mockImplementation((key: string) => {
if (key === "codeIndexOpenAiKey") return "test-key"
return undefined
})
await configManager.loadConfiguration()
const result = configManager.doesConfigChangeRequireRestart(previousSnapshot)
expect(result).toBe(true)
})
it("should return false when enabled state does not change (both enabled)", async () => {
// Initial state: enabled and configured
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: true,
codebaseIndexEmbedderProvider: "openai",
codebaseIndexQdrantUrl: "http://localhost:6333",
})
mockContextProxy.getSecret.mockImplementation((key: string) => {
if (key === "codeIndexOpenAiKey") return "test-key"
return undefined
})
configManager = new CodeIndexConfigManager(mockContextProxy)
// Get initial configuration
const { configSnapshot: previousSnapshot } = await configManager.loadConfiguration()
// Load again with same config - should not require restart
const { requiresRestart } = await configManager.loadConfiguration()
expect(requiresRestart).toBe(false)
})
it("should return false when enabled state does not change (both disabled)", async () => {
// Initial state: disabled
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: false,
})
mockContextProxy.getSecret.mockReturnValue(undefined)
configManager = new CodeIndexConfigManager(mockContextProxy)
const previousSnapshot: PreviousConfigSnapshot = {
enabled: false,
configured: false,
embedderProvider: "openai",
}
// Same config, still disabled
const result = configManager.doesConfigChangeRequireRestart(previousSnapshot)
expect(result).toBe(false)
})
it("should return true when provider changes while enabled", async () => {
// Initial state: enabled with openai
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: true,
codebaseIndexEmbedderProvider: "ollama",
codebaseIndexOllamaBaseUrl: "http://localhost:11434",
codebaseIndexQdrantUrl: "http://localhost:6333",
})
mockContextProxy.getSecret.mockReturnValue(undefined)
configManager = new CodeIndexConfigManager(mockContextProxy)
const previousSnapshot: PreviousConfigSnapshot = {
enabled: true,
configured: true,
embedderProvider: "openai",
openAiKey: "test-key",
qdrantUrl: "http://localhost:6333",
}
const result = configManager.doesConfigChangeRequireRestart(previousSnapshot)
expect(result).toBe(true)
})
it("should return false when provider changes while disabled", async () => {
// Initial state: disabled with openai
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: false,
codebaseIndexEmbedderProvider: "ollama",
})
mockContextProxy.getSecret.mockReturnValue(undefined)
configManager = new CodeIndexConfigManager(mockContextProxy)
const previousSnapshot: PreviousConfigSnapshot = {
enabled: false,
configured: false,
embedderProvider: "openai",
}
// Provider changed but feature is disabled
const result = configManager.doesConfigChangeRequireRestart(previousSnapshot)
expect(result).toBe(false)
})
})
describe("loadConfiguration", () => {
it("should load configuration and return proper structure", async () => {
const mockConfigValues = {
codebaseIndexEnabled: true,
codebaseIndexEmbedderProvider: "openai",
codebaseIndexEmbedderModelId: "text-embedding-ada-002",
codebaseIndexQdrantUrl: "http://localhost:6333",
codebaseIndexSearchMinScore: 0.5,
codebaseIndexSearchMaxResults: 20,
}
mockContextProxy.getGlobalState.mockReturnValue(mockConfigValues)
mockContextProxy.getSecret.mockImplementation((key: string) => {
if (key === "codeIndexOpenAiKey") return "test-key"
if (key === "codeIndexQdrantApiKey") return "qdrant-key"
return undefined
})
const result = await configManager.loadConfiguration()
// Verify the structure
expect(result).toHaveProperty("configSnapshot")
expect(result).toHaveProperty("currentConfig")
expect(result).toHaveProperty("requiresRestart")
// Verify current config reflects loaded values
expect(result.currentConfig.embedderProvider).toBe("openai")
expect(result.currentConfig.isConfigured).toBe(true)
})
it("should detect restart requirement when configuration changes", async () => {
// Initial state: disabled
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: false,
codebaseIndexEmbedderProvider: "openai",
codebaseIndexQdrantUrl: "http://localhost:6333",
})
mockContextProxy.getSecret.mockReturnValue(undefined)
configManager = new CodeIndexConfigManager(mockContextProxy)
// Get initial state
await configManager.loadConfiguration()
// Change to enabled with proper configuration
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: true,
codebaseIndexEmbedderProvider: "openai",
codebaseIndexQdrantUrl: "http://localhost:6333",
})
mockContextProxy.getSecret.mockImplementation((key: string) => {
if (key === "codeIndexOpenAiKey") return "test-key"
return undefined
})
const result = await configManager.loadConfiguration()
expect(result.requiresRestart).toBe(true)
})
})
describe("getConfig", () => {
it("should return the current configuration", () => {
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: true,
codebaseIndexEmbedderProvider: "openai",
codebaseIndexQdrantUrl: "http://localhost:6333",
})
mockContextProxy.getSecret.mockImplementation((key: string) => {
if (key === "codeIndexOpenAiKey") return "test-key"
return undefined
})
configManager = new CodeIndexConfigManager(mockContextProxy)
const config = configManager.getConfig()
expect(config).toHaveProperty("isConfigured")
expect(config).toHaveProperty("embedderProvider")
expect(config.embedderProvider).toBe("openai")
})
})
describe("isConfigured", () => {
it("should return true when OpenAI provider is properly configured", () => {
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: true,
codebaseIndexEmbedderProvider: "openai",
codebaseIndexQdrantUrl: "http://localhost:6333",
})
mockContextProxy.getSecret.mockImplementation((key: string) => {
if (key === "codeIndexOpenAiKey") return "test-key"
return undefined
})
configManager = new CodeIndexConfigManager(mockContextProxy)
expect(configManager.isConfigured()).toBe(true)
})
it("should return false when OpenAI provider is missing API key", () => {
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: true,
codebaseIndexEmbedderProvider: "openai",
codebaseIndexQdrantUrl: "http://localhost:6333",
})
mockContextProxy.getSecret.mockReturnValue(undefined)
configManager = new CodeIndexConfigManager(mockContextProxy)
expect(configManager.isConfigured()).toBe(false)
})
it("should return true when Ollama provider is properly configured", () => {
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: true,
codebaseIndexEmbedderProvider: "ollama",
codebaseIndexEmbedderBaseUrl: "http://localhost:11434",
codebaseIndexQdrantUrl: "http://localhost:6333",
})
mockContextProxy.getSecret.mockReturnValue(undefined)
configManager = new CodeIndexConfigManager(mockContextProxy)
expect(configManager.isConfigured()).toBe(true)
})
it("should return false when Qdrant URL is missing", () => {
mockContextProxy.getGlobalState.mockReturnValue({
codebaseIndexEnabled: true,
codebaseIndexEmbedderProvider: "openai",
})
mockContextProxy.getSecret.mockImplementation((key: string) => {
if (key === "codeIndexOpenAiKey") return "test-key"
return undefined
})
configManager = new CodeIndexConfigManager(mockContextProxy)
expect(configManager.isConfigured()).toBe(false)
})
})
})

View file

@ -10,6 +10,7 @@ import { getDefaultModelId, getModelDimension, getModelScoreThreshold } from "..
* Handles loading, validating, and providing access to configuration values.
*/
export class CodeIndexConfigManager {
private codebaseIndexEnabled: boolean = true
private embedderProvider: EmbedderProvider = "openai"
private modelId?: string
private modelDimension?: number
@ -68,7 +69,7 @@ export class CodeIndexConfigManager {
const geminiApiKey = this.contextProxy?.getSecret("codebaseIndexGeminiApiKey") ?? ""
// Update instance variables with configuration
// Note: codebaseIndexEnabled is no longer used as the feature is always enabled
this.codebaseIndexEnabled = codebaseIndexEnabled ?? true
this.qdrantUrl = codebaseIndexQdrantUrl
this.qdrantApiKey = qdrantApiKey ?? ""
this.searchMinScore = codebaseIndexSearchMinScore
@ -142,7 +143,7 @@ export class CodeIndexConfigManager {
}> {
// Capture the ACTUAL previous state before loading new configuration
const previousConfigSnapshot: PreviousConfigSnapshot = {
enabled: true, // Feature is always enabled
enabled: this.codebaseIndexEnabled,
configured: this.isConfigured(),
embedderProvider: this.embedderProvider,
modelId: this.modelId,
@ -243,19 +244,26 @@ export class CodeIndexConfigManager {
const prevQdrantUrl = prev?.qdrantUrl ?? ""
const prevQdrantApiKey = prev?.qdrantApiKey ?? ""
// 1. Transition from unconfigured to configured
// Since the feature is always enabled, we only check configuration status
if (!prevConfigured && nowConfigured) {
// 1. Transition from disabled/unconfigured to enabled/configured
if ((!prevEnabled || !prevConfigured) && this.codebaseIndexEnabled && nowConfigured) {
return true
}
// 2. Transition from enabled to disabled
if (prevEnabled && !this.codebaseIndexEnabled) {
return true
}
// 3. If wasn't ready before and isn't ready now, no restart needed
if (!prevConfigured && !nowConfigured) {
if ((!prevEnabled || !prevConfigured) && (!this.codebaseIndexEnabled || !nowConfigured)) {
return false
}
// 4. CRITICAL CHANGES - Always restart for these
// Since feature is always enabled, we always check for critical changes
// Only check for critical changes if feature is enabled
if (!this.codebaseIndexEnabled) {
return false
}
// Provider change
if (prevProvider !== this.embedderProvider) {
@ -354,7 +362,7 @@ export class CodeIndexConfigManager {
* Gets whether the code indexing feature is enabled
*/
public get isFeatureEnabled(): boolean {
return true
return this.codebaseIndexEnabled
}
/**

View file

@ -310,8 +310,25 @@ export class CodeIndexManager {
const isFeatureEnabled = this.isFeatureEnabled
const isFeatureConfigured = this.isFeatureConfigured
// If feature is disabled, stop the service
if (!isFeatureEnabled) {
// Stop the orchestrator if it exists
if (this._orchestrator) {
this._orchestrator.stopWatcher()
}
// Set state to indicate service is disabled
this._stateManager.setSystemState("Standby", "Code indexing is disabled")
return
}
if (requiresRestart && isFeatureEnabled && isFeatureConfigured) {
try {
// Ensure cacheManager is initialized before recreating services
if (!this._cacheManager) {
this._cacheManager = new CacheManager(this.context, this.workspacePath)
await this._cacheManager.initialize()
}
// Recreate services with new configuration
await this._recreateServices()
} catch (error) {

View file

@ -7,6 +7,7 @@ import {
VSCodeDropdown,
VSCodeOption,
VSCodeLink,
VSCodeCheckbox,
} from "@vscode/webview-ui-toolkit/react"
import * as ProgressPrimitive from "@radix-ui/react-progress"
import { vscode } from "@src/utils/vscode"
@ -72,6 +73,7 @@ interface LocalCodeIndexSettings {
// Validation schema for codebase index settings
const createValidationSchema = (provider: EmbedderProvider, t: any) => {
const baseSchema = z.object({
codebaseIndexEnabled: z.boolean(),
codebaseIndexQdrantUrl: z
.string()
.min(1, t("settings:codeIndex.validation.qdrantUrlRequired"))
@ -213,6 +215,10 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
}
}, [open])
// Use a ref to capture current settings for the save handler
const currentSettingsRef = useRef(currentSettings)
currentSettingsRef.current = currentSettings
// Listen for indexing status updates and save responses
useEffect(() => {
const handleMessage = (event: MessageEvent<any>) => {
@ -227,21 +233,24 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
} else if (event.data.type === "codeIndexSettingsSaved") {
if (event.data.success) {
setSaveStatus("saved")
// Don't update initial settings here - wait for the secret status response
// Request updated secret status after save
// Update initial settings to match current settings after successful save
// This ensures hasUnsavedChanges becomes false
const savedSettings = { ...currentSettingsRef.current }
setInitialSettings(savedSettings)
// Also update current settings to maintain consistency
setCurrentSettings(savedSettings)
// Request secret status to ensure we have the latest state
// This is important to maintain placeholder display after save
vscode.postMessage({ type: "requestCodeIndexSecretStatus" })
// Reset status after 3 seconds
setTimeout(() => {
setSaveStatus("idle")
}, 3000)
setSaveStatus("idle")
} else {
setSaveStatus("error")
setSaveError(event.data.error || t("settings:codeIndex.saveError"))
// Clear error message after 5 seconds
setTimeout(() => {
setSaveStatus("idle")
setSaveError(null)
}, 5000)
setSaveStatus("idle")
setSaveError(null)
}
}
}
@ -284,14 +293,18 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
return updated
}
setCurrentSettings(updateWithSecrets)
setInitialSettings(updateWithSecrets)
// Only update settings if we're not in the middle of saving
// After save is complete (saved status), we still want to update to maintain consistency
if (saveStatus === "idle" || saveStatus === "saved") {
setCurrentSettings(updateWithSecrets)
setInitialSettings(updateWithSecrets)
}
}
}
window.addEventListener("message", handleMessage)
return () => window.removeEventListener("message", handleMessage)
}, [])
}, [saveStatus])
// Generic comparison function that detects changes between initial and current settings
const hasUnsavedChanges = useMemo(() => {
@ -417,20 +430,26 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
setSaveStatus("saving")
setSaveError(null)
// Prepare settings to save - include all fields except secrets with placeholder values
// Prepare settings to save
const settingsToSave: any = {}
// Iterate through all current settings
for (const [key, value] of Object.entries(currentSettings)) {
// Skip secret fields that still have placeholder value
// For secret fields with placeholder, don't send the placeholder
// but also don't send an empty string - just skip the field
// This tells the backend to keep the existing secret
if (value === SECRET_PLACEHOLDER) {
// Skip sending placeholder values - backend will preserve existing secrets
continue
}
// Include all other fields
// Include all other fields, including empty strings (which clear secrets)
settingsToSave[key] = value
}
// Always include codebaseIndexEnabled to ensure it's persisted
settingsToSave.codebaseIndexEnabled = currentSettings.codebaseIndexEnabled
// Save settings to backend
vscode.postMessage({
type: "saveCodeIndexSettingsAtomic",
@ -494,6 +513,20 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
</div>
<div className="p-4">
{/* Enable/Disable Toggle */}
<div className="mb-4">
<div className="flex items-center gap-2">
<VSCodeCheckbox
checked={currentSettings.codebaseIndexEnabled}
onChange={(e: any) => updateSetting("codebaseIndexEnabled", e.target.checked)}>
<span className="font-medium">{t("settings:codeIndex.enableLabel")}</span>
</VSCodeCheckbox>
<StandardTooltip content={t("settings:codeIndex.enableDescription")}>
<span className="codicon codicon-info text-xs text-vscode-descriptionForeground cursor-help" />
</StandardTooltip>
</div>
</div>
{/* Status Section */}
<div className="space-y-2">
<h4 className="text-sm font-medium">{t("settings:codeIndex.statusTitle")}</h4>
@ -1049,44 +1082,46 @@ export const CodeIndexPopover: React.FC<CodeIndexPopoverProps> = ({
{/* Action Buttons */}
<div className="flex items-center justify-between gap-2 pt-6">
<div className="flex gap-2">
{(indexingStatus.systemStatus === "Error" ||
indexingStatus.systemStatus === "Standby") && (
<VSCodeButton
onClick={() => vscode.postMessage({ type: "startIndexing" })}
disabled={saveStatus === "saving" || hasUnsavedChanges}>
{t("settings:codeIndex.startIndexingButton")}
</VSCodeButton>
)}
{currentSettings.codebaseIndexEnabled &&
(indexingStatus.systemStatus === "Error" ||
indexingStatus.systemStatus === "Standby") && (
<VSCodeButton
onClick={() => vscode.postMessage({ type: "startIndexing" })}
disabled={saveStatus === "saving" || hasUnsavedChanges}>
{t("settings:codeIndex.startIndexingButton")}
</VSCodeButton>
)}
{(indexingStatus.systemStatus === "Indexed" ||
indexingStatus.systemStatus === "Error") && (
<AlertDialog>
<AlertDialogTrigger asChild>
<VSCodeButton appearance="secondary">
{t("settings:codeIndex.clearIndexDataButton")}
</VSCodeButton>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
{t("settings:codeIndex.clearDataDialog.title")}
</AlertDialogTitle>
<AlertDialogDescription>
{t("settings:codeIndex.clearDataDialog.description")}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>
{t("settings:codeIndex.clearDataDialog.cancelButton")}
</AlertDialogCancel>
<AlertDialogAction
onClick={() => vscode.postMessage({ type: "clearIndexData" })}>
{t("settings:codeIndex.clearDataDialog.confirmButton")}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)}
{currentSettings.codebaseIndexEnabled &&
(indexingStatus.systemStatus === "Indexed" ||
indexingStatus.systemStatus === "Error") && (
<AlertDialog>
<AlertDialogTrigger asChild>
<VSCodeButton appearance="secondary">
{t("settings:codeIndex.clearIndexDataButton")}
</VSCodeButton>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
{t("settings:codeIndex.clearDataDialog.title")}
</AlertDialogTitle>
<AlertDialogDescription>
{t("settings:codeIndex.clearDataDialog.description")}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>
{t("settings:codeIndex.clearDataDialog.cancelButton")}
</AlertDialogCancel>
<AlertDialogAction
onClick={() => vscode.postMessage({ type: "clearIndexData" })}>
{t("settings:codeIndex.clearDataDialog.confirmButton")}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)}
</div>
<VSCodeButton

View file

@ -103,6 +103,12 @@ vi.mock("@vscode/webview-ui-toolkit/react", () => ({
{children}
</a>
),
VSCodeCheckbox: ({ checked, onChange, children, ...rest }: any) => (
<label>
<input type="checkbox" checked={checked || false} onChange={(e) => onChange && onChange(e)} {...rest} />
{children}
</label>
),
}))
// Helper function to simulate input on form elements

View file

@ -39,7 +39,7 @@
"codeIndex": {
"title": "Indexació de codi",
"enableLabel": "Habilitar indexació de codi",
"enableDescription": "<0>Indexació de codi</0> és una característica experimental que crea un índex de cerca semàntica del vostre projecte utilitzant embeddings d'IA. Això permet a Roo Code entendre millor i navegar per grans bases de codi trobant codi rellevant basat en significat en lloc de només paraules clau.",
"enableDescription": "Habilita la indexació de codi per millorar la cerca i la comprensió del context",
"providerLabel": "Proveïdor d'embeddings",
"selectProviderPlaceholder": "Seleccionar proveïdor",
"openaiProvider": "OpenAI",

View file

@ -41,7 +41,7 @@
"description": "Konfiguriere Codebase-Indexierungseinstellungen, um semantische Suche in deinem Projekt zu aktivieren. <0>Mehr erfahren</0>",
"statusTitle": "Status",
"enableLabel": "Codebase-Indexierung aktivieren",
"enableDescription": "<0>Codebase-Indexierung</0> ist eine experimentelle Funktion, die einen semantischen Suchindex deines Projekts mit KI-Embeddings erstellt. Dies ermöglicht es Roo Code, große Codebasen besser zu verstehen und zu navigieren, indem relevanter Code basierend auf Bedeutung statt nur Schlüsselwörtern gefunden wird.",
"enableDescription": "Aktiviere die Code-Indizierung für eine verbesserte Suche und ein besseres Kontextverständnis",
"settingsTitle": "Indexierungseinstellungen",
"disabledMessage": "Codebase-Indexierung ist derzeit deaktiviert. Aktiviere sie in den globalen Einstellungen, um Indexierungsoptionen zu konfigurieren.",
"providerLabel": "Embeddings-Anbieter",

View file

@ -41,7 +41,7 @@
"description": "Configure codebase indexing settings to enable semantic search of your project. <0>Learn more</0>",
"statusTitle": "Status",
"enableLabel": "Enable Codebase Indexing",
"enableDescription": "<0>Codebase Indexing</0> is an experimental feature that creates a semantic search index of your project using AI embeddings. This enables Roo Code to better understand and navigate large codebases by finding relevant code based on meaning rather than just keywords.",
"enableDescription": "Enable code indexing for improved search and context understanding",
"settingsTitle": "Indexing Settings",
"disabledMessage": "Codebase indexing is currently disabled. Enable it in the global settings to configure indexing options.",
"providerLabel": "Embeddings Provider",

View file

@ -41,7 +41,7 @@
"description": "Configura los ajustes de indexación de código para habilitar búsqueda semántica en tu proyecto. <0>Más información</0>",
"statusTitle": "Estado",
"enableLabel": "Habilitar indexación de código",
"enableDescription": "<0>La indexación de código</0> es una función experimental que crea un índice de búsqueda semántica de tu proyecto usando embeddings de IA. Esto permite a Roo Code entender mejor y navegar grandes bases de código encontrando código relevante basado en significado en lugar de solo palabras clave.",
"enableDescription": "Habilita la indexación de código para mejorar la búsqueda y la comprensión del contexto",
"settingsTitle": "Configuración de indexación",
"disabledMessage": "La indexación de código está actualmente deshabilitada. Habilítala en la configuración global para configurar las opciones de indexación.",
"providerLabel": "Proveedor de embeddings",

View file

@ -41,7 +41,7 @@
"description": "Configurez les paramètres d'indexation de la base de code pour activer la recherche sémantique dans votre projet. <0>En savoir plus</0>",
"statusTitle": "Statut",
"enableLabel": "Activer l'indexation de la base de code",
"enableDescription": "<0>L'indexation de la base de code</0> est une fonctionnalité expérimentale qui crée un index de recherche sémantique de votre projet en utilisant des embeddings IA. Cela permet à Roo Code de mieux comprendre et naviguer dans de grandes bases de code en trouvant du code pertinent basé sur le sens plutôt que seulement sur des mots-clés.",
"enableDescription": "Activer l'indexation du code pour une recherche et une compréhension du contexte améliorées",
"settingsTitle": "Paramètres d'indexation",
"disabledMessage": "L'indexation de la base de code est actuellement désactivée. Activez-la dans les paramètres globaux pour configurer les options d'indexation.",
"providerLabel": "Fournisseur d'embeddings",

View file

@ -39,7 +39,7 @@
"codeIndex": {
"title": "कोडबेस इंडेक्सिंग",
"enableLabel": "कोडबेस इंडेक्सिंग सक्षम करें",
"enableDescription": "<0>कोडबेस इंडेक्सिंग</0> एक प्रयोगात्मक सुविधा है जो AI एम्बेडिंग का उपयोग करके आपके प्रोजेक्ट का सिमेंटिक सर्च इंडेक्स बनाती है। यह Roo Code को केवल कीवर्ड के बजाय अर्थ के आधार पर संबंधित कोड खोजकर बड़े कोडबेस को बेहतर तरीके से समझने और नेविगेट करने में सक्षम बनाता है।",
"enableDescription": "बेहतर खोज और संदर्भ समझने के लिए कोड इंडेक्सिंग सक्षम करें",
"providerLabel": "एम्बेडिंग प्रदाता",
"selectProviderPlaceholder": "प्रदाता चुनें",
"openaiProvider": "OpenAI",

View file

@ -39,7 +39,7 @@
"codeIndex": {
"title": "Pengindeksan Codebase",
"enableLabel": "Aktifkan Pengindeksan Codebase",
"enableDescription": "<0>Pengindeksan Codebase</0> adalah fitur eksperimental yang membuat indeks pencarian semantik dari proyek kamu menggunakan AI embeddings. Ini memungkinkan Roo Code untuk lebih memahami dan menavigasi codebase besar dengan menemukan kode yang relevan berdasarkan makna daripada hanya kata kunci.",
"enableDescription": "Aktifkan pengindeksan kode untuk pencarian dan pemahaman konteks yang lebih baik",
"providerLabel": "Provider Embeddings",
"selectProviderPlaceholder": "Pilih provider",
"openaiProvider": "OpenAI",

View file

@ -39,7 +39,7 @@
"codeIndex": {
"title": "Indicizzazione del codice",
"enableLabel": "Abilita indicizzazione del codice",
"enableDescription": "<0>L'indicizzazione del codice</0> è una funzionalità sperimentale che crea un indice di ricerca semantica del tuo progetto utilizzando embedding AI. Questo permette a Roo Code di comprendere meglio e navigare grandi basi di codice trovando codice rilevante basato sul significato piuttosto che solo su parole chiave.",
"enableDescription": "Abilita l'indicizzazione del codice per una ricerca e una comprensione del contesto migliorate",
"providerLabel": "Fornitore di embedding",
"selectProviderPlaceholder": "Seleziona fornitore",
"openaiProvider": "OpenAI",

View file

@ -39,7 +39,7 @@
"codeIndex": {
"title": "コードベースのインデックス作成",
"enableLabel": "コードベースのインデックス作成を有効化",
"enableDescription": "<0>コードベースのインデックス作成</0>は、AIエンベディングを使用してプロジェクトのセマンティック検索インデックスを作成する実験的機能です。これにより、Roo Codeは単なるキーワードではなく意味に基づいて関連するコードを見つけることで、大規模なコードベースをより良く理解し、ナビゲートできるようになります。",
"enableDescription": "コードのインデックス作成を有効にして、検索とコンテキストの理解を向上させます",
"providerLabel": "埋め込みプロバイダー",
"selectProviderPlaceholder": "プロバイダーを選択",
"openaiProvider": "OpenAI",

View file

@ -39,7 +39,7 @@
"codeIndex": {
"title": "코드베이스 인덱싱",
"enableLabel": "코드베이스 인덱싱 활성화",
"enableDescription": "<0>코드베이스 인덱싱</0>은 AI 임베딩을 사용하여 프로젝트의 의미론적 검색 인덱스를 생성하는 실험적 기능입니다. 이를 통해 Roo Code는 단순한 키워드가 아닌 의미를 기반으로 관련 코드를 찾아 대규모 코드베이스를 더 잘 이해하고 탐색할 수 있습니다.",
"enableDescription": "향상된 검색 및 컨텍스트 이해를 위해 코드 인덱싱 활성화",
"providerLabel": "임베딩 제공자",
"selectProviderPlaceholder": "제공자 선택",
"openaiProvider": "OpenAI",

View file

@ -39,7 +39,7 @@
"codeIndex": {
"title": "Codebase indexering",
"enableLabel": "Codebase indexering inschakelen",
"enableDescription": "<0>Codebase indexering</0> is een experimentele functie die een semantische zoekindex van je project creëert met behulp van AI-embeddings. Dit stelt Roo Code in staat om grote codebases beter te begrijpen en te navigeren door relevante code te vinden op basis van betekenis in plaats van alleen trefwoorden.",
"enableDescription": "Code-indexering inschakelen voor verbeterde zoekresultaten en contextbegrip",
"providerLabel": "Embeddings provider",
"selectProviderPlaceholder": "Selecteer provider",
"openaiProvider": "OpenAI",

View file

@ -39,7 +39,7 @@
"codeIndex": {
"title": "Indeksowanie kodu",
"enableLabel": "Włącz indeksowanie kodu",
"enableDescription": "<0>Indeksowanie kodu</0> to eksperymentalna funkcja, która tworzy semantyczny indeks wyszukiwania Twojego projektu przy użyciu osadzeń AI. Umożliwia to Roo Code lepsze zrozumienie i nawigację po dużych bazach kodu poprzez znajdowanie odpowiedniego kodu na podstawie znaczenia, a nie tylko słów kluczowych.",
"enableDescription": "Włącz indeksowanie kodu, aby poprawić wyszukiwanie i zrozumienie kontekstu",
"providerLabel": "Dostawca osadzania",
"selectProviderPlaceholder": "Wybierz dostawcę",
"openaiProvider": "OpenAI",

View file

@ -39,7 +39,7 @@
"codeIndex": {
"title": "Indexação de Código",
"enableLabel": "Ativar Indexação de Código",
"enableDescription": "<0>Indexação de Código</0> é um recurso experimental que cria um índice de busca semântica do seu projeto usando embeddings de IA. Isso permite ao Roo Code entender melhor e navegar grandes bases de código encontrando código relevante baseado em significado ao invés de apenas palavras-chave.",
"enableDescription": "Ative a indexação de código para pesquisa e compreensão de contexto aprimoradas",
"providerLabel": "Provedor de Embeddings",
"selectProviderPlaceholder": "Selecionar provedor",
"openaiProvider": "OpenAI",

View file

@ -39,7 +39,7 @@
"codeIndex": {
"title": "Индексация кодовой базы",
"enableLabel": "Включить индексацию кодовой базы",
"enableDescription": "<0>Индексация кодовой базы</0> — это экспериментальная функция, которая создает семантический поисковый индекс вашего проекта с использованием ИИ-эмбеддингов. Это позволяет Roo Code лучше понимать и навигировать по большим кодовым базам, находя релевантный код на основе смысла, а не только ключевых слов.",
"enableDescription": "Включите индексацию кода для улучшения поиска и понимания контекста",
"providerLabel": "Провайдер эмбеддингов",
"selectProviderPlaceholder": "Выберите провайдера",
"openaiProvider": "OpenAI",

View file

@ -39,7 +39,7 @@
"codeIndex": {
"title": "Kod Tabanı İndeksleme",
"enableLabel": "Kod Tabanı İndekslemeyi Etkinleştir",
"enableDescription": "<0>Kod Tabanı İndeksleme</0>, AI gömme teknolojisini kullanarak projenizin semantik arama indeksini oluşturan deneysel bir özelliktir. Bu, Roo Code'un sadece anahtar kelimeler yerine anlam temelinde ilgili kodu bularak büyük kod tabanlarını daha iyi anlamasını ve gezinmesini sağlar.",
"enableDescription": "Geliştirilmiş arama ve bağlam anlayışı için kod indekslemeyi etkinleştirin",
"providerLabel": "Gömme Sağlayıcısı",
"selectProviderPlaceholder": "Sağlayıcı seç",
"openaiProvider": "OpenAI",

View file

@ -39,7 +39,7 @@
"codeIndex": {
"title": "Lập chỉ mục mã nguồn",
"enableLabel": "Bật lập chỉ mục mã nguồn",
"enableDescription": "<0>Lập chỉ mục mã nguồn</0> là một tính năng thử nghiệm tạo ra chỉ mục tìm kiếm ngữ nghĩa cho dự án của bạn bằng cách sử dụng AI embeddings. Điều này cho phép Roo Code hiểu rõ hơn và điều hướng các codebase lớn bằng cách tìm mã liên quan dựa trên ý nghĩa thay vì chỉ từ khóa.",
"enableDescription": "Bật lập chỉ mục mã để cải thiện tìm kiếm và sự hiểu biết về ngữ cảnh",
"providerLabel": "Nhà cung cấp nhúng",
"selectProviderPlaceholder": "Chọn nhà cung cấp",
"openaiProvider": "OpenAI",

View file

@ -41,7 +41,7 @@
"description": "配置代码库索引设置以启用项目的语义搜索。<0>了解更多</0>",
"statusTitle": "状态",
"enableLabel": "启用代码库索引",
"enableDescription": "<0>代码库索引</0>是一个实验性功能,使用 AI 嵌入为您的项目创建语义搜索索引。这使 Roo Code 能够通过基于含义而非仅仅关键词来查找相关代码,从而更好地理解和导航大型代码库。",
"enableDescription": "启用代码索引以改进搜索和上下文理解",
"settingsTitle": "索引设置",
"disabledMessage": "代码库索引当前已禁用。在全局设置中启用它以配置索引选项。",
"providerLabel": "嵌入提供商",

View file

@ -39,7 +39,7 @@
"codeIndex": {
"title": "程式碼庫索引",
"enableLabel": "啟用程式碼庫索引",
"enableDescription": "<0>程式碼庫索引</0>是一個實驗性功能,使用 AI 嵌入為您的專案建立語義搜尋索引。這使 Roo Code 能夠透過基於含義而非僅僅關鍵詞來尋找相關程式碼,從而更好地理解和導覽大型程式碼庫。",
"enableDescription": "啟用程式碼索引以改進搜尋和上下文理解",
"providerLabel": "嵌入提供者",
"selectProviderPlaceholder": "選擇提供者",
"openaiProvider": "OpenAI",