From 738c239cfb58151c4dbc02a257c14fdaa88fe2c2 Mon Sep 17 00:00:00 2001 From: James Mtendamema Date: Thu, 12 Feb 2026 22:02:06 -0700 Subject: [PATCH 1/9] feat: add per-workspace indexing opt-in and stop/cancel control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add codeIndexWorkspaceEnabled flag in workspaceState (default: false) - Thread AbortController/AbortSignal through orchestrator → scanner - Add Stop Indexing button and Stopping state to UI - Fix handleSettingsChange() to abort active scan when disabling toggle - Add translations for all 18 locales --- ...exing-workspace-opt-in-and-stop-control.md | 9 + packages/types/src/vscode-extension-host.ts | 5 +- src/core/webview/webviewMessageHandler.ts | 56 +++++- src/i18n/locales/ca/embeddings.json | 4 +- src/i18n/locales/de/embeddings.json | 4 +- src/i18n/locales/en/embeddings.json | 4 +- src/i18n/locales/es/embeddings.json | 4 +- src/i18n/locales/fr/embeddings.json | 4 +- src/i18n/locales/hi/embeddings.json | 4 +- src/i18n/locales/id/embeddings.json | 4 +- src/i18n/locales/it/embeddings.json | 4 +- src/i18n/locales/ja/embeddings.json | 4 +- src/i18n/locales/ko/embeddings.json | 4 +- src/i18n/locales/nl/embeddings.json | 4 +- src/i18n/locales/pl/embeddings.json | 4 +- src/i18n/locales/pt-BR/embeddings.json | 4 +- src/i18n/locales/ru/embeddings.json | 4 +- src/i18n/locales/tr/embeddings.json | 4 +- src/i18n/locales/vi/embeddings.json | 4 +- src/i18n/locales/zh-CN/embeddings.json | 4 +- src/i18n/locales/zh-TW/embeddings.json | 4 +- .../code-index/__tests__/manager.spec.ts | 99 +++++++++- .../code-index/__tests__/orchestrator.spec.ts | 174 ++++++++++++++++++ .../code-index/interfaces/file-processor.ts | 1 + src/services/code-index/interfaces/manager.ts | 7 +- src/services/code-index/manager.ts | 40 ++-- src/services/code-index/orchestrator.ts | 38 +++- .../processors/__tests__/scanner.spec.ts | 64 +++++++ src/services/code-index/processors/scanner.ts | 31 ++++ src/services/code-index/state-manager.ts | 6 +- .../src/components/chat/CodeIndexPopover.tsx | 43 +++++ .../components/chat/IndexingStatusBadge.tsx | 3 + webview-ui/src/i18n/locales/ca/chat.json | 3 +- webview-ui/src/i18n/locales/ca/settings.json | 6 +- webview-ui/src/i18n/locales/de/chat.json | 3 +- webview-ui/src/i18n/locales/de/settings.json | 6 +- webview-ui/src/i18n/locales/en/chat.json | 3 +- webview-ui/src/i18n/locales/en/settings.json | 6 +- webview-ui/src/i18n/locales/es/chat.json | 3 +- webview-ui/src/i18n/locales/es/settings.json | 6 +- webview-ui/src/i18n/locales/fr/chat.json | 3 +- webview-ui/src/i18n/locales/fr/settings.json | 6 +- webview-ui/src/i18n/locales/hi/chat.json | 3 +- webview-ui/src/i18n/locales/hi/settings.json | 6 +- webview-ui/src/i18n/locales/id/chat.json | 3 +- webview-ui/src/i18n/locales/id/settings.json | 6 +- webview-ui/src/i18n/locales/it/chat.json | 3 +- webview-ui/src/i18n/locales/it/settings.json | 6 +- webview-ui/src/i18n/locales/ja/chat.json | 3 +- webview-ui/src/i18n/locales/ja/settings.json | 6 +- webview-ui/src/i18n/locales/ko/chat.json | 3 +- webview-ui/src/i18n/locales/ko/settings.json | 6 +- webview-ui/src/i18n/locales/nl/chat.json | 3 +- webview-ui/src/i18n/locales/nl/settings.json | 6 +- webview-ui/src/i18n/locales/pl/chat.json | 3 +- webview-ui/src/i18n/locales/pl/settings.json | 6 +- webview-ui/src/i18n/locales/pt-BR/chat.json | 3 +- .../src/i18n/locales/pt-BR/settings.json | 6 +- webview-ui/src/i18n/locales/ru/chat.json | 3 +- webview-ui/src/i18n/locales/ru/settings.json | 6 +- webview-ui/src/i18n/locales/tr/chat.json | 3 +- webview-ui/src/i18n/locales/tr/settings.json | 6 +- webview-ui/src/i18n/locales/vi/chat.json | 3 +- webview-ui/src/i18n/locales/vi/settings.json | 6 +- webview-ui/src/i18n/locales/zh-CN/chat.json | 3 +- .../src/i18n/locales/zh-CN/settings.json | 6 +- webview-ui/src/i18n/locales/zh-TW/chat.json | 3 +- .../src/i18n/locales/zh-TW/settings.json | 6 +- 68 files changed, 731 insertions(+), 79 deletions(-) create mode 100644 .changeset/indexing-workspace-opt-in-and-stop-control.md diff --git a/.changeset/indexing-workspace-opt-in-and-stop-control.md b/.changeset/indexing-workspace-opt-in-and-stop-control.md new file mode 100644 index 00000000000..27a1fbe0b0e --- /dev/null +++ b/.changeset/indexing-workspace-opt-in-and-stop-control.md @@ -0,0 +1,9 @@ +--- +"roo-cline": minor +--- + +Add per-workspace indexing opt-in and stop/cancel indexing controls + +- **Per-workspace indexing opt-in**: Indexing no longer auto-starts on every workspace. A new `codeIndexWorkspaceEnabled` flag (stored in `workspaceState`, default: false) requires users to explicitly enable indexing per workspace via a toggle in the CodeIndex popover. The choice is remembered across sessions. +- **Stop/cancel indexing**: Users can stop an in-progress indexing operation via a "Stop Indexing" button. Uses `AbortController`/`AbortSignal` threaded through the orchestrator → scanner pipeline with graceful abort at file and batch boundaries. +- **Disable toggle bug fix**: Unchecking "Enable Codebase Indexing" during active indexing now properly stops the scan via `stopIndexing()` instead of only calling `stopWatcher()`, which left the scanner running asynchronously. diff --git a/packages/types/src/vscode-extension-host.ts b/packages/types/src/vscode-extension-host.ts index a72f087d24c..3d20ebba73a 100644 --- a/packages/types/src/vscode-extension-host.ts +++ b/packages/types/src/vscode-extension-host.ts @@ -507,9 +507,11 @@ export interface WebviewMessage { | "condenseTaskContextRequest" | "requestIndexingStatus" | "startIndexing" + | "stopIndexing" | "clearIndexData" | "indexingStatusUpdate" | "indexCleared" + | "toggleWorkspaceIndexing" | "focusPanelRequest" | "openExternal" | "filterMarketplaceItems" @@ -704,7 +706,7 @@ export const checkoutRestorePayloadSchema = z.object({ export type CheckpointRestorePayload = z.infer export interface IndexingStatusPayload { - state: "Standby" | "Indexing" | "Indexed" | "Error" + state: "Standby" | "Indexing" | "Indexed" | "Error" | "Stopping" message: string } @@ -738,6 +740,7 @@ export interface IndexingStatus { totalItems: number currentItemUnit?: string workspacePath?: string + workspaceEnabled?: boolean } export interface IndexingStatusUpdateMessage { diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 041cc729835..81c84a7c505 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -2611,7 +2611,6 @@ export const webviewMessageHandler = async ( try { const manager = provider.getCurrentWorkspaceCodeIndexManager() if (!manager) { - // No workspace open - send error status provider.postMessageToWebview({ type: "indexingStatusUpdate", values: { @@ -2625,23 +2624,19 @@ export const webviewMessageHandler = async ( provider.log("Cannot start indexing: No workspace folder open") return } + + // "Start Indexing" implicitly enables the workspace + await manager.setWorkspaceEnabled(true) + if (manager.isFeatureEnabled && manager.isFeatureConfigured) { - // Mimic extension startup behavior: initialize first, which will - // check if Qdrant container is active and reuse existing collection await manager.initialize(provider.contextProxy) - // Only call startIndexing if we're in a state that requires it - // (e.g., Standby or Error). If already Indexed or Indexing, the - // initialize() call above will have already started the watcher. const currentState = manager.state if (currentState === "Standby" || currentState === "Error") { - // startIndexing now handles error recovery internally manager.startIndexing() - // If startIndexing recovered from error, we need to reinitialize if (!manager.isInitialized) { await manager.initialize(provider.contextProxy) - // Try starting again after initialization if (manager.state === "Standby" || manager.state === "Error") { manager.startIndexing() } @@ -2653,6 +2648,49 @@ export const webviewMessageHandler = async ( } break } + case "stopIndexing": { + try { + const manager = provider.getCurrentWorkspaceCodeIndexManager() + if (!manager) { + provider.log("Cannot stop indexing: No workspace folder open") + return + } + manager.stopIndexing() + provider.postMessageToWebview({ + type: "indexingStatusUpdate", + values: manager.getCurrentStatus(), + }) + } catch (error) { + provider.log(`Error stopping indexing: ${error instanceof Error ? error.message : String(error)}`) + } + break + } + case "toggleWorkspaceIndexing": { + try { + const manager = provider.getCurrentWorkspaceCodeIndexManager() + if (!manager) { + provider.log("Cannot toggle workspace indexing: No workspace folder open") + return + } + const enabled = message.bool ?? false + await manager.setWorkspaceEnabled(enabled) + if (enabled && manager.isFeatureEnabled && manager.isFeatureConfigured) { + await manager.initialize(provider.contextProxy) + manager.startIndexing() + } else if (!enabled) { + manager.stopIndexing() + } + provider.postMessageToWebview({ + type: "indexingStatusUpdate", + values: manager.getCurrentStatus(), + }) + } catch (error) { + provider.log( + `Error toggling workspace indexing: ${error instanceof Error ? error.message : String(error)}`, + ) + } + break + } case "clearIndexData": { try { const manager = provider.getCurrentWorkspaceCodeIndexManager() diff --git a/src/i18n/locales/ca/embeddings.json b/src/i18n/locales/ca/embeddings.json index 21a4a27ab41..86c7ad14346 100644 --- a/src/i18n/locales/ca/embeddings.json +++ b/src/i18n/locales/ca/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "Monitor de fitxers aturat.", "failedDuringInitialScan": "Ha fallat durant l'escaneig inicial: {{errorMessage}}", "unknownError": "Error desconegut", - "indexingRequiresWorkspace": "Indexació requereix una carpeta de workspace oberta" + "indexingRequiresWorkspace": "Indexació requereix una carpeta de workspace oberta", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/de/embeddings.json b/src/i18n/locales/de/embeddings.json index 0297ec03091..7291556c5fd 100644 --- a/src/i18n/locales/de/embeddings.json +++ b/src/i18n/locales/de/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "Datei-Watcher gestoppt.", "failedDuringInitialScan": "Fehler während des ersten Scans: {{errorMessage}}", "unknownError": "Unbekannter Fehler", - "indexingRequiresWorkspace": "Indexierung erfordert einen offenen Workspace-Ordner" + "indexingRequiresWorkspace": "Indexierung erfordert einen offenen Workspace-Ordner", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/en/embeddings.json b/src/i18n/locales/en/embeddings.json index 5819e45c1a8..7777af9027e 100644 --- a/src/i18n/locales/en/embeddings.json +++ b/src/i18n/locales/en/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "File watcher stopped.", "failedDuringInitialScan": "Failed during initial scan: {{errorMessage}}", "unknownError": "Unknown error", - "indexingRequiresWorkspace": "Indexing requires an open workspace folder" + "indexingRequiresWorkspace": "Indexing requires an open workspace folder", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/es/embeddings.json b/src/i18n/locales/es/embeddings.json index eca9efcc075..ecc1fd7cc9b 100644 --- a/src/i18n/locales/es/embeddings.json +++ b/src/i18n/locales/es/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "Monitor de archivos detenido.", "failedDuringInitialScan": "Falló durante el escaneo inicial: {{errorMessage}}", "unknownError": "Error desconocido", - "indexingRequiresWorkspace": "La indexación requiere una carpeta de workspace abierta" + "indexingRequiresWorkspace": "La indexación requiere una carpeta de workspace abierta", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/fr/embeddings.json b/src/i18n/locales/fr/embeddings.json index fa922179870..ca14469ee24 100644 --- a/src/i18n/locales/fr/embeddings.json +++ b/src/i18n/locales/fr/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "Surveillant de fichiers arrêté.", "failedDuringInitialScan": "Échec lors du scan initial : {{errorMessage}}", "unknownError": "Erreur inconnue", - "indexingRequiresWorkspace": "L'indexation nécessite l'ouverture d'un dossier workspace" + "indexingRequiresWorkspace": "L'indexation nécessite l'ouverture d'un dossier workspace", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/hi/embeddings.json b/src/i18n/locales/hi/embeddings.json index eb7f066c56f..97baebcd7cb 100644 --- a/src/i18n/locales/hi/embeddings.json +++ b/src/i18n/locales/hi/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "फाइल वॉचर रुक गया।", "failedDuringInitialScan": "प्रारंभिक स्कैन के दौरान असफल: {{errorMessage}}", "unknownError": "अज्ञात त्रुटि", - "indexingRequiresWorkspace": "इंडेक्सिंग के लिए एक खुला वर्कस्पेस फ़ोल्डर आवश्यक है" + "indexingRequiresWorkspace": "इंडेक्सिंग के लिए एक खुला वर्कस्पेस फ़ोल्डर आवश्यक है", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/id/embeddings.json b/src/i18n/locales/id/embeddings.json index cceb965430e..8149f7d23a4 100644 --- a/src/i18n/locales/id/embeddings.json +++ b/src/i18n/locales/id/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "Pemantau file dihentikan.", "failedDuringInitialScan": "Gagal selama pemindaian awal: {{errorMessage}}", "unknownError": "Kesalahan tidak diketahui", - "indexingRequiresWorkspace": "Pengindeksan memerlukan folder workspace yang terbuka" + "indexingRequiresWorkspace": "Pengindeksan memerlukan folder workspace yang terbuka", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/it/embeddings.json b/src/i18n/locales/it/embeddings.json index 2e339ef5d88..30d5ff83b25 100644 --- a/src/i18n/locales/it/embeddings.json +++ b/src/i18n/locales/it/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "Monitoraggio file fermato.", "failedDuringInitialScan": "Fallito durante la scansione iniziale: {{errorMessage}}", "unknownError": "Errore sconosciuto", - "indexingRequiresWorkspace": "L'indicizzazione richiede una cartella di workspace aperta" + "indexingRequiresWorkspace": "L'indicizzazione richiede una cartella di workspace aperta", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/ja/embeddings.json b/src/i18n/locales/ja/embeddings.json index 5223c204e0d..77cfc005ad9 100644 --- a/src/i18n/locales/ja/embeddings.json +++ b/src/i18n/locales/ja/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "ファイルウォッチャーが停止されました。", "failedDuringInitialScan": "初期スキャン中に失敗しました:{{errorMessage}}", "unknownError": "不明なエラー", - "indexingRequiresWorkspace": "インデックス作成には、開かれたワークスペースフォルダーが必要です" + "indexingRequiresWorkspace": "インデックス作成には、開かれたワークスペースフォルダーが必要です", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/ko/embeddings.json b/src/i18n/locales/ko/embeddings.json index 236662eea22..7893b09ae5c 100644 --- a/src/i18n/locales/ko/embeddings.json +++ b/src/i18n/locales/ko/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "파일 감시자가 중지되었습니다.", "failedDuringInitialScan": "초기 스캔 중 실패: {{errorMessage}}", "unknownError": "알 수 없는 오류", - "indexingRequiresWorkspace": "인덱싱에는 열린 워크스페이스 폴더가 필요합니다" + "indexingRequiresWorkspace": "인덱싱에는 열린 워크스페이스 폴더가 필요합니다", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/nl/embeddings.json b/src/i18n/locales/nl/embeddings.json index cce3f05c625..0764101f105 100644 --- a/src/i18n/locales/nl/embeddings.json +++ b/src/i18n/locales/nl/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "Bestandsmonitor gestopt.", "failedDuringInitialScan": "Mislukt tijdens initiële scan: {{errorMessage}}", "unknownError": "Onbekende fout", - "indexingRequiresWorkspace": "Indexering vereist een geopende workspace map" + "indexingRequiresWorkspace": "Indexering vereist een geopende workspace map", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/pl/embeddings.json b/src/i18n/locales/pl/embeddings.json index 133f9f40da2..a8a6cf28581 100644 --- a/src/i18n/locales/pl/embeddings.json +++ b/src/i18n/locales/pl/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "Monitor plików zatrzymany.", "failedDuringInitialScan": "Niepowodzenie podczas początkowego skanowania: {{errorMessage}}", "unknownError": "Nieznany błąd", - "indexingRequiresWorkspace": "Indeksowanie wymaga otwartego folderu workspace" + "indexingRequiresWorkspace": "Indeksowanie wymaga otwartego folderu workspace", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/pt-BR/embeddings.json b/src/i18n/locales/pt-BR/embeddings.json index 09f4a557874..0d5c792b7e8 100644 --- a/src/i18n/locales/pt-BR/embeddings.json +++ b/src/i18n/locales/pt-BR/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "Monitor de arquivos parado.", "failedDuringInitialScan": "Falhou durante a varredura inicial: {{errorMessage}}", "unknownError": "Erro desconhecido", - "indexingRequiresWorkspace": "A indexação requer uma pasta de workspace aberta" + "indexingRequiresWorkspace": "A indexação requer uma pasta de workspace aberta", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/ru/embeddings.json b/src/i18n/locales/ru/embeddings.json index 9e94082bbfb..0ccd6e36532 100644 --- a/src/i18n/locales/ru/embeddings.json +++ b/src/i18n/locales/ru/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "Наблюдатель файлов остановлен.", "failedDuringInitialScan": "Ошибка во время первоначального сканирования: {{errorMessage}}", "unknownError": "Неизвестная ошибка", - "indexingRequiresWorkspace": "Для индексации требуется открытая папка рабочего пространства" + "indexingRequiresWorkspace": "Для индексации требуется открытая папка рабочего пространства", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/tr/embeddings.json b/src/i18n/locales/tr/embeddings.json index 411ed7ab526..5de3e523c1f 100644 --- a/src/i18n/locales/tr/embeddings.json +++ b/src/i18n/locales/tr/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "Dosya izleyici durduruldu.", "failedDuringInitialScan": "İlk tarama sırasında başarısız: {{errorMessage}}", "unknownError": "Bilinmeyen hata", - "indexingRequiresWorkspace": "İndeksleme açık bir workspace klasörü gerektirir" + "indexingRequiresWorkspace": "İndeksleme açık bir workspace klasörü gerektirir", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/vi/embeddings.json b/src/i18n/locales/vi/embeddings.json index c9f9880df08..1b284e171f5 100644 --- a/src/i18n/locales/vi/embeddings.json +++ b/src/i18n/locales/vi/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "Trình theo dõi tệp đã dừng.", "failedDuringInitialScan": "Thất bại trong quá trình quét ban đầu: {{errorMessage}}", "unknownError": "Lỗi không xác định", - "indexingRequiresWorkspace": "Lập chỉ mục yêu cầu một thư mục workspace đang mở" + "indexingRequiresWorkspace": "Lập chỉ mục yêu cầu một thư mục workspace đang mở", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/zh-CN/embeddings.json b/src/i18n/locales/zh-CN/embeddings.json index c27bc078015..5485a024773 100644 --- a/src/i18n/locales/zh-CN/embeddings.json +++ b/src/i18n/locales/zh-CN/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "文件监控已停止。", "failedDuringInitialScan": "初始扫描失败:{{errorMessage}}", "unknownError": "未知错误", - "indexingRequiresWorkspace": "索引需要打开的工作区文件夹" + "indexingRequiresWorkspace": "索引需要打开的工作区文件夹", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/i18n/locales/zh-TW/embeddings.json b/src/i18n/locales/zh-TW/embeddings.json index 744e7022ea1..30f974fb162 100644 --- a/src/i18n/locales/zh-TW/embeddings.json +++ b/src/i18n/locales/zh-TW/embeddings.json @@ -69,6 +69,8 @@ "fileWatcherStopped": "檔案監控已停止。", "failedDuringInitialScan": "初始掃描失敗:{{errorMessage}}", "unknownError": "未知錯誤", - "indexingRequiresWorkspace": "索引需要開啟的工作區資料夾" + "indexingRequiresWorkspace": "索引需要開啟的工作區資料夾", + "indexingStopped": "Indexing stopped by user.", + "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." } } diff --git a/src/services/code-index/__tests__/manager.spec.ts b/src/services/code-index/__tests__/manager.spec.ts index 929f6f93c8a..04a1bcde86e 100644 --- a/src/services/code-index/__tests__/manager.spec.ts +++ b/src/services/code-index/__tests__/manager.spec.ts @@ -95,9 +95,15 @@ describe("CodeIndexManager - handleSettingsChange regression", () => { // Clear all instances before each test CodeIndexManager.disposeAll() + const workspaceStateStore: Record = {} mockContext = { subscriptions: [], - workspaceState: {} as any, + workspaceState: { + get: vi.fn((key: string, defaultValue?: any) => workspaceStateStore[key] ?? defaultValue), + update: vi.fn(async (key: string, value: any) => { + workspaceStateStore[key] = value + }), + } as any, globalState: {} as any, extensionUri: {} as any, extensionPath: testExtensionPath, @@ -608,4 +614,95 @@ describe("CodeIndexManager - handleSettingsChange regression", () => { consoleErrorSpy.mockRestore() }) }) + + describe("workspace-enabled gating", () => { + it("should not start indexing when workspace is not enabled", async () => { + const mockStateManager = (manager as any)._stateManager + mockStateManager.setSystemState = vi.fn() + mockStateManager.getCurrentStatus = vi.fn().mockReturnValue({ + systemStatus: "Standby", + message: "", + processedItems: 0, + totalItems: 0, + currentItemUnit: "items", + }) + + expect(manager.isWorkspaceEnabled).toBe(false) + + await manager.startIndexing() + + expect(mockStateManager.setSystemState).not.toHaveBeenCalledWith("Indexing", expect.any(String)) + }) + + it("should include workspaceEnabled in getCurrentStatus", () => { + const mockStateManager = (manager as any)._stateManager + mockStateManager.getCurrentStatus = vi.fn().mockReturnValue({ + systemStatus: "Standby", + message: "", + processedItems: 0, + totalItems: 0, + currentItemUnit: "items", + }) + + const status = manager.getCurrentStatus() + expect(status.workspaceEnabled).toBe(false) + }) + + it("should persist workspace enabled state", async () => { + expect(manager.isWorkspaceEnabled).toBe(false) + + await manager.setWorkspaceEnabled(true) + expect(manager.isWorkspaceEnabled).toBe(true) + + await manager.setWorkspaceEnabled(false) + expect(manager.isWorkspaceEnabled).toBe(false) + }) + }) + + describe("stopIndexing", () => { + it("should delegate to orchestrator.stopIndexing()", () => { + const mockOrchestrator = { + stopIndexing: vi.fn(), + stopWatcher: vi.fn(), + state: "Indexing", + } + ;(manager as any)._orchestrator = mockOrchestrator + + manager.stopIndexing() + + expect(mockOrchestrator.stopIndexing).toHaveBeenCalled() + }) + + it("should be safe to call when orchestrator is not set", () => { + ;(manager as any)._orchestrator = undefined + + expect(() => manager.stopIndexing()).not.toThrow() + }) + }) + + describe("handleSettingsChange - disable toggle bug fix", () => { + it("should abort active indexing when feature is disabled", async () => { + const mockOrchestrator = { + stopIndexing: vi.fn(), + stopWatcher: vi.fn(), + state: "Indexing", + } + ;(manager as any)._orchestrator = mockOrchestrator + + const mockConfigManager = { + loadConfiguration: vi.fn().mockResolvedValue({ requiresRestart: false }), + isFeatureConfigured: true, + isFeatureEnabled: false, + } + ;(manager as any)._configManager = mockConfigManager + + const mockStateManager = (manager as any)._stateManager + mockStateManager.setSystemState = vi.fn() + + await manager.handleSettingsChange() + + expect(mockOrchestrator.stopIndexing).toHaveBeenCalled() + expect(mockStateManager.setSystemState).toHaveBeenCalledWith("Standby", "Code indexing is disabled") + }) + }) }) diff --git a/src/services/code-index/__tests__/orchestrator.spec.ts b/src/services/code-index/__tests__/orchestrator.spec.ts index aab1ef888d3..a109a3282e9 100644 --- a/src/services/code-index/__tests__/orchestrator.spec.ts +++ b/src/services/code-index/__tests__/orchestrator.spec.ts @@ -158,3 +158,177 @@ describe("CodeIndexOrchestrator - error path cleanup gating", () => { expect(lastCall[0]).toBe("Error") }) }) + +describe("CodeIndexOrchestrator - stopIndexing", () => { + const workspacePath = "/test/workspace" + + let configManager: any + let stateManager: any + let cacheManager: any + let vectorStore: any + let scanner: any + let fileWatcher: any + + beforeEach(() => { + vi.clearAllMocks() + + configManager = { + isFeatureConfigured: true, + } + + let currentState = "Standby" + stateManager = { + get state() { + return currentState + }, + setSystemState: vi.fn().mockImplementation((state: string, _msg: string) => { + currentState = state + }), + reportFileQueueProgress: vi.fn(), + reportBlockIndexingProgress: vi.fn(), + } + + cacheManager = { + clearCacheFile: vi.fn().mockResolvedValue(undefined), + } + + vectorStore = { + initialize: vi.fn().mockResolvedValue(false), + hasIndexedData: vi.fn().mockResolvedValue(false), + markIndexingIncomplete: vi.fn().mockResolvedValue(undefined), + markIndexingComplete: vi.fn().mockResolvedValue(undefined), + clearCollection: vi.fn().mockResolvedValue(undefined), + } + + scanner = { + scanDirectory: vi.fn(), + } + + fileWatcher = { + initialize: vi.fn().mockResolvedValue(undefined), + onDidStartBatchProcessing: vi.fn().mockReturnValue({ dispose: vi.fn() }), + onBatchProgressUpdate: vi.fn().mockReturnValue({ dispose: vi.fn() }), + onDidFinishBatchProcessing: vi.fn().mockReturnValue({ dispose: vi.fn() }), + dispose: vi.fn(), + } + }) + + it("should abort indexing when stopIndexing() is called", async () => { + // Make scanner hang until aborted + scanner.scanDirectory.mockImplementation( + async (_dir: string, _onError?: any, _onBlocksIndexed?: any, _onFileParsed?: any, signal?: AbortSignal) => { + // Wait for abort signal + await new Promise((resolve) => { + if (signal?.aborted) { + resolve() + return + } + signal?.addEventListener("abort", () => resolve()) + }) + return { stats: { processed: 0, skipped: 0 }, totalBlockCount: 0 } + }, + ) + + const orchestrator = new CodeIndexOrchestrator( + configManager, + stateManager, + workspacePath, + cacheManager, + vectorStore, + scanner, + fileWatcher, + ) + + // Start indexing (async, don't await) + const indexingPromise = orchestrator.startIndexing() + + // Give it a tick to begin + await new Promise((resolve) => setTimeout(resolve, 10)) + + // Stop indexing + orchestrator.stopIndexing() + + // Wait for indexing to complete + await indexingPromise + + // State should be Standby (not Error) + const setStateCalls = stateManager.setSystemState.mock.calls + const lastCall = setStateCalls[setStateCalls.length - 1] + expect(lastCall[0]).toBe("Standby") + }) + + it("should set state to Standby after abort, not Error", async () => { + // Make scanner throw AbortError when signal is aborted + scanner.scanDirectory.mockImplementation( + async (_dir: string, _onError?: any, _onBlocksIndexed?: any, _onFileParsed?: any, signal?: AbortSignal) => { + await new Promise((resolve) => { + if (signal?.aborted) { + resolve() + return + } + signal?.addEventListener("abort", () => resolve()) + }) + throw new DOMException("Indexing aborted", "AbortError") + }, + ) + + const orchestrator = new CodeIndexOrchestrator( + configManager, + stateManager, + workspacePath, + cacheManager, + vectorStore, + scanner, + fileWatcher, + ) + + const indexingPromise = orchestrator.startIndexing() + await new Promise((resolve) => setTimeout(resolve, 10)) + + orchestrator.stopIndexing() + await indexingPromise + + // Should NOT have set Error state — abort is handled gracefully + const errorCalls = stateManager.setSystemState.mock.calls.filter((call: any[]) => call[0] === "Error") + expect(errorCalls).toHaveLength(0) + + // Should NOT have cleared collection on abort + expect(vectorStore.clearCollection).not.toHaveBeenCalled() + }) + + it("should preserve partial index data after stop", async () => { + scanner.scanDirectory.mockImplementation( + async (_dir: string, _onError?: any, _onBlocksIndexed?: any, _onFileParsed?: any, signal?: AbortSignal) => { + await new Promise((resolve) => { + if (signal?.aborted) { + resolve() + return + } + signal?.addEventListener("abort", () => resolve()) + }) + return { stats: { processed: 5, skipped: 0 }, totalBlockCount: 5 } + }, + ) + + const orchestrator = new CodeIndexOrchestrator( + configManager, + stateManager, + workspacePath, + cacheManager, + vectorStore, + scanner, + fileWatcher, + ) + + const indexingPromise = orchestrator.startIndexing() + await new Promise((resolve) => setTimeout(resolve, 10)) + + orchestrator.stopIndexing() + await indexingPromise + + // Cache should NOT be cleared on user-initiated stop + expect(cacheManager.clearCacheFile).not.toHaveBeenCalled() + // Collection should NOT be cleared on user-initiated stop + expect(vectorStore.clearCollection).not.toHaveBeenCalled() + }) +}) diff --git a/src/services/code-index/interfaces/file-processor.ts b/src/services/code-index/interfaces/file-processor.ts index 88b19007c37..8ecdc518c8d 100644 --- a/src/services/code-index/interfaces/file-processor.ts +++ b/src/services/code-index/interfaces/file-processor.ts @@ -37,6 +37,7 @@ export interface IDirectoryScanner { onError?: (error: Error) => void, onBlocksIndexed?: (indexedCount: number) => void, onFileParsed?: (fileBlockCount: number) => void, + signal?: AbortSignal, ): Promise<{ stats: { processed: number diff --git a/src/services/code-index/interfaces/manager.ts b/src/services/code-index/interfaces/manager.ts index 28ff5523277..d657ad667c7 100644 --- a/src/services/code-index/interfaces/manager.ts +++ b/src/services/code-index/interfaces/manager.ts @@ -39,6 +39,11 @@ export interface ICodeIndexManager { */ startIndexing(): Promise + /** + * Stops any in-progress indexing operation and the file watcher + */ + stopIndexing(): void + /** * Stops the file watcher */ @@ -69,7 +74,7 @@ export interface ICodeIndexManager { dispose(): void } -export type IndexingState = "Standby" | "Indexing" | "Indexed" | "Error" +export type IndexingState = "Standby" | "Indexing" | "Indexed" | "Error" | "Stopping" export type EmbedderProvider = | "openai" | "ollama" diff --git a/src/services/code-index/manager.ts b/src/services/code-index/manager.ts index dd79a3f1616..4546713f00d 100644 --- a/src/services/code-index/manager.ts +++ b/src/services/code-index/manager.ts @@ -75,6 +75,14 @@ export class CodeIndexManager { // --- Public API --- + public get isWorkspaceEnabled(): boolean { + return this.context.workspaceState.get("codeIndexWorkspaceEnabled", false) + } + + public async setWorkspaceEnabled(enabled: boolean): Promise { + await this.context.workspaceState.update("codeIndexWorkspaceEnabled", enabled) + } + public get onProgressUpdate() { return this._stateManager.onProgressUpdate } @@ -151,15 +159,19 @@ export class CodeIndexManager { await this._recreateServices() } - // 5. Handle Indexing Start/Restart - // The enhanced vectorStore.initialize() in startIndexing() now handles dimension changes automatically - // by detecting incompatible collections and recreating them, so we rely on that for dimension changes + // 5. Check workspace-level enablement + if (!this.isWorkspaceEnabled) { + this._stateManager.setSystemState("Standby", "Indexing not enabled for this workspace") + return { requiresRestart } + } + + // 6. Handle Indexing Start/Restart const shouldStartOrRestartIndexing = requiresRestart || (needsServiceRecreation && (!this._orchestrator || this._orchestrator.state !== "Indexing")) if (shouldStartOrRestartIndexing) { - this._orchestrator?.startIndexing() // This method is async, but we don't await it here + this._orchestrator?.startIndexing() } return { requiresRestart } @@ -173,7 +185,7 @@ export class CodeIndexManager { * The indexing will continue asynchronously and progress will be reported through events. */ public async startIndexing(): Promise { - if (!this.isFeatureEnabled) { + if (!this.isFeatureEnabled || !this.isWorkspaceEnabled) { return } @@ -191,6 +203,15 @@ export class CodeIndexManager { await this._orchestrator!.startIndexing() } + /** + * Stops any in-progress indexing operation and the file watcher. + */ + public stopIndexing(): void { + if (this._orchestrator) { + this._orchestrator.stopIndexing() + } + } + /** * Stops the file watcher and potentially cleans up resources. */ @@ -273,6 +294,7 @@ export class CodeIndexManager { return { ...status, workspacePath: this.workspacePath, + workspaceEnabled: this.isWorkspaceEnabled, } } @@ -384,13 +406,9 @@ export class CodeIndexManager { const isFeatureEnabled = this.isFeatureEnabled const isFeatureConfigured = this.isFeatureConfigured - // If feature is disabled, stop the service + // If feature is disabled, stop the service (including any active scan) if (!isFeatureEnabled) { - // Stop the orchestrator if it exists - if (this._orchestrator) { - this._orchestrator.stopWatcher() - } - // Set state to indicate service is disabled + this.stopIndexing() this._stateManager.setSystemState("Standby", "Code indexing is disabled") return } diff --git a/src/services/code-index/orchestrator.ts b/src/services/code-index/orchestrator.ts index 99f317882b8..4e5ddf8f685 100644 --- a/src/services/code-index/orchestrator.ts +++ b/src/services/code-index/orchestrator.ts @@ -15,6 +15,7 @@ import { t } from "../../i18n" export class CodeIndexOrchestrator { private _fileWatcherSubscriptions: vscode.Disposable[] = [] private _isProcessing: boolean = false + private _abortController: AbortController | null = null constructor( private readonly configManager: CodeIndexConfigManager, @@ -121,6 +122,8 @@ export class CodeIndexOrchestrator { } this._isProcessing = true + this._abortController = new AbortController() + const signal = this._abortController.signal this.stateManager.setSystemState("Indexing", "Initializing services...") // Track whether we successfully connected to Qdrant and started indexing @@ -178,8 +181,14 @@ export class CodeIndexOrchestrator { }, handleBlocksIndexed, handleFileParsed, + signal, ) + if (signal.aborted) { + this.stateManager.setSystemState("Standby", t("embeddings:orchestrator.indexingStopped")) + return + } + if (!result) { throw new Error("Incremental scan failed, is scanner initialized?") } @@ -231,8 +240,14 @@ export class CodeIndexOrchestrator { }, handleBlocksIndexed, handleFileParsed, + signal, ) + if (signal.aborted) { + this.stateManager.setSystemState("Standby", t("embeddings:orchestrator.indexingStopped")) + return + } + if (!result) { throw new Error("Scan failed, is scanner initialized?") } @@ -282,6 +297,14 @@ export class CodeIndexOrchestrator { this.stateManager.setSystemState("Indexed", t("embeddings:orchestrator.fileWatcherStarted")) } } catch (error: any) { + // Handle abort gracefully — not an error, just a user-initiated stop + if (error?.name === "AbortError" || signal.aborted) { + console.log("[CodeIndexOrchestrator] Indexing aborted by user.") + this.stateManager.setSystemState("Standby", t("embeddings:orchestrator.indexingStopped")) + this.stopWatcher() + return + } + console.error("[CodeIndexOrchestrator] Error during indexing:", error) TelemetryService.instance.captureEvent(TelemetryEventName.CODE_INDEX_ERROR, { error: error instanceof Error ? error.message : String(error), @@ -325,7 +348,20 @@ export class CodeIndexOrchestrator { this.stopWatcher() } finally { this._isProcessing = false + this._abortController = null + } + } + + /** + * Stops any in-progress indexing by aborting the scan and stopping the file watcher. + */ + public stopIndexing(): void { + if (this._abortController) { + this.stateManager.setSystemState("Stopping", t("embeddings:orchestrator.indexingStoppedPartial")) + this._abortController.abort() + this._abortController = null } + this.stopWatcher() } /** @@ -336,7 +372,7 @@ export class CodeIndexOrchestrator { this._fileWatcherSubscriptions.forEach((sub) => sub.dispose()) this._fileWatcherSubscriptions = [] - if (this.stateManager.state !== "Error") { + if (this.stateManager.state !== "Error" && this.stateManager.state !== "Stopping") { this.stateManager.setSystemState("Standby", t("embeddings:orchestrator.fileWatcherStopped")) } this._isProcessing = false diff --git a/src/services/code-index/processors/__tests__/scanner.spec.ts b/src/services/code-index/processors/__tests__/scanner.spec.ts index 4d4150b4439..f6a3cea0927 100644 --- a/src/services/code-index/processors/__tests__/scanner.spec.ts +++ b/src/services/code-index/processors/__tests__/scanner.spec.ts @@ -394,5 +394,69 @@ describe("DirectoryScanner", () => { expect(points[1].payload.segmentHash).toBe("unique-segment-hash-2") expect(points[2].payload.segmentHash).toBe("unique-segment-hash-3") }) + + it("should stop processing files when signal is aborted", async () => { + const { listFiles } = await import("../../../glob/list-files") + vi.mocked(listFiles).mockResolvedValue([["test/file1.js", "test/file2.js", "test/file3.js"], false]) + + // Create an already-aborted signal + const controller = new AbortController() + controller.abort() + + const result = await scanner.scanDirectory("/test", undefined, undefined, undefined, controller.signal) + + // No files should have been processed since signal was already aborted + expect(mockCodeParser.parseFile).not.toHaveBeenCalled() + expect(result.stats.processed).toBe(0) + }) + + it("should stop processing batches when signal is aborted mid-scan", async () => { + const { listFiles } = await import("../../../glob/list-files") + vi.mocked(listFiles).mockResolvedValue([["test/file1.js", "test/file2.js"], false]) + + const controller = new AbortController() + + const mockBlocks: any[] = [ + { + file_path: "test/file1.js", + content: "function hello() {}", + start_line: 1, + end_line: 3, + identifier: "hello", + type: "function", + fileHash: "hash1", + segmentHash: "seg-hash-1", + }, + ] + + // Abort after first file is parsed + ;(mockCodeParser.parseFile as any).mockImplementation(async () => { + controller.abort() + return mockBlocks + }) + + const result = await scanner.scanDirectory("/test", undefined, undefined, undefined, controller.signal) + + // The scan should have returned partial results without error + expect(result).toBeDefined() + expect(result.stats).toBeDefined() + }) + + it("should not process deleted files when signal is aborted", async () => { + const { listFiles } = await import("../../../glob/list-files") + vi.mocked(listFiles).mockResolvedValue([[], false]) + + // Set up cached files that would normally be detected as deleted + ;(mockCacheManager.getAllHashes as any).mockReturnValue({ "old/file.js": "old-hash" }) + + // Create an already-aborted signal + const controller = new AbortController() + controller.abort() + + await scanner.scanDirectory("/test", undefined, undefined, undefined, controller.signal) + + // Deleted file cleanup should not have run + expect(mockVectorStore.deletePointsByFilePath).not.toHaveBeenCalled() + }) }) }) diff --git a/src/services/code-index/processors/scanner.ts b/src/services/code-index/processors/scanner.ts index 91689a56d7c..1fa3944b479 100644 --- a/src/services/code-index/processors/scanner.ts +++ b/src/services/code-index/processors/scanner.ts @@ -71,6 +71,7 @@ export class DirectoryScanner implements IDirectoryScanner { onError?: (error: Error) => void, onBlocksIndexed?: (indexedCount: number) => void, onFileParsed?: (fileBlockCount: number) => void, + signal?: AbortSignal, ): Promise<{ stats: { processed: number; skipped: number }; totalBlockCount: number }> { const directoryPath = directory // Capture workspace context at scan start @@ -127,6 +128,9 @@ export class DirectoryScanner implements IDirectoryScanner { // Process all files in parallel with concurrency control const parsePromises = supportedPaths.map((filePath) => parseLimiter(async () => { + // Check abort signal before processing each file + if (signal?.aborted) return + try { // Check file size const stats = await stat(filePath) @@ -173,6 +177,11 @@ export class DirectoryScanner implements IDirectoryScanner { addedBlocksFromFile = true // Check if batch threshold is met + // Check abort signal before dispatching batch + if (signal?.aborted) { + throw new DOMException("Indexing aborted", "AbortError") + } + if (currentBatchBlocks.length >= this.batchSegmentThreshold) { // Wait if we've reached the maximum pending batches while (pendingBatchCount >= MAX_PENDING_BATCHES) { @@ -258,6 +267,17 @@ export class DirectoryScanner implements IDirectoryScanner { // Wait for all parsing to complete await Promise.all(parsePromises) + // Check abort signal before processing remaining batch + if (signal?.aborted) { + return { + stats: { + processed: processedCount, + skipped: skippedCount, + }, + totalBlockCount, + } + } + // Process any remaining items in batch if (currentBatchBlocks.length > 0) { const release = await mutex.acquire() @@ -292,6 +312,17 @@ export class DirectoryScanner implements IDirectoryScanner { // Wait for all batch processing to complete await Promise.all(activeBatchPromises) + // Check abort signal before handling deleted files + if (signal?.aborted) { + return { + stats: { + processed: processedCount, + skipped: skippedCount, + }, + totalBlockCount, + } + } + // Handle deleted files const oldHashes = this.cacheManager.getAllHashes() for (const cachedFilePath of Object.keys(oldHashes)) { diff --git a/src/services/code-index/state-manager.ts b/src/services/code-index/state-manager.ts index 90257fdfb19..b6788251478 100644 --- a/src/services/code-index/state-manager.ts +++ b/src/services/code-index/state-manager.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode" -export type IndexingState = "Standby" | "Indexing" | "Indexed" | "Error" +export type IndexingState = "Standby" | "Indexing" | "Indexed" | "Error" | "Stopping" export class CodeIndexStateManager { private _systemStatus: IndexingState = "Standby" @@ -58,6 +58,8 @@ export class CodeIndexStateManager { public reportBlockIndexingProgress(processedItems: number, totalItems: number): void { const progressChanged = processedItems !== this._processedItems || totalItems !== this._totalItems + // Don't override Stopping state with progress updates + if (this._systemStatus === "Stopping") return // Update if progress changes OR if the system wasn't already in 'Indexing' state if (progressChanged || this._systemStatus !== "Indexing") { this._processedItems = processedItems @@ -81,6 +83,8 @@ export class CodeIndexStateManager { public reportFileQueueProgress(processedFiles: number, totalFiles: number, currentFileBasename?: string): void { const progressChanged = processedFiles !== this._processedItems || totalFiles !== this._totalItems + // Don't override Stopping state with progress updates + if (this._systemStatus === "Stopping") return if (progressChanged || this._systemStatus !== "Indexing") { this._processedItems = processedFiles this._totalItems = totalFiles diff --git a/webview-ui/src/components/chat/CodeIndexPopover.tsx b/webview-ui/src/components/chat/CodeIndexPopover.tsx index 4fcf6406e3b..924ea5648c4 100644 --- a/webview-ui/src/components/chat/CodeIndexPopover.tsx +++ b/webview-ui/src/components/chat/CodeIndexPopover.tsx @@ -1590,6 +1590,35 @@ export const CodeIndexPopover: React.FC = ({ )} + {/* Workspace Toggle */} + {currentSettings.codebaseIndexEnabled && ( +
+ + vscode.postMessage({ + type: "toggleWorkspaceIndexing", + bool: e.target.checked, + }) + } + className="accent-vscode-focusBorder" + /> + +
+ )} + + {currentSettings.codebaseIndexEnabled && !indexingStatus.workspaceEnabled && ( +

+ {t("settings:codeIndex.workspaceDisabledMessage")} +

+ )} + {/* Action Buttons */}
@@ -1603,6 +1632,20 @@ export const CodeIndexPopover: React.FC = ({ )} + {currentSettings.codebaseIndexEnabled && indexingStatus.systemStatus === "Indexing" && ( + + )} + + {currentSettings.codebaseIndexEnabled && indexingStatus.systemStatus === "Stopping" && ( + + )} + {currentSettings.codebaseIndexEnabled && (indexingStatus.systemStatus === "Indexed" || indexingStatus.systemStatus === "Error") && ( diff --git a/webview-ui/src/components/chat/IndexingStatusBadge.tsx b/webview-ui/src/components/chat/IndexingStatusBadge.tsx index 82f654a82fa..227df3e645f 100644 --- a/webview-ui/src/components/chat/IndexingStatusBadge.tsx +++ b/webview-ui/src/components/chat/IndexingStatusBadge.tsx @@ -64,6 +64,8 @@ export const IndexingStatusBadge: React.FC = ({ classN return t("chat:indexingStatus.indexing", { percentage: progressPercentage }) case "Indexed": return t("chat:indexingStatus.indexed") + case "Stopping": + return t("chat:indexingStatus.stopping") case "Error": return t("chat:indexingStatus.error") default: @@ -76,6 +78,7 @@ export const IndexingStatusBadge: React.FC = ({ classN Standby: "bg-vscode-descriptionForeground/60", Indexing: "bg-yellow-500 animate-pulse", Indexed: "bg-green-500", + Stopping: "bg-amber-500 animate-pulse", Error: "bg-red-500", } diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json index d16a4466958..caa1b67992a 100644 --- a/webview-ui/src/i18n/locales/ca/chat.json +++ b/webview-ui/src/i18n/locales/ca/chat.json @@ -424,7 +424,8 @@ "indexing": "Indexant {{percentage}}%", "indexed": "Indexat", "error": "Error d'índex", - "status": "Estat de l'índex" + "status": "Estat de l'índex", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "Versió {{version}} - Feu clic per veure les notes de llançament" diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index f1e5ad10e6d..9216d358232 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "Restablir al valor per defecte (0.4)", "searchMaxResultsLabel": "Màxim de resultats de cerca", "searchMaxResultsDescription": "Nombre màxim de resultats de cerca a retornar quan es consulta l'índex de la base de codi. Els valors més alts proporcionen més context però poden incloure resultats menys rellevants.", - "resetToDefault": "Restablir al valor per defecte" + "resetToDefault": "Restablir al valor per defecte", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "Pots configurar una drecera global per a aquesta configuració a les preferències del teu IDE.", diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json index fb1dd293004..48df2e869e7 100644 --- a/webview-ui/src/i18n/locales/de/chat.json +++ b/webview-ui/src/i18n/locales/de/chat.json @@ -424,7 +424,8 @@ "indexing": "Indizierung {{percentage}}%", "indexed": "Indiziert", "error": "Index-Fehler", - "status": "Index-Status" + "status": "Index-Status", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "Version {{version}} - Klicken Sie, um die Versionshinweise anzuzeigen" diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 0e8d7a3a8e3..ae32c702ecc 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "Auf Standardwert zurücksetzen (0.4)", "searchMaxResultsLabel": "Maximale Suchergebnisse", "searchMaxResultsDescription": "Maximale Anzahl von Suchergebnissen, die bei der Abfrage des Codebase-Index zurückgegeben werden. Höhere Werte bieten mehr Kontext, können aber weniger relevante Ergebnisse enthalten.", - "resetToDefault": "Auf Standard zurücksetzen" + "resetToDefault": "Auf Standard zurücksetzen", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "Du kannst in deinen IDE-Einstellungen einen globalen Shortcut für diese Einstellung konfigurieren.", diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json index b597fdbcc33..4e6fe8b47ae 100644 --- a/webview-ui/src/i18n/locales/en/chat.json +++ b/webview-ui/src/i18n/locales/en/chat.json @@ -420,7 +420,8 @@ "indexing": "Indexing {{percentage}}%", "indexed": "Indexed", "error": "Index error", - "status": "Index status" + "status": "Index status", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "Version {{version}} - Click to view release notes" diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 471309718bc..5993cf6053a 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -274,7 +274,11 @@ "baseUrlRequired": "Base URL is required", "modelDimensionMinValue": "Model dimension must be greater than 0" }, - "optional": "optional" + "optional": "optional", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "description": "Run these actions without asking for permission. Only enable for actions you fully trust and if you understand the security risks.", diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json index eb8833b8337..12f6d99e67f 100644 --- a/webview-ui/src/i18n/locales/es/chat.json +++ b/webview-ui/src/i18n/locales/es/chat.json @@ -424,7 +424,8 @@ "indexing": "Indexando {{percentage}}%", "indexed": "Indexado", "error": "Error de índice", - "status": "Estado del índice" + "status": "Estado del índice", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "Versión {{version}} - Haz clic para ver las notas de la versión" diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 42688dd5411..bc8289c07a4 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "Restablecer al valor predeterminado (0.4)", "searchMaxResultsLabel": "Resultados máximos de búsqueda", "searchMaxResultsDescription": "Número máximo de resultados de búsqueda a devolver al consultar el índice de código. Valores más altos proporcionan más contexto pero pueden incluir resultados menos relevantes.", - "resetToDefault": "Restablecer al valor predeterminado" + "resetToDefault": "Restablecer al valor predeterminado", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "Puedes configurar un atajo global para esta configuración en las preferencias de tu IDE.", diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json index e2858c8e8c1..4db1a5478da 100644 --- a/webview-ui/src/i18n/locales/fr/chat.json +++ b/webview-ui/src/i18n/locales/fr/chat.json @@ -424,7 +424,8 @@ "indexing": "Indexation {{percentage}}%", "indexed": "Indexé", "error": "Erreur d'index", - "status": "Statut de l'index" + "status": "Statut de l'index", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "Version {{version}} - Cliquez pour voir les notes de version" diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 4a213f31801..8fb3bda5a31 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "Réinitialiser à la valeur par défaut (0.4)", "searchMaxResultsLabel": "Résultats de recherche maximum", "searchMaxResultsDescription": "Nombre maximum de résultats de recherche à retourner lors de l'interrogation de l'index de code. Des valeurs plus élevées fournissent plus de contexte mais peuvent inclure des résultats moins pertinents.", - "resetToDefault": "Réinitialiser par défaut" + "resetToDefault": "Réinitialiser par défaut", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "Vous pouvez configurer un raccourci global pour ce paramètre dans les préférences de votre IDE.", diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index 75ee2c9abf5..dad2b9439b3 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -424,7 +424,8 @@ "indexing": "इंडेक्सिंग {{percentage}}%", "indexed": "इंडेक्स किया गया", "error": "इंडेक्स त्रुटि", - "status": "इंडेक्स स्थिति" + "status": "इंडेक्स स्थिति", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "संस्करण {{version}} - रिलीज़ नोट्स देखने के लिए क्लिक करें" diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 3544dbb7681..5539cf7bf13 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "डिफ़ॉल्ट मान पर रीसेट करें (0.4)", "searchMaxResultsLabel": "अधिकतम खोज परिणाम", "searchMaxResultsDescription": "कोडबेस इंडेक्स को क्वेरी करते समय वापस करने के लिए खोज परिणामों की अधिकतम संख्या। उच्च मान अधिक संदर्भ प्रदान करते हैं लेकिन कम प्रासंगिक परिणाम शामिल कर सकते हैं।", - "resetToDefault": "डिफ़ॉल्ट पर रीसेट करें" + "resetToDefault": "डिफ़ॉल्ट पर रीसेट करें", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "आप अपनी आईडीई वरीयताओं में इस सेटिंग के लिए एक वैश्विक शॉर्टकट कॉन्फ़िगर कर सकते हैं।", diff --git a/webview-ui/src/i18n/locales/id/chat.json b/webview-ui/src/i18n/locales/id/chat.json index ee41b9ceb65..d06ea14be25 100644 --- a/webview-ui/src/i18n/locales/id/chat.json +++ b/webview-ui/src/i18n/locales/id/chat.json @@ -430,7 +430,8 @@ "indexing": "Mengindeks {{percentage}}%", "indexed": "Terindeks", "error": "Error indeks", - "status": "Status indeks" + "status": "Status indeks", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "Versi {{version}} - Klik untuk melihat catatan rilis" diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index bc5db3ae85a..01409190590 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "Reset ke nilai default (0.4)", "searchMaxResultsLabel": "Hasil Pencarian Maksimum", "searchMaxResultsDescription": "Jumlah maksimum hasil pencarian yang dikembalikan saat melakukan query indeks basis kode. Nilai yang lebih tinggi memberikan lebih banyak konteks tetapi mungkin menyertakan hasil yang kurang relevan.", - "resetToDefault": "Reset ke default" + "resetToDefault": "Reset ke default", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "Anda dapat mengonfigurasi pintasan global untuk pengaturan ini di preferensi IDE Anda.", diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json index 54f5bf9061d..6b4c201e602 100644 --- a/webview-ui/src/i18n/locales/it/chat.json +++ b/webview-ui/src/i18n/locales/it/chat.json @@ -424,7 +424,8 @@ "indexing": "Indicizzazione {{percentage}}%", "indexed": "Indicizzato", "error": "Errore indice", - "status": "Stato indice" + "status": "Stato indice", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "Versione {{version}} - Clicca per visualizzare le note di rilascio" diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 7eddf6c6127..215a1c4414a 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "Ripristina al valore predefinito (0.4)", "searchMaxResultsLabel": "Risultati di ricerca massimi", "searchMaxResultsDescription": "Numero massimo di risultati di ricerca da restituire quando si interroga l'indice del codice. Valori più alti forniscono più contesto ma possono includere risultati meno pertinenti.", - "resetToDefault": "Ripristina al valore predefinito" + "resetToDefault": "Ripristina al valore predefinito", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "Puoi configurare una scorciatoia globale per questa impostazione nelle preferenze del tuo IDE.", diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json index 2cf71855032..dd2c923048a 100644 --- a/webview-ui/src/i18n/locales/ja/chat.json +++ b/webview-ui/src/i18n/locales/ja/chat.json @@ -424,7 +424,8 @@ "indexing": "インデックス作成中 {{percentage}}%", "indexed": "インデックス作成済み", "error": "インデックスエラー", - "status": "インデックス状態" + "status": "インデックス状態", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "バージョン {{version}} - クリックしてリリースノートを表示" diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 533acf119c9..effb6df0ac5 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "デフォルト値(0.4)にリセット", "searchMaxResultsLabel": "最大検索結果数", "searchMaxResultsDescription": "コードベースインデックスをクエリする際に返される検索結果の最大数。値を高くするとより多くのコンテキストが提供されますが、関連性の低い結果が含まれる可能性があります。", - "resetToDefault": "デフォルトにリセット" + "resetToDefault": "デフォルトにリセット", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "IDEの環境設定で、この設定のグローバルショートカットを設定できます。", diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json index 24debd83edc..5be2a29413b 100644 --- a/webview-ui/src/i18n/locales/ko/chat.json +++ b/webview-ui/src/i18n/locales/ko/chat.json @@ -424,7 +424,8 @@ "indexing": "인덱싱 중 {{percentage}}%", "indexed": "인덱싱 완료", "error": "인덱스 오류", - "status": "인덱스 상태" + "status": "인덱스 상태", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "버전 {{version}} - 릴리스 노트를 보려면 클릭하세요" diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 52544154027..fbea30375e0 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "기본값(0.4)으로 재설정", "searchMaxResultsLabel": "최대 검색 결과", "searchMaxResultsDescription": "코드베이스 인덱스를 쿼리할 때 반환할 최대 검색 결과 수입니다. 값이 높을수록 더 많은 컨텍스트를 제공하지만 관련성이 낮은 결과가 포함될 수 있습니다.", - "resetToDefault": "기본값으로 재설정" + "resetToDefault": "기본값으로 재설정", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "IDE 환경 설정에서 이 설정에 대한 전역 바로 가기를 구성할 수 있습니다.", diff --git a/webview-ui/src/i18n/locales/nl/chat.json b/webview-ui/src/i18n/locales/nl/chat.json index 0bec6846c04..f18afac65f2 100644 --- a/webview-ui/src/i18n/locales/nl/chat.json +++ b/webview-ui/src/i18n/locales/nl/chat.json @@ -424,7 +424,8 @@ "indexing": "Indexeren {{percentage}}%", "indexed": "Geïndexeerd", "error": "Index fout", - "status": "Index status" + "status": "Index status", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "Versie {{version}} - Klik om release notes te bekijken" diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index db7b0554c3a..e8808cbb8f6 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "Reset naar standaardwaarde (0.4)", "searchMaxResultsLabel": "Maximum Zoekresultaten", "searchMaxResultsDescription": "Maximum aantal zoekresultaten dat wordt geretourneerd bij het doorzoeken van de codebase-index. Hogere waarden bieden meer context maar kunnen minder relevante resultaten bevatten.", - "resetToDefault": "Reset naar standaard" + "resetToDefault": "Reset naar standaard", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "U kunt een globale sneltoets voor deze instelling configureren in de voorkeuren van uw IDE.", diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json index be012354aa0..e5af6f445f9 100644 --- a/webview-ui/src/i18n/locales/pl/chat.json +++ b/webview-ui/src/i18n/locales/pl/chat.json @@ -424,7 +424,8 @@ "indexing": "Indeksowanie {{percentage}}%", "indexed": "Zaindeksowane", "error": "Błąd indeksu", - "status": "Status indeksu" + "status": "Status indeksu", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "Wersja {{version}} - Kliknij, aby wyświetlić informacje o wydaniu" diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 875f00838da..128172ce010 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "Zresetuj do wartości domyślnej (0.4)", "searchMaxResultsLabel": "Maksymalna liczba wyników wyszukiwania", "searchMaxResultsDescription": "Maksymalna liczba wyników wyszukiwania zwracanych podczas zapytania do indeksu bazy kodu. Wyższe wartości zapewniają więcej kontekstu, ale mogą zawierać mniej istotne wyniki.", - "resetToDefault": "Przywróć domyślne" + "resetToDefault": "Przywróć domyślne", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "Możesz skonfigurować globalny skrót dla tego ustawienia w preferencjach swojego IDE.", diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json index ed4eaf541ea..36af15b0ae1 100644 --- a/webview-ui/src/i18n/locales/pt-BR/chat.json +++ b/webview-ui/src/i18n/locales/pt-BR/chat.json @@ -424,7 +424,8 @@ "indexing": "Indexando {{percentage}}%", "indexed": "Indexado", "error": "Erro do índice", - "status": "Status do índice" + "status": "Status do índice", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "Versão {{version}} - Clique para ver as notas de lançamento" diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index 0d77ea6e5aa..f95c5e4eb3c 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "Redefinir para o valor padrão (0.4)", "searchMaxResultsLabel": "Resultados máximos de busca", "searchMaxResultsDescription": "Número máximo de resultados de busca a retornar ao consultar o índice de código. Valores mais altos fornecem mais contexto, mas podem incluir resultados menos relevantes.", - "resetToDefault": "Redefinir para o padrão" + "resetToDefault": "Redefinir para o padrão", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "Você pode configurar um atalho global para esta configuração nas preferências do seu IDE.", diff --git a/webview-ui/src/i18n/locales/ru/chat.json b/webview-ui/src/i18n/locales/ru/chat.json index 15d8c9ee990..f0a3cac6aa7 100644 --- a/webview-ui/src/i18n/locales/ru/chat.json +++ b/webview-ui/src/i18n/locales/ru/chat.json @@ -425,7 +425,8 @@ "indexing": "Индексация {{percentage}}%", "indexed": "Проиндексировано", "error": "Ошибка индекса", - "status": "Статус индекса" + "status": "Статус индекса", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "Версия {{version}} - Нажмите, чтобы просмотреть примечания к выпуску" diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 87563bdab66..3a3ff3dd8f3 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "Сбросить к значению по умолчанию (0.4)", "searchMaxResultsLabel": "Максимальное количество результатов поиска", "searchMaxResultsDescription": "Максимальное количество результатов поиска, возвращаемых при запросе индекса кодовой базы. Более высокие значения предоставляют больше контекста, но могут включать менее релевантные результаты.", - "resetToDefault": "Сбросить к значению по умолчанию" + "resetToDefault": "Сбросить к значению по умолчанию", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "Вы можете настроить глобальное сочетание клавиш для этого параметра в настройках вашей IDE.", diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json index e9552d5bfd1..dfa19f9e25c 100644 --- a/webview-ui/src/i18n/locales/tr/chat.json +++ b/webview-ui/src/i18n/locales/tr/chat.json @@ -425,7 +425,8 @@ "indexing": "İndeksleniyor {{percentage}}%", "indexed": "İndekslendi", "error": "İndeks hatası", - "status": "İndeks durumu" + "status": "İndeks durumu", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "Sürüm {{version}} - Sürüm notlarını görüntülemek için tıklayın" diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index ee46b9f01cd..c491c90c630 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "Varsayılan değere sıfırla (0.4)", "searchMaxResultsLabel": "Maksimum Arama Sonuçları", "searchMaxResultsDescription": "Kod tabanı dizinini sorgularken döndürülecek maksimum arama sonucu sayısı. Daha yüksek değerler daha fazla bağlam sağlar ancak daha az alakalı sonuçlar içerebilir.", - "resetToDefault": "Varsayılana sıfırla" + "resetToDefault": "Varsayılana sıfırla", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "IDE tercihlerinizde bu ayar için genel bir kısayol yapılandırabilirsiniz.", diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index dfa5b56c4b2..18ecfb7caed 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -425,7 +425,8 @@ "indexing": "Đang lập chỉ mục {{percentage}}%", "indexed": "Đã lập chỉ mục", "error": "Lỗi chỉ mục", - "status": "Trạng thái chỉ mục" + "status": "Trạng thái chỉ mục", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "Phiên bản {{version}} - Nhấp để xem ghi chú phát hành" diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 1eb0fb09d30..310b91c3738 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "Đặt lại về giá trị mặc định (0.4)", "searchMaxResultsLabel": "Số Kết Quả Tìm Kiếm Tối Đa", "searchMaxResultsDescription": "Số lượng kết quả tìm kiếm tối đa được trả về khi truy vấn chỉ mục cơ sở mã. Giá trị cao hơn cung cấp nhiều ngữ cảnh hơn nhưng có thể bao gồm các kết quả ít liên quan hơn.", - "resetToDefault": "Đặt lại về mặc định" + "resetToDefault": "Đặt lại về mặc định", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "Bạn có thể định cấu hình một phím tắt chung cho cài đặt này trong tùy chọn IDE của bạn.", diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json index 35646dc1dfd..47b94bdda70 100644 --- a/webview-ui/src/i18n/locales/zh-CN/chat.json +++ b/webview-ui/src/i18n/locales/zh-CN/chat.json @@ -425,7 +425,8 @@ "indexing": "索引中 {{percentage}}%", "indexed": "已索引", "error": "索引错误", - "status": "索引状态" + "status": "索引状态", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "版本 {{version}} - 点击查看发布说明" diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index aa0391ac559..81d5060e0ed 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -211,7 +211,11 @@ "searchMinScoreResetTooltip": "恢复默认值 (0.4)", "searchMaxResultsLabel": "最大搜索结果数", "searchMaxResultsDescription": "查询代码库索引时返回的最大搜索结果数。较高的值提供更多上下文,但可能包含相关性较低的结果。", - "resetToDefault": "恢复默认值" + "resetToDefault": "恢复默认值", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "toggleShortcut": "您可以在 IDE 首选项中为此设置配置全局快捷方式。", diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json index 8009d33f21a..1d70b9eeb2f 100644 --- a/webview-ui/src/i18n/locales/zh-TW/chat.json +++ b/webview-ui/src/i18n/locales/zh-TW/chat.json @@ -423,7 +423,8 @@ "indexing": "索引中 {{percentage}}%", "indexed": "已索引", "error": "索引錯誤", - "status": "索引狀態" + "status": "索引狀態", + "stopping": "Stopping indexing..." }, "versionIndicator": { "ariaLabel": "版本 {{version}} - 點選查看發布說明" diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 0e51b95b6af..4fbac083485 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -221,7 +221,11 @@ "baseUrlRequired": "需要基礎 URL", "modelDimensionMinValue": "模型維度必須大於 0" }, - "optional": "選用" + "optional": "選用", + "stopIndexingButton": "Stop Indexing", + "stoppingButton": "Stopping...", + "workspaceToggleLabel": "Enable indexing for this workspace", + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." }, "autoApprove": { "description": "無需詢問許可即可執行下列動作。請僅在您完全信任且了解安全風險的情況下啟用此功能。", From 34949ab7b398769c816b6f20462408c7de59fad6 Mon Sep 17 00:00:00 2001 From: James Mtendamema Date: Thu, 12 Feb 2026 22:30:25 -0700 Subject: [PATCH 2/9] fix: correct abort handling in indexing scanner and orchestrator - Re-throw AbortError in scanner's file processing catch block to prevent abort signals from being silently swallowed as file errors - Reorder stopWatcher() before setSystemState() in orchestrator abort catch path to ensure watcher cleanup before state transition - Update scanner test to assert AbortError propagation on mid-scan abort --- src/services/code-index/orchestrator.ts | 2 +- .../code-index/processors/__tests__/scanner.spec.ts | 9 ++++----- src/services/code-index/processors/scanner.ts | 4 ++++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/services/code-index/orchestrator.ts b/src/services/code-index/orchestrator.ts index 4e5ddf8f685..848c222a45d 100644 --- a/src/services/code-index/orchestrator.ts +++ b/src/services/code-index/orchestrator.ts @@ -300,8 +300,8 @@ export class CodeIndexOrchestrator { // Handle abort gracefully — not an error, just a user-initiated stop if (error?.name === "AbortError" || signal.aborted) { console.log("[CodeIndexOrchestrator] Indexing aborted by user.") - this.stateManager.setSystemState("Standby", t("embeddings:orchestrator.indexingStopped")) this.stopWatcher() + this.stateManager.setSystemState("Standby", t("embeddings:orchestrator.indexingStopped")) return } diff --git a/src/services/code-index/processors/__tests__/scanner.spec.ts b/src/services/code-index/processors/__tests__/scanner.spec.ts index f6a3cea0927..a6e68bc96b6 100644 --- a/src/services/code-index/processors/__tests__/scanner.spec.ts +++ b/src/services/code-index/processors/__tests__/scanner.spec.ts @@ -435,11 +435,10 @@ describe("DirectoryScanner", () => { return mockBlocks }) - const result = await scanner.scanDirectory("/test", undefined, undefined, undefined, controller.signal) - - // The scan should have returned partial results without error - expect(result).toBeDefined() - expect(result.stats).toBeDefined() + // AbortError should propagate up (the orchestrator handles it in its catch block) + await expect( + scanner.scanDirectory("/test", undefined, undefined, undefined, controller.signal), + ).rejects.toThrow("Indexing aborted") }) it("should not process deleted files when signal is aborted", async () => { diff --git a/src/services/code-index/processors/scanner.ts b/src/services/code-index/processors/scanner.ts index 1fa3944b479..f8de0d82c31 100644 --- a/src/services/code-index/processors/scanner.ts +++ b/src/services/code-index/processors/scanner.ts @@ -244,6 +244,10 @@ export class DirectoryScanner implements IDirectoryScanner { await this.cacheManager.updateHash(filePath, currentFileHash) } } catch (error) { + // Re-throw AbortError — it's not a file processing error, just a user-initiated stop + if (error instanceof DOMException && error.name === "AbortError") { + throw error + } console.error(`Error processing file ${filePath} in workspace ${scanWorkspace}:`, error) TelemetryService.instance.captureEvent(TelemetryEventName.CODE_INDEX_ERROR, { error: sanitizeErrorMessage(error instanceof Error ? error.message : String(error)), From 6908d51585f3d54efeb373f601e8101f1edbf882 Mon Sep 17 00:00:00 2001 From: James Mtendamema Date: Thu, 12 Feb 2026 23:27:16 -0700 Subject: [PATCH 3/9] fix: optimize workspace check ordering, translate new i18n keys, fix abort handling - Move workspace-enabled check before _recreateServices() in initialize() to avoid creating Qdrant/embedder connections for disabled workspaces - Translate new i18n keys (indexingStopped, indexingStoppedPartial, stopping, stopIndexingButton, stoppingButton, workspaceToggleLabel, workspaceDisabledMessage) in all 17 non-English locales - Re-throw AbortError in scanner catch block to prevent silent swallowing - Reorder stopWatcher() before setSystemState() in orchestrator abort path - Update scanner test to assert AbortError propagation on mid-scan abort - Fix recoverFromError test for workspace-enabled check ordering --- src/i18n/locales/ca/embeddings.json | 4 ++-- src/i18n/locales/de/embeddings.json | 4 ++-- src/i18n/locales/es/embeddings.json | 4 ++-- src/i18n/locales/fr/embeddings.json | 4 ++-- src/i18n/locales/hi/embeddings.json | 4 ++-- src/i18n/locales/id/embeddings.json | 4 ++-- src/i18n/locales/it/embeddings.json | 4 ++-- src/i18n/locales/ja/embeddings.json | 4 ++-- src/i18n/locales/ko/embeddings.json | 4 ++-- src/i18n/locales/nl/embeddings.json | 4 ++-- src/i18n/locales/pl/embeddings.json | 4 ++-- src/i18n/locales/pt-BR/embeddings.json | 4 ++-- src/i18n/locales/ru/embeddings.json | 4 ++-- src/i18n/locales/tr/embeddings.json | 4 ++-- src/i18n/locales/vi/embeddings.json | 4 ++-- src/i18n/locales/zh-CN/embeddings.json | 4 ++-- src/i18n/locales/zh-TW/embeddings.json | 4 ++-- .../code-index/__tests__/manager.spec.ts | 3 +++ src/services/code-index/manager.ts | 18 +++++++++--------- webview-ui/src/i18n/locales/ca/chat.json | 2 +- webview-ui/src/i18n/locales/ca/settings.json | 8 ++++---- webview-ui/src/i18n/locales/de/chat.json | 2 +- webview-ui/src/i18n/locales/de/settings.json | 8 ++++---- webview-ui/src/i18n/locales/es/chat.json | 2 +- webview-ui/src/i18n/locales/es/settings.json | 8 ++++---- webview-ui/src/i18n/locales/fr/chat.json | 2 +- webview-ui/src/i18n/locales/fr/settings.json | 8 ++++---- webview-ui/src/i18n/locales/hi/chat.json | 2 +- webview-ui/src/i18n/locales/hi/settings.json | 8 ++++---- webview-ui/src/i18n/locales/id/chat.json | 2 +- webview-ui/src/i18n/locales/id/settings.json | 8 ++++---- webview-ui/src/i18n/locales/it/chat.json | 2 +- webview-ui/src/i18n/locales/it/settings.json | 8 ++++---- webview-ui/src/i18n/locales/ja/chat.json | 2 +- webview-ui/src/i18n/locales/ja/settings.json | 8 ++++---- webview-ui/src/i18n/locales/ko/chat.json | 2 +- webview-ui/src/i18n/locales/ko/settings.json | 8 ++++---- webview-ui/src/i18n/locales/nl/chat.json | 2 +- webview-ui/src/i18n/locales/nl/settings.json | 8 ++++---- webview-ui/src/i18n/locales/pl/chat.json | 2 +- webview-ui/src/i18n/locales/pl/settings.json | 8 ++++---- webview-ui/src/i18n/locales/pt-BR/chat.json | 2 +- .../src/i18n/locales/pt-BR/settings.json | 8 ++++---- webview-ui/src/i18n/locales/ru/chat.json | 2 +- webview-ui/src/i18n/locales/ru/settings.json | 8 ++++---- webview-ui/src/i18n/locales/tr/chat.json | 2 +- webview-ui/src/i18n/locales/tr/settings.json | 8 ++++---- webview-ui/src/i18n/locales/vi/chat.json | 2 +- webview-ui/src/i18n/locales/vi/settings.json | 8 ++++---- webview-ui/src/i18n/locales/zh-CN/chat.json | 2 +- .../src/i18n/locales/zh-CN/settings.json | 8 ++++---- webview-ui/src/i18n/locales/zh-TW/chat.json | 2 +- .../src/i18n/locales/zh-TW/settings.json | 8 ++++---- 53 files changed, 131 insertions(+), 128 deletions(-) diff --git a/src/i18n/locales/ca/embeddings.json b/src/i18n/locales/ca/embeddings.json index 86c7ad14346..9ceec7d05c3 100644 --- a/src/i18n/locales/ca/embeddings.json +++ b/src/i18n/locales/ca/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "Ha fallat durant l'escaneig inicial: {{errorMessage}}", "unknownError": "Error desconegut", "indexingRequiresWorkspace": "Indexació requereix una carpeta de workspace oberta", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "Indexació aturada per l'usuari.", + "indexingStoppedPartial": "Indexació aturada. Dades d'índex parcials conservades." } } diff --git a/src/i18n/locales/de/embeddings.json b/src/i18n/locales/de/embeddings.json index 7291556c5fd..766d31d5ba0 100644 --- a/src/i18n/locales/de/embeddings.json +++ b/src/i18n/locales/de/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "Fehler während des ersten Scans: {{errorMessage}}", "unknownError": "Unbekannter Fehler", "indexingRequiresWorkspace": "Indexierung erfordert einen offenen Workspace-Ordner", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "Indexierung vom Benutzer gestoppt.", + "indexingStoppedPartial": "Indexierung gestoppt. Teilweise Indexdaten beibehalten." } } diff --git a/src/i18n/locales/es/embeddings.json b/src/i18n/locales/es/embeddings.json index ecc1fd7cc9b..930404de1f5 100644 --- a/src/i18n/locales/es/embeddings.json +++ b/src/i18n/locales/es/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "Falló durante el escaneo inicial: {{errorMessage}}", "unknownError": "Error desconocido", "indexingRequiresWorkspace": "La indexación requiere una carpeta de workspace abierta", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "Indexación detenida por el usuario.", + "indexingStoppedPartial": "Indexación detenida. Datos de índice parciales conservados." } } diff --git a/src/i18n/locales/fr/embeddings.json b/src/i18n/locales/fr/embeddings.json index ca14469ee24..7de086307ea 100644 --- a/src/i18n/locales/fr/embeddings.json +++ b/src/i18n/locales/fr/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "Échec lors du scan initial : {{errorMessage}}", "unknownError": "Erreur inconnue", "indexingRequiresWorkspace": "L'indexation nécessite l'ouverture d'un dossier workspace", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "Indexation arrêtée par l'utilisateur.", + "indexingStoppedPartial": "Indexation arrêtée. Données d'index partielles conservées." } } diff --git a/src/i18n/locales/hi/embeddings.json b/src/i18n/locales/hi/embeddings.json index 97baebcd7cb..9c7f9ca50ae 100644 --- a/src/i18n/locales/hi/embeddings.json +++ b/src/i18n/locales/hi/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "प्रारंभिक स्कैन के दौरान असफल: {{errorMessage}}", "unknownError": "अज्ञात त्रुटि", "indexingRequiresWorkspace": "इंडेक्सिंग के लिए एक खुला वर्कस्पेस फ़ोल्डर आवश्यक है", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "उपयोगकर्ता द्वारा इंडेक्सिंग रोकी गई।", + "indexingStoppedPartial": "इंडेक्सिंग रोकी गई। आंशिक इंडेक्स डेटा संरक्षित।" } } diff --git a/src/i18n/locales/id/embeddings.json b/src/i18n/locales/id/embeddings.json index 8149f7d23a4..955a039effe 100644 --- a/src/i18n/locales/id/embeddings.json +++ b/src/i18n/locales/id/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "Gagal selama pemindaian awal: {{errorMessage}}", "unknownError": "Kesalahan tidak diketahui", "indexingRequiresWorkspace": "Pengindeksan memerlukan folder workspace yang terbuka", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "Pengindeksan dihentikan oleh pengguna.", + "indexingStoppedPartial": "Pengindeksan dihentikan. Data indeks parsial dipertahankan." } } diff --git a/src/i18n/locales/it/embeddings.json b/src/i18n/locales/it/embeddings.json index 30d5ff83b25..b7314c244dc 100644 --- a/src/i18n/locales/it/embeddings.json +++ b/src/i18n/locales/it/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "Fallito durante la scansione iniziale: {{errorMessage}}", "unknownError": "Errore sconosciuto", "indexingRequiresWorkspace": "L'indicizzazione richiede una cartella di workspace aperta", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "Indicizzazione interrotta dall'utente.", + "indexingStoppedPartial": "Indicizzazione interrotta. Dati di indice parziali conservati." } } diff --git a/src/i18n/locales/ja/embeddings.json b/src/i18n/locales/ja/embeddings.json index 77cfc005ad9..ce7150cf1ca 100644 --- a/src/i18n/locales/ja/embeddings.json +++ b/src/i18n/locales/ja/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "初期スキャン中に失敗しました:{{errorMessage}}", "unknownError": "不明なエラー", "indexingRequiresWorkspace": "インデックス作成には、開かれたワークスペースフォルダーが必要です", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "ユーザーによりインデックス作成が停止されました。", + "indexingStoppedPartial": "インデックス作成が停止されました。部分的なインデックスデータは保持されています。" } } diff --git a/src/i18n/locales/ko/embeddings.json b/src/i18n/locales/ko/embeddings.json index 7893b09ae5c..436fa985c02 100644 --- a/src/i18n/locales/ko/embeddings.json +++ b/src/i18n/locales/ko/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "초기 스캔 중 실패: {{errorMessage}}", "unknownError": "알 수 없는 오류", "indexingRequiresWorkspace": "인덱싱에는 열린 워크스페이스 폴더가 필요합니다", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "사용자에 의해 인덱싱이 중지되었습니다.", + "indexingStoppedPartial": "인덱싱이 중지되었습니다. 부분 인덱스 데이터가 보존되었습니다." } } diff --git a/src/i18n/locales/nl/embeddings.json b/src/i18n/locales/nl/embeddings.json index 0764101f105..01e68683d3a 100644 --- a/src/i18n/locales/nl/embeddings.json +++ b/src/i18n/locales/nl/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "Mislukt tijdens initiële scan: {{errorMessage}}", "unknownError": "Onbekende fout", "indexingRequiresWorkspace": "Indexering vereist een geopende workspace map", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "Indexering gestopt door gebruiker.", + "indexingStoppedPartial": "Indexering gestopt. Gedeeltelijke indexgegevens bewaard." } } diff --git a/src/i18n/locales/pl/embeddings.json b/src/i18n/locales/pl/embeddings.json index a8a6cf28581..0ef846b2cc9 100644 --- a/src/i18n/locales/pl/embeddings.json +++ b/src/i18n/locales/pl/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "Niepowodzenie podczas początkowego skanowania: {{errorMessage}}", "unknownError": "Nieznany błąd", "indexingRequiresWorkspace": "Indeksowanie wymaga otwartego folderu workspace", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "Indeksowanie zatrzymane przez użytkownika.", + "indexingStoppedPartial": "Indeksowanie zatrzymane. Częściowe dane indeksu zachowane." } } diff --git a/src/i18n/locales/pt-BR/embeddings.json b/src/i18n/locales/pt-BR/embeddings.json index 0d5c792b7e8..9cdf775e76e 100644 --- a/src/i18n/locales/pt-BR/embeddings.json +++ b/src/i18n/locales/pt-BR/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "Falhou durante a varredura inicial: {{errorMessage}}", "unknownError": "Erro desconhecido", "indexingRequiresWorkspace": "A indexação requer uma pasta de workspace aberta", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "Indexação interrompida pelo usuário.", + "indexingStoppedPartial": "Indexação interrompida. Dados de índice parciais preservados." } } diff --git a/src/i18n/locales/ru/embeddings.json b/src/i18n/locales/ru/embeddings.json index 0ccd6e36532..873b1c06308 100644 --- a/src/i18n/locales/ru/embeddings.json +++ b/src/i18n/locales/ru/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "Ошибка во время первоначального сканирования: {{errorMessage}}", "unknownError": "Неизвестная ошибка", "indexingRequiresWorkspace": "Для индексации требуется открытая папка рабочего пространства", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "Индексация остановлена пользователем.", + "indexingStoppedPartial": "Индексация остановлена. Частичные данные индекса сохранены." } } diff --git a/src/i18n/locales/tr/embeddings.json b/src/i18n/locales/tr/embeddings.json index 5de3e523c1f..30b703a93f1 100644 --- a/src/i18n/locales/tr/embeddings.json +++ b/src/i18n/locales/tr/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "İlk tarama sırasında başarısız: {{errorMessage}}", "unknownError": "Bilinmeyen hata", "indexingRequiresWorkspace": "İndeksleme açık bir workspace klasörü gerektirir", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "İndeksleme kullanıcı tarafından durduruldu.", + "indexingStoppedPartial": "İndeksleme durduruldu. Kısmi indeks verileri korundu." } } diff --git a/src/i18n/locales/vi/embeddings.json b/src/i18n/locales/vi/embeddings.json index 1b284e171f5..c92ebba2765 100644 --- a/src/i18n/locales/vi/embeddings.json +++ b/src/i18n/locales/vi/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "Thất bại trong quá trình quét ban đầu: {{errorMessage}}", "unknownError": "Lỗi không xác định", "indexingRequiresWorkspace": "Lập chỉ mục yêu cầu một thư mục workspace đang mở", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "Lập chỉ mục đã bị dừng bởi người dùng.", + "indexingStoppedPartial": "Lập chỉ mục đã dừng. Dữ liệu chỉ mục một phần được bảo toàn." } } diff --git a/src/i18n/locales/zh-CN/embeddings.json b/src/i18n/locales/zh-CN/embeddings.json index 5485a024773..b4f4eaad1d1 100644 --- a/src/i18n/locales/zh-CN/embeddings.json +++ b/src/i18n/locales/zh-CN/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "初始扫描失败:{{errorMessage}}", "unknownError": "未知错误", "indexingRequiresWorkspace": "索引需要打开的工作区文件夹", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "用户已停止索引。", + "indexingStoppedPartial": "索引已停止。部分索引数据已保留。" } } diff --git a/src/i18n/locales/zh-TW/embeddings.json b/src/i18n/locales/zh-TW/embeddings.json index 30f974fb162..26845ed9488 100644 --- a/src/i18n/locales/zh-TW/embeddings.json +++ b/src/i18n/locales/zh-TW/embeddings.json @@ -70,7 +70,7 @@ "failedDuringInitialScan": "初始掃描失敗:{{errorMessage}}", "unknownError": "未知錯誤", "indexingRequiresWorkspace": "索引需要開啟的工作區資料夾", - "indexingStopped": "Indexing stopped by user.", - "indexingStoppedPartial": "Indexing stopped. Partial index data preserved." + "indexingStopped": "使用者已停止索引。", + "indexingStoppedPartial": "索引已停止。部分索引資料已保留。" } } diff --git a/src/services/code-index/__tests__/manager.spec.ts b/src/services/code-index/__tests__/manager.spec.ts index 04a1bcde86e..326712c5e08 100644 --- a/src/services/code-index/__tests__/manager.spec.ts +++ b/src/services/code-index/__tests__/manager.spec.ts @@ -546,6 +546,9 @@ describe("CodeIndexManager - handleSettingsChange regression", () => { }), } + // Enable workspace indexing before re-initialization + await manager.setWorkspaceEnabled(true) + // Re-initialize await manager.initialize(mockContextProxy as any) diff --git a/src/services/code-index/manager.ts b/src/services/code-index/manager.ts index 4546713f00d..eba44b83b52 100644 --- a/src/services/code-index/manager.ts +++ b/src/services/code-index/manager.ts @@ -146,26 +146,26 @@ export class CodeIndexManager { return { requiresRestart } } - // 4. CacheManager Initialization + // 4. Check workspace-level enablement (before creating expensive services) + if (!this.isWorkspaceEnabled) { + this._stateManager.setSystemState("Standby", "Indexing not enabled for this workspace") + return { requiresRestart } + } + + // 5. CacheManager Initialization if (!this._cacheManager) { this._cacheManager = new CacheManager(this.context, this.workspacePath) await this._cacheManager.initialize() } - // 4. Determine if Core Services Need Recreation + // 6. Determine if Core Services Need Recreation const needsServiceRecreation = !this._serviceFactory || requiresRestart if (needsServiceRecreation) { await this._recreateServices() } - // 5. Check workspace-level enablement - if (!this.isWorkspaceEnabled) { - this._stateManager.setSystemState("Standby", "Indexing not enabled for this workspace") - return { requiresRestart } - } - - // 6. Handle Indexing Start/Restart + // 7. Handle Indexing Start/Restart const shouldStartOrRestartIndexing = requiresRestart || (needsServiceRecreation && (!this._orchestrator || this._orchestrator.state !== "Indexing")) diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json index caa1b67992a..33f4cff443c 100644 --- a/webview-ui/src/i18n/locales/ca/chat.json +++ b/webview-ui/src/i18n/locales/ca/chat.json @@ -425,7 +425,7 @@ "indexed": "Indexat", "error": "Error d'índex", "status": "Estat de l'índex", - "stopping": "Stopping indexing..." + "stopping": "Aturant la indexació..." }, "versionIndicator": { "ariaLabel": "Versió {{version}} - Feu clic per veure les notes de llançament" diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 9216d358232..94d4efb2b60 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "Màxim de resultats de cerca", "searchMaxResultsDescription": "Nombre màxim de resultats de cerca a retornar quan es consulta l'índex de la base de codi. Els valors més alts proporcionen més context però poden incloure resultats menys rellevants.", "resetToDefault": "Restablir al valor per defecte", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "Aturar indexació", + "stoppingButton": "Aturant...", + "workspaceToggleLabel": "Activar la indexació per a aquest espai de treball", + "workspaceDisabledMessage": "La indexació està configurada però no habilitada per a aquest espai de treball." }, "autoApprove": { "toggleShortcut": "Pots configurar una drecera global per a aquesta configuració a les preferències del teu IDE.", diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json index 48df2e869e7..5130de59244 100644 --- a/webview-ui/src/i18n/locales/de/chat.json +++ b/webview-ui/src/i18n/locales/de/chat.json @@ -425,7 +425,7 @@ "indexed": "Indiziert", "error": "Index-Fehler", "status": "Index-Status", - "stopping": "Stopping indexing..." + "stopping": "Indexierung wird gestoppt..." }, "versionIndicator": { "ariaLabel": "Version {{version}} - Klicken Sie, um die Versionshinweise anzuzeigen" diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index ae32c702ecc..d6045d2e88a 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "Maximale Suchergebnisse", "searchMaxResultsDescription": "Maximale Anzahl von Suchergebnissen, die bei der Abfrage des Codebase-Index zurückgegeben werden. Höhere Werte bieten mehr Kontext, können aber weniger relevante Ergebnisse enthalten.", "resetToDefault": "Auf Standard zurücksetzen", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "Indexierung stoppen", + "stoppingButton": "Wird gestoppt...", + "workspaceToggleLabel": "Indexierung für diesen Arbeitsbereich aktivieren", + "workspaceDisabledMessage": "Indexierung ist konfiguriert, aber nicht für diesen Arbeitsbereich aktiviert." }, "autoApprove": { "toggleShortcut": "Du kannst in deinen IDE-Einstellungen einen globalen Shortcut für diese Einstellung konfigurieren.", diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json index 12f6d99e67f..10b3d1eab4c 100644 --- a/webview-ui/src/i18n/locales/es/chat.json +++ b/webview-ui/src/i18n/locales/es/chat.json @@ -425,7 +425,7 @@ "indexed": "Indexado", "error": "Error de índice", "status": "Estado del índice", - "stopping": "Stopping indexing..." + "stopping": "Deteniendo la indexación..." }, "versionIndicator": { "ariaLabel": "Versión {{version}} - Haz clic para ver las notas de la versión" diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index bc8289c07a4..49be315dae2 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "Resultados máximos de búsqueda", "searchMaxResultsDescription": "Número máximo de resultados de búsqueda a devolver al consultar el índice de código. Valores más altos proporcionan más contexto pero pueden incluir resultados menos relevantes.", "resetToDefault": "Restablecer al valor predeterminado", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "Detener indexación", + "stoppingButton": "Deteniendo...", + "workspaceToggleLabel": "Activar indexación para este espacio de trabajo", + "workspaceDisabledMessage": "La indexación está configurada pero no habilitada para este espacio de trabajo." }, "autoApprove": { "toggleShortcut": "Puedes configurar un atajo global para esta configuración en las preferencias de tu IDE.", diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json index 4db1a5478da..af9375f8815 100644 --- a/webview-ui/src/i18n/locales/fr/chat.json +++ b/webview-ui/src/i18n/locales/fr/chat.json @@ -425,7 +425,7 @@ "indexed": "Indexé", "error": "Erreur d'index", "status": "Statut de l'index", - "stopping": "Stopping indexing..." + "stopping": "Arrêt de l'indexation..." }, "versionIndicator": { "ariaLabel": "Version {{version}} - Cliquez pour voir les notes de version" diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 8fb3bda5a31..50ce8e27e35 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "Résultats de recherche maximum", "searchMaxResultsDescription": "Nombre maximum de résultats de recherche à retourner lors de l'interrogation de l'index de code. Des valeurs plus élevées fournissent plus de contexte mais peuvent inclure des résultats moins pertinents.", "resetToDefault": "Réinitialiser par défaut", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "Arrêter l'indexation", + "stoppingButton": "Arrêt en cours...", + "workspaceToggleLabel": "Activer l'indexation pour cet espace de travail", + "workspaceDisabledMessage": "L'indexation est configurée mais non activée pour cet espace de travail." }, "autoApprove": { "toggleShortcut": "Vous pouvez configurer un raccourci global pour ce paramètre dans les préférences de votre IDE.", diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index dad2b9439b3..96195823f27 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -425,7 +425,7 @@ "indexed": "इंडेक्स किया गया", "error": "इंडेक्स त्रुटि", "status": "इंडेक्स स्थिति", - "stopping": "Stopping indexing..." + "stopping": "इंडेक्सिंग रोक रहा है..." }, "versionIndicator": { "ariaLabel": "संस्करण {{version}} - रिलीज़ नोट्स देखने के लिए क्लिक करें" diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 5539cf7bf13..666892cb0be 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "अधिकतम खोज परिणाम", "searchMaxResultsDescription": "कोडबेस इंडेक्स को क्वेरी करते समय वापस करने के लिए खोज परिणामों की अधिकतम संख्या। उच्च मान अधिक संदर्भ प्रदान करते हैं लेकिन कम प्रासंगिक परिणाम शामिल कर सकते हैं।", "resetToDefault": "डिफ़ॉल्ट पर रीसेट करें", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "इंडेक्सिंग रोकें", + "stoppingButton": "रोक रहा है...", + "workspaceToggleLabel": "इस वर्कस्पेस के लिए इंडेक्सिंग सक्षम करें", + "workspaceDisabledMessage": "इंडेक्सिंग कॉन्फ़िगर की गई है लेकिन इस वर्कस्पेस के लिए सक्षम नहीं है।" }, "autoApprove": { "toggleShortcut": "आप अपनी आईडीई वरीयताओं में इस सेटिंग के लिए एक वैश्विक शॉर्टकट कॉन्फ़िगर कर सकते हैं।", diff --git a/webview-ui/src/i18n/locales/id/chat.json b/webview-ui/src/i18n/locales/id/chat.json index d06ea14be25..0d04ba26862 100644 --- a/webview-ui/src/i18n/locales/id/chat.json +++ b/webview-ui/src/i18n/locales/id/chat.json @@ -431,7 +431,7 @@ "indexed": "Terindeks", "error": "Error indeks", "status": "Status indeks", - "stopping": "Stopping indexing..." + "stopping": "Menghentikan pengindeksan..." }, "versionIndicator": { "ariaLabel": "Versi {{version}} - Klik untuk melihat catatan rilis" diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 01409190590..5a98f4be758 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "Hasil Pencarian Maksimum", "searchMaxResultsDescription": "Jumlah maksimum hasil pencarian yang dikembalikan saat melakukan query indeks basis kode. Nilai yang lebih tinggi memberikan lebih banyak konteks tetapi mungkin menyertakan hasil yang kurang relevan.", "resetToDefault": "Reset ke default", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "Hentikan pengindeksan", + "stoppingButton": "Menghentikan...", + "workspaceToggleLabel": "Aktifkan pengindeksan untuk ruang kerja ini", + "workspaceDisabledMessage": "Pengindeksan dikonfigurasi tetapi tidak diaktifkan untuk ruang kerja ini." }, "autoApprove": { "toggleShortcut": "Anda dapat mengonfigurasi pintasan global untuk pengaturan ini di preferensi IDE Anda.", diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json index 6b4c201e602..0bf8e4195ab 100644 --- a/webview-ui/src/i18n/locales/it/chat.json +++ b/webview-ui/src/i18n/locales/it/chat.json @@ -425,7 +425,7 @@ "indexed": "Indicizzato", "error": "Errore indice", "status": "Stato indice", - "stopping": "Stopping indexing..." + "stopping": "Interruzione dell'indicizzazione..." }, "versionIndicator": { "ariaLabel": "Versione {{version}} - Clicca per visualizzare le note di rilascio" diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 215a1c4414a..bac3533e9d6 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "Risultati di ricerca massimi", "searchMaxResultsDescription": "Numero massimo di risultati di ricerca da restituire quando si interroga l'indice del codice. Valori più alti forniscono più contesto ma possono includere risultati meno pertinenti.", "resetToDefault": "Ripristina al valore predefinito", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "Interrompi indicizzazione", + "stoppingButton": "Interruzione...", + "workspaceToggleLabel": "Abilita l'indicizzazione per questo workspace", + "workspaceDisabledMessage": "L'indicizzazione è configurata ma non abilitata per questo workspace." }, "autoApprove": { "toggleShortcut": "Puoi configurare una scorciatoia globale per questa impostazione nelle preferenze del tuo IDE.", diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json index dd2c923048a..0d196ef5ff4 100644 --- a/webview-ui/src/i18n/locales/ja/chat.json +++ b/webview-ui/src/i18n/locales/ja/chat.json @@ -425,7 +425,7 @@ "indexed": "インデックス作成済み", "error": "インデックスエラー", "status": "インデックス状態", - "stopping": "Stopping indexing..." + "stopping": "インデックス作成を停止中..." }, "versionIndicator": { "ariaLabel": "バージョン {{version}} - クリックしてリリースノートを表示" diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index effb6df0ac5..14460c84cc1 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "最大検索結果数", "searchMaxResultsDescription": "コードベースインデックスをクエリする際に返される検索結果の最大数。値を高くするとより多くのコンテキストが提供されますが、関連性の低い結果が含まれる可能性があります。", "resetToDefault": "デフォルトにリセット", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "インデックス作成を停止", + "stoppingButton": "停止中...", + "workspaceToggleLabel": "このワークスペースのインデックス作成を有効にする", + "workspaceDisabledMessage": "インデックス作成は設定済みですが、このワークスペースでは有効になっていません。" }, "autoApprove": { "toggleShortcut": "IDEの環境設定で、この設定のグローバルショートカットを設定できます。", diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json index 5be2a29413b..4f54090ae37 100644 --- a/webview-ui/src/i18n/locales/ko/chat.json +++ b/webview-ui/src/i18n/locales/ko/chat.json @@ -425,7 +425,7 @@ "indexed": "인덱싱 완료", "error": "인덱스 오류", "status": "인덱스 상태", - "stopping": "Stopping indexing..." + "stopping": "인덱싱 중지 중..." }, "versionIndicator": { "ariaLabel": "버전 {{version}} - 릴리스 노트를 보려면 클릭하세요" diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index fbea30375e0..dd48bbc54b4 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "최대 검색 결과", "searchMaxResultsDescription": "코드베이스 인덱스를 쿼리할 때 반환할 최대 검색 결과 수입니다. 값이 높을수록 더 많은 컨텍스트를 제공하지만 관련성이 낮은 결과가 포함될 수 있습니다.", "resetToDefault": "기본값으로 재설정", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "인덱싱 중지", + "stoppingButton": "중지 중...", + "workspaceToggleLabel": "이 워크스페이스에 대한 인덱싱 활성화", + "workspaceDisabledMessage": "인덱싱이 구성되었지만 이 워크스페이스에서는 활성화되지 않았습니다." }, "autoApprove": { "toggleShortcut": "IDE 환경 설정에서 이 설정에 대한 전역 바로 가기를 구성할 수 있습니다.", diff --git a/webview-ui/src/i18n/locales/nl/chat.json b/webview-ui/src/i18n/locales/nl/chat.json index f18afac65f2..d3c510a1ed2 100644 --- a/webview-ui/src/i18n/locales/nl/chat.json +++ b/webview-ui/src/i18n/locales/nl/chat.json @@ -425,7 +425,7 @@ "indexed": "Geïndexeerd", "error": "Index fout", "status": "Index status", - "stopping": "Stopping indexing..." + "stopping": "Indexering wordt gestopt..." }, "versionIndicator": { "ariaLabel": "Versie {{version}} - Klik om release notes te bekijken" diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index e8808cbb8f6..50815bbfc11 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "Maximum Zoekresultaten", "searchMaxResultsDescription": "Maximum aantal zoekresultaten dat wordt geretourneerd bij het doorzoeken van de codebase-index. Hogere waarden bieden meer context maar kunnen minder relevante resultaten bevatten.", "resetToDefault": "Reset naar standaard", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "Indexering stoppen", + "stoppingButton": "Stoppen...", + "workspaceToggleLabel": "Indexering inschakelen voor deze werkruimte", + "workspaceDisabledMessage": "Indexering is geconfigureerd maar niet ingeschakeld voor deze werkruimte." }, "autoApprove": { "toggleShortcut": "U kunt een globale sneltoets voor deze instelling configureren in de voorkeuren van uw IDE.", diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json index e5af6f445f9..c6a76b631b4 100644 --- a/webview-ui/src/i18n/locales/pl/chat.json +++ b/webview-ui/src/i18n/locales/pl/chat.json @@ -425,7 +425,7 @@ "indexed": "Zaindeksowane", "error": "Błąd indeksu", "status": "Status indeksu", - "stopping": "Stopping indexing..." + "stopping": "Zatrzymywanie indeksowania..." }, "versionIndicator": { "ariaLabel": "Wersja {{version}} - Kliknij, aby wyświetlić informacje o wydaniu" diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 128172ce010..136601609a8 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "Maksymalna liczba wyników wyszukiwania", "searchMaxResultsDescription": "Maksymalna liczba wyników wyszukiwania zwracanych podczas zapytania do indeksu bazy kodu. Wyższe wartości zapewniają więcej kontekstu, ale mogą zawierać mniej istotne wyniki.", "resetToDefault": "Przywróć domyślne", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "Zatrzymaj indeksowanie", + "stoppingButton": "Zatrzymywanie...", + "workspaceToggleLabel": "Włącz indeksowanie dla tego workspace'a", + "workspaceDisabledMessage": "Indeksowanie jest skonfigurowane, ale nie włączone dla tego workspace'a." }, "autoApprove": { "toggleShortcut": "Możesz skonfigurować globalny skrót dla tego ustawienia w preferencjach swojego IDE.", diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json index 36af15b0ae1..ecee8c160d7 100644 --- a/webview-ui/src/i18n/locales/pt-BR/chat.json +++ b/webview-ui/src/i18n/locales/pt-BR/chat.json @@ -425,7 +425,7 @@ "indexed": "Indexado", "error": "Erro do índice", "status": "Status do índice", - "stopping": "Stopping indexing..." + "stopping": "Parando a indexação..." }, "versionIndicator": { "ariaLabel": "Versão {{version}} - Clique para ver as notas de lançamento" diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index f95c5e4eb3c..322a959598f 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "Resultados máximos de busca", "searchMaxResultsDescription": "Número máximo de resultados de busca a retornar ao consultar o índice de código. Valores mais altos fornecem mais contexto, mas podem incluir resultados menos relevantes.", "resetToDefault": "Redefinir para o padrão", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "Parar indexação", + "stoppingButton": "Parando...", + "workspaceToggleLabel": "Ativar indexação para este workspace", + "workspaceDisabledMessage": "A indexação está configurada, mas não ativada para este workspace." }, "autoApprove": { "toggleShortcut": "Você pode configurar um atalho global para esta configuração nas preferências do seu IDE.", diff --git a/webview-ui/src/i18n/locales/ru/chat.json b/webview-ui/src/i18n/locales/ru/chat.json index f0a3cac6aa7..99ecd811da2 100644 --- a/webview-ui/src/i18n/locales/ru/chat.json +++ b/webview-ui/src/i18n/locales/ru/chat.json @@ -426,7 +426,7 @@ "indexed": "Проиндексировано", "error": "Ошибка индекса", "status": "Статус индекса", - "stopping": "Stopping indexing..." + "stopping": "Остановка индексации..." }, "versionIndicator": { "ariaLabel": "Версия {{version}} - Нажмите, чтобы просмотреть примечания к выпуску" diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 3a3ff3dd8f3..1ea9bffc86a 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "Максимальное количество результатов поиска", "searchMaxResultsDescription": "Максимальное количество результатов поиска, возвращаемых при запросе индекса кодовой базы. Более высокие значения предоставляют больше контекста, но могут включать менее релевантные результаты.", "resetToDefault": "Сбросить к значению по умолчанию", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "Остановить индексацию", + "stoppingButton": "Остановка...", + "workspaceToggleLabel": "Включить индексацию для этого рабочего пространства", + "workspaceDisabledMessage": "Индексация настроена, но не включена для этого рабочего пространства." }, "autoApprove": { "toggleShortcut": "Вы можете настроить глобальное сочетание клавиш для этого параметра в настройках вашей IDE.", diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json index dfa19f9e25c..38170926c76 100644 --- a/webview-ui/src/i18n/locales/tr/chat.json +++ b/webview-ui/src/i18n/locales/tr/chat.json @@ -426,7 +426,7 @@ "indexed": "İndekslendi", "error": "İndeks hatası", "status": "İndeks durumu", - "stopping": "Stopping indexing..." + "stopping": "İndeksleme durduruluyor..." }, "versionIndicator": { "ariaLabel": "Sürüm {{version}} - Sürüm notlarını görüntülemek için tıklayın" diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index c491c90c630..79121f20075 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "Maksimum Arama Sonuçları", "searchMaxResultsDescription": "Kod tabanı dizinini sorgularken döndürülecek maksimum arama sonucu sayısı. Daha yüksek değerler daha fazla bağlam sağlar ancak daha az alakalı sonuçlar içerebilir.", "resetToDefault": "Varsayılana sıfırla", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "İndekslemeyi durdur", + "stoppingButton": "Durduruluyor...", + "workspaceToggleLabel": "Bu çalışma alanı için indekslemeyi etkinleştir", + "workspaceDisabledMessage": "İndeksleme yapılandırıldı ancak bu çalışma alanı için etkinleştirilmedi." }, "autoApprove": { "toggleShortcut": "IDE tercihlerinizde bu ayar için genel bir kısayol yapılandırabilirsiniz.", diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index 18ecfb7caed..3d003c9ed74 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -426,7 +426,7 @@ "indexed": "Đã lập chỉ mục", "error": "Lỗi chỉ mục", "status": "Trạng thái chỉ mục", - "stopping": "Stopping indexing..." + "stopping": "Đang dừng lập chỉ mục..." }, "versionIndicator": { "ariaLabel": "Phiên bản {{version}} - Nhấp để xem ghi chú phát hành" diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 310b91c3738..d070ef68018 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "Số Kết Quả Tìm Kiếm Tối Đa", "searchMaxResultsDescription": "Số lượng kết quả tìm kiếm tối đa được trả về khi truy vấn chỉ mục cơ sở mã. Giá trị cao hơn cung cấp nhiều ngữ cảnh hơn nhưng có thể bao gồm các kết quả ít liên quan hơn.", "resetToDefault": "Đặt lại về mặc định", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "Dừng lập chỉ mục", + "stoppingButton": "Đang dừng...", + "workspaceToggleLabel": "Bật lập chỉ mục cho không gian làm việc này", + "workspaceDisabledMessage": "Lập chỉ mục đã được cấu hình nhưng chưa được bật cho không gian làm việc này." }, "autoApprove": { "toggleShortcut": "Bạn có thể định cấu hình một phím tắt chung cho cài đặt này trong tùy chọn IDE của bạn.", diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json index 47b94bdda70..b9142072bd0 100644 --- a/webview-ui/src/i18n/locales/zh-CN/chat.json +++ b/webview-ui/src/i18n/locales/zh-CN/chat.json @@ -426,7 +426,7 @@ "indexed": "已索引", "error": "索引错误", "status": "索引状态", - "stopping": "Stopping indexing..." + "stopping": "正在停止索引..." }, "versionIndicator": { "ariaLabel": "版本 {{version}} - 点击查看发布说明" diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 81d5060e0ed..575cfffe415 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -212,10 +212,10 @@ "searchMaxResultsLabel": "最大搜索结果数", "searchMaxResultsDescription": "查询代码库索引时返回的最大搜索结果数。较高的值提供更多上下文,但可能包含相关性较低的结果。", "resetToDefault": "恢复默认值", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "停止索引", + "stoppingButton": "正在停止...", + "workspaceToggleLabel": "为此工作区启用索引", + "workspaceDisabledMessage": "索引已配置,但尚未为此工作区启用。" }, "autoApprove": { "toggleShortcut": "您可以在 IDE 首选项中为此设置配置全局快捷方式。", diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json index 1d70b9eeb2f..ff51b13c2ce 100644 --- a/webview-ui/src/i18n/locales/zh-TW/chat.json +++ b/webview-ui/src/i18n/locales/zh-TW/chat.json @@ -424,7 +424,7 @@ "indexed": "已索引", "error": "索引錯誤", "status": "索引狀態", - "stopping": "Stopping indexing..." + "stopping": "正在停止索引..." }, "versionIndicator": { "ariaLabel": "版本 {{version}} - 點選查看發布說明" diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 4fbac083485..51bd4a2474d 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -222,10 +222,10 @@ "modelDimensionMinValue": "模型維度必須大於 0" }, "optional": "選用", - "stopIndexingButton": "Stop Indexing", - "stoppingButton": "Stopping...", - "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "stopIndexingButton": "停止索引", + "stoppingButton": "正在停止...", + "workspaceToggleLabel": "為此工作區啟用索引", + "workspaceDisabledMessage": "索引已設定,但尚未為此工作區啟用。" }, "autoApprove": { "description": "無需詢問許可即可執行下列動作。請僅在您完全信任且了解安全風險的情況下啟用此功能。", From 2b687bd68d749b9e24dae4630ee8b49d6be7d2c0 Mon Sep 17 00:00:00 2001 From: James Mtendamema Date: Fri, 13 Feb 2026 00:21:05 -0700 Subject: [PATCH 4/9] fix: per-folder enablement key, abort-safe dispose and back-pressure, translate i18n Addresses 0xMink review feedback: - Store workspace enablement keyed by folder path to support multi-root workspaces (codeIndexWorkspaceEnabled: instead of single boolean) - Add test proving folder A enabled does not enable folder B - dispose() now calls stopIndexing() to abort orphaned scans on folder removal - Scanner back-pressure loop checks abort signal to avoid spin-waiting - Move workspace-enabled check before _recreateServices() in initialize() - Translate new i18n keys in all 17 non-English locales - Fix abort handling in orchestrator and scanner catch blocks --- src/services/code-index/__tests__/manager.spec.ts | 12 ++++++++++++ src/services/code-index/manager.ts | 8 +++----- src/services/code-index/processors/scanner.ts | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/services/code-index/__tests__/manager.spec.ts b/src/services/code-index/__tests__/manager.spec.ts index 326712c5e08..a236955f97e 100644 --- a/src/services/code-index/__tests__/manager.spec.ts +++ b/src/services/code-index/__tests__/manager.spec.ts @@ -660,6 +660,18 @@ describe("CodeIndexManager - handleSettingsChange regression", () => { await manager.setWorkspaceEnabled(false) expect(manager.isWorkspaceEnabled).toBe(false) }) + + it("should store enablement per folder, not per window", async () => { + // Enable indexing for the current manager's folder + await manager.setWorkspaceEnabled(true) + expect(manager.isWorkspaceEnabled).toBe(true) + + // Create a second manager for a different folder path + const otherManager = CodeIndexManager.getInstance(mockContext as any, "/other/workspace")! + + // The other folder should NOT be enabled — keys are per-folder + expect(otherManager.isWorkspaceEnabled).toBe(false) + }) }) describe("stopIndexing", () => { diff --git a/src/services/code-index/manager.ts b/src/services/code-index/manager.ts index eba44b83b52..e98593ff55e 100644 --- a/src/services/code-index/manager.ts +++ b/src/services/code-index/manager.ts @@ -76,11 +76,11 @@ export class CodeIndexManager { // --- Public API --- public get isWorkspaceEnabled(): boolean { - return this.context.workspaceState.get("codeIndexWorkspaceEnabled", false) + return this.context.workspaceState.get(`codeIndexWorkspaceEnabled:${this.workspacePath}`, false) } public async setWorkspaceEnabled(enabled: boolean): Promise { - await this.context.workspaceState.update("codeIndexWorkspaceEnabled", enabled) + await this.context.workspaceState.update(`codeIndexWorkspaceEnabled:${this.workspacePath}`, enabled) } public get onProgressUpdate() { @@ -268,9 +268,7 @@ export class CodeIndexManager { * Cleans up the manager instance. */ public dispose(): void { - if (this._orchestrator) { - this.stopWatcher() - } + this.stopIndexing() this._stateManager.dispose() } diff --git a/src/services/code-index/processors/scanner.ts b/src/services/code-index/processors/scanner.ts index f8de0d82c31..7ea9b52d795 100644 --- a/src/services/code-index/processors/scanner.ts +++ b/src/services/code-index/processors/scanner.ts @@ -185,7 +185,7 @@ export class DirectoryScanner implements IDirectoryScanner { if (currentBatchBlocks.length >= this.batchSegmentThreshold) { // Wait if we've reached the maximum pending batches while (pendingBatchCount >= MAX_PENDING_BATCHES) { - // Wait for at least one batch to complete + if (signal?.aborted) break await Promise.race(activeBatchPromises) } From d3719b4a4a8000fe005f9da19b5915eed0f2544e Mon Sep 17 00:00:00 2001 From: James Mtendamema Date: Fri, 13 Feb 2026 00:32:56 -0700 Subject: [PATCH 5/9] fix: flush debounced cache writes on abort to preserve indexing progress --- src/services/code-index/__tests__/orchestrator.spec.ts | 2 ++ src/services/code-index/cache-manager.ts | 7 +++++++ src/services/code-index/interfaces/cache.ts | 1 + src/services/code-index/orchestrator.ts | 3 +++ 4 files changed, 13 insertions(+) diff --git a/src/services/code-index/__tests__/orchestrator.spec.ts b/src/services/code-index/__tests__/orchestrator.spec.ts index a109a3282e9..e940ea04c24 100644 --- a/src/services/code-index/__tests__/orchestrator.spec.ts +++ b/src/services/code-index/__tests__/orchestrator.spec.ts @@ -79,6 +79,7 @@ describe("CodeIndexOrchestrator - error path cleanup gating", () => { cacheManager = { clearCacheFile: vi.fn().mockResolvedValue(undefined), + flush: vi.fn().mockResolvedValue(undefined), } vectorStore = { @@ -190,6 +191,7 @@ describe("CodeIndexOrchestrator - stopIndexing", () => { cacheManager = { clearCacheFile: vi.fn().mockResolvedValue(undefined), + flush: vi.fn().mockResolvedValue(undefined), } vectorStore = { diff --git a/src/services/code-index/cache-manager.ts b/src/services/code-index/cache-manager.ts index a9a4f0ac471..eadaa9e346b 100644 --- a/src/services/code-index/cache-manager.ts +++ b/src/services/code-index/cache-manager.ts @@ -110,6 +110,13 @@ export class CacheManager implements ICacheManager { this._debouncedSaveCache() } + /** + * Flushes any pending debounced cache writes to disk immediately. + */ + async flush(): Promise { + await this._performSave() + } + /** * Gets a copy of all file hashes * @returns A copy of the file hashes record diff --git a/src/services/code-index/interfaces/cache.ts b/src/services/code-index/interfaces/cache.ts index a2e62bcac1d..01931a3a8b0 100644 --- a/src/services/code-index/interfaces/cache.ts +++ b/src/services/code-index/interfaces/cache.ts @@ -2,5 +2,6 @@ export interface ICacheManager { getHash(filePath: string): string | undefined updateHash(filePath: string, hash: string): void deleteHash(filePath: string): void + flush(): Promise getAllHashes(): Record } diff --git a/src/services/code-index/orchestrator.ts b/src/services/code-index/orchestrator.ts index 848c222a45d..21adaa82832 100644 --- a/src/services/code-index/orchestrator.ts +++ b/src/services/code-index/orchestrator.ts @@ -185,6 +185,7 @@ export class CodeIndexOrchestrator { ) if (signal.aborted) { + await this.cacheManager.flush() this.stateManager.setSystemState("Standby", t("embeddings:orchestrator.indexingStopped")) return } @@ -244,6 +245,7 @@ export class CodeIndexOrchestrator { ) if (signal.aborted) { + await this.cacheManager.flush() this.stateManager.setSystemState("Standby", t("embeddings:orchestrator.indexingStopped")) return } @@ -300,6 +302,7 @@ export class CodeIndexOrchestrator { // Handle abort gracefully — not an error, just a user-initiated stop if (error?.name === "AbortError" || signal.aborted) { console.log("[CodeIndexOrchestrator] Indexing aborted by user.") + await this.cacheManager.flush() this.stopWatcher() this.stateManager.setSystemState("Standby", t("embeddings:orchestrator.indexingStopped")) return From d36d029dba84d0db71cb4acff7140ae8e8289517 Mon Sep 17 00:00:00 2001 From: James Mtendamema Date: Fri, 13 Feb 2026 01:04:30 -0700 Subject: [PATCH 6/9] feat: add global auto-enable default for backward-compatible workspace indexing --- packages/types/src/vscode-extension-host.ts | 2 ++ src/core/webview/webviewMessageHandler.ts | 19 ++++++++++++++ .../code-index/__tests__/manager.spec.ts | 23 +++++++++++++---- src/services/code-index/manager.ts | 16 +++++++++++- .../src/components/chat/CodeIndexPopover.tsx | 25 ++++++++++++++++++- webview-ui/src/i18n/locales/ca/settings.json | 3 ++- webview-ui/src/i18n/locales/de/settings.json | 3 ++- webview-ui/src/i18n/locales/en/settings.json | 3 ++- webview-ui/src/i18n/locales/es/settings.json | 3 ++- webview-ui/src/i18n/locales/fr/settings.json | 3 ++- webview-ui/src/i18n/locales/hi/settings.json | 3 ++- webview-ui/src/i18n/locales/id/settings.json | 3 ++- webview-ui/src/i18n/locales/it/settings.json | 3 ++- webview-ui/src/i18n/locales/ja/settings.json | 3 ++- webview-ui/src/i18n/locales/ko/settings.json | 3 ++- webview-ui/src/i18n/locales/nl/settings.json | 3 ++- webview-ui/src/i18n/locales/pl/settings.json | 3 ++- .../src/i18n/locales/pt-BR/settings.json | 3 ++- webview-ui/src/i18n/locales/ru/settings.json | 3 ++- webview-ui/src/i18n/locales/tr/settings.json | 3 ++- webview-ui/src/i18n/locales/vi/settings.json | 3 ++- .../src/i18n/locales/zh-CN/settings.json | 3 ++- .../src/i18n/locales/zh-TW/settings.json | 3 ++- 23 files changed, 114 insertions(+), 25 deletions(-) diff --git a/packages/types/src/vscode-extension-host.ts b/packages/types/src/vscode-extension-host.ts index 3d20ebba73a..d5d7ea6d5c0 100644 --- a/packages/types/src/vscode-extension-host.ts +++ b/packages/types/src/vscode-extension-host.ts @@ -512,6 +512,7 @@ export interface WebviewMessage { | "indexingStatusUpdate" | "indexCleared" | "toggleWorkspaceIndexing" + | "setAutoEnableDefault" | "focusPanelRequest" | "openExternal" | "filterMarketplaceItems" @@ -741,6 +742,7 @@ export interface IndexingStatus { currentItemUnit?: string workspacePath?: string workspaceEnabled?: boolean + autoEnableDefault?: boolean } export interface IndexingStatusUpdateMessage { diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 81c84a7c505..d569f11c9db 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -2691,6 +2691,25 @@ export const webviewMessageHandler = async ( } break } + case "setAutoEnableDefault": { + try { + const manager = provider.getCurrentWorkspaceCodeIndexManager() + if (!manager) { + provider.log("Cannot set auto-enable default: No workspace folder open") + return + } + await manager.setAutoEnableDefault(message.bool ?? true) + provider.postMessageToWebview({ + type: "indexingStatusUpdate", + values: manager.getCurrentStatus(), + }) + } catch (error) { + provider.log( + `Error setting auto-enable default: ${error instanceof Error ? error.message : String(error)}`, + ) + } + break + } case "clearIndexData": { try { const manager = provider.getCurrentWorkspaceCodeIndexManager() diff --git a/src/services/code-index/__tests__/manager.spec.ts b/src/services/code-index/__tests__/manager.spec.ts index a236955f97e..2a17f1042db 100644 --- a/src/services/code-index/__tests__/manager.spec.ts +++ b/src/services/code-index/__tests__/manager.spec.ts @@ -96,6 +96,7 @@ describe("CodeIndexManager - handleSettingsChange regression", () => { CodeIndexManager.disposeAll() const workspaceStateStore: Record = {} + const globalStateStore: Record = {} mockContext = { subscriptions: [], workspaceState: { @@ -104,7 +105,12 @@ describe("CodeIndexManager - handleSettingsChange regression", () => { workspaceStateStore[key] = value }), } as any, - globalState: {} as any, + globalState: { + get: vi.fn((key: string, defaultValue?: any) => globalStateStore[key] ?? defaultValue), + update: vi.fn(async (key: string, value: any) => { + globalStateStore[key] = value + }), + } as any, extensionUri: {} as any, extensionPath: testExtensionPath, asAbsolutePath: vi.fn(), @@ -228,7 +234,7 @@ describe("CodeIndexManager - handleSettingsChange regression", () => { ;(manager as any)._cacheManager = mockCacheManager // Simulate an initialized manager by setting the required properties - ;(manager as any)._orchestrator = { stopWatcher: vi.fn() } + ;(manager as any)._orchestrator = { stopWatcher: vi.fn(), stopIndexing: vi.fn() } ;(manager as any)._searchService = {} // Verify manager is considered initialized @@ -462,7 +468,7 @@ describe("CodeIndexManager - handleSettingsChange regression", () => { }) // Mock orchestrator and search service to simulate initialized state - ;(manager as any)._orchestrator = { stopWatcher: vi.fn(), state: "Error" } + ;(manager as any)._orchestrator = { stopWatcher: vi.fn(), stopIndexing: vi.fn(), state: "Error" } ;(manager as any)._searchService = {} ;(manager as any)._serviceFactory = {} }) @@ -592,7 +598,7 @@ describe("CodeIndexManager - handleSettingsChange regression", () => { // Setup manager with service instances ;(manager as any)._configManager = mockConfigManager ;(manager as any)._serviceFactory = {} - ;(manager as any)._orchestrator = { stopWatcher: vi.fn() } + ;(manager as any)._orchestrator = { stopWatcher: vi.fn(), stopIndexing: vi.fn() } ;(manager as any)._searchService = {} // Spy on console.error @@ -620,6 +626,8 @@ describe("CodeIndexManager - handleSettingsChange regression", () => { describe("workspace-enabled gating", () => { it("should not start indexing when workspace is not enabled", async () => { + await manager.setAutoEnableDefault(false) + const mockStateManager = (manager as any)._stateManager mockStateManager.setSystemState = vi.fn() mockStateManager.getCurrentStatus = vi.fn().mockReturnValue({ @@ -637,7 +645,9 @@ describe("CodeIndexManager - handleSettingsChange regression", () => { expect(mockStateManager.setSystemState).not.toHaveBeenCalledWith("Indexing", expect.any(String)) }) - it("should include workspaceEnabled in getCurrentStatus", () => { + it("should include workspaceEnabled in getCurrentStatus", async () => { + await manager.setAutoEnableDefault(false) + const mockStateManager = (manager as any)._stateManager mockStateManager.getCurrentStatus = vi.fn().mockReturnValue({ systemStatus: "Standby", @@ -652,6 +662,7 @@ describe("CodeIndexManager - handleSettingsChange regression", () => { }) it("should persist workspace enabled state", async () => { + await manager.setAutoEnableDefault(false) expect(manager.isWorkspaceEnabled).toBe(false) await manager.setWorkspaceEnabled(true) @@ -662,6 +673,8 @@ describe("CodeIndexManager - handleSettingsChange regression", () => { }) it("should store enablement per folder, not per window", async () => { + await manager.setAutoEnableDefault(false) + // Enable indexing for the current manager's folder await manager.setWorkspaceEnabled(true) expect(manager.isWorkspaceEnabled).toBe(true) diff --git a/src/services/code-index/manager.ts b/src/services/code-index/manager.ts index e98593ff55e..d6eb9247988 100644 --- a/src/services/code-index/manager.ts +++ b/src/services/code-index/manager.ts @@ -76,13 +76,26 @@ export class CodeIndexManager { // --- Public API --- public get isWorkspaceEnabled(): boolean { - return this.context.workspaceState.get(`codeIndexWorkspaceEnabled:${this.workspacePath}`, false) + const explicit = this.context.workspaceState.get( + `codeIndexWorkspaceEnabled:${this.workspacePath}`, + undefined, + ) + if (explicit !== undefined) return explicit + return this.autoEnableDefault } public async setWorkspaceEnabled(enabled: boolean): Promise { await this.context.workspaceState.update(`codeIndexWorkspaceEnabled:${this.workspacePath}`, enabled) } + public get autoEnableDefault(): boolean { + return this.context.globalState.get("codeIndexAutoEnableDefault", true) + } + + public async setAutoEnableDefault(enabled: boolean): Promise { + await this.context.globalState.update("codeIndexAutoEnableDefault", enabled) + } + public get onProgressUpdate() { return this._stateManager.onProgressUpdate } @@ -293,6 +306,7 @@ export class CodeIndexManager { ...status, workspacePath: this.workspacePath, workspaceEnabled: this.isWorkspaceEnabled, + autoEnableDefault: this.autoEnableDefault, } } diff --git a/webview-ui/src/components/chat/CodeIndexPopover.tsx b/webview-ui/src/components/chat/CodeIndexPopover.tsx index 924ea5648c4..763c243ec1e 100644 --- a/webview-ui/src/components/chat/CodeIndexPopover.tsx +++ b/webview-ui/src/components/chat/CodeIndexPopover.tsx @@ -1590,9 +1590,32 @@ export const CodeIndexPopover: React.FC = ({ )}
+ {/* Auto-enable default */} + {currentSettings.codebaseIndexEnabled && ( +
+ + vscode.postMessage({ + type: "setAutoEnableDefault", + bool: e.target.checked, + }) + } + className="accent-vscode-focusBorder" + /> + +
+ )} + {/* Workspace Toggle */} {currentSettings.codebaseIndexEnabled && ( -
+
a les preferències del teu IDE.", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index d6045d2e88a..1d2abfc096b 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -215,7 +215,8 @@ "stopIndexingButton": "Indexierung stoppen", "stoppingButton": "Wird gestoppt...", "workspaceToggleLabel": "Indexierung für diesen Arbeitsbereich aktivieren", - "workspaceDisabledMessage": "Indexierung ist konfiguriert, aber nicht für diesen Arbeitsbereich aktiviert." + "workspaceDisabledMessage": "Indexierung ist konfiguriert, aber nicht für diesen Arbeitsbereich aktiviert.", + "autoEnableDefaultLabel": "Indexierung für neue Arbeitsbereiche automatisch aktivieren" }, "autoApprove": { "toggleShortcut": "Du kannst in deinen IDE-Einstellungen einen globalen Shortcut für diese Einstellung konfigurieren.", diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 5993cf6053a..b5595c5e829 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -278,7 +278,8 @@ "stopIndexingButton": "Stop Indexing", "stoppingButton": "Stopping...", "workspaceToggleLabel": "Enable indexing for this workspace", - "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace." + "workspaceDisabledMessage": "Indexing is configured but not enabled for this workspace.", + "autoEnableDefaultLabel": "Auto-enable indexing for new workspaces" }, "autoApprove": { "description": "Run these actions without asking for permission. Only enable for actions you fully trust and if you understand the security risks.", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 49be315dae2..19f1cbb3cc0 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -215,7 +215,8 @@ "stopIndexingButton": "Detener indexación", "stoppingButton": "Deteniendo...", "workspaceToggleLabel": "Activar indexación para este espacio de trabajo", - "workspaceDisabledMessage": "La indexación está configurada pero no habilitada para este espacio de trabajo." + "workspaceDisabledMessage": "La indexación está configurada pero no habilitada para este espacio de trabajo.", + "autoEnableDefaultLabel": "Habilitar automáticamente la indexación para nuevos espacios de trabajo" }, "autoApprove": { "toggleShortcut": "Puedes configurar un atajo global para esta configuración en las preferencias de tu IDE.", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 50ce8e27e35..ea476f08e02 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -215,7 +215,8 @@ "stopIndexingButton": "Arrêter l'indexation", "stoppingButton": "Arrêt en cours...", "workspaceToggleLabel": "Activer l'indexation pour cet espace de travail", - "workspaceDisabledMessage": "L'indexation est configurée mais non activée pour cet espace de travail." + "workspaceDisabledMessage": "L'indexation est configurée mais non activée pour cet espace de travail.", + "autoEnableDefaultLabel": "Activer automatiquement l'indexation pour les nouveaux espaces de travail" }, "autoApprove": { "toggleShortcut": "Vous pouvez configurer un raccourci global pour ce paramètre dans les préférences de votre IDE.", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 666892cb0be..5e523e5e6cd 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -215,7 +215,8 @@ "stopIndexingButton": "इंडेक्सिंग रोकें", "stoppingButton": "रोक रहा है...", "workspaceToggleLabel": "इस वर्कस्पेस के लिए इंडेक्सिंग सक्षम करें", - "workspaceDisabledMessage": "इंडेक्सिंग कॉन्फ़िगर की गई है लेकिन इस वर्कस्पेस के लिए सक्षम नहीं है।" + "workspaceDisabledMessage": "इंडेक्सिंग कॉन्फ़िगर की गई है लेकिन इस वर्कस्पेस के लिए सक्षम नहीं है।", + "autoEnableDefaultLabel": "नए वर्कस्पेस के लिए स्वचालित रूप से इंडेक्सिंग सक्षम करें" }, "autoApprove": { "toggleShortcut": "आप अपनी आईडीई वरीयताओं में इस सेटिंग के लिए एक वैश्विक शॉर्टकट कॉन्फ़िगर कर सकते हैं।", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 5a98f4be758..ac940f9a505 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -215,7 +215,8 @@ "stopIndexingButton": "Hentikan pengindeksan", "stoppingButton": "Menghentikan...", "workspaceToggleLabel": "Aktifkan pengindeksan untuk ruang kerja ini", - "workspaceDisabledMessage": "Pengindeksan dikonfigurasi tetapi tidak diaktifkan untuk ruang kerja ini." + "workspaceDisabledMessage": "Pengindeksan dikonfigurasi tetapi tidak diaktifkan untuk ruang kerja ini.", + "autoEnableDefaultLabel": "Aktifkan pengindeksan secara otomatis untuk ruang kerja baru" }, "autoApprove": { "toggleShortcut": "Anda dapat mengonfigurasi pintasan global untuk pengaturan ini di preferensi IDE Anda.", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index bac3533e9d6..79297f130fd 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -215,7 +215,8 @@ "stopIndexingButton": "Interrompi indicizzazione", "stoppingButton": "Interruzione...", "workspaceToggleLabel": "Abilita l'indicizzazione per questo workspace", - "workspaceDisabledMessage": "L'indicizzazione è configurata ma non abilitata per questo workspace." + "workspaceDisabledMessage": "L'indicizzazione è configurata ma non abilitata per questo workspace.", + "autoEnableDefaultLabel": "Abilita automaticamente l'indicizzazione per i nuovi workspace" }, "autoApprove": { "toggleShortcut": "Puoi configurare una scorciatoia globale per questa impostazione nelle preferenze del tuo IDE.", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 14460c84cc1..25ebd575c8e 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -215,7 +215,8 @@ "stopIndexingButton": "インデックス作成を停止", "stoppingButton": "停止中...", "workspaceToggleLabel": "このワークスペースのインデックス作成を有効にする", - "workspaceDisabledMessage": "インデックス作成は設定済みですが、このワークスペースでは有効になっていません。" + "workspaceDisabledMessage": "インデックス作成は設定済みですが、このワークスペースでは有効になっていません。", + "autoEnableDefaultLabel": "新しいワークスペースのインデックス作成を自動的に有効にする" }, "autoApprove": { "toggleShortcut": "IDEの環境設定で、この設定のグローバルショートカットを設定できます。", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index dd48bbc54b4..5ff16d00f8c 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -215,7 +215,8 @@ "stopIndexingButton": "인덱싱 중지", "stoppingButton": "중지 중...", "workspaceToggleLabel": "이 워크스페이스에 대한 인덱싱 활성화", - "workspaceDisabledMessage": "인덱싱이 구성되었지만 이 워크스페이스에서는 활성화되지 않았습니다." + "workspaceDisabledMessage": "인덱싱이 구성되었지만 이 워크스페이스에서는 활성화되지 않았습니다.", + "autoEnableDefaultLabel": "새 워크스페이스에 대한 인덱싱 자동 활성화" }, "autoApprove": { "toggleShortcut": "IDE 환경 설정에서 이 설정에 대한 전역 바로 가기를 구성할 수 있습니다.", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 50815bbfc11..55c9cdac6fd 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -215,7 +215,8 @@ "stopIndexingButton": "Indexering stoppen", "stoppingButton": "Stoppen...", "workspaceToggleLabel": "Indexering inschakelen voor deze werkruimte", - "workspaceDisabledMessage": "Indexering is geconfigureerd maar niet ingeschakeld voor deze werkruimte." + "workspaceDisabledMessage": "Indexering is geconfigureerd maar niet ingeschakeld voor deze werkruimte.", + "autoEnableDefaultLabel": "Indexering automatisch inschakelen voor nieuwe werkruimtes" }, "autoApprove": { "toggleShortcut": "U kunt een globale sneltoets voor deze instelling configureren in de voorkeuren van uw IDE.", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 136601609a8..4f70809e78b 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -215,7 +215,8 @@ "stopIndexingButton": "Zatrzymaj indeksowanie", "stoppingButton": "Zatrzymywanie...", "workspaceToggleLabel": "Włącz indeksowanie dla tego workspace'a", - "workspaceDisabledMessage": "Indeksowanie jest skonfigurowane, ale nie włączone dla tego workspace'a." + "workspaceDisabledMessage": "Indeksowanie jest skonfigurowane, ale nie włączone dla tego workspace'a.", + "autoEnableDefaultLabel": "Automatycznie włączaj indeksowanie dla nowych workspace'ów" }, "autoApprove": { "toggleShortcut": "Możesz skonfigurować globalny skrót dla tego ustawienia w preferencjach swojego IDE.", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index 322a959598f..ba68f18eff8 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -215,7 +215,8 @@ "stopIndexingButton": "Parar indexação", "stoppingButton": "Parando...", "workspaceToggleLabel": "Ativar indexação para este workspace", - "workspaceDisabledMessage": "A indexação está configurada, mas não ativada para este workspace." + "workspaceDisabledMessage": "A indexação está configurada, mas não ativada para este workspace.", + "autoEnableDefaultLabel": "Ativar indexação automaticamente para novos workspaces" }, "autoApprove": { "toggleShortcut": "Você pode configurar um atalho global para esta configuração nas preferências do seu IDE.", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 1ea9bffc86a..8c49bf6ee8d 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -215,7 +215,8 @@ "stopIndexingButton": "Остановить индексацию", "stoppingButton": "Остановка...", "workspaceToggleLabel": "Включить индексацию для этого рабочего пространства", - "workspaceDisabledMessage": "Индексация настроена, но не включена для этого рабочего пространства." + "workspaceDisabledMessage": "Индексация настроена, но не включена для этого рабочего пространства.", + "autoEnableDefaultLabel": "Автоматически включать индексацию для новых рабочих пространств" }, "autoApprove": { "toggleShortcut": "Вы можете настроить глобальное сочетание клавиш для этого параметра в настройках вашей IDE.", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 79121f20075..73178c816ff 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -215,7 +215,8 @@ "stopIndexingButton": "İndekslemeyi durdur", "stoppingButton": "Durduruluyor...", "workspaceToggleLabel": "Bu çalışma alanı için indekslemeyi etkinleştir", - "workspaceDisabledMessage": "İndeksleme yapılandırıldı ancak bu çalışma alanı için etkinleştirilmedi." + "workspaceDisabledMessage": "İndeksleme yapılandırıldı ancak bu çalışma alanı için etkinleştirilmedi.", + "autoEnableDefaultLabel": "Yeni çalışma alanları için indekslemeyi otomatik etkinleştir" }, "autoApprove": { "toggleShortcut": "IDE tercihlerinizde bu ayar için genel bir kısayol yapılandırabilirsiniz.", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index d070ef68018..ba1776471e7 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -215,7 +215,8 @@ "stopIndexingButton": "Dừng lập chỉ mục", "stoppingButton": "Đang dừng...", "workspaceToggleLabel": "Bật lập chỉ mục cho không gian làm việc này", - "workspaceDisabledMessage": "Lập chỉ mục đã được cấu hình nhưng chưa được bật cho không gian làm việc này." + "workspaceDisabledMessage": "Lập chỉ mục đã được cấu hình nhưng chưa được bật cho không gian làm việc này.", + "autoEnableDefaultLabel": "Tự động bật lập chỉ mục cho không gian làm việc mới" }, "autoApprove": { "toggleShortcut": "Bạn có thể định cấu hình một phím tắt chung cho cài đặt này trong tùy chọn IDE của bạn.", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 575cfffe415..d35bb63d726 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -215,7 +215,8 @@ "stopIndexingButton": "停止索引", "stoppingButton": "正在停止...", "workspaceToggleLabel": "为此工作区启用索引", - "workspaceDisabledMessage": "索引已配置,但尚未为此工作区启用。" + "workspaceDisabledMessage": "索引已配置,但尚未为此工作区启用。", + "autoEnableDefaultLabel": "自动为新工作区启用索引" }, "autoApprove": { "toggleShortcut": "您可以在 IDE 首选项中为此设置配置全局快捷方式。", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 51bd4a2474d..e1e8709d81a 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -225,7 +225,8 @@ "stopIndexingButton": "停止索引", "stoppingButton": "正在停止...", "workspaceToggleLabel": "為此工作區啟用索引", - "workspaceDisabledMessage": "索引已設定,但尚未為此工作區啟用。" + "workspaceDisabledMessage": "索引已設定,但尚未為此工作區啟用。", + "autoEnableDefaultLabel": "自動為新工作區啟用索引" }, "autoApprove": { "description": "無需詢問許可即可執行下列動作。請僅在您完全信任且了解安全風險的情況下啟用此功能。", From 051f80e9d860f35d9f1d5c6b38fdaf277138fff9 Mon Sep 17 00:00:00 2001 From: James Mtendamema Date: Fri, 13 Feb 2026 01:17:13 -0700 Subject: [PATCH 7/9] fix: stop/start indexer when auto-enable default changes effective state --- src/core/webview/webviewMessageHandler.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index d569f11c9db..47d020f51ed 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -2698,7 +2698,15 @@ export const webviewMessageHandler = async ( provider.log("Cannot set auto-enable default: No workspace folder open") return } + const wasEnabled = manager.isWorkspaceEnabled await manager.setAutoEnableDefault(message.bool ?? true) + const isNowEnabled = manager.isWorkspaceEnabled + if (wasEnabled && !isNowEnabled) { + manager.stopIndexing() + } else if (!wasEnabled && isNowEnabled && manager.isFeatureEnabled && manager.isFeatureConfigured) { + await manager.initialize(provider.contextProxy) + manager.startIndexing() + } provider.postMessageToWebview({ type: "indexingStatusUpdate", values: manager.getCurrentStatus(), From 6f4be506f5bda825dbb5d40a3e34e3b52bf22eea Mon Sep 17 00:00:00 2001 From: James Mtendamema Date: Fri, 13 Feb 2026 01:41:55 -0700 Subject: [PATCH 8/9] fix: URI-keyed enablement, throw AbortError in back-pressure, stopWatcher on early-return --- .../code-index/__tests__/manager.spec.ts | 91 ++++++++++++++++--- src/services/code-index/manager.ts | 50 +++++++--- src/services/code-index/orchestrator.ts | 2 + src/services/code-index/processors/scanner.ts | 4 +- 4 files changed, 120 insertions(+), 27 deletions(-) diff --git a/src/services/code-index/__tests__/manager.spec.ts b/src/services/code-index/__tests__/manager.spec.ts index 2a17f1042db..49a6d91c767 100644 --- a/src/services/code-index/__tests__/manager.spec.ts +++ b/src/services/code-index/__tests__/manager.spec.ts @@ -3,18 +3,45 @@ import { CodeIndexServiceFactory } from "../service-factory" import type { MockedClass } from "vitest" import * as path from "path" +// Helper: create a mock vscode.Uri from an fsPath +function mockUri(fsPath: string, scheme = "file") { + return { + fsPath, + scheme, + authority: "", + path: fsPath, + toString: (skipEncoding?: boolean) => `${scheme}://${fsPath}`, + } +} + // Mock vscode module vi.mock("vscode", () => { const testPath = require("path") const testWorkspacePath = testPath.join(testPath.sep, "test", "workspace") return { + Uri: { + file: (p: string) => ({ + fsPath: p, + scheme: "file", + authority: "", + path: p, + toString: (_skipEncoding?: boolean) => `file://${p}`, + }), + joinPath: vi.fn((...args: any[]) => ({ fsPath: args.join("/") })), + }, window: { activeTextEditor: null, }, workspace: { workspaceFolders: [ { - uri: { fsPath: testWorkspacePath }, + uri: { + fsPath: testWorkspacePath, + scheme: "file", + authority: "", + path: testWorkspacePath, + toString: (_skipEncoding?: boolean) => `file://${testWorkspacePath}`, + }, name: "test", index: 0, }, @@ -25,8 +52,9 @@ vi.mock("vscode", () => { onDidDelete: vi.fn().mockReturnValue({ dispose: vi.fn() }), dispose: vi.fn(), }), + getWorkspaceFolder: vi.fn(), }, - RelativePattern: vi.fn().mockImplementation((base, pattern) => ({ base, pattern })), + RelativePattern: vi.fn().mockImplementation((base: any, pattern: any) => ({ base, pattern })), } }) @@ -672,18 +700,59 @@ describe("CodeIndexManager - handleSettingsChange regression", () => { expect(manager.isWorkspaceEnabled).toBe(false) }) - it("should store enablement per folder, not per window", async () => { - await manager.setAutoEnableDefault(false) + it("should store enablement per folder URI, not per window", async () => { + CodeIndexManager.disposeAll() + + const vscode = await import("vscode") + + const folderAPath = path.join(path.sep, "test", "folderA") + const folderBPath = path.join(path.sep, "test", "folderB") + const folderAUri = mockUri(folderAPath) + const folderBUri = mockUri(folderBPath) + + // Both folders share the same workspaceState (same window) + const sharedStore: Record = {} + const sharedContext = { + ...mockContext, + workspaceState: { + get: vi.fn((key: string, defaultValue?: any) => sharedStore[key] ?? defaultValue), + update: vi.fn(async (key: string, value: any) => { + sharedStore[key] = value + }), + } as any, + globalState: { + get: vi.fn((_key: string, _defaultValue?: any) => false), + update: vi.fn(), + } as any, + } - // Enable indexing for the current manager's folder - await manager.setWorkspaceEnabled(true) - expect(manager.isWorkspaceEnabled).toBe(true) + // Patch workspaceFolders to include both folders + ;(vscode.workspace as any).workspaceFolders = [ + { uri: folderAUri, name: "folderA", index: 0 }, + { uri: folderBUri, name: "folderB", index: 1 }, + ] + + const managerA = CodeIndexManager.getInstance(sharedContext as any, folderAPath)! + const managerB = CodeIndexManager.getInstance(sharedContext as any, folderBPath)! + + // Both start disabled (autoEnableDefault is false via globalState mock) + expect(managerA.isWorkspaceEnabled).toBe(false) + expect(managerB.isWorkspaceEnabled).toBe(false) + + // Enable A only + await managerA.setWorkspaceEnabled(true) + + expect(managerA.isWorkspaceEnabled).toBe(true) + expect(managerB.isWorkspaceEnabled).toBe(false) + + // Enable B, disable A + await managerB.setWorkspaceEnabled(true) + await managerA.setWorkspaceEnabled(false) - // Create a second manager for a different folder path - const otherManager = CodeIndexManager.getInstance(mockContext as any, "/other/workspace")! + expect(managerA.isWorkspaceEnabled).toBe(false) + expect(managerB.isWorkspaceEnabled).toBe(true) - // The other folder should NOT be enabled — keys are per-folder - expect(otherManager.isWorkspaceEnabled).toBe(false) + CodeIndexManager.disposeAll() }) }) diff --git a/src/services/code-index/manager.ts b/src/services/code-index/manager.ts index d6eb9247988..d0ef4ccc30a 100644 --- a/src/services/code-index/manager.ts +++ b/src/services/code-index/manager.ts @@ -32,26 +32,39 @@ export class CodeIndexManager { private _isRecoveringFromError = false public static getInstance(context: vscode.ExtensionContext, workspacePath?: string): CodeIndexManager | undefined { - // If workspacePath is not provided, try to get it from the active editor or first workspace folder - if (!workspacePath) { + // Resolve the workspace folder to get both fsPath and the real URI + let folder: vscode.WorkspaceFolder | undefined + + if (workspacePath) { + folder = vscode.workspace.workspaceFolders?.find((f) => f.uri.fsPath === workspacePath) + } else { const activeEditor = vscode.window.activeTextEditor if (activeEditor) { - const workspaceFolder = vscode.workspace.getWorkspaceFolder(activeEditor.document.uri) - workspacePath = workspaceFolder?.uri.fsPath + folder = vscode.workspace.getWorkspaceFolder(activeEditor.document.uri) } - - if (!workspacePath) { + if (!folder) { const workspaceFolders = vscode.workspace.workspaceFolders if (!workspaceFolders || workspaceFolders.length === 0) { return undefined } - // Use the first workspace folder as fallback - workspacePath = workspaceFolders[0].uri.fsPath + folder = workspaceFolders[0] } + workspacePath = folder.uri.fsPath } if (!CodeIndexManager.instances.has(workspacePath)) { - CodeIndexManager.instances.set(workspacePath, new CodeIndexManager(workspacePath, context)) + // folder may be undefined when workspacePath was provided but doesn't match + // any workspace folder (e.g. cwd passed from a tool). Fall back to file:// URI. + const folderUri = + folder?.uri ?? + ({ + fsPath: workspacePath, + scheme: "file", + authority: "", + path: workspacePath, + toString: () => `file://${workspacePath}`, + } as unknown as vscode.Uri) + CodeIndexManager.instances.set(workspacePath, new CodeIndexManager(workspacePath, folderUri, context)) } return CodeIndexManager.instances.get(workspacePath)! } @@ -64,28 +77,35 @@ export class CodeIndexManager { } private readonly workspacePath: string + private readonly _folderUri: vscode.Uri private readonly context: vscode.ExtensionContext // Private constructor for singleton pattern - private constructor(workspacePath: string, context: vscode.ExtensionContext) { + private constructor(workspacePath: string, folderUri: vscode.Uri, context: vscode.ExtensionContext) { this.workspacePath = workspacePath + this._folderUri = folderUri this.context = context this._stateManager = new CodeIndexStateManager() } // --- Public API --- + /** + * Returns the workspaceState key for per-folder indexing enablement, + * keyed by the real workspace folder URI so local/remote schemes cannot collide. + */ + private _workspaceEnabledKey(): string { + return "codeIndexWorkspaceEnabled:" + this._folderUri.toString(true) + } + public get isWorkspaceEnabled(): boolean { - const explicit = this.context.workspaceState.get( - `codeIndexWorkspaceEnabled:${this.workspacePath}`, - undefined, - ) + const explicit = this.context.workspaceState.get(this._workspaceEnabledKey(), undefined) if (explicit !== undefined) return explicit return this.autoEnableDefault } public async setWorkspaceEnabled(enabled: boolean): Promise { - await this.context.workspaceState.update(`codeIndexWorkspaceEnabled:${this.workspacePath}`, enabled) + await this.context.workspaceState.update(this._workspaceEnabledKey(), enabled) } public get autoEnableDefault(): boolean { diff --git a/src/services/code-index/orchestrator.ts b/src/services/code-index/orchestrator.ts index 21adaa82832..cd65fceb5ef 100644 --- a/src/services/code-index/orchestrator.ts +++ b/src/services/code-index/orchestrator.ts @@ -186,6 +186,7 @@ export class CodeIndexOrchestrator { if (signal.aborted) { await this.cacheManager.flush() + this.stopWatcher() this.stateManager.setSystemState("Standby", t("embeddings:orchestrator.indexingStopped")) return } @@ -246,6 +247,7 @@ export class CodeIndexOrchestrator { if (signal.aborted) { await this.cacheManager.flush() + this.stopWatcher() this.stateManager.setSystemState("Standby", t("embeddings:orchestrator.indexingStopped")) return } diff --git a/src/services/code-index/processors/scanner.ts b/src/services/code-index/processors/scanner.ts index 7ea9b52d795..5d9ff5e362d 100644 --- a/src/services/code-index/processors/scanner.ts +++ b/src/services/code-index/processors/scanner.ts @@ -185,7 +185,9 @@ export class DirectoryScanner implements IDirectoryScanner { if (currentBatchBlocks.length >= this.batchSegmentThreshold) { // Wait if we've reached the maximum pending batches while (pendingBatchCount >= MAX_PENDING_BATCHES) { - if (signal?.aborted) break + if (signal?.aborted) { + throw new DOMException("Indexing aborted", "AbortError") + } await Promise.race(activeBatchPromises) } From 332bd0e71e2d3a804f42a7e39e68c70732b4b502 Mon Sep 17 00:00:00 2001 From: James Mtendamema Date: Fri, 13 Feb 2026 10:52:00 -0700 Subject: [PATCH 9/9] fix: iterate all managers when auto-enable default changes in multi-root workspaces --- src/core/webview/webviewMessageHandler.ts | 21 ++++++++++++++------- src/services/code-index/manager.ts | 4 ++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 47d020f51ed..ddeff675697 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -44,6 +44,7 @@ import { Package } from "../../shared/package" import { type RouterName, toRouterName } from "../../shared/api" import { MessageEnhancer } from "./messageEnhancer" +import { CodeIndexManager } from "../../services/code-index/manager" import { checkExistKey } from "../../shared/checkExistApiConfig" import { experimentDefault } from "../../shared/experiments" import { Terminal } from "../../integrations/terminal/Terminal" @@ -2698,14 +2699,20 @@ export const webviewMessageHandler = async ( provider.log("Cannot set auto-enable default: No workspace folder open") return } - const wasEnabled = manager.isWorkspaceEnabled + // Capture prior state for every manager before persisting the global change + const allManagers = CodeIndexManager.getAllInstances() + const priorStates = new Map(allManagers.map((m) => [m, m.isWorkspaceEnabled])) await manager.setAutoEnableDefault(message.bool ?? true) - const isNowEnabled = manager.isWorkspaceEnabled - if (wasEnabled && !isNowEnabled) { - manager.stopIndexing() - } else if (!wasEnabled && isNowEnabled && manager.isFeatureEnabled && manager.isFeatureConfigured) { - await manager.initialize(provider.contextProxy) - manager.startIndexing() + // Apply stop/start to every affected manager + for (const m of allManagers) { + const wasEnabled = priorStates.get(m)! + const isNowEnabled = m.isWorkspaceEnabled + if (wasEnabled && !isNowEnabled) { + m.stopIndexing() + } else if (!wasEnabled && isNowEnabled && m.isFeatureEnabled && m.isFeatureConfigured) { + await m.initialize(provider.contextProxy) + m.startIndexing() + } } provider.postMessageToWebview({ type: "indexingStatusUpdate", diff --git a/src/services/code-index/manager.ts b/src/services/code-index/manager.ts index d0ef4ccc30a..91ea515e402 100644 --- a/src/services/code-index/manager.ts +++ b/src/services/code-index/manager.ts @@ -69,6 +69,10 @@ export class CodeIndexManager { return CodeIndexManager.instances.get(workspacePath)! } + public static getAllInstances(): CodeIndexManager[] { + return Array.from(CodeIndexManager.instances.values()) + } + public static disposeAll(): void { for (const instance of CodeIndexManager.instances.values()) { instance.dispose()