diff --git a/.changeset/agent-manager-terminal-rendering.md b/.changeset/agent-manager-terminal-rendering.md deleted file mode 100644 index c375a577662..00000000000 --- a/.changeset/agent-manager-terminal-rendering.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": minor ---- - -Improved command output rendering in Agent Manager with new CommandExecutionBlock component that displays terminal output with status indicators, collapsible output sections, and proper escape sequence handling. diff --git a/.changeset/am-base-branch-selection.md b/.changeset/am-base-branch-selection.md deleted file mode 100644 index 5d60e448d4f..00000000000 --- a/.changeset/am-base-branch-selection.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": minor ---- - -Add branch picker to Agent Manager for selecting base branch in worktree mode diff --git a/.changeset/clean-dogs-teach.md b/.changeset/clean-dogs-teach.md deleted file mode 100644 index 57c599f4594..00000000000 --- a/.changeset/clean-dogs-teach.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Add a tooltip explaining why speech-to-text may be unavailable diff --git a/.changeset/few-ducks-smoke.md b/.changeset/few-ducks-smoke.md deleted file mode 100644 index c240a509538..00000000000 --- a/.changeset/few-ducks-smoke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Added a snooze for autocomplete in the settings diff --git a/.changeset/green-cobras-dress.md b/.changeset/green-cobras-dress.md deleted file mode 100644 index 83017648a53..00000000000 --- a/.changeset/green-cobras-dress.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Fix text.startsWith is not a function crash diff --git a/.changeset/little-ravens-rest.md b/.changeset/little-ravens-rest.md deleted file mode 100644 index d56f2dded97..00000000000 --- a/.changeset/little-ravens-rest.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Fix image generation handler not using Kilo Gateway properly diff --git a/.changeset/neat-ghosts-argue.md b/.changeset/neat-ghosts-argue.md deleted file mode 100644 index adf36b41c51..00000000000 --- a/.changeset/neat-ghosts-argue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Prevent autocomplete from showing suggestions duplicating the previous or next line diff --git a/.changeset/silly-lamps-create.md b/.changeset/silly-lamps-create.md deleted file mode 100644 index 897d1154b5a..00000000000 --- a/.changeset/silly-lamps-create.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Fix duplicate tool processing in OpenAI-compatible provider diff --git a/.changeset/tall-rockets-brake.md b/.changeset/tall-rockets-brake.md deleted file mode 100644 index bb010658435..00000000000 --- a/.changeset/tall-rockets-brake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Normalize line endings in search and replace tool diff --git a/.changeset/wacky-lions-kiss.md b/.changeset/wacky-lions-kiss.md new file mode 100644 index 00000000000..be58208d287 --- /dev/null +++ b/.changeset/wacky-lions-kiss.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Change the default value of auto-approval for reading outside workspace to false diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c2cee44ea8..640da968382 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,33 @@ # kilo-code +## 4.139.0 + +### Minor Changes + +- [#4481](https://github.com/Kilo-Org/kilocode/pull/4481) [`61c951c`](https://github.com/Kilo-Org/kilocode/commit/61c951c0ad11d60b07406338b6053cc5d1f01cac) Thanks [@marius-kilocode](https://github.com/marius-kilocode)! - Improved command output rendering in Agent Manager with new CommandExecutionBlock component that displays terminal output with status indicators, collapsible output sections, and proper escape sequence handling. + +- [#4483](https://github.com/Kilo-Org/kilocode/pull/4483) [`fd639ab`](https://github.com/Kilo-Org/kilocode/commit/fd639ab78aa4ab62ea2d120bd2844d1160b20067) Thanks [@marius-kilocode](https://github.com/marius-kilocode)! - Add branch picker to Agent Manager for selecting base branch in worktree mode + +- [#4539](https://github.com/Kilo-Org/kilocode/pull/4539) [`62a0241`](https://github.com/Kilo-Org/kilocode/commit/62a02418cafa23a733f92a9e14ba904552acdcc4) Thanks [@brianc](https://github.com/brianc)! - Improve managed indexer error handling & backoff. + +### Patch Changes + +- [#4512](https://github.com/Kilo-Org/kilocode/pull/4512) [`f979b56`](https://github.com/Kilo-Org/kilocode/commit/f979b56b6a631eeeb671caaca276316b63b5fb82) Thanks [@hassoncs](https://github.com/hassoncs)! - Add a tooltip explaining why speech-to-text may be unavailable + +- [#4424](https://github.com/Kilo-Org/kilocode/pull/4424) [`cd0cd88`](https://github.com/Kilo-Org/kilocode/commit/cd0cd8833f0e892cc2f1c96bb24ede6254cf12c9) Thanks [@markijbema](https://github.com/markijbema)! - Added a snooze for autocomplete in the settings + +- [#4519](https://github.com/Kilo-Org/kilocode/pull/4519) [`a9fd203`](https://github.com/Kilo-Org/kilocode/commit/a9fd2038ecb60fd799d164bcf1b2e4393302d15a) Thanks [@chrarnoldus](https://github.com/chrarnoldus)! - Fix text.startsWith is not a function crash + +- [#4536](https://github.com/Kilo-Org/kilocode/pull/4536) [`51f4774`](https://github.com/Kilo-Org/kilocode/commit/51f4774adcb90778826e00e9a50c45bb7bf11bc8) Thanks [@kevinvandijk](https://github.com/kevinvandijk)! - Fix image generation handler not using Kilo Gateway properly + +- [#4491](https://github.com/Kilo-Org/kilocode/pull/4491) [`823b86f`](https://github.com/Kilo-Org/kilocode/commit/823b86f196868f12efc60e5acb9b385d014bc644) Thanks [@markijbema](https://github.com/markijbema)! - Prevent autocomplete from showing suggestions duplicating the previous or next line + +- [#4531](https://github.com/Kilo-Org/kilocode/pull/4531) [`9413d73`](https://github.com/Kilo-Org/kilocode/commit/9413d730814d88ac67c88e6eec9a66c2c701613e) Thanks [@chrarnoldus](https://github.com/chrarnoldus)! - Fix duplicate tool processing in OpenAI-compatible provider + +- [#4533](https://github.com/Kilo-Org/kilocode/pull/4533) [`20b2c29`](https://github.com/Kilo-Org/kilocode/commit/20b2c29140f401ac65d437e35c52b48329e5f52d) Thanks [@mcowger](https://github.com/mcowger)! - Add gemini-3-flash-preview model configuration to vertex models + +- [#4520](https://github.com/Kilo-Org/kilocode/pull/4520) [`8342fc4`](https://github.com/Kilo-Org/kilocode/commit/8342fc4fbdc2a83601c706e734ef3377ef114f98) Thanks [@chrarnoldus](https://github.com/chrarnoldus)! - Normalize line endings in search and replace tool + ## 4.138.0 ### Minor Changes diff --git a/apps/kilocode-docs/docs/features/auto-approving-actions.md b/apps/kilocode-docs/docs/features/auto-approving-actions.md index e3d2db8a2db..28726acb3f6 100644 --- a/apps/kilocode-docs/docs/features/auto-approving-actions.md +++ b/apps/kilocode-docs/docs/features/auto-approving-actions.md @@ -80,6 +80,22 @@ _Complete settings panel view_ **Risk level:** Medium While this setting only allows reading files (not modifying them), it could potentially expose sensitive data. Still recommended as a starting point for most users, but be mindful of what files Kilo Code can access. + +#### Read Outside Workspace + +**Setting:** "Allow reading files outside the workspace" + +**Description:** "When enabled, Kilo Code can read files outside the current workspace directory without asking for approval." + +**Risk level:** Medium-High + +This setting extends read permissions beyond your project folder. Consider the security implications: + +- Kilo Code could access sensitive files in your home directory +- Configuration files, SSH keys, or credentials could be read +- Only enable if you trust the AI and need it to access external files + +**Recommendation:** Keep disabled unless you specifically need Kilo Code to read files outside your project. ::: ### Write Operations @@ -102,25 +118,52 @@ This setting allows Kilo Code to modify your files without confirmation. The del - Lower values: Use only when speed is critical and you're in a controlled environment - Zero: No delay for diagnostics (not recommended for critical code) -#### Write Delay & Problems Pane Integration +#### Write Outside Workspace -VSCode Problems pane showing diagnostic information +**Setting:** "Allow writing files outside the workspace" -_VSCode Problems pane that Kilo Code checks during the write delay_ +**Description:** "When enabled, Kilo Code can create or modify files outside the current workspace directory without asking for approval." -When you enable auto-approval for writing files, the delay timer works with VSCode's Problems pane: +**Risk level:** Very High -1. Kilo Code makes a change to your file -2. VSCode's diagnostic tools analyze the change -3. The Problems pane updates with any errors or warnings -4. Kilo Code notices these issues before continuing +Use with caution and in controlled environments. It allows Kilo Code to: -This works like a human developer pausing to check for errors after changing code. You can adjust the delay time based on: +- Modify your shell configuration files +- Change system configurations +- Write to any location your user has access to -- Project complexity -- Language server speed -- How important error detection is for your workflow - ::: +**Recommendation:** Keep disabled unless absolutely necessary. Even experienced users should avoid this setting. + +#### Write to Protected Files + +**Setting:** "Allow writing to protected files" + +**Description:** "When enabled, Kilo Code can overwrite or modify files that are normally protected by the `.kilocodeignore` file." + +**Risk level:** Very High + +Protected files are intentionally shielded from modification. Enable only if you understand the consequences. + +### Delete Operations + +:::danger Delete Operations + +**Setting:** "Always approve delete operations" + +**Description:** "Automatically delete files and directories without requiring approval" + +**Risk level:** Very High + +This setting allows Kilo Code to permanently remove files without confirmation. + +**Safeguards:** + +- Kilo Code still respects `.kilocodeignore` rules +- Protected files cannot be deleted +- The delete tool shows what will be removed before execution + +**Recommendation:** Enable only in isolated environments or when working with temporary/generated files. Always ensure you have backups, checkpoints, or version control. +::: ### Browser Actions @@ -153,11 +196,11 @@ Consider the security implications of allowing automated browser access. **Description:** "Automatically retry failed API requests when server returns an error response" -**Delay slider:** "Delay before retrying the request" (Default: 5s) - **Risk level:** Low -This setting automatically retries API calls when they fail. The delay controls how long Kilo Code waits before trying again: +This setting automatically retries API calls when they fail. + +The delay controls how long Kilo Code waits before trying again: - Longer delays are gentler on API rate limits - Shorter delays give faster recovery from transient errors @@ -214,23 +257,34 @@ Enables Kilo Code to create and complete subtasks automatically. This relates to **Description:** "Automatically execute allowed terminal commands without requiring approval" -**Command management:** "Command prefixes that can be auto-executed when 'Always approve execute operations' is enabled. Add \* to allow all commands (use with caution)." - **Risk level:** High -This setting allows terminal command execution with controls. While risky, the whitelist feature limits what commands can run. Important security features: +This setting allows terminal command execution with controls. While risky, the allowlist and denylist features limit what commands can run. -- Whitelist specific command prefixes (recommended) +- Allowlist specific command prefixes (recommended) - Never use \* wildcard in production or with sensitive data - Consider security implications of each allowed command +- Consider including potentially dangerous common commands in the deny list - Always verify commands that interact with external systems +#### Allowed Commands + +**Setting:** "Command prefixes that can be auto-executed" + +Add command prefixes (e.g., `git`, `npm`, `ls`) that Kilo Code can run without asking. Use `*` to allow all commands (use with caution). + **Interface elements:** - Text field to enter command prefixes (e.g., 'git') - "Add" button to add new prefixes - Clickable command buttons with X to remove them - ::: + +#### Denied Commands + +**Setting:** "Command prefixes that are always blocked" + +Commands in this list will never run, even if `*` is in the allowed list. Use this to create exceptions for potentially dangerous commands. +::: ### Follow-Up Questions @@ -240,9 +294,9 @@ This setting allows terminal command execution with controls. While risky, the w **Description:** Automatically selects the first AI-suggested answer for a follow-up question after a configurable timeout. This speeds up your workflow by letting Kilo Code proceed without manual intervention. -**Visual countdown:** When enabled, a countdown timer appears on the first suggestion button, showing the remaining time before auto-selection. The timer is displayed as a circular progress indicator that depletes as time passes. +**Visual countdown:** When enabled, a countdown timer appears on the first suggestion button in the chat interface, showing the remaining time before auto-selection. The timer displays seconds remaining (e.g., "3s") and counts down in real-time. -**Timeout slider:** Use the slider to set the wait time from 1 to 300 seconds (Default: 60s). +**Timeout slider:** Use the slider to set the wait time (Range: 1-300 seconds, Default: 60s). **Override options:** You can cancel the auto-selection at any time by: @@ -277,13 +331,6 @@ This setting allows Kilo Code to automatically update task progress and todo lis - Updating task status (pending, in progress, completed) - Reorganizing task priorities -**Benefits:** - -- Maintains real-time task progress visibility -- Reduces interruptions during multi-step workflows -- Keeps project status accurately reflected -- Helps track complex task dependencies - **Use cases:** - Long-running development sessions @@ -294,7 +341,7 @@ This setting allows Kilo Code to automatically update task progress and todo lis This is particularly useful when combined with the Subtasks permission, as it allows Kilo Code to maintain a complete picture of project progress without constant approval requests. ::: -## YOLO mode +## YOLO Mode :::danger YOLO Mode (Risk: Maximum) diff --git a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-1.png b/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-1.png index a10c0fce509..679265c5c5a 100644 Binary files a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-1.png and b/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-1.png differ diff --git a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-10.png b/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-10.png deleted file mode 100644 index 75d8b2834e1..00000000000 Binary files a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-10.png and /dev/null differ diff --git a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-11.png b/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-11.png deleted file mode 100644 index 0b4e3ad7315..00000000000 Binary files a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-11.png and /dev/null differ diff --git a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-12.png b/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-12.png deleted file mode 100644 index b00c8b442cb..00000000000 Binary files a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-12.png and /dev/null differ diff --git a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-13.png b/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-13.png index d7afb227ad2..6998442dbc5 100644 Binary files a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-13.png and b/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-13.png differ diff --git a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-4.png b/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-4.png index 795e6d4ec85..aca74d783f9 100644 Binary files a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-4.png and b/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-4.png differ diff --git a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-5.png b/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-5.png deleted file mode 100644 index 67a78e503ed..00000000000 Binary files a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-5.png and /dev/null differ diff --git a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-6.png b/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-6.png deleted file mode 100644 index 428b3963671..00000000000 Binary files a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-6.png and /dev/null differ diff --git a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-7.png b/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-7.png deleted file mode 100644 index b99d3a12181..00000000000 Binary files a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-7.png and /dev/null differ diff --git a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-8.png b/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-8.png deleted file mode 100644 index d495e474ce9..00000000000 Binary files a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-8.png and /dev/null differ diff --git a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-9.png b/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-9.png index f5650cff7a2..238cbd30c77 100644 Binary files a/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-9.png and b/apps/kilocode-docs/static/img/auto-approving-actions/auto-approving-actions-9.png differ diff --git a/packages/types/src/providers/vertex.ts b/packages/types/src/providers/vertex.ts index 53b67418cf0..db7c90edafe 100644 --- a/packages/types/src/providers/vertex.ts +++ b/packages/types/src/providers/vertex.ts @@ -6,6 +6,19 @@ export type VertexModelId = keyof typeof vertexModels export const vertexDefaultModelId: VertexModelId = "claude-sonnet-4-5@20250929" export const vertexModels = { + "gemini-3-flash-preview": { + maxTokens: 65_536, + contextWindow: 1_048_576, + supportsImages: true, + supportsNativeTools: true, + supportsPromptCache: true, + supportsReasoningEffort: ["minimal", "low", "medium", "high"], + reasoningEffort: "medium", + supportsTemperature: true, + defaultTemperature: 1, + inputPrice: 0.5, + outputPrice: 3.0, + }, "gemini-3-pro-preview": { maxTokens: 65_536, contextWindow: 1_048_576, diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 52436dccdb1..d4008f7001c 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -2264,7 +2264,7 @@ ${prompt} apiConfiguration, customInstructions, alwaysAllowReadOnly: alwaysAllowReadOnly ?? true, - alwaysAllowReadOnlyOutsideWorkspace: alwaysAllowReadOnlyOutsideWorkspace ?? true, + alwaysAllowReadOnlyOutsideWorkspace: alwaysAllowReadOnlyOutsideWorkspace ?? false, alwaysAllowWrite: alwaysAllowWrite ?? true, alwaysAllowWriteOutsideWorkspace: alwaysAllowWriteOutsideWorkspace ?? false, alwaysAllowWriteProtected: alwaysAllowWriteProtected ?? false, @@ -2559,7 +2559,7 @@ ${prompt} customInstructions: stateValues.customInstructions, apiModelId: stateValues.apiModelId, alwaysAllowReadOnly: stateValues.alwaysAllowReadOnly ?? true, - alwaysAllowReadOnlyOutsideWorkspace: stateValues.alwaysAllowReadOnlyOutsideWorkspace ?? true, + alwaysAllowReadOnlyOutsideWorkspace: stateValues.alwaysAllowReadOnlyOutsideWorkspace ?? false, alwaysAllowWrite: stateValues.alwaysAllowWrite ?? true, alwaysAllowWriteOutsideWorkspace: stateValues.alwaysAllowWriteOutsideWorkspace ?? false, alwaysAllowWriteProtected: stateValues.alwaysAllowWriteProtected ?? false, diff --git a/src/package.json b/src/package.json index efe6a90785b..6594de000cc 100644 --- a/src/package.json +++ b/src/package.json @@ -3,7 +3,7 @@ "displayName": "%extension.displayName%", "description": "%extension.description%", "publisher": "kilocode", - "version": "4.138.0", + "version": "4.139.0", "icon": "assets/icons/logo-outline-black.png", "galleryBanner": { "color": "#FFFFFF", diff --git a/src/services/code-index/managed/ManagedIndexer.ts b/src/services/code-index/managed/ManagedIndexer.ts index 54f5900bf13..d38c414b8f3 100644 --- a/src/services/code-index/managed/ManagedIndexer.ts +++ b/src/services/code-index/managed/ManagedIndexer.ts @@ -63,6 +63,55 @@ interface ManagedIndexerWorkspaceFolderState { ignoreController: RooIgnoreController | null } +function logGitEvent(event: GitWatcherEvent) { + // Handle different event types + switch (event.type) { + case "branch-changed": { + console.info(`[ManagedIndexer] Branch changed from ${event.previousBranch} to ${event.newBranch}`) + break + } + + case "commit": { + console.info(`[ManagedIndexer] Commit detected from ${event.previousCommit} to ${event.newCommit}`) + break + } + + case "start": { + console.info( + `[ManagedIndexer] Watcher started on branch ${event.branch} ${event.isBaseBranch ? `(base)` : `(feature)`} - doing initial indexing`, + ) + break + } + } +} + +/** + * Serialize workspace folder state to a plain object for communication + * @param state The workspace folder state to serialize + * @returns A serializable object representation of the state + */ +function serializeWorkspaceFolderState(state: ManagedIndexerWorkspaceFolderState) { + return { + workspaceFolderPath: state.workspaceFolder.uri.fsPath, + workspaceFolderName: state.workspaceFolder.name, + gitBranch: state.gitBranch, + projectId: state.projectId, + repositoryUrl: state.repositoryUrl, + isIndexing: state.isIndexing, + hasManifest: !!state.manifest, + manifestFileCount: state.manifest ? Object.keys(state.manifest.files).length : 0, + hasWatcher: !!state.watcher, + error: state.error + ? { + type: state.error.type, + message: state.error.message, + timestamp: state.error.timestamp, + context: state.error.context, + } + : undefined, + } +} + export class ManagedIndexer implements vscode.Disposable { private static prevInstance: ManagedIndexer | null = null private disabledViaConfig: boolean = false @@ -154,40 +203,23 @@ export class ManagedIndexer implements vscode.Disposable { } /** - * Get a complete serializable snapshot of the managed indexer state - * for communication to the webview + * Send the complete managed indexer state to the webview */ - private getManagedIndexerStateSnapshot() { - return { + sendStateToWebview(stateOverride?: ManagedIndexerWorkspaceFolderState, fileCount?: number) { + const state = { isEnabled: this.isEnabled(), isActive: this.isActive, - workspaceFolders: this.workspaceFolderState.map((state) => ({ - workspaceFolderPath: state.workspaceFolder.uri.fsPath, - workspaceFolderName: state.workspaceFolder.name, - gitBranch: state.gitBranch, - projectId: state.projectId, - repositoryUrl: state.repositoryUrl, - isIndexing: state.isIndexing, - hasManifest: !!state.manifest, - manifestFileCount: state.manifest ? Object.keys(state.manifest.files).length : 0, - hasWatcher: !!state.watcher, - error: state.error - ? { - type: state.error.type, - message: state.error.message, - timestamp: state.error.timestamp, - context: state.error.context, - } - : undefined, - })), + workspaceFolders: this.workspaceFolderState.map(serializeWorkspaceFolderState), + } + if (stateOverride && fileCount) { + const index = this.workspaceFolderState.indexOf(stateOverride) + if (index > -1) { + const folderState = state.workspaceFolders[index] + if (folderState) { + folderState.manifestFileCount = fileCount + } + } } - } - - /** - * Send the complete managed indexer state to the webview - */ - sendStateToWebview() { - const state = this.getManagedIndexerStateSnapshot() const provider = ClineProvider.getVisibleInstance() if (provider) { provider.postMessageToWebview({ @@ -415,11 +447,6 @@ export class ManagedIndexer implements vscode.Disposable { return state.manifestFetchPromise } - // If manifest is already cached for this branch, return it - if (state.manifest && state.gitBranch === branch && !force) { - return state.manifest - } - // Update branch BEFORE starting fetch so concurrent calls know we're fetching for this branch state.gitBranch = branch @@ -517,43 +544,10 @@ export class ManagedIndexer implements vscode.Disposable { const controller = new AbortController() state.currentAbortController = controller - try { - // Handle different event types - switch (event.type) { - case "branch-changed": { - console.info(`[ManagedIndexer] Branch changed from ${event.previousBranch} to ${event.newBranch}`) - - try { - // Fetch manifest for the new branch (will reuse if already fetching) - await this.getManifest(state, event.newBranch) - } catch (error) { - // Error already logged and stored in getManifest - console.warn(`[ManagedIndexer] Continuing despite manifest fetch error`) - } - - // Process files from the async iterable - await this.processFiles(state, event, controller.signal) - break - } - - case "commit": { - console.info(`[ManagedIndexer] Commit detected from ${event.previousCommit} to ${event.newCommit}`) - - // Process files from the async iterable - await this.processFiles(state, event, controller.signal) - break - } + logGitEvent(event) - case "start": { - console.info( - `[ManagedIndexer] Watcher started on branch ${event.branch} ${event.isBaseBranch ? `(base)` : `(feature)`} - doing initial indexing`, - ) - - // Process files from the async iterable - await this.processFiles(state, event, controller.signal) - break - } - } + try { + await this.processFiles(state, event, controller.signal) } catch (error) { // Check if this was an abort if (error instanceof Error && (error.name === "AbortError" || error.message === "AbortError")) { @@ -597,6 +591,8 @@ export class ManagedIndexer implements vscode.Disposable { // Start with all files from manifest - we'll remove entries as we encounter them in git const manifestFilesToCheck = new Set(Object.values(manifest.files)) const filesToDelete: string[] = [] + let upsertCount = manifestFilesToCheck.size + let errorCount = 0 await pMap( event.files, @@ -610,6 +606,10 @@ export class ManagedIndexer implements vscode.Disposable { throw new Error("ManagedIndexing is not enabled") } + if (!this.isActive) { + return + } + const { filePath } = file if (file.type === "file-deleted") { @@ -636,90 +636,97 @@ export class ManagedIndexer implements vscode.Disposable { return } - { - // Check if operation was aborted before processing - if (signal.aborted) { - throw new Error("AbortError") + // Check if operation was aborted before processing + if (signal.aborted) { + throw new Error("AbortError") + } + + try { + // Ensure we have the necessary configuration + // check again inside loop as this can change mid-flight + if (!this.config?.kilocodeToken || !state.projectId) { + return + } + const projectId = state.projectId + + const absoluteFilePath = path.isAbsolute(filePath) + ? filePath + : path.join(event.watcher.config.cwd, filePath) + + // if file is larger than 1 megabyte, skip it + const stats = await fs.stat(absoluteFilePath) + if (stats.size > 1 * 1024 * 1024) { + return + } + + const fileBuffer = await fs.readFile(absoluteFilePath) + const relativeFilePath = path.relative(event.watcher.config.cwd, absoluteFilePath) + + // Check RooIgnoreController + const ignore = state.ignoreController + if (ignore && !ignore.validateAccess(relativeFilePath)) { + return } - try { - // Ensure we have the necessary configuration - // check again inside loop as this can change mid-flight - if (!this.config?.kilocodeToken || !state.projectId) { - return - } - const projectId = state.projectId - - const absoluteFilePath = path.isAbsolute(filePath) - ? filePath - : path.join(event.watcher.config.cwd, filePath) - - // if file is larger than 1 megabyte, skip it - const stats = await fs.stat(absoluteFilePath) - if (stats.size > 1 * 1024 * 1024) { - return - } - - const fileBuffer = await fs.readFile(absoluteFilePath) - const relativeFilePath = path.relative(event.watcher.config.cwd, absoluteFilePath) - - // Check RooIgnoreController - const ignore = state.ignoreController - if (ignore && !ignore.validateAccess(relativeFilePath)) { - return - } - - // Check hardcoded ignore list - if (shouldIgnoreFile(relativeFilePath)) { - return - } - - // Call the upsertFile API with abort signal - await upsertFile( - { - fileBuffer, - fileHash, - filePath: relativeFilePath, - gitBranch: event.branch, - isBaseBranch: event.isBaseBranch, - organizationId: this.config.kilocodeOrganizationId, - projectId, - kilocodeToken: this.config.kilocodeToken, - }, - signal, - ) - - // Clear any previous file-upsert errors on success - if (state.error?.type === "file-upsert") { - state.error = undefined - this.sendStateToWebview() - } - } catch (error) { - // Don't log abort errors as failures - if (error instanceof Error && error.message === "AbortError") { - throw error - } - - const errorMessage = error instanceof Error ? error.message : String(error) - console.error(`[ManagedIndexer] Failed to upsert file ${filePath}: ${errorMessage}`) - - // Store the error in state - state.error = { - type: "file-upsert", - message: `Failed to upsert file: ${errorMessage}`, - timestamp: new Date().toISOString(), - context: { - filePath, - branch: event.branch, - operation: "file-upsert", - }, - details: error instanceof Error ? error.stack : undefined, - } + // Check hardcoded ignore list + if (shouldIgnoreFile(relativeFilePath)) { + return + } + + // Call the upsertFile API with abort signal + await upsertFile( + { + fileBuffer, + fileHash, + filePath: relativeFilePath, + gitBranch: event.branch, + isBaseBranch: event.isBaseBranch, + organizationId: this.config.kilocodeOrganizationId, + projectId, + kilocodeToken: this.config.kilocodeToken, + }, + signal, + ) + + upsertCount++ + this.sendStateToWebview(state, upsertCount) + + // Clear any previous file-upsert errors on success + if (state.error?.type === "file-upsert") { + state.error = undefined this.sendStateToWebview() } + } catch (error) { + // Don't log abort errors as failures + if (error instanceof Error && error.message === "AbortError") { + throw error + } + + errorCount++ + // if we have 3 indexing errors, something is wrong....stop trying + if (errorCount > 2) { + this.dispose() + } + + const errorMessage = error instanceof Error ? error.message : String(error) + console.error(`[ManagedIndexer] Failed to upsert file ${filePath}: ${errorMessage}`) + + // Store the error in state + state.error = { + type: "file-upsert", + message: `Failed to upsert file: ${errorMessage}`, + timestamp: new Date().toISOString(), + context: { + filePath, + branch: event.branch, + operation: "file-upsert", + }, + details: error instanceof Error ? error.stack : undefined, + } + this.sendStateToWebview() } }, - { concurrency: 5 }, + { concurrency: 2 }, ) // Any files remaining in manifestFilesToCheck were not encountered in git @@ -784,31 +791,6 @@ export class ManagedIndexer implements vscode.Disposable { this.sendStateToWebview() } - /** - * Get a serializable representation of the current workspace folder state - * for debugging and introspection purposes - */ - getWorkspaceFolderStateSnapshot() { - return this.workspaceFolderState.map((state) => ({ - workspaceFolderPath: state.workspaceFolder.uri.fsPath, - workspaceFolderName: state.workspaceFolder.name, - gitBranch: state.gitBranch, - projectId: state.projectId, - isIndexing: state.isIndexing, - hasManifest: !!state.manifest, - manifestFileCount: state.manifest ? Object.keys(state.manifest.files).length : 0, - hasWatcher: !!state.watcher, - error: state.error - ? { - type: state.error.type, - message: state.error.message, - timestamp: state.error.timestamp, - context: state.error.context, - } - : undefined, - })) - } - public async search(query: string, directoryPrefix?: string): Promise { const { kilocodeOrganizationId, kilocodeToken } = this.config ?? {} @@ -852,102 +834,4 @@ export class ManagedIndexer implements vscode.Disposable { })) .sort((a, b) => b.score - a.score) } - - /** - * Manually trigger a scan for a specific workspace folder - * This is useful for forcing a rescan from the UI - * - * @param workspaceFolderPath The path of the workspace folder to scan - * @throws Error if the workspace folder is not found or not properly initialized - */ - async startScanForWorkspaceFolder(workspaceFolderPath: string): Promise { - console.log("[ManagedIndexer] Manual scan requested for workspace folder", { workspaceFolderPath }) - - if (!this.isActive) { - throw new Error("ManagedIndexer is not active") - } - - // Find the workspace folder state - const state = this.workspaceFolderState.find((s) => s.workspaceFolder.uri.fsPath === workspaceFolderPath) - - if (!state) { - throw new Error(`Workspace folder not found: ${workspaceFolderPath}`) - } - - if (!state.watcher) { - throw new Error(`Watcher not initialized for workspace folder: ${workspaceFolderPath}`) - } - - if (!state.projectId || !state.gitBranch) { - throw new Error(`Workspace folder not fully initialized: ${workspaceFolderPath}`) - } - - // Cancel any previous indexing operation - if (state.currentAbortController) { - console.info("[ManagedIndexer] Aborting previous indexing operation for manual scan") - state.currentAbortController.abort() - } - - // Create new AbortController for this operation - const controller = new AbortController() - state.currentAbortController = controller - - try { - console.info( - `[ManagedIndexer] Starting manual scan for ${workspaceFolderPath} on branch ${state.gitBranch}`, - ) - - // Determine if this is the base branch - const defaultBranch = await state.watcher?.getDefaultBranch() - const isBaseBranch = state.gitBranch.toLowerCase() === defaultBranch.toLowerCase() - - // Create a synthetic event to trigger file processing using GitWatcher's getFiles method - const syntheticEvent: GitWatcherEvent = { - type: "commit", - previousCommit: "", - newCommit: await getCurrentCommitSha(state.workspaceFolder.uri.fsPath), - branch: state.gitBranch, - isBaseBranch, - watcher: state.watcher, - files: state.watcher.getFiles(state.gitBranch, isBaseBranch), - } - - // Refresh the manifest before scanning - try { - await this.getManifest(state, state.gitBranch) - } catch (error) { - console.warn(`[ManagedIndexer] Failed to refresh manifest, continuing with cached version`) - } - - // Process files using the existing logic - await this.processFiles(state, syntheticEvent, controller.signal) - - console.info(`[ManagedIndexer] Manual scan completed for ${workspaceFolderPath}`) - } catch (error) { - // Check if this was an abort - if (error instanceof Error && (error.name === "AbortError" || error.message === "AbortError")) { - console.info("[ManagedIndexer] Manual scan was aborted") - return - } - - const errorMessage = error instanceof Error ? error.message : String(error) - console.error(`[ManagedIndexer] Manual scan failed for ${workspaceFolderPath}: ${errorMessage}`) - - state.error = { - type: "scan", - message: `Manual scan failed: ${errorMessage}`, - timestamp: new Date().toISOString(), - context: { - operation: "manual-scan", - branch: state.gitBranch, - }, - details: error instanceof Error ? error.stack : undefined, - } - - // Send state update after error - this.sendStateToWebview() - - throw error - } - } } diff --git a/src/services/code-index/managed/api-client.ts b/src/services/code-index/managed/api-client.ts index 1c755b69487..5da76a379d2 100644 --- a/src/services/code-index/managed/api-client.ts +++ b/src/services/code-index/managed/api-client.ts @@ -21,6 +21,7 @@ export async function isEnabled(kilocodeToken: string, organizationId: string | const response = await fetchWithRetries({ url, method: "GET", + retries: 2, headers: { Authorization: `Bearer ${kilocodeToken}`, "Content-Type": "application/json", @@ -60,6 +61,7 @@ export async function searchCode( const response = await fetchWithRetries({ url: `${baseUrl}/api/code-indexing/search`, method: "POST", + retries: 2, headers: { Authorization: `Bearer ${kilocodeToken}`, "Content-Type": "application/json", @@ -144,6 +146,7 @@ export async function upsertFile(params: UpsertFileParams, signal?: AbortSignal) const response = await fetchWithRetries({ url: `${baseUrl}/api/code-indexing/upsert-by-file`, method: "PUT", + retries: 2, headers: { Authorization: `Bearer ${kilocodeToken}`, }, @@ -197,6 +200,7 @@ export async function getServerManifest( const response = await fetchWithRetries({ url: `${baseUrl}/api/code-indexing/manifest?${params.toString()}`, method: "GET", + retries: 2, headers: { Authorization: `Bearer ${kilocodeToken}`, "Content-Type": "application/json", @@ -266,6 +270,7 @@ export async function deleteFiles(params: DeleteFilesParams, signal?: AbortSigna const response = await fetchWithRetries({ url: `${baseUrl}/api/code-indexing/delete`, method: "POST", + retries: 2, headers: { Authorization: `Bearer ${kilocodeToken}`, "Content-Type": "application/json",