diff --git a/.changeset/tidy-indexing-button.md b/.changeset/tidy-indexing-button.md new file mode 100644 index 0000000000..9b5fe509aa --- /dev/null +++ b/.changeset/tidy-indexing-button.md @@ -0,0 +1,5 @@ +--- +"kilo-code": minor +--- + +Let users hide the codebase indexing button while indexing is off. diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-kilo-catalog-loading-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-kilo-catalog-loading-chromium-linux.png index aac2e629fe..0230012032 100644 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-kilo-catalog-loading-chromium-linux.png +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-kilo-catalog-loading-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:add00c319d54f53c7c9859428b18182fa91da1b17e4c03b1ee8015ed08f73d19 -size 48653 +oid sha256:4d5db71fbed0542dd8ef3101d7b56b9538b9e6411921150d0957996acd620fde +size 51161 diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-kilo-model-preset-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-kilo-model-preset-chromium-linux.png index 714c7562e7..21f11b47d2 100644 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-kilo-model-preset-chromium-linux.png +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-kilo-model-preset-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d9fbce155629b97a30ee9f95f226ef883b6febf8002a657516ff439e3fae0f6c -size 51829 +oid sha256:c501793cb8d0ad50b2d8d283a6314ce4b21dabdc0e95f63174c4a7e475523e32 +size 54055 diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-provider-blur-race-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-provider-blur-race-chromium-linux.png index 13e53ad7ee..041e7f16fe 100644 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-provider-blur-race-chromium-linux.png +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-provider-blur-race-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3330276aded477430e615ababb2caa7eeb2fa7f7406974b9b829e6092d5a619a -size 51792 +oid sha256:8d280dc15c3e64ddf365e1bdaa572d07da0199d0cb9d37acb174ae70db5ae746 +size 57329 diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-scope-switch-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-scope-switch-chromium-linux.png index 49e6bf669a..cda24ddb93 100644 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-scope-switch-chromium-linux.png +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/indexing-scope-switch-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bb78008c0fcbc47cb4b73fcea0739ce975c64b31d58852d74fd31078f3774694 -size 54958 +oid sha256:16b0e2bed3c576328a5565ae957c3af4abbc884a0db894472f587b29e1c355b4 +size 56194 diff --git a/packages/kilo-vscode/package.json b/packages/kilo-vscode/package.json index 136cea8061..0b3c113edb 100644 --- a/packages/kilo-vscode/package.json +++ b/packages/kilo-vscode/package.json @@ -924,6 +924,12 @@ "default": false, "description": "Enable chat textarea autocomplete" }, + "kilo-code.new.indexing.showButtonWhenDisabled": { + "type": "boolean", + "default": true, + "scope": "application", + "description": "Show the codebase indexing button below the prompt while indexing is disabled." + }, "kilo-code.new.claudeCodeCompat": { "type": "boolean", "default": false, diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index c3a27446d7..18ef1427c0 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -150,6 +150,11 @@ import { createAutoApproveBridge } from "./kilo-provider/auto-approve" import type { KiloProviderOptions } from "./kilo-provider/options" import { fetchKiloEmbeddingModelCatalog } from "@kilocode/kilo-gateway" import { stopSessionProcesses } from "./kilo-provider/background-process" +import { + buildIndexingSettingsMessage, + validIndexingSetting, + watchIndexingConfig, +} from "./kilo-provider/indexing-settings" type MessageLoadMode = "replace" | "prepend" | "focus" | "reconcile" type ContextMessage = { contextDirectory?: unknown } @@ -359,6 +364,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper private initConnectionPromise: Promise | null = null private webviewMessageDisposable: vscode.Disposable | null = null private autocompleteConfigDisposable: vscode.Disposable | null = null + private indexingConfigDisposable: vscode.Disposable | null = null private telemetryStateDisposable: vscode.Disposable | null = null private viewStateDisposable: vscode.Disposable | null = null private visibilityDisposable: vscode.Disposable | null = null @@ -796,6 +802,8 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper this.webviewMessageDisposable?.dispose() this.autocompleteConfigDisposable?.dispose() this.autocompleteConfigDisposable = watchAutocompleteConfig((msg) => this.postMessage(msg)) + this.indexingConfigDisposable?.dispose() + this.indexingConfigDisposable = watchIndexingConfig((msg) => this.postMessage(msg)) this.telemetryStateDisposable?.dispose() this.telemetryStateDisposable = watchTelemetryState((msg) => this.postMessage(msg)) this.webviewMessageDisposable = webview.onDidReceiveMessage(async (message) => { @@ -1080,6 +1088,9 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper console.error("[Kilo New] fetchAndSendIndexingStatus failed:", e), ) break + case "requestIndexingSettings": + this.postMessage(buildIndexingSettingsMessage()) + break case "requestKiloEmbeddingModels": this.fetchAndSendKiloEmbeddingModels().catch((e) => console.error("[Kilo New] fetchAndSendKiloEmbeddingModels failed:", e), @@ -2998,6 +3009,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper private async handleUpdateSetting(key: string, value: unknown): Promise { const { section, leaf } = buildSettingPath(key) if (section === "autocomplete" && !validAutocompleteSetting(leaf, value)) return + if (section === "indexing" && !validIndexingSetting(leaf, value)) return const config = vscode.workspace.getConfiguration(`kilo-code.new${section ? `.${section}` : ""}`) // Normalize a webview-side clear to `undefined` so VS Code removes the // key from settings.json rather than persisting a literal `null`. This @@ -3044,6 +3056,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper // Re-send all settings to the webview so the UI reflects the reset this.postMessage(buildAutocompleteSettingsMessage()) + this.postMessage(buildIndexingSettingsMessage()) this.sendBrowserSettings() this.sendNotificationSettings() this.sendTimelineSetting() @@ -3649,6 +3662,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper this.visibilityDisposable?.dispose() this.webviewMessageDisposable?.dispose() this.autocompleteConfigDisposable?.dispose() + this.indexingConfigDisposable?.dispose() this.telemetryStateDisposable?.dispose() this.autoApproveBridge?.dispose() this.visibleTaskStreams.clear() diff --git a/packages/kilo-vscode/src/kilo-provider/indexing-settings.ts b/packages/kilo-vscode/src/kilo-provider/indexing-settings.ts new file mode 100644 index 0000000000..8fbd0ace48 --- /dev/null +++ b/packages/kilo-vscode/src/kilo-provider/indexing-settings.ts @@ -0,0 +1,25 @@ +import * as vscode from "vscode" + +type Post = (msg: unknown) => void + +export function buildIndexingSettingsMessage() { + const config = vscode.workspace.getConfiguration("kilo-code.new.indexing") + return { + type: "indexingSettingsLoaded" as const, + settings: { + showButtonWhenDisabled: config.get("showButtonWhenDisabled", true), + }, + } +} + +export function watchIndexingConfig(post: Post): vscode.Disposable { + return vscode.workspace.onDidChangeConfiguration((event) => { + if (event.affectsConfiguration("kilo-code.new.indexing")) { + post(buildIndexingSettingsMessage()) + } + }) +} + +export function validIndexingSetting(key: string, value: unknown) { + return key === "showButtonWhenDisabled" && typeof value === "boolean" +} diff --git a/packages/kilo-vscode/tests/unit/indexing-settings-message.test.ts b/packages/kilo-vscode/tests/unit/indexing-settings-message.test.ts new file mode 100644 index 0000000000..b80f479de0 --- /dev/null +++ b/packages/kilo-vscode/tests/unit/indexing-settings-message.test.ts @@ -0,0 +1,54 @@ +import { afterEach, beforeEach, describe, expect, it } from "bun:test" +import * as vscode from "vscode" +import { buildIndexingSettingsMessage, validIndexingSetting } from "../../src/kilo-provider/indexing-settings" + +type Stub = { + getConfiguration: (section?: string) => { + get: (key: string, fallback?: T) => T | undefined + } +} + +const original = vscode.workspace.getConfiguration + +function stubConfig(state: Map) { + ;(vscode.workspace as unknown as Stub).getConfiguration = (section?: string) => { + if (section !== "kilo-code.new.indexing") { + return { get: (_key: string, fallback?: T) => fallback } + } + return { + get: (key: string, fallback?: T) => (state.has(key) ? (state.get(key) as T) : fallback), + } + } +} + +afterEach(() => { + ;(vscode.workspace as unknown as Stub).getConfiguration = original as Stub["getConfiguration"] +}) + +describe("buildIndexingSettingsMessage", () => { + let state: Map + + beforeEach(() => { + state = new Map() + stubConfig(state) + }) + + it("shows the indexing button by default", () => { + expect(buildIndexingSettingsMessage().settings.showButtonWhenDisabled).toBe(true) + }) + + it("returns the persisted button preference", () => { + state.set("showButtonWhenDisabled", false) + + expect(buildIndexingSettingsMessage().settings.showButtonWhenDisabled).toBe(false) + }) +}) + +describe("validIndexingSetting", () => { + it("accepts only boolean button visibility updates", () => { + expect(validIndexingSetting("showButtonWhenDisabled", true)).toBe(true) + expect(validIndexingSetting("showButtonWhenDisabled", false)).toBe(true) + expect(validIndexingSetting("showButtonWhenDisabled", "false")).toBe(false) + expect(validIndexingSetting("unknown", true)).toBe(false) + }) +}) diff --git a/packages/kilo-vscode/tests/unit/indexing-utils.test.ts b/packages/kilo-vscode/tests/unit/indexing-utils.test.ts index 0d20e40d65..ad6551e802 100644 --- a/packages/kilo-vscode/tests/unit/indexing-utils.test.ts +++ b/packages/kilo-vscode/tests/unit/indexing-utils.test.ts @@ -2,6 +2,7 @@ import { describe, expect, it } from "bun:test" import { applyIndexingStatusMessage, formatIndexingLabel, + indexingButtonVisible, indexingTone, } from "../../webview-ui/src/context/indexing-utils" import { mapSSEEventToWebviewMessage } from "../../src/kilo-provider-utils" @@ -19,6 +20,41 @@ function makeStatus(overrides: Partial = {}): IndexingStatus { } } +describe("indexing button visibility", () => { + it("hides the button when the indexing feature is unavailable", () => { + expect(indexingButtonVisible(false, true, { indexing: { enabled: true } }, { indexing: { enabled: true } })).toBe( + false, + ) + }) + + it("shows the button while indexing is off by default", () => { + expect(indexingButtonVisible(true, true, {}, {})).toBe(true) + }) + + it("hides the button when indexing is off and the preference is disabled", () => { + expect(indexingButtonVisible(true, false, {}, {})).toBe(false) + }) + + it("shows the button when project indexing is enabled", () => { + expect(indexingButtonVisible(true, false, { indexing: { enabled: true } }, {})).toBe(true) + expect(indexingButtonVisible(true, false, { indexing: { enabled: true } }, { indexing: { enabled: false } })).toBe( + true, + ) + }) + + it("stays hidden when global and project indexing are off", () => { + expect(indexingButtonVisible(true, false, { indexing: { enabled: false } }, { indexing: { enabled: false } })).toBe( + false, + ) + }) + + it("shows the button whenever global indexing is enabled", () => { + expect(indexingButtonVisible(true, false, { indexing: { enabled: false } }, { indexing: { enabled: true } })).toBe( + true, + ) + }) +}) + describe("indexing formatting", () => { it("formats in-progress status like the TUI", () => { const status = makeStatus({ state: "In Progress", percent: 42, processedFiles: 21, totalFiles: 50 }) diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx index 71b87c08ce..dc81fc25e7 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx @@ -13,6 +13,7 @@ import { showToast } from "@kilocode/kilo-ui/toast" import { useSession } from "../../context/session" import { useServer } from "../../context/server" import { useIndexing } from "../../context/indexing" +import { indexingButtonVisible } from "../../context/indexing-utils" import { useLanguage } from "../../context/language" import { useVSCode } from "../../context/vscode" import { useConfig } from "../../context/config" @@ -78,7 +79,7 @@ export const PromptInput: Component = (props) => { const session = useSession() const server = useServer() const indexing = useIndexing() - const { config, features } = useConfig() + const { config, globalConfig, settings, features } = useConfig() const provider = useProvider() const language = useLanguage() const vscode = useVSCode() @@ -295,6 +296,13 @@ export const PromptInput: Component = (props) => { const isBusy = () => isPromptBusy(session.status(), !!props.suggesting?.(), !!props.questioning?.(), session.submitting()) + const showIndexing = () => + indexingButtonVisible( + features().indexing, + Boolean(settings()["indexing.showButtonWhenDisabled"] ?? true), + config(), + globalConfig(), + ) const isDisabled = () => !server.isConnected() const canUseSpeech = () => canUseSpeechToText(config(), provider.authStates()) const speechModel = () => selectedSpeechToTextModel(config()) @@ -1015,7 +1023,7 @@ export const PromptInput: Component = (props) => {
- +