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

View File

@@ -51,7 +51,7 @@ describe("file HttpApi", () => {
expect(await content.json()).toMatchObject({ type: "text", content: "hello" })
expect(status.status).toBe(200)
expect(await status.json()).toContainEqual({ path: "hello.txt", added: 1, removed: 0, status: "added" })
expect(await status.json()).toEqual([])
})
test("serves search endpoints", async () => {

View File

@@ -25,11 +25,6 @@ function app() {
type TestApp = ReturnType<typeof app>
type TestHandler = ReturnType<typeof HttpApiApp.webHandler>
const handlerScoped = Effect.acquireRelease(
Effect.sync(() => HttpApiApp.webHandler()),
(handler) => Effect.promise(() => handler.dispose()).pipe(Effect.ignore),
)
const request = Effect.fnUntraced(function* (
handler: TestHandler,
route: string,
@@ -69,7 +64,7 @@ describe("mcp HttpApi", () => {
() =>
Effect.gen(function* () {
const tmp = yield* TestInstance
const handler = yield* handlerScoped
const handler = HttpApiApp.webHandler()
const response = yield* request(handler, McpPaths.status, tmp.directory)
expect(response.status).toBe(200)
@@ -93,7 +88,7 @@ describe("mcp HttpApi", () => {
() =>
Effect.gen(function* () {
const tmp = yield* TestInstance
const handler = yield* handlerScoped
const handler = HttpApiApp.webHandler()
const added = yield* request(handler, McpPaths.status, tmp.directory, {
method: "POST",
headers: { "content-type": "application/json" },
@@ -139,7 +134,7 @@ describe("mcp HttpApi", () => {
() =>
Effect.gen(function* () {
const tmp = yield* TestInstance
const handler = yield* handlerScoped
const handler = HttpApiApp.webHandler()
const start = yield* request(handler, "/mcp/demo/auth", tmp.directory, { method: "POST" })
expect(start.status).toBe(400)
@@ -202,7 +197,7 @@ describe("mcp HttpApi", () => {
() =>
Effect.gen(function* () {
const tmp = yield* TestInstance
const handler = yield* handlerScoped
const handler = HttpApiApp.webHandler()
for (const input of [
{ method: "POST", route: "/mcp/missing/auth" },

View File

@@ -1,5 +1,5 @@
import { describe, expect } from "bun:test"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { FSUtil } from "@opencode-ai/core/fs-util"
import { Effect, Layer } from "effect"
import path from "path"
import * as Log from "@opencode-ai/core/util/log"
@@ -18,7 +18,7 @@ const testStateLayer = Layer.effectDiscard(
),
)
const it = testEffect(Layer.mergeAll(testStateLayer, AppFileSystem.defaultLayer, httpApiLayer))
const it = testEffect(Layer.mergeAll(testStateLayer, FSUtil.defaultLayer, httpApiLayer))
const projectOptions = { config: { formatter: false, lsp: false } }
const providerID = "test-oauth-parity"
const oauthURL = "https://example.com/oauth"
@@ -107,7 +107,7 @@ function requestCallback(input: { providerID: string; method: number; headers: H
function writeProviderAuthPlugin(dir: string) {
return Effect.gen(function* () {
const fs = yield* AppFileSystem.Service
const fs = yield* FSUtil.Service
yield* Effect.promise(() => markPluginDependenciesReady(path.join(dir, ".opencode")))
yield* fs.writeWithDirs(
@@ -142,7 +142,7 @@ function writeProviderAuthPlugin(dir: string) {
function writeProviderAuthValidationPlugin(dir: string) {
return Effect.gen(function* () {
const fs = yield* AppFileSystem.Service
const fs = yield* FSUtil.Service
yield* Effect.promise(() => markPluginDependenciesReady(path.join(dir, ".opencode")))
yield* fs.writeWithDirs(
@@ -184,7 +184,7 @@ function writeProviderAuthValidationPlugin(dir: string) {
function writeFunctionOptionsPlugin(dir: string) {
return Effect.gen(function* () {
const fs = yield* AppFileSystem.Service
const fs = yield* FSUtil.Service
yield* Effect.promise(() => markPluginDependenciesReady(path.join(dir, ".opencode")))
yield* fs.writeWithDirs(
@@ -216,7 +216,7 @@ function writeFunctionOptionsPlugin(dir: string) {
function writeProviderModelsMutationPlugin(dir: string) {
return Effect.gen(function* () {
const fs = yield* AppFileSystem.Service
const fs = yield* FSUtil.Service
yield* Effect.promise(() => markPluginDependenciesReady(path.join(dir, ".opencode")))
yield* fs.writeWithDirs(

View File

@@ -4,7 +4,7 @@ import { Deferred, Effect, Layer } from "effect"
import type * as Scope from "effect/Scope"
import { HttpServer } from "effect/unstable/http"
import { ChildProcessSpawner } from "effect/unstable/process"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { FSUtil } from "@opencode-ai/core/fs-util"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { Flag } from "@opencode-ai/core/flag/flag"
import { createOpencodeClient } from "@opencode-ai/sdk/v2"
@@ -30,7 +30,7 @@ import { httpApiLayer } from "./httpapi-layer"
const noopBootstrap = Layer.succeed(InstanceBootstrap.Service, InstanceBootstrap.Service.of({ run: Effect.void }))
const it = testEffect(
Layer.mergeAll(
AppFileSystem.defaultLayer,
FSUtil.defaultLayer,
CrossSpawnSpawner.defaultLayer,
InstanceStore.defaultLayer.pipe(Layer.provide(noopBootstrap)),
Database.defaultLayer,
@@ -50,7 +50,7 @@ type Captured = { status: number; data?: unknown; error?: unknown }
type ProjectFixture = { sdk: Sdk; directory: string }
type LlmProjectFixture = ProjectFixture & { llm: TestLLMServer["Service"] }
type TestServices =
| AppFileSystem.Service
| FSUtil.Service
| ChildProcessSpawner.ChildProcessSpawner
| InstanceStore.Service
| HttpServer.HttpServer
@@ -262,7 +262,7 @@ function withFakeLlmProject<A, E>(
}
function writeStandardFiles(dir: string) {
return AppFileSystem.Service.use((fs) =>
return FSUtil.Service.use((fs) =>
Effect.all([
fs.writeWithDirs(path.join(dir, "hello.txt"), "hello"),
fs.writeWithDirs(path.join(dir, "needle.ts"), "export const needle = 'sdk-parity'\n"),
@@ -271,7 +271,7 @@ function writeStandardFiles(dir: string) {
}
function writeProjectSkill(dir: string) {
return AppFileSystem.Service.use((fs) =>
return FSUtil.Service.use((fs) =>
fs.writeWithDirs(
path.join(dir, ".opencode", "skills", "project-rest-skill", "SKILL.md"),
`---

View File

@@ -12,7 +12,7 @@ import {
HttpServerRequest,
HttpServerResponse,
} from "effect/unstable/http"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { FSUtil } from "@opencode-ai/core/fs-util"
import { RuntimeFlags } from "../../src/effect/runtime-flags"
import { ServerAuth } from "../../src/server/auth"
import { authorizationRouterMiddleware } from "../../src/server/routes/instance/httpapi/middleware/authorization"
@@ -42,7 +42,7 @@ const testStateLayer = Layer.effectDiscard(
}),
)
const it = testEffect(Layer.mergeAll(testStateLayer, AppFileSystem.defaultLayer, RuntimeFlags.layer()))
const it = testEffect(Layer.mergeAll(testStateLayer, FSUtil.defaultLayer, RuntimeFlags.layer()))
function restoreEnv(key: string, value: string | undefined) {
if (value === undefined) {
@@ -89,7 +89,7 @@ function uiApp(input?: {
const handler = HttpRouter.toWebHandler(
HttpRouter.use((router) =>
Effect.gen(function* () {
const fs = yield* AppFileSystem.Service
const fs = yield* FSUtil.Service
const client = yield* HttpClient.HttpClient
const flags = yield* RuntimeFlags.Service
yield* router.add("*", "/*", (request) =>
@@ -99,7 +99,7 @@ function uiApp(input?: {
).pipe(
Layer.provide(authorizationRouterMiddleware.layer.pipe(Layer.provide(ServerAuth.Config.defaultLayer))),
Layer.provide([
AppFileSystem.defaultLayer,
FSUtil.defaultLayer,
input?.client ?? httpClient(new Response("ui")),
RuntimeFlags.layer({ disableEmbeddedWebUi: input?.disableEmbeddedWebUi ?? false }),
HttpServer.layerServices,
@@ -132,7 +132,7 @@ function routeOrderingApp() {
const handler = HttpRouter.toWebHandler(
HttpRouter.use((router) =>
Effect.gen(function* () {
const fs = yield* AppFileSystem.Service
const fs = yield* FSUtil.Service
const client = yield* HttpClient.HttpClient
const flags = yield* RuntimeFlags.Service
yield* router.add("GET", "/session/:sessionID", () =>
@@ -144,7 +144,7 @@ function routeOrderingApp() {
}),
).pipe(
Layer.provide([
AppFileSystem.defaultLayer,
FSUtil.defaultLayer,
RuntimeFlags.layer({ disableEmbeddedWebUi: true }),
httpClient(new Response("ui"), (request) => {
proxiedUrl = request.url
@@ -210,7 +210,7 @@ describe("HttpApi UI fallback", () => {
let proxiedUrl: string | undefined
const response = yield* Effect.gen(function* () {
const fs = yield* AppFileSystem.Service
const fs = yield* FSUtil.Service
const client = yield* HttpClient.HttpClient
const flags = yield* RuntimeFlags.Service
return yield* serveUIEffect(HttpServerRequest.fromWeb(new Request("http://localhost/assets/app.js")), {
@@ -260,7 +260,7 @@ describe("HttpApi UI fallback", () => {
it.live("strips upstream transfer-encoding header from proxied assets", () =>
Effect.gen(function* () {
const response = yield* Effect.gen(function* () {
const fs = yield* AppFileSystem.Service
const fs = yield* FSUtil.Service
const client = yield* HttpClient.HttpClient
const flags = yield* RuntimeFlags.Service
return yield* serveUIEffect(HttpServerRequest.fromWeb(new Request("http://localhost/")), {
@@ -303,7 +303,7 @@ describe("HttpApi UI fallback", () => {
Effect.gen(function* () {
let readPath: string | undefined
const fs = yield* AppFileSystem.Service
const fs = yield* FSUtil.Service
const response = yield* serveEmbeddedUIEffect(
"/assets/app.js",
{
@@ -330,7 +330,7 @@ describe("HttpApi UI fallback", () => {
Effect.gen(function* () {
const script = 'document.documentElement.dataset.theme = "dark"'
const fs = yield* AppFileSystem.Service
const fs = yield* FSUtil.Service
const response = yield* serveEmbeddedUIEffect(
"/",
{

View File

@@ -1,5 +1,5 @@
import { afterEach, describe, expect } from "bun:test"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { FSUtil } from "@opencode-ai/core/fs-util"
import { Effect, Layer } from "effect"
import { HttpClientResponse } from "effect/unstable/http"
import path from "path"
@@ -24,9 +24,7 @@ afterEach(async () => {
const noopBootstrap = Layer.succeed(InstanceBootstrap.Service, InstanceBootstrap.Service.of({ run: Effect.void }))
const testInstanceStore = InstanceStore.defaultLayer.pipe(Layer.provide(noopBootstrap))
const it = testEffect(
Layer.mergeAll(AppFileSystem.defaultLayer, Snapshot.defaultLayer, testInstanceStore, httpApiLayer),
)
const it = testEffect(Layer.mergeAll(FSUtil.defaultLayer, Snapshot.defaultLayer, testInstanceStore, httpApiLayer))
function request(directory: string, url: string, init: RequestInit = {}) {
return requestInDirectory(url, directory, init)
@@ -57,7 +55,7 @@ describe("project.initGit endpoint", () => {
it.instance("initializes git and reloads immediately", () =>
Effect.gen(function* () {
const tmp = yield* TestInstance
const fs = yield* AppFileSystem.Service
const fs = yield* FSUtil.Service
const events = yield* collectGlobalEvents()
const init = yield* request(tmp.directory, "/project/git/init", {