fix(vscode): defer unused worktree watchers

This commit is contained in:
marius-kilocode
2026-08-04 16:28:59 +02:00
parent 842453544e
commit 35801cbeed
5 changed files with 126 additions and 15 deletions
+6
View File
@@ -0,0 +1,6 @@
---
"@kilocode/cli": patch
"kilo-code": patch
---
Prevent VS Code sessions and Agent Manager worktrees from starting unused file watchers and defer file indexing until search is used.
+25 -12
View File
@@ -166,22 +166,33 @@ export const fffLayer = Layer.effect(
return real !== undefined && FSUtil.contains(root.path, real)
})
// kilocode_change end
const result = yield* Effect.try({
try: () =>
Fff.create({
basePath: location.directory,
aiMode: true,
...scanning(location.directory), // kilocode_change - permit broad scanning only at the exact boundary.
}),
catch: (cause) => cause,
}).pipe(Effect.orDie)
if (!result.ok) return yield* Effect.die(result.error)
yield* Effect.addFinalizer(() => Effect.sync(() => result.value.destroy()).pipe(Effect.ignore))
// kilocode_change start - defer FFF until search because other location consumers do not need its native index.
const scope = yield* Scope.Scope
const load = yield* Effect.cached(
Effect.gen(function* () {
const result = yield* Effect.try({
try: () =>
Fff.create({
basePath: location.directory,
aiMode: true,
disableMmapCache: true,
disableContentIndexing: true,
...scanning(location.directory),
}),
catch: (cause) => cause,
}).pipe(Effect.orDie)
if (!result.ok) return yield* Effect.die(result.error)
yield* Scope.addFinalizer(scope, Effect.sync(() => result.value.destroy()).pipe(Effect.ignore))
return result
}),
)
// kilocode_change end
return Service.of({
glob: (input) =>
// kilocode_change start
Effect.gen(function* () {
const { root, target } = yield* inspect(input.path)
const result = yield* load
// kilocode_change end
const prefix = input.path?.replaceAll("\\", "/").replace(/\/$/, "")
// kilocode_change start
@@ -210,6 +221,7 @@ export const fffLayer = Layer.effect(
// kilocode_change start
Effect.gen(function* () {
const { root, target } = yield* inspect(input.path)
const result = yield* load
// kilocode_change end
const prefix = input.path?.replaceAll("\\", "/").replace(/\/$/, "")
// kilocode_change start
@@ -247,7 +259,8 @@ export const fffLayer = Layer.effect(
})
}),
find: (input) =>
Effect.sync(() => {
Effect.gen(function* () { // kilocode_change - load the native index only for an actual search.
const result = yield* load // kilocode_change
const options = { pageIndex: 0, pageSize: input.limit ?? 50 }
const items = (() => {
if (input.type === "file") {
+80
View File
@@ -1,7 +1,16 @@
import { describe, expect, test } from "bun:test"
import { FileFinder, type InitOptions } from "@ff-labs/fff-bun"
import "@opencode-ai/core/filesystem"
import { Fff } from "@opencode-ai/core/filesystem/fff.bun"
import { FSUtil } from "@opencode-ai/core/fs-util"
import os from "os"
import path from "path"
import { Context, Effect, Layer, Scope } from "effect"
import { scanning } from "@opencode-ai/core/kilocode/fff"
import { Location } from "@opencode-ai/core/location"
import { AbsolutePath } from "@opencode-ai/core/schema"
import { location } from "../fixture/location"
import { tmpdir } from "../fixture/tmpdir"
describe("FFF scanning boundaries", () => {
test("enables filesystem-root scanning only at the exact root", () => {
@@ -25,3 +34,74 @@ describe("FFF scanning boundaries", () => {
})
})
})
describe("FFF lifecycle", () => {
test("initializes on the first search and reuses one picker", async () => {
if (!Fff.available()) return
const dir = await tmpdir()
const create = FileFinder.create
const calls = { create: 0, destroy: 0, opts: undefined as InitOptions | undefined }
try {
FileFinder.create = (opts) => {
calls.create++
calls.opts = opts
const result = create(opts)
if (!result.ok) return result
const destroy = result.value.destroy.bind(result.value)
result.value.destroy = () => {
calls.destroy++
destroy()
}
return result
}
await Effect.runPromise(
Effect.acquireUseRelease(
Scope.make(),
(scope) =>
Effect.gen(function* () {
const { FileSystemSearch } = yield* Effect.promise(() => import("@opencode-ai/core/filesystem/search"))
const layer = FileSystemSearch.fffLayer.pipe(
Layer.provide(FSUtil.defaultLayer),
Layer.provide(
Layer.succeed(
Location.Service,
Location.Service.of(
location(
{ directory: AbsolutePath.make(dir.path) },
{ vcs: { type: "git", store: AbsolutePath.make(path.join(dir.path, ".git")) } },
),
),
),
),
)
const context = yield* Layer.buildWithScope(layer, scope)
const service = Context.get(context, FileSystemSearch.Service)
expect(calls.create).toBe(0)
yield* Effect.all(
[
service.find({ query: "", type: "file", limit: 1 }),
service.find({ query: "", type: "file", limit: 1 }),
],
{ concurrency: "unbounded" },
)
expect(calls.create).toBe(1)
expect(calls.opts?.disableMmapCache).toBe(true)
expect(calls.opts?.disableContentIndexing).toBe(true)
yield* service.find({ query: "", type: "file", limit: 1 })
expect(calls.create).toBe(1)
expect(calls.destroy).toBe(0)
}),
(scope, exit) => Scope.close(scope, exit),
),
)
expect(calls.destroy).toBe(1)
} finally {
FileFinder.create = create
await dir[Symbol.asyncDispose]()
}
})
})
@@ -29,7 +29,12 @@ export function resolveIndexingEnv(folders: readonly WorkspaceFolderLike[] | und
}
export function resolveManagedServerEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
return { ...env, KILO_DISABLE_CHANNEL_DB: "true" }
return {
...env,
KILO_DISABLE_CHANNEL_DB: "true",
// VS Code does not consume the backend's file.watcher.updated events.
KILO_EXPERIMENTAL_DISABLE_FILEWATCHER: "true",
}
}
export class ServerManager {
@@ -315,10 +315,17 @@ describe("server workspace helpers", () => {
expect(resolveIndexingEnv([{ uri: { fsPath: "/repo" } }])).toEqual({})
})
it("uses the shared database for the managed backend while preserving the environment", () => {
expect(resolveManagedServerEnv({ PATH: "/usr/bin", KILO_DISABLE_CHANNEL_DB: "false" })).toEqual({
it("disables unused managed-backend services while preserving the environment", () => {
expect(
resolveManagedServerEnv({
PATH: "/usr/bin",
KILO_DISABLE_CHANNEL_DB: "false",
KILO_EXPERIMENTAL_DISABLE_FILEWATCHER: "false",
}),
).toEqual({
PATH: "/usr/bin",
KILO_DISABLE_CHANNEL_DB: "true",
KILO_EXPERIMENTAL_DISABLE_FILEWATCHER: "true",
})
})
})