refactor(core): consolidate filesystem services (#30447)

This commit is contained in:
Dax
2026-06-02 16:09:26 -04:00
committed by GitHub
parent b93963e462
commit 604a5f781f
153 changed files with 2553 additions and 4312 deletions
+12 -16
View File
@@ -1,18 +1,14 @@
import * as Log from "@opencode-ai/core/util/log"
import path from "path"
import { Global } from "@opencode-ai/core/global"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { FSUtil } from "@opencode-ai/core/fs-util"
import { Effect, Exit, Layer, Option, RcMap, Schema, Context, TxReentrantLock } from "effect"
import { NonNegativeInt } from "@opencode-ai/core/schema"
import { Git } from "@/git"
const log = Log.create({ service: "storage" })
type Migration = (
dir: string,
fs: AppFileSystem.Interface,
git: Git.Interface,
) => Effect.Effect<void, AppFileSystem.Error>
type Migration = (dir: string, fs: FSUtil.Interface, git: Git.Interface) => Effect.Effect<void, FSUtil.Error>
export class NotFoundError extends Schema.TaggedErrorClass<NotFoundError>()("NotFoundError", {
message: Schema.String,
@@ -22,7 +18,7 @@ export class NotFoundError extends Schema.TaggedErrorClass<NotFoundError>()("Not
}
}
export type Error = AppFileSystem.Error | NotFoundError
export type Error = FSUtil.Error | NotFoundError
const RootFile = Schema.Struct({
path: Schema.optional(
@@ -57,11 +53,11 @@ const decodeMessage = Schema.decodeUnknownOption(MessageFile)
const decodeSummary = Schema.decodeUnknownOption(SummaryFile)
export interface Interface {
readonly remove: (key: string[]) => Effect.Effect<void, AppFileSystem.Error>
readonly remove: (key: string[]) => Effect.Effect<void, FSUtil.Error>
readonly read: <T>(key: string[]) => Effect.Effect<T, Error>
readonly update: <T>(key: string[], fn: (draft: T) => void) => Effect.Effect<T, Error>
readonly write: <T>(key: string[], content: T) => Effect.Effect<void, AppFileSystem.Error>
readonly list: (prefix: string[]) => Effect.Effect<string[][], AppFileSystem.Error>
readonly write: <T>(key: string[], content: T) => Effect.Effect<void, FSUtil.Error>
readonly list: (prefix: string[]) => Effect.Effect<string[][], FSUtil.Error>
}
export class Service extends Context.Service<Service, Interface>()("@opencode/Storage") {}
@@ -85,7 +81,7 @@ function parseMigration(text: string) {
}
const MIGRATIONS: Migration[] = [
Effect.fn("Storage.migration.1")(function* (dir: string, fs: AppFileSystem.Interface, git: Git.Interface) {
Effect.fn("Storage.migration.1")(function* (dir: string, fs: FSUtil.Interface, git: Git.Interface) {
const project = path.resolve(dir, "../project")
if (!(yield* fs.isDir(project))) return
const projectDirs = yield* fs.glob("*", {
@@ -185,7 +181,7 @@ const MIGRATIONS: Migration[] = [
}
}
}),
Effect.fn("Storage.migration.2")(function* (dir: string, fs: AppFileSystem.Interface) {
Effect.fn("Storage.migration.2")(function* (dir: string, fs: FSUtil.Interface) {
for (const item of yield* fs.glob("session/*/*.json", {
cwd: dir,
absolute: true,
@@ -219,7 +215,7 @@ const MIGRATIONS: Migration[] = [
export const layer = Layer.effect(
Service,
Effect.gen(function* () {
const fs = yield* AppFileSystem.Service
const fs = yield* FSUtil.Service
const git = yield* Git.Service
const locks = yield* RcMap.make({
lookup: () => TxReentrantLock.make(),
@@ -251,7 +247,7 @@ export const layer = Layer.effect(
const fail = (target: string): Effect.Effect<never, NotFoundError> =>
Effect.fail(new NotFoundError({ message: `Resource not found: ${target}` }))
const wrap = <A>(target: string, body: Effect.Effect<A, AppFileSystem.Error>) =>
const wrap = <A>(target: string, body: Effect.Effect<A, FSUtil.Error>) =>
body.pipe(Effect.catchIf(missing, () => fail(target)))
const writeJson = Effect.fnUntraced(function* (target: string, content: unknown) {
@@ -261,7 +257,7 @@ export const layer = Layer.effect(
const withResolved = <A, E>(
key: string[],
fn: (target: string, rw: TxReentrantLock.TxReentrantLock) => Effect.Effect<A, E>,
): Effect.Effect<A, E | AppFileSystem.Error> =>
): Effect.Effect<A, E | FSUtil.Error> =>
Effect.scoped(
Effect.gen(function* () {
const target = file((yield* state).dir, key)
@@ -328,6 +324,6 @@ export const layer = Layer.effect(
}),
)
export const defaultLayer = layer.pipe(Layer.provide(AppFileSystem.defaultLayer), Layer.provide(Git.defaultLayer))
export const defaultLayer = layer.pipe(Layer.provide(FSUtil.defaultLayer), Layer.provide(Git.defaultLayer))
export * as Storage from "./storage"