From 30e1f2872c6cb8c1da31a48d660daf683888e3e3 Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Mon, 4 May 2026 13:49:50 +0200 Subject: [PATCH] fix: exclude generated data from Spotlight indexing --- .changeset/spotlight-indexing.md | 6 +++ .../src/agent-manager/WorktreeManager.ts | 3 ++ packages/kilo-vscode/src/extension.ts | 5 ++ packages/kilo-vscode/src/util/spotlight.ts | 49 +++++++++++++++++++ packages/opencode/src/global/index.ts | 5 ++ packages/opencode/src/kilocode/spotlight.ts | 24 +++++++++ 6 files changed, 92 insertions(+) create mode 100644 .changeset/spotlight-indexing.md create mode 100644 packages/kilo-vscode/src/util/spotlight.ts create mode 100644 packages/opencode/src/kilocode/spotlight.ts diff --git a/.changeset/spotlight-indexing.md b/.changeset/spotlight-indexing.md new file mode 100644 index 00000000000..790f72b7924 --- /dev/null +++ b/.changeset/spotlight-indexing.md @@ -0,0 +1,6 @@ +--- +"@kilocode/cli": patch +"kilo-code": patch +--- + +Prevent macOS Spotlight from indexing Kilo-generated data directories. diff --git a/packages/kilo-vscode/src/agent-manager/WorktreeManager.ts b/packages/kilo-vscode/src/agent-manager/WorktreeManager.ts index 5d6c92edf9a..6a64d4bd176 100644 --- a/packages/kilo-vscode/src/agent-manager/WorktreeManager.ts +++ b/packages/kilo-vscode/src/agent-manager/WorktreeManager.ts @@ -13,6 +13,7 @@ import simpleGit, { type SimpleGit } from "simple-git" import { generateBranchName, sanitizeBranchName } from "./branch-name" import { type GitOps, nonInteractiveEnv } from "./GitOps" import { execWithShellEnv } from "./shell-env" +import { markNoIndex } from "../util/spotlight" import { parsePRUrl, localBranchName, @@ -424,6 +425,7 @@ export class WorktreeManager { async discoverWorktrees(): Promise { await this.ensureMigrated() if (!fs.existsSync(this.dir)) return [] + await markNoIndex(this.dir, this.log) const entries = await fs.promises.readdir(this.dir, { withFileTypes: true }) this.cleanupOrphanedTempDirs() @@ -575,6 +577,7 @@ export class WorktreeManager { if (!fs.existsSync(this.dir)) { await fs.promises.mkdir(this.dir, { recursive: true }) } + await markNoIndex(this.dir, this.log) } private async resolveGitDir(): Promise { diff --git a/packages/kilo-vscode/src/extension.ts b/packages/kilo-vscode/src/extension.ts index 5089d1cdbe6..fadee229dc8 100644 --- a/packages/kilo-vscode/src/extension.ts +++ b/packages/kilo-vscode/src/extension.ts @@ -19,6 +19,7 @@ import { registerCodeActions, registerTerminalActions, KiloCodeActionProvider } import { registerToggleAutoApprove } from "./commands/toggle-auto-approve" import { registerHeapSnapshot } from "./commands/heap-snapshot" import { RemoteStatusService } from "./services/RemoteStatusService" +import { markWorkspace } from "./util/spotlight" // Activated via "onStartupFinished" (package.json) so that commands, code actions, keybindings, // autocomplete, commit-message generation, and URI deep links all work immediately — without @@ -67,6 +68,10 @@ export function activate(context: vscode.ExtensionContext) { // Prewarm the CLI backend early so autocomplete is ready before first editor use. ensureBackendForAutocomplete(connectionService) + for (const folder of vscode.workspace.workspaceFolders ?? []) { + void markWorkspace(folder.uri.fsPath, (msg) => console.warn(`[Kilo New] ${msg}`)) + } + // Track all open tab panel providers so toolbar button commands can target them. // NOTE: The editor/title toolbar for tab panels intentionally omits Agent Manager // and Marketplace buttons (unlike the sidebar). Too many icons causes VS Code to diff --git a/packages/kilo-vscode/src/util/spotlight.ts b/packages/kilo-vscode/src/util/spotlight.ts new file mode 100644 index 00000000000..c1cd193098d --- /dev/null +++ b/packages/kilo-vscode/src/util/spotlight.ts @@ -0,0 +1,49 @@ +import * as fs from "fs" +import * as path from "path" + +const marker = ".metadata_never_index" + +function exists(err: unknown): boolean { + if (typeof err !== "object" || err === null) return false + return "code" in err && err.code === "EEXIST" +} + +function message(err: unknown): string { + if (err instanceof Error) return err.message + return String(err) +} + +export async function markNoIndex(dir: string, log: (msg: string) => void): Promise { + if (process.platform !== "darwin") return + const file = path.join(dir, marker) + await fs.promises.writeFile(file, "", { flag: "wx" }).catch((err) => { + if (exists(err)) return + log(`Warning: Failed to mark ${dir} as Spotlight-excluded: ${message(err)}`) + }) +} + +async function directory(dir: string): Promise { + return fs.promises + .stat(dir) + .then((stat) => stat.isDirectory()) + .catch(() => false) +} + +function parent(dir: string): string | undefined { + const parts = path.resolve(dir).split(path.sep) + for (let i = 0; i < parts.length - 1; i++) { + const hidden = parts[i] === ".kilo" || parts[i] === ".kilocode" + if (hidden && parts[i + 1] === "worktrees") return parts.slice(0, i + 2).join(path.sep) || path.sep + } + return undefined +} + +export async function markWorkspace(root: string, log: (msg: string) => void): Promise { + const ancestor = parent(root) + if (ancestor) await markNoIndex(ancestor, log) + + for (const name of [".kilo", ".kilocode"]) { + const dir = path.join(root, name, "worktrees") + if (await directory(dir)) await markNoIndex(dir, log) + } +} diff --git a/packages/opencode/src/global/index.ts b/packages/opencode/src/global/index.ts index fb44048c0a5..f3dc2420fd4 100644 --- a/packages/opencode/src/global/index.ts +++ b/packages/opencode/src/global/index.ts @@ -4,6 +4,7 @@ import path from "path" import os from "os" import { Filesystem } from "../util" import { Flock } from "@opencode-ai/shared/util/flock" +import { markNoIndex } from "../kilocode/spotlight" // kilocode_change const app = "kilo" // kilocode_change @@ -65,4 +66,8 @@ if (version !== CACHE_VERSION) { await Filesystem.write(path.join(Path.cache, "version"), CACHE_VERSION) } +// kilocode_change start - keep generated Kilo data out of macOS Spotlight +await Promise.all([Path.data, Path.cache, Path.state].map(markNoIndex)) +// kilocode_change end + export * as Global from "." diff --git a/packages/opencode/src/kilocode/spotlight.ts b/packages/opencode/src/kilocode/spotlight.ts new file mode 100644 index 00000000000..d3bda71a491 --- /dev/null +++ b/packages/opencode/src/kilocode/spotlight.ts @@ -0,0 +1,24 @@ +// kilocode_change - new file +import fs from "fs/promises" +import path from "path" + +const marker = ".metadata_never_index" + +function exists(err: unknown): boolean { + if (typeof err !== "object" || err === null) return false + return "code" in err && err.code === "EEXIST" +} + +function message(err: unknown): string { + if (err instanceof Error) return err.message + return String(err) +} + +export async function markNoIndex(dir: string): Promise { + if (process.platform !== "darwin") return + const file = path.join(dir, marker) + await fs.writeFile(file, "", { flag: "wx" }).catch((err) => { + if (exists(err)) return + process.emitWarning(`Failed to mark ${dir} as Spotlight-excluded: ${message(err)}`) + }) +}