From e4c4796c50a5e83a1dc70b1ec635e0aede4b4f58 Mon Sep 17 00:00:00 2001 From: kitlangton Date: Sun, 23 Aug 2026 00:10:36 +0000 Subject: [PATCH] fix(core): protect home descendants from FFF --- packages/core/src/filesystem/protected.ts | 5 +++++ packages/core/src/filesystem/search.ts | 6 +++++- packages/core/test/filesystem/search.test.ts | 21 ++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/core/src/filesystem/protected.ts b/packages/core/src/filesystem/protected.ts index aaf14509fd..004335afb3 100644 --- a/packages/core/src/filesystem/protected.ts +++ b/packages/core/src/filesystem/protected.ts @@ -7,6 +7,11 @@ export function isHome(directory: string) { return path.resolve(directory) === path.resolve(home) } +export function containsHome(directory: string) { + const relative = path.relative(directory, home) + return relative === "" || (relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative)) +} + const DARWIN_HOME = [ "Music", "Pictures", diff --git a/packages/core/src/filesystem/search.ts b/packages/core/src/filesystem/search.ts index ed939ba2b2..cae26f70ae 100644 --- a/packages/core/src/filesystem/search.ts +++ b/packages/core/src/filesystem/search.ts @@ -177,6 +177,10 @@ export const fffLayer = Layer.effect( }), ) +export function isPersistentEligible(location: Location.Interface) { + return !!location.vcs && !Protected.containsHome(location.project.directory) +} + export const layer = (options?: Options) => Layer.unwrap( Effect.gen(function* () { @@ -184,7 +188,7 @@ export const layer = (options?: Options) => return ripgrepLayer const location = yield* Location.Service // Non-VCS locations can contain many repositories, so avoid eagerly content-indexing the entire aggregate tree. - return location.vcs && !Protected.isHome(location.directory) ? fffLayer : ripgrepLayer + return isPersistentEligible(location) ? fffLayer : ripgrepLayer }), ) diff --git a/packages/core/test/filesystem/search.test.ts b/packages/core/test/filesystem/search.test.ts index c29c8431eb..bbfef25e70 100644 --- a/packages/core/test/filesystem/search.test.ts +++ b/packages/core/test/filesystem/search.test.ts @@ -15,6 +15,27 @@ import { AbsolutePath, RelativePath } from "@opencode-ai/core/schema" import { location } from "../fixture/location" describe("FileSystemSearch", () => { + test("disables persistent indexing when the worktree contains home", () => { + const home = AbsolutePath.make(os.homedir()) + const directory = AbsolutePath.make(path.join(home, "broad-location")) + const vcs = { type: "git" as const, store: AbsolutePath.make(path.join(home, ".git")) } + expect(FileSystemSearch.isPersistentEligible(location({ directory }, { projectDirectory: home, vcs }))).toBe(false) + expect( + FileSystemSearch.isPersistentEligible( + location({ directory }, { projectDirectory: AbsolutePath.make(path.dirname(home)), vcs }), + ), + ).toBe(false) + }) + + test("enables persistent indexing for a nested worktree below home", () => { + const directory = AbsolutePath.make(path.join(os.homedir(), "project")) + expect( + FileSystemSearch.isPersistentEligible( + location({ directory }, { vcs: { type: "git", store: AbsolutePath.make(path.join(directory, ".git")) } }), + ), + ).toBe(true) + }) + test("honors wildcard directory rules from .gitignore", async () => { const directory = await mkdtemp(path.join(os.tmpdir(), "opencode-fff-ignore-")) try {