refactor(core): consolidate filesystem services (#30447)
This commit is contained in:
@@ -4,7 +4,7 @@ import * as fs from "fs/promises"
|
||||
import { Cause, Effect, Exit, Layer } from "effect"
|
||||
import { ApplyPatchTool } from "../../src/tool/apply_patch"
|
||||
import { LSP } from "@/lsp/lsp"
|
||||
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { Format } from "../../src/format"
|
||||
import { Agent } from "../../src/agent/agent"
|
||||
import { EventV2Bridge } from "../../src/event-v2-bridge"
|
||||
@@ -16,7 +16,7 @@ import { testEffect } from "../lib/effect"
|
||||
const it = testEffect(
|
||||
Layer.mergeAll(
|
||||
LSP.defaultLayer,
|
||||
AppFileSystem.defaultLayer,
|
||||
FSUtil.defaultLayer,
|
||||
Format.defaultLayer,
|
||||
EventV2Bridge.defaultLayer,
|
||||
Truncate.defaultLayer,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Cause, Deferred, Effect, Exit, Fiber, Layer } from "effect"
|
||||
import { EditTool } from "../../src/tool/edit"
|
||||
import { disposeAllInstances, TestInstance } from "../fixture/fixture"
|
||||
import { LSP } from "@/lsp/lsp"
|
||||
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { Format } from "../../src/format"
|
||||
import { Agent } from "../../src/agent/agent"
|
||||
import { EventV2Bridge } from "../../src/event-v2-bridge"
|
||||
@@ -13,7 +13,7 @@ import { Truncate } from "@/tool/truncate"
|
||||
import { SessionID, MessageID } from "../../src/session/schema"
|
||||
import * as Tool from "../../src/tool/tool"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { FileWatcher } from "../../src/file/watcher"
|
||||
import { Watcher } from "@opencode-ai/core/filesystem/watcher"
|
||||
|
||||
const ctx = {
|
||||
sessionID: SessionID.make("ses_test-edit-session"),
|
||||
@@ -32,7 +32,7 @@ afterEach(async () => {
|
||||
|
||||
const layer = Layer.mergeAll(
|
||||
LSP.defaultLayer,
|
||||
AppFileSystem.defaultLayer,
|
||||
FSUtil.defaultLayer,
|
||||
Format.defaultLayer,
|
||||
EventV2Bridge.defaultLayer,
|
||||
Truncate.defaultLayer,
|
||||
@@ -64,12 +64,12 @@ const fail = Effect.fn("EditToolTest.fail")(function* (args: Tool.InferParameter
|
||||
})
|
||||
|
||||
const put = Effect.fn("EditToolTest.put")(function* (p: string, content: string) {
|
||||
const fs = yield* AppFileSystem.Service
|
||||
const fs = yield* FSUtil.Service
|
||||
yield* fs.writeWithDirs(p, content)
|
||||
})
|
||||
|
||||
const load = Effect.fn("EditToolTest.load")(function* (p: string) {
|
||||
const fs = yield* AppFileSystem.Service
|
||||
const fs = yield* FSUtil.Service
|
||||
return yield* fs.readFileString(p)
|
||||
})
|
||||
|
||||
@@ -78,11 +78,11 @@ const loadRaw = Effect.fn("EditToolTest.loadRaw")(function* (p: string) {
|
||||
})
|
||||
|
||||
const makeDirectory = Effect.fn("EditToolTest.makeDirectory")(function* (p: string) {
|
||||
const fs = yield* AppFileSystem.Service
|
||||
const fs = yield* FSUtil.Service
|
||||
yield* fs.makeDirectory(p)
|
||||
})
|
||||
|
||||
const onceBus = Effect.fn("EditToolTest.onceBus")(function* (def: typeof FileWatcher.Event.Updated) {
|
||||
const onceBus = Effect.fn("EditToolTest.onceBus")(function* (def: typeof Watcher.Event.Updated) {
|
||||
const events = yield* EventV2Bridge.Service
|
||||
const deferred = yield* Deferred.make<void>()
|
||||
const unsub = yield* events.listen((event) => {
|
||||
@@ -138,7 +138,7 @@ describe("tool.edit", () => {
|
||||
it.instance("emits add event for new files", () =>
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
const updated = yield* onceBus(FileWatcher.Event.Updated)
|
||||
const updated = yield* onceBus(Watcher.Event.Updated)
|
||||
|
||||
yield* run({ filePath: path.join(test.directory, "new.txt"), oldString: "", newString: "content" })
|
||||
yield* Deferred.await(updated)
|
||||
@@ -230,7 +230,7 @@ describe("tool.edit", () => {
|
||||
const test = yield* TestInstance
|
||||
const filepath = path.join(test.directory, "file.txt")
|
||||
yield* put(filepath, "original")
|
||||
const updated = yield* onceBus(FileWatcher.Event.Updated)
|
||||
const updated = yield* onceBus(Watcher.Event.Updated)
|
||||
|
||||
yield* run({ filePath: filepath, oldString: "original", newString: "modified" })
|
||||
yield* Deferred.await(updated)
|
||||
|
||||
@@ -5,8 +5,8 @@ import { Cause, Effect, Exit, Layer } from "effect"
|
||||
import { GlobTool } from "../../src/tool/glob"
|
||||
import { SessionID, MessageID } from "../../src/session/schema"
|
||||
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||
import { Ripgrep } from "../../src/file/ripgrep"
|
||||
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||
import { Ripgrep } from "@opencode-ai/core/filesystem/ripgrep"
|
||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { Global } from "@opencode-ai/core/global"
|
||||
import { Truncate } from "@/tool/truncate"
|
||||
import { Agent } from "../../src/agent/agent"
|
||||
@@ -30,7 +30,7 @@ const referenceLayer = (flags: Partial<RuntimeFlags.Info> = {}) =>
|
||||
const toolLayer = (flags: Partial<RuntimeFlags.Info> = {}) =>
|
||||
Layer.mergeAll(
|
||||
CrossSpawnSpawner.defaultLayer,
|
||||
AppFileSystem.defaultLayer,
|
||||
FSUtil.defaultLayer,
|
||||
Ripgrep.defaultLayer,
|
||||
Truncate.defaultLayer,
|
||||
Agent.defaultLayer,
|
||||
@@ -148,7 +148,7 @@ describe("tool.glob", () => {
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
yield* TestInstance
|
||||
const fs = yield* AppFileSystem.Service
|
||||
const fs = yield* FSUtil.Service
|
||||
const cache = path.join(Global.Path.repos, "github.com", "opencode-glob-reference", "repo")
|
||||
yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore)
|
||||
yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore))
|
||||
|
||||
@@ -11,8 +11,8 @@ import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||
import { Global } from "@opencode-ai/core/global"
|
||||
import { Truncate } from "@/tool/truncate"
|
||||
import { Agent } from "../../src/agent/agent"
|
||||
import { Ripgrep } from "../../src/file/ripgrep"
|
||||
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||
import { Ripgrep } from "@opencode-ai/core/filesystem/ripgrep"
|
||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { Reference } from "@/reference/reference"
|
||||
import { RepositoryCache } from "@/reference/repository-cache"
|
||||
@@ -33,7 +33,7 @@ const referenceLayer = (flags: Partial<RuntimeFlags.Info> = {}) =>
|
||||
const toolLayer = (flags: Partial<RuntimeFlags.Info> = {}) =>
|
||||
Layer.mergeAll(
|
||||
CrossSpawnSpawner.defaultLayer,
|
||||
AppFileSystem.defaultLayer,
|
||||
FSUtil.defaultLayer,
|
||||
Ripgrep.defaultLayer,
|
||||
Truncate.defaultLayer,
|
||||
Agent.defaultLayer,
|
||||
@@ -220,7 +220,7 @@ describe("tool.grep", () => {
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
yield* TestInstance
|
||||
const appfs = yield* AppFileSystem.Service
|
||||
const appfs = yield* FSUtil.Service
|
||||
const cache = path.join(Global.Path.repos, "github.com", "opencode-grep-reference", "repo")
|
||||
yield* appfs.remove(cache, { recursive: true }).pipe(Effect.ignore)
|
||||
yield* Effect.addFinalizer(() => appfs.remove(cache, { recursive: true }).pipe(Effect.ignore))
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Effect, Layer } from "effect"
|
||||
import path from "path"
|
||||
import { Agent } from "../../src/agent/agent"
|
||||
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { LSP } from "@/lsp/lsp"
|
||||
import { Permission } from "../../src/permission"
|
||||
import { MessageID, SessionID } from "../../src/session/schema"
|
||||
@@ -56,13 +56,7 @@ const lsp = Layer.succeed(
|
||||
)
|
||||
|
||||
const it = testEffect(
|
||||
Layer.mergeAll(
|
||||
Agent.defaultLayer,
|
||||
AppFileSystem.defaultLayer,
|
||||
CrossSpawnSpawner.defaultLayer,
|
||||
Truncate.defaultLayer,
|
||||
lsp,
|
||||
),
|
||||
Layer.mergeAll(Agent.defaultLayer, FSUtil.defaultLayer, CrossSpawnSpawner.defaultLayer, Truncate.defaultLayer, lsp),
|
||||
)
|
||||
|
||||
const init = Effect.fn("LspToolTest.init")(function* () {
|
||||
@@ -79,7 +73,7 @@ const run = Effect.fn("LspToolTest.run")(function* (
|
||||
})
|
||||
|
||||
const put = Effect.fn("LspToolTest.put")(function* (file: string) {
|
||||
const fs = yield* AppFileSystem.Service
|
||||
const fs = yield* FSUtil.Service
|
||||
yield* fs.writeWithDirs(file, "export const x = 1\n")
|
||||
})
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Cause, Effect, Exit, Layer, Stream } from "effect"
|
||||
import path from "path"
|
||||
import { Agent } from "../../src/agent/agent"
|
||||
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { Global } from "@opencode-ai/core/global"
|
||||
import { Config } from "@/config/config"
|
||||
import { RuntimeFlags } from "@/effect/runtime-flags"
|
||||
@@ -54,7 +54,7 @@ const referenceLayer = (flags: Partial<RuntimeFlags.Info> = {}) =>
|
||||
const readLayer = (flags: Partial<RuntimeFlags.Info> = {}) =>
|
||||
Layer.mergeAll(
|
||||
Agent.defaultLayer,
|
||||
AppFileSystem.defaultLayer,
|
||||
FSUtil.defaultLayer,
|
||||
CrossSpawnSpawner.defaultLayer,
|
||||
Instruction.defaultLayer,
|
||||
LSP.defaultLayer,
|
||||
@@ -133,11 +133,11 @@ const git = Effect.fn("ReadToolTest.git")(function* (cwd: string, args: string[]
|
||||
})
|
||||
})
|
||||
const put = Effect.fn("ReadToolTest.put")(function* (p: string, content: string | Buffer | Uint8Array) {
|
||||
const fs = yield* AppFileSystem.Service
|
||||
const fs = yield* FSUtil.Service
|
||||
yield* fs.writeWithDirs(p, content)
|
||||
})
|
||||
const load = Effect.fn("ReadToolTest.load")(function* (p: string) {
|
||||
const fs = yield* AppFileSystem.Service
|
||||
const fs = yield* FSUtil.Service
|
||||
return yield* fs.readFileString(p)
|
||||
})
|
||||
const asks = () => {
|
||||
@@ -266,7 +266,7 @@ describe("tool.read external_directory permission", () => {
|
||||
|
||||
references.live("does not ask for external_directory permission when reading configured references", () =>
|
||||
Effect.gen(function* () {
|
||||
const fs = yield* AppFileSystem.Service
|
||||
const fs = yield* FSUtil.Service
|
||||
const cache = path.join(Global.Path.repos, "github.com", "opencode-read-reference", "repo")
|
||||
yield* fs.remove(cache, { recursive: true }).pipe(Effect.ignore)
|
||||
yield* Effect.addFinalizer(() => fs.remove(cache, { recursive: true }).pipe(Effect.ignore))
|
||||
@@ -379,12 +379,12 @@ describe("tool.read truncation", () => {
|
||||
const content = `${"x".repeat(80)}\n`.repeat(50_000)
|
||||
yield* put(filepath, content)
|
||||
|
||||
const fs = yield* AppFileSystem.Service
|
||||
const fs = yield* FSUtil.Service
|
||||
const counter = { bytes: 0 }
|
||||
const result = yield* run({ filePath: filepath }).pipe(
|
||||
Effect.provideService(
|
||||
AppFileSystem.Service,
|
||||
AppFileSystem.Service.of({
|
||||
FSUtil.Service,
|
||||
FSUtil.Service.of({
|
||||
...fs,
|
||||
stream: (file, options) =>
|
||||
fs.stream(file, options).pipe(
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Tool } from "@/tool/tool"
|
||||
import { disposeAllInstances, TestInstance } from "../fixture/fixture"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { TestConfig } from "../fixture/config"
|
||||
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { Plugin } from "@/plugin"
|
||||
import { Question } from "@/question"
|
||||
import { Todo } from "@/session/todo"
|
||||
@@ -26,7 +26,7 @@ import { Instruction } from "@/session/instruction"
|
||||
import { EventV2Bridge } from "@/event-v2-bridge"
|
||||
import { FetchHttpClient } from "effect/unstable/http"
|
||||
import { Format } from "@/format"
|
||||
import { Ripgrep } from "@/file/ripgrep"
|
||||
import { Ripgrep } from "@opencode-ai/core/filesystem/ripgrep"
|
||||
import * as Truncate from "@/tool/truncate"
|
||||
import { InstanceState } from "@/effect/instance-state"
|
||||
import { Reference } from "@/reference/reference"
|
||||
@@ -63,7 +63,7 @@ const registryLayer = (opts: RegistryLayerOptions = {}) =>
|
||||
Layer.provide(Reference.defaultLayer),
|
||||
Layer.provide(LSP.defaultLayer),
|
||||
Layer.provide(Instruction.defaultLayer),
|
||||
Layer.provide(AppFileSystem.defaultLayer),
|
||||
Layer.provide(FSUtil.defaultLayer),
|
||||
Layer.provide(EventV2Bridge.defaultLayer),
|
||||
Layer.provide(FetchHttpClient.layer),
|
||||
Layer.provide(Format.defaultLayer),
|
||||
|
||||
@@ -14,7 +14,7 @@ import { Agent } from "../../src/agent/agent"
|
||||
import { Truncate } from "@/tool/truncate"
|
||||
import { SessionID, MessageID } from "../../src/session/schema"
|
||||
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { Plugin } from "../../src/plugin"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { Tool } from "@/tool/tool"
|
||||
@@ -23,7 +23,7 @@ import { InstanceStore } from "@/project/instance-store"
|
||||
|
||||
const shellLayer = Layer.mergeAll(
|
||||
CrossSpawnSpawner.defaultLayer,
|
||||
AppFileSystem.defaultLayer,
|
||||
FSUtil.defaultLayer,
|
||||
Plugin.defaultLayer,
|
||||
Truncate.defaultLayer,
|
||||
Config.defaultLayer,
|
||||
@@ -1223,7 +1223,7 @@ describe("tool.shell truncation", () => {
|
||||
const filepath = (result.metadata as { outputPath?: string }).outputPath
|
||||
expect(filepath).toBeTruthy()
|
||||
|
||||
const saved = yield* (yield* AppFileSystem.Service).readFileString(filepath!)
|
||||
const saved = yield* (yield* FSUtil.Service).readFileString(filepath!)
|
||||
const lines = saved.trim().split(/\r?\n/)
|
||||
expect(lines.length).toBe(lineCount)
|
||||
expect(lines[0]).toBe("1")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, test, expect } from "bun:test"
|
||||
import { NodeFileSystem } from "@effect/platform-node"
|
||||
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { Effect, FileSystem, Layer } from "effect"
|
||||
import { Truncate } from "@/tool/truncate"
|
||||
import { Config } from "@/config/config"
|
||||
@@ -14,13 +14,13 @@ import { TestConfig } from "../fixture/config"
|
||||
const FIXTURES_DIR = path.join(import.meta.dir, "fixtures")
|
||||
const ROOT = path.resolve(import.meta.dir, "..", "..")
|
||||
|
||||
const it = testEffect(Layer.mergeAll(Truncate.defaultLayer, NodeFileSystem.layer, AppFileSystem.defaultLayer))
|
||||
const it = testEffect(Layer.mergeAll(Truncate.defaultLayer, NodeFileSystem.layer, FSUtil.defaultLayer))
|
||||
|
||||
const configuredLayer = (cfg: Config.Info) =>
|
||||
Layer.mergeAll(
|
||||
Truncate.defaultLayer,
|
||||
NodeFileSystem.layer,
|
||||
AppFileSystem.defaultLayer,
|
||||
FSUtil.defaultLayer,
|
||||
TestConfig.layer({ get: () => Effect.succeed(cfg) }),
|
||||
)
|
||||
const configuredIt = (cfg: Config.Info) => testEffect(configuredLayer(cfg))
|
||||
@@ -30,7 +30,7 @@ describe("Truncate", () => {
|
||||
it.live("truncates large json file by bytes", () =>
|
||||
Effect.gen(function* () {
|
||||
const svc = yield* Truncate.Service
|
||||
const fsys = yield* AppFileSystem.Service
|
||||
const fsys = yield* FSUtil.Service
|
||||
const content = yield* fsys.readFileString(path.join(FIXTURES_DIR, "models-api.json"))
|
||||
const result = yield* svc.output(content)
|
||||
|
||||
@@ -164,7 +164,7 @@ describe("Truncate", () => {
|
||||
it.live("large single-line file truncates with byte message", () =>
|
||||
Effect.gen(function* () {
|
||||
const svc = yield* Truncate.Service
|
||||
const fsys = yield* AppFileSystem.Service
|
||||
const fsys = yield* FSUtil.Service
|
||||
const content = yield* fsys.readFileString(path.join(FIXTURES_DIR, "models-api.json"))
|
||||
const result = yield* svc.output(content)
|
||||
|
||||
@@ -187,7 +187,7 @@ describe("Truncate", () => {
|
||||
expect(result.outputPath).toBeDefined()
|
||||
expect(result.outputPath).toContain("tool_")
|
||||
|
||||
const fsys = yield* AppFileSystem.Service
|
||||
const fsys = yield* FSUtil.Service
|
||||
const written = yield* fsys.readFileString(result.outputPath!)
|
||||
expect(written).toBe(lines)
|
||||
}),
|
||||
|
||||
@@ -4,7 +4,7 @@ import path from "path"
|
||||
import fs from "fs/promises"
|
||||
import { WriteTool } from "../../src/tool/write"
|
||||
import { LSP } from "@/lsp/lsp"
|
||||
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { EventV2Bridge } from "../../src/event-v2-bridge"
|
||||
import { Format } from "../../src/format"
|
||||
import { Truncate } from "@/tool/truncate"
|
||||
@@ -33,7 +33,7 @@ afterEach(async () => {
|
||||
const it = testEffect(
|
||||
Layer.mergeAll(
|
||||
LSP.defaultLayer,
|
||||
AppFileSystem.defaultLayer,
|
||||
FSUtil.defaultLayer,
|
||||
EventV2Bridge.defaultLayer,
|
||||
Format.defaultLayer,
|
||||
CrossSpawnSpawner.defaultLayer,
|
||||
|
||||
Reference in New Issue
Block a user