diff --git a/.changeset/visible-semantic-indexing.md b/.changeset/visible-semantic-indexing.md new file mode 100644 index 00000000000..b7e258038a6 --- /dev/null +++ b/.changeset/visible-semantic-indexing.md @@ -0,0 +1,6 @@ +--- +"@kilocode/cli": patch +"kilo-code": patch +--- + +Access semantic indexing without an experimental feature toggle while keeping indexing disabled until enabled globally or for a project. diff --git a/packages/kilo-docs/pages/customize/context/codebase-indexing.md b/packages/kilo-docs/pages/customize/context/codebase-indexing.md index f577678670b..819ae399d7b 100644 --- a/packages/kilo-docs/pages/customize/context/codebase-indexing.md +++ b/packages/kilo-docs/pages/customize/context/codebase-indexing.md @@ -7,8 +7,8 @@ description: "Index your codebase for improved AI understanding" Codebase Indexing enables semantic code search across your entire project using AI embeddings. Instead of searching for exact text matches, it understands the _meaning_ of your queries, helping Kilo Code find relevant code even when you don't know specific function names or file locations. -{% callout type="warning" title="Experimental" %} -Codebase Indexing is currently **experimental** in the CLI and the new VS Code extension. You must explicitly opt in before the feature becomes available — see the **Setup** section below. Behavior, configuration, and defaults may change in future releases. +{% callout type="info" title="Opt-in indexing" %} +Codebase Indexing is disabled by default. It starts only after you enable indexing globally or for an individual project. Configuring an embedding provider without enabling one of those toggles does not start indexing. {% /callout %} ## What It Does @@ -34,28 +34,10 @@ This enables natural language queries like "user authentication logic" or "datab {% tabs %} {% tab label="VSCode" %} -### 1. Enable the experimental flag - -Codebase Indexing is gated behind an experimental flag. Until the flag is on, the Indexing UI is hidden and `semantic_search` is unavailable. - -1. Open Kilo Code **Settings** → **Experimental**. -2. Toggle **Semantic Indexing** on. -3. The **Indexing** tab will appear in Settings and the indexing status indicator will appear at the bottom of the prompt input panel. - -Alternatively, set `experimental.semantic_indexing` to `true` in your `kilo.jsonc`: - -```json -{ - "experimental": { - "semantic_indexing": true - } -} -``` - -### 2. Configure indexing +### Configure indexing 1. Open Kilo Code **Settings** → **Indexing**, or click the indexing indicator at the bottom of the prompt input panel. -2. Toggle **Enable Indexing** on. +2. Turn on **Global Enable** to index every workspace, or turn on **Enable for This Project** to index only the current workspace. Both toggles are off until explicitly enabled. 3. Pick an **Embedding Provider** and fill in its required fields. 4. Pick a **Vector Store** (`Qdrant` or `LanceDB`) and configure it. 5. Optionally adjust **Tuning Parameters** (search score, batch size, retries, max results). @@ -106,23 +88,9 @@ The prompt input panel shows a compact indexing status indicator that reflects t {% /tab %} {% tab label="CLI" %} -### 1. Enable the experimental flag - -Codebase Indexing is gated behind an experimental flag. Until the flag is on, the `/indexing` command is hidden and `semantic_search` is unavailable. - -Set the flag in your `kilo.jsonc`: - -```json -{ - "experimental": { - "semantic_indexing": true - } -} -``` - -Restart the CLI for the change to take effect. The `/indexing` command (and aliases `/index`, `/embedding`) will appear in the command palette once the flag is active. +### Configure indexing -### 2. Configure indexing +The `/indexing` command (and aliases `/index`, `/embedding`) is available when the indexing plugin is installed. Indexing remains disabled until it is enabled globally or for the current project. Open a Kilo TUI session and run: @@ -198,7 +166,7 @@ When indexing is enabled, the CLI shows an indexing status badge at the bottom o {% /tab %} {% tab label="VSCode (Legacy)" %} -The legacy extension does not require an experimental flag. +The legacy extension uses its own Codebase Indexing settings panel. ### Open Codebase Indexing Settings diff --git a/packages/kilo-vscode/src/features.ts b/packages/kilo-vscode/src/features.ts index 889c12d8e71..0e0423b9046 100644 --- a/packages/kilo-vscode/src/features.ts +++ b/packages/kilo-vscode/src/features.ts @@ -4,7 +4,6 @@ type PluginSpec = string | [string, Record] type ConfigLike = { plugin?: readonly PluginSpec[] | null - experimental?: { semantic_indexing?: boolean } | null } export type Features = { @@ -13,6 +12,6 @@ export type Features = { export function configFeatures(config?: ConfigLike | null): Features { return { - indexing: hasIndexingPlugin(config?.plugin ?? []) && config?.experimental?.semantic_indexing === true, + indexing: hasIndexingPlugin(config?.plugin ?? []), } } diff --git a/packages/kilo-vscode/tests/unit/indexing-utils.test.ts b/packages/kilo-vscode/tests/unit/indexing-utils.test.ts index cd91df1ecff..0d20e40d656 100644 --- a/packages/kilo-vscode/tests/unit/indexing-utils.test.ts +++ b/packages/kilo-vscode/tests/unit/indexing-utils.test.ts @@ -85,37 +85,19 @@ describe("indexing SSE mapping", () => { }) describe("indexing feature detection", () => { - it("requires experimental.semantic_indexing when indexing plugin is present", () => { - expect(configFeatures({ plugin: ["kilo-indexing"] }).indexing).toBe(false) - expect(configFeatures({ plugin: ["kilo-indexing"], experimental: {} }).indexing).toBe(false) - expect(configFeatures({ plugin: ["kilo-indexing"], experimental: { semantic_indexing: false } }).indexing).toBe( - false, - ) + it("enables indexing settings when the indexing plugin is present", () => { + expect(configFeatures({ plugin: ["kilo-indexing"] }).indexing).toBe(true) }) - it("detects supported indexing plugin specifiers when experimental.semantic_indexing is true", () => { - expect(configFeatures({ plugin: ["kilo-indexing"], experimental: { semantic_indexing: true } }).indexing).toBe(true) - expect( - configFeatures({ plugin: ["kilo-indexing@1.2.3"], experimental: { semantic_indexing: true } }).indexing, - ).toBe(true) - expect( - configFeatures({ plugin: ["@kilocode/kilo-indexing"], experimental: { semantic_indexing: true } }).indexing, - ).toBe(true) - expect( - configFeatures({ plugin: ["@kilocode/kilo-indexing@1.2.3"], experimental: { semantic_indexing: true } }).indexing, - ).toBe(true) - expect( - configFeatures({ - plugin: ["file:///tmp/.opencode/plugin/kilo-indexing.js"], - experimental: { semantic_indexing: true }, - }).indexing, - ).toBe(true) - expect( - configFeatures({ - plugin: ["file:///tmp/node_modules/@kilocode/kilo-indexing/index.js"], - experimental: { semantic_indexing: true }, - }).indexing, - ).toBe(true) + it("detects supported indexing plugin specifiers", () => { + expect(configFeatures({ plugin: ["kilo-indexing"] }).indexing).toBe(true) + expect(configFeatures({ plugin: ["kilo-indexing@1.2.3"] }).indexing).toBe(true) + expect(configFeatures({ plugin: ["@kilocode/kilo-indexing"] }).indexing).toBe(true) + expect(configFeatures({ plugin: ["@kilocode/kilo-indexing@1.2.3"] }).indexing).toBe(true) + expect(configFeatures({ plugin: ["file:///tmp/.opencode/plugin/kilo-indexing.js"] }).indexing).toBe(true) + expect(configFeatures({ plugin: ["file:///tmp/node_modules/@kilocode/kilo-indexing/index.js"] }).indexing).toBe( + true, + ) }) it("ignores unrelated plugin lists", () => { diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/ExperimentalTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/ExperimentalTab.tsx index 320153907f1..77d65f6779f 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/ExperimentalTab.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/ExperimentalTab.tsx @@ -164,19 +164,6 @@ const ExperimentalTab: Component = () => { - - updateExperimental("semantic_indexing", checked)} - hideLabel - > - {language.t("settings.experimental.semanticIndexing.title")} - - - { const [saved, setSaved] = createSignal>({}) const cfg: Config = { - experimental: { - semantic_indexing: true, - }, indexing: { provider: "openai", model: "text-embedding-3-large", @@ -439,9 +436,6 @@ export const IndexingKiloModelPreset: Story = { name: "IndexingTab - Kilo stale custom model fallback", render: () => { const cfg: Config = { - experimental: { - semantic_indexing: true, - }, indexing: { provider: "kilo", model: "custom/model", @@ -473,9 +467,6 @@ export const IndexingKiloCatalogLoading: Story = { render: () => { const [saved, setSaved] = createSignal>({}) const cfg: Config = { - experimental: { - semantic_indexing: true, - }, indexing: {}, } return ( diff --git a/packages/kilo-vscode/webview-ui/src/types/messages/config.ts b/packages/kilo-vscode/webview-ui/src/types/messages/config.ts index 28497f83da9..bd47ed509b8 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages/config.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages/config.ts @@ -40,7 +40,6 @@ export interface WatcherConfig { export interface ExperimentalConfig { disable_paste_summary?: boolean batch_tool?: boolean - semantic_indexing?: boolean codebase_search?: boolean speech_to_text_model?: string primary_tools?: string[] diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 48746eb0c9f..742ef72deef 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -74,7 +74,7 @@ function mergeConfigConcatArrays(target: Info, source: Info): Info { function normalizeLoadedConfig(data: unknown, source: string) { if (!isRecord(data)) return data - const copy = { ...data } + const copy = KilocodeConfig.retireIndexingFlag({ ...data }, source) // kilocode_change const hadLegacy = "theme" in copy || "keybinds" in copy || "tui" in copy if (!hadLegacy) return copy delete copy.theme @@ -350,9 +350,6 @@ export const Info = Schema.Struct({ batch_tool: Schema.optional(Schema.Boolean).annotate({ description: "Enable the batch tool" }), codebase_search: Schema.optional(Schema.Boolean).annotate({ description: "Enable AI-powered codebase search" }), // kilocode_change // kilocode_change start - semantic_indexing: Schema.optional(Schema.Boolean).annotate({ - description: "Enable semantic codebase indexing and the semantic_search tool", - }), speech_to_text_model: Schema.optional(Schema.String).annotate({ description: "Speech-to-text transcription model ID to use for voice input", }), diff --git a/packages/opencode/src/kilocode/config/config.ts b/packages/opencode/src/kilocode/config/config.ts index 71844ca3d06..cbaf9afc362 100644 --- a/packages/opencode/src/kilocode/config/config.ts +++ b/packages/opencode/src/kilocode/config/config.ts @@ -115,6 +115,14 @@ export namespace KilocodeConfig { return stripGlobalIndexing(info) } + export function retireIndexingFlag(info: Record, source: string) { + if (!isRecord(info.experimental) || !("semantic_indexing" in info.experimental)) return info + const experimental = { ...info.experimental } + delete experimental.semantic_indexing + log.warn("ignored retired experimental.semantic_indexing config; use indexing.enabled instead", { path: source }) + return { ...info, experimental } + } + function stripGlobalIndexing(info: Config.Info): Config.Info { // Indexing provider/storage settings can be global, but enablement is exposed separately from project enablement. if (info.indexing?.enabled === undefined) return info diff --git a/packages/opencode/src/kilocode/indexing-feature.ts b/packages/opencode/src/kilocode/indexing-feature.ts index a19b1b316b9..3cb2e6042ce 100644 --- a/packages/opencode/src/kilocode/indexing-feature.ts +++ b/packages/opencode/src/kilocode/indexing-feature.ts @@ -9,7 +9,6 @@ type PluginSpec = string | [string, Record] type ConfigLike = { plugin?: readonly PluginSpec[] | null - experimental?: { semantic_indexing?: boolean } | null } type Req = { @@ -21,7 +20,7 @@ type LogLike = { } export function indexingEnabled(config?: ConfigLike | null): boolean { - return hasIndexingPlugin(config?.plugin ?? []) && config?.experimental?.semantic_indexing === true + return hasIndexingPlugin(config?.plugin ?? []) } export function resolveIndexingPlugin(req: Req, log?: LogLike): string { diff --git a/packages/opencode/src/kilocode/indexing.ts b/packages/opencode/src/kilocode/indexing.ts index 03ccf671b9e..ab0c883de69 100644 --- a/packages/opencode/src/kilocode/indexing.ts +++ b/packages/opencode/src/kilocode/indexing.ts @@ -242,15 +242,6 @@ export namespace KiloIndexing { return track(hit, await inert(() => missing())) } - if (cfg.experimental?.semantic_indexing !== true) { - return track( - hit, - await inert(() => - disabledIndexingStatus("Semantic indexing is disabled. Enable it in the Experimental settings."), - ), - ) - } - if (isWorktreePath(dir)) { return track(hit, await inert(() => worktreeDisabled())) } diff --git a/packages/opencode/test/kilocode/config/config.test.ts b/packages/opencode/test/kilocode/config/config.test.ts index cce16404aae..32327bbdc8b 100644 --- a/packages/opencode/test/kilocode/config/config.test.ts +++ b/packages/opencode/test/kilocode/config/config.test.ts @@ -54,9 +54,6 @@ async function writeConfig(dir: string, config: object, name = "kilo.json") { const cfg: Partial = { plugin: ["@kilocode/kilo-indexing"], - experimental: { - semantic_indexing: true, - }, indexing: { provider: "ollama", vectorStore: "qdrant", @@ -93,6 +90,22 @@ describe("markdown substitutions", () => { }) describe("kilocode indexing config", () => { + test("ignores retired semantic indexing flags in existing configs", async () => { + await using tmp = await tmpdir({ git: true }) + await writeConfig(tmp.path, { + experimental: { semantic_indexing: true, batch_tool: true }, + }) + + await WithInstance.provide({ + directory: tmp.path, + fn: async () => { + const config = await load() + expect(config.experimental?.batch_tool).toBe(true) + expect(config.experimental).not.toHaveProperty("semantic_indexing") + }, + }) + }) + test("keeps global indexing enabled in global config", async () => { await using globalTmp = await tmpdir() await using tmp = await tmpdir() diff --git a/packages/opencode/test/kilocode/indexing-feature.test.ts b/packages/opencode/test/kilocode/indexing-feature.test.ts index 627e0d096f4..1cfde17a0b1 100644 --- a/packages/opencode/test/kilocode/indexing-feature.test.ts +++ b/packages/opencode/test/kilocode/indexing-feature.test.ts @@ -9,12 +9,8 @@ import { describe("indexing plugin helpers", () => { test("detects plugin-enabled configs", () => { expect(indexingEnabled({ plugin: ["global-plugin"] })).toBe(false) - expect(indexingEnabled({ plugin: [INDEXING_PLUGIN] })).toBe(false) - expect(indexingEnabled({ plugin: [INDEXING_PLUGIN], experimental: { semantic_indexing: false } })).toBe(false) - expect(indexingEnabled({ plugin: [INDEXING_PLUGIN], experimental: { semantic_indexing: true } })).toBe(true) - expect( - indexingEnabled({ plugin: ["@kilocode/kilo-indexing@1.0.0"], experimental: { semantic_indexing: true } }), - ).toBe(true) + expect(indexingEnabled({ plugin: [INDEXING_PLUGIN] })).toBe(true) + expect(indexingEnabled({ plugin: ["@kilocode/kilo-indexing@1.0.0"] })).toBe(true) }) test("adds indexing plugin when present but missing from config", () => { diff --git a/packages/opencode/test/kilocode/indexing-startup.test.ts b/packages/opencode/test/kilocode/indexing-startup.test.ts index e90222ee0aa..63c873a994c 100644 --- a/packages/opencode/test/kilocode/indexing-startup.test.ts +++ b/packages/opencode/test/kilocode/indexing-startup.test.ts @@ -16,9 +16,6 @@ const fetch = global.fetch const cfg: Partial = { plugin: ["@kilocode/kilo-indexing"], - experimental: { - semantic_indexing: true, - }, indexing: { enabled: true, provider: "ollama", @@ -29,13 +26,9 @@ const cfg: Partial = { }, } -const off: Partial = { +const unset: Partial = { plugin: ["@kilocode/kilo-indexing"], - experimental: { - semantic_indexing: false, - }, indexing: { - enabled: true, provider: "ollama", vectorStore: "qdrant", ollama: { @@ -45,9 +38,6 @@ const off: Partial = { } const inactive: Partial = { plugin: ["@kilocode/kilo-indexing"], - experimental: { - semantic_indexing: true, - }, indexing: { enabled: false, provider: "ollama", @@ -56,9 +46,6 @@ const inactive: Partial = { } const kilo: Partial = { plugin: ["@kilocode/kilo-indexing"], - experimental: { - semantic_indexing: true, - }, indexing: { enabled: true, vectorStore: "qdrant", @@ -66,9 +53,6 @@ const kilo: Partial = { } const implicitOpenAi: Partial = { plugin: ["@kilocode/kilo-indexing"], - experimental: { - semantic_indexing: true, - }, indexing: { enabled: true, vectorStore: "qdrant", @@ -79,9 +63,6 @@ const implicitOpenAi: Partial = { } const staleKilo: Partial = { plugin: ["@kilocode/kilo-indexing"], - experimental: { - semantic_indexing: true, - }, indexing: { enabled: true, provider: "kilo", @@ -303,23 +284,23 @@ describe("indexing startup degradation", () => { } }) - test("stays disabled when semantic indexing flag is off", async () => { - await using tmp = await tmpdir({ git: true, config: off }) + test("stays disabled when indexing enablement is unset", async () => { + await using tmp = await tmpdir({ git: true, config: unset }) process.env["KILO_CONFIG_DIR"] = tmp.path const init = spyOn(CodeIndexManager.prototype, "initialize") await WithInstance.provide({ directory: tmp.path, fn: async () => { - const status = await KiloIndexing.current() + const status = await wait(() => KiloIndexing.current(), "Disabled") expect(status).toMatchObject({ state: "Disabled", - message: "Semantic indexing is disabled. Enable it in the Experimental settings.", + message: "Indexing disabled.", }) expect(await KiloIndexing.available()).toBe(false) expect(KiloIndexing.ready()).toBe(false) - expect(await KiloIndexing.search("flag off")).toEqual([]) + expect(await KiloIndexing.search("disabled")).toEqual([]) expect(init).not.toHaveBeenCalled() }, }) diff --git a/packages/opencode/test/kilocode/indexing-worktree.test.ts b/packages/opencode/test/kilocode/indexing-worktree.test.ts index 0a9a303e505..fa42d92e1be 100644 --- a/packages/opencode/test/kilocode/indexing-worktree.test.ts +++ b/packages/opencode/test/kilocode/indexing-worktree.test.ts @@ -7,9 +7,6 @@ import { disposeAllInstances, tmpdir } from "../fixture/fixture" const cfg: Partial = { plugin: ["@kilocode/kilo-indexing"], - experimental: { - semantic_indexing: true, - }, indexing: { enabled: true, provider: "ollama", diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 653ff749dbc..4beaea772f3 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -1427,7 +1427,6 @@ export type Config = { disable_paste_summary?: boolean batch_tool?: boolean codebase_search?: boolean - semantic_indexing?: boolean speech_to_text_model?: string openTelemetry?: boolean primary_tools?: Array diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 8f41c9639c3..a752025f001 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -16786,9 +16786,6 @@ "codebase_search": { "type": "boolean" }, - "semantic_indexing": { - "type": "boolean" - }, "speech_to_text_model": { "type": "string" },