fix(core): initialize fff lazily

This commit is contained in:
Kit Langton 2026-07-11 14:35:00 -04:00
commit 7b49c490a5
2 changed files with 182 additions and 99 deletions

View file

@ -1,10 +1,15 @@
import { describe, expect } from "bun:test"
import fs from "fs/promises"
import path from "path"
import { Effect } from "effect"
import { Context, Effect, Layer, Scope } from "effect"
import { FileFinder } from "@ff-labs/fff-bun"
import "@opencode-ai/core/filesystem"
import { Fff } from "@opencode-ai/core/filesystem/fff.bun"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Location } from "@opencode-ai/core/location"
import { Ripgrep } from "@opencode-ai/core/ripgrep"
import { AbsolutePath, RelativePath } from "@opencode-ai/core/schema"
import { location } from "../fixture/location"
import { tmpdir } from "../fixture/tmpdir"
import { testEffect } from "../lib/effect"
@ -42,3 +47,70 @@ describe("Ripgrep", () => {
),
)
})
describe("FileSystemSearch", () => {
it.live("initializes fff on the first search", () =>
withTmp((directory) =>
Effect.gen(function* () {
if (!Fff.available()) return
yield* Effect.promise(() => fs.writeFile(path.join(directory, "README.md"), "hello\n"))
const { FileSystemSearch } = yield* Effect.promise(() => import("@opencode-ai/core/filesystem/search"))
const create = FileFinder.create
const calls = { create: 0, destroy: 0 }
yield* Effect.acquireUseRelease(
Effect.sync(() => {
FileFinder.create = (options) => {
calls.create++
const result = create(options)
if (!result.ok) return result
const destroy = result.value.destroy.bind(result.value)
result.value.destroy = () => {
calls.destroy++
destroy()
}
return result
}
}),
() =>
Effect.gen(function* () {
yield* Effect.acquireUseRelease(
Scope.make(),
(scope) =>
Effect.gen(function* () {
const context = yield* Layer.buildWithScope(
FileSystemSearch.fffLayer.pipe(
Layer.provide(
Layer.succeed(
Location.Service,
Location.Service.of(location(Location.Ref.make({ directory }))),
),
),
),
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)
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)
}),
() => Effect.sync(() => (FileFinder.create = create)),
)
}),
),
)
})