feat: add per-workspace indexing opt-in and stop/cancel control#11456
feat: add per-workspace indexing opt-in and stop/cancel control#11456JamesRobert20 wants to merge 9 commits intoRooCodeInc:mainfrom
Conversation
- 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
- 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
All previously flagged issues have been addressed as of 332bd0e. The multi-root
Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues. |
src/services/code-index/manager.ts
Outdated
| // 5. Check workspace-level enablement | ||
| if (!this.isWorkspaceEnabled) { | ||
| this._stateManager.setSystemState("Standby", "Indexing not enabled for this workspace") | ||
| return { requiresRestart } | ||
| } |
There was a problem hiding this comment.
This workspace-enabled check runs after _recreateServices() (step 4, a few lines above). On extension activation, initialize() is called for every workspace folder (extension.ts:182). Since isWorkspaceEnabled defaults to false, every workspace with global indexing enabled will create Qdrant connections, embedder instances, run embedder validation (potentially making network calls), instantiate scanner/fileWatcher, etc. -- then discard all of it here. Moving this check before the needsServiceRecreation / _recreateServices() block would avoid that wasted work on every disabled workspace.
Fix it with Roo Code or mention @roomote and request a fix.
src/i18n/locales/de/embeddings.json
Outdated
| "indexingRequiresWorkspace": "Indexierung erfordert einen offenen Workspace-Ordner", | ||
| "indexingStopped": "Indexing stopped by user.", |
There was a problem hiding this comment.
The new keys (indexingStopped, indexingStoppedPartial) are in English here and across all 17 non-English locale files (embeddings.json, chat.json, settings.json). The existing keys in these files are properly translated (e.g., this file has "Datei-Watcher gestoppt." above). Leaving these untranslated means non-English users will see English strings for the new stop/workspace controls while the rest of the UI is localized.
Fix it with Roo Code or mention @roomote and request a 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
0xMink
left a comment
There was a problem hiding this comment.
Blocking clarification (semantics): In this repo, indexing runtime instances are per-workspace-folder (one manager/indexer per root), but the PR stores codeIndexWorkspaceEnabled as a single workspaceState boolean. That makes enablement effectively per-window, not per-folder, in multi-root workspaces.
Issue #11455 explicitly calls out multi-root severity; please confirm the intended granularity:
- "Enable indexing for this workspace" == enable for the whole multi-root window (all folders), or
- Enable per root folder inside a multi-root workspace.
If (2) is intended, the fix is to store per-folder enablement keyed by folder URI/path (e.g., workspaceState.get("codeIndexWorkspaceEnabled:<folderKey>")), plus a unit test that proves folder A enabled does not enable folder B.
Non-blocking follow-ups worth tracking:
dispose()should abort any in-flight scan (avoids orphaned indexing after folder removal / deactivation).- Scanner back-pressure loop should check abort signal while waiting.
- Consider flushing debounced cache writes on abort (avoids unnecessary re-index on restart).
… translate i18n Addresses 0xMink review feedback: - Store workspace enablement keyed by folder path to support multi-root workspaces (codeIndexWorkspaceEnabled:<path> 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
|
Good catch, workspaceState is per-window. Switched the key to codeIndexWorkspaceEnabled:<folderPath> so each root folder gets its own toggle in multi-root workspaces. Added an isolation test too. Also addressed the other issues brought up:
|
| await manager.setAutoEnableDefault(message.bool ?? true) | ||
| provider.postMessageToWebview({ | ||
| type: "indexingStatusUpdate", | ||
| values: manager.getCurrentStatus(), | ||
| }) |
There was a problem hiding this comment.
When autoEnableDefault flips from true to false, the handler persists the setting and sends a status update, but it does not stop the orchestrator on workspaces that were implicitly enabled (no explicit per-workspace toggle). Since isWorkspaceEnabled falls back to autoEnableDefault, the workspace toggle in the UI will flip to unchecked, yet the indexer keeps running in the background. The toggleWorkspaceIndexing handler at line 2680 handles the analogous case by calling manager.stopIndexing(). This handler should do the same when the effective isWorkspaceEnabled becomes false.
| await manager.setAutoEnableDefault(message.bool ?? true) | |
| provider.postMessageToWebview({ | |
| type: "indexingStatusUpdate", | |
| values: manager.getCurrentStatus(), | |
| }) | |
| 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(), | |
| }) |
Fix it with Roo Code or mention @roomote and request a fix.
|
I compared against the latest PR head (d36d029). Three small deltas remain:
Patch (applies cleanly on d36d029): https://gist.github.com/0xMink/51a7326f4744fc0b93d760b103da9dd4 All 35 tests pass (manager 20, orchestrator 5, scanner 10). The patch also replaces the existing per-folder test with a stronger multi-root isolation test using two managers sharing the same |
|
Follow-up: rechecked against current PR head (051f80e). The three deltas remain:
The latest commit (051f80e) only touches |
Should now be addressed in latest commit |
765af53 to
d67e0e2
Compare
…cher on early-return
d67e0e2 to
6f4be50
Compare
All three previously flagged issues are resolved as of 6f4be50. One new low-severity issue found in the
Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues. |
| case "setAutoEnableDefault": { | ||
| try { | ||
| const manager = provider.getCurrentWorkspaceCodeIndexManager() | ||
| if (!manager) { | ||
| 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(), | ||
| }) | ||
| } catch (error) { | ||
| provider.log( | ||
| `Error setting auto-enable default: ${error instanceof Error ? error.message : String(error)}`, | ||
| ) | ||
| } | ||
| break |
There was a problem hiding this comment.
setAutoEnableDefault() writes to globalState, which affects isWorkspaceEnabled on every CodeIndexManager instance that has no explicit per-workspace toggle. However, this handler only calls stopIndexing() / startIndexing() on the current workspace's manager. In a multi-root workspace where folders B and C have no explicit workspace-level setting, flipping autoEnableDefault from true to false would leave their orchestrators indexing in the background while the UI (on next status request) would show them as disabled. The inverse (false to true) would similarly fail to start indexing on the other folders. A fix could iterate over all CodeIndexManager instances (e.g., via a new static accessor) and apply the stop/start logic to each affected manager.
Fix it with Roo Code or mention @roomote and request a fix.
Related GitHub Issue
Closes: #11455
Related: #10569
Description
Adds two features and one bug fix to the codebase indexing system:
Per-workspace opt-in: Indexing no longer auto-starts on every workspace. A new
codeIndexWorkspaceEnabled:<folderPath>flag (stored inworkspaceState, keyed per folder) requires users to explicitly enable indexing per root folder. In multi-root workspaces, enabling one folder does not enable others. The choice is remembered across sessions.Stop/cancel indexing: Users can stop an in-progress indexing operation via a "Stop Indexing" button. Uses
AbortController/AbortSignalthreaded through the orchestrator → scanner pipeline with graceful abort at file and batch boundaries. Debounced cache writes are flushed on abort to preserve progress.Disable toggle bug fix: Unchecking "Enable Codebase Indexing" during active indexing now properly stops the scan via
stopIndexing()instead of only callingstopWatcher(), which left the scanner running asynchronously and caused the yellow pulsing indicator to persist.Configurable auto-enable default: A global "Auto-enable indexing for new workspaces" toggle (default: ON) preserves backward compatibility while allowing users to opt into per-workspace control by setting it to OFF.
Test Procedure
Automated tests (35 tests, all passing):
Manual testing:
Pre-Submission Checklist
pnpm lintpassespnpm check-typespassespnpm knip— no new unused exportsminorbump createdDocumentation Updates
Screenshots / Videos