refactor(core): consolidate filesystem services (#30447)
This commit is contained in:
@@ -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 () => {
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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"),
|
||||
`---
|
||||
|
||||
@@ -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(
|
||||
"/",
|
||||
{
|
||||
|
||||
@@ -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", {
|
||||
|
||||
Reference in New Issue
Block a user