From 1d16effe952f6da42044550c718e15213e930058 Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Tue, 23 Jun 2026 11:16:54 +0200 Subject: [PATCH 1/2] feat(vscode): let users hide disabled indexing button --- .changeset/tidy-indexing-button.md | 5 ++ packages/kilo-vscode/package.json | 6 +++ packages/kilo-vscode/src/KiloProvider.ts | 14 +++++ .../src/kilo-provider/indexing-settings.ts | 25 +++++++++ .../unit/indexing-settings-message.test.ts | 54 +++++++++++++++++++ .../tests/unit/indexing-utils.test.ts | 36 +++++++++++++ .../src/components/chat/PromptInput.tsx | 12 ++++- .../src/components/settings/IndexingTab.tsx | 16 +++++- .../webview-ui/src/context/config.tsx | 7 +++ .../webview-ui/src/context/indexing-utils.ts | 9 +++- .../kilo-vscode/webview-ui/src/i18n/ar.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/br.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/bs.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/da.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/de.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/en.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/es.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/fr.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/it.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/ja.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/ko.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/nl.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/no.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/pl.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/ru.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/th.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/tr.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/uk.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/zh.ts | 3 ++ .../kilo-vscode/webview-ui/src/i18n/zht.ts | 3 ++ .../src/types/messages/extension-messages.ts | 8 +++ .../src/types/messages/webview-messages.ts | 5 ++ 32 files changed, 252 insertions(+), 5 deletions(-) create mode 100644 .changeset/tidy-indexing-button.md create mode 100644 packages/kilo-vscode/src/kilo-provider/indexing-settings.ts create mode 100644 packages/kilo-vscode/tests/unit/indexing-settings-message.test.ts 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-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) => {
- +