refactor(server): serve raw filesystem content (#31911)
This commit is contained in:
parent
31b233e9db
commit
31c5454ee6
12 changed files with 67 additions and 93 deletions
|
|
@ -38,8 +38,11 @@ const FileReadCommand = effectCmd({
|
|||
description: "File path to read",
|
||||
}),
|
||||
handler: Effect.fn("Cli.debug.file.read")(function* (args) {
|
||||
const content = yield* filesystem(FileSystem.Service.use((svc) => svc.read({ path: RelativePath.make(args.path) })))
|
||||
process.stdout.write(JSON.stringify(content, null, 2) + EOL)
|
||||
const file = yield* filesystem(FileSystem.Service.use((svc) => svc.read({ path: RelativePath.make(args.path) })))
|
||||
process.stdout.write(
|
||||
JSON.stringify({ content: Buffer.from(file.content).toString("base64"), encoding: "base64", mime: file.mime }, null, 2) +
|
||||
EOL,
|
||||
)
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { Ripgrep } from "@opencode-ai/core/ripgrep"
|
|||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { Location } from "@opencode-ai/core/location"
|
||||
import { AbsolutePath, RelativePath } from "@opencode-ai/core/schema"
|
||||
import { Effect, Layer } from "effect"
|
||||
import { Effect, Layer, Option } from "effect"
|
||||
import ignore from "ignore"
|
||||
import path from "path"
|
||||
import { HttpApiBuilder } from "effect/unstable/httpapi"
|
||||
|
|
@ -101,11 +101,26 @@ export const fileHandlers = HttpApiBuilder.group(InstanceHttpApi, "file", (handl
|
|||
return yield* filesystem(
|
||||
FileSystem.Service.use((fs) => fs.read({ path: RelativePath.make(ctx.query.path) })),
|
||||
).pipe(
|
||||
Effect.map((item) => ({
|
||||
type: item.encoding === "utf8" ? ("text" as const) : ("binary" as const),
|
||||
content: item.encoding === "utf8" ? item.content.trim() : item.content,
|
||||
...(item.encoding === "base64" ? { encoding: item.encoding, mimeType: item.mime } : {}),
|
||||
})),
|
||||
Effect.flatMap((item) =>
|
||||
Effect.gen(function* () {
|
||||
const text = item.content.includes(0)
|
||||
? Option.none<string>()
|
||||
: yield* Effect.sync(() => new TextDecoder("utf-8", { fatal: true }).decode(item.content)).pipe(
|
||||
Effect.option,
|
||||
)
|
||||
return { item, text }
|
||||
}),
|
||||
),
|
||||
Effect.map(({ item, text }) =>
|
||||
Option.isSome(text)
|
||||
? { type: "text" as const, content: text.value.trim() }
|
||||
: {
|
||||
type: "binary" as const,
|
||||
content: Buffer.from(item.content).toString("base64"),
|
||||
encoding: "base64" as const,
|
||||
mimeType: item.mime,
|
||||
},
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -709,10 +709,18 @@ const scenarios: Scenario[] = [
|
|||
"status",
|
||||
),
|
||||
http.protected
|
||||
.get("/api/fs/read", "v2.fs.read")
|
||||
.get("/api/fs/read/*", "v2.fs.read")
|
||||
.seeded((ctx) => ctx.file("hello.txt", "hello\n"))
|
||||
.at((ctx) => ({ path: "/api/fs/read?path=hello.txt", headers: ctx.headers() }))
|
||||
.json(200, locationData(object)),
|
||||
.at((ctx) => ({ path: "/api/fs/read/hello.txt", headers: ctx.headers() }))
|
||||
.status(
|
||||
200,
|
||||
(_ctx, result) =>
|
||||
Effect.sync(() => {
|
||||
check(result.text === "hello\n", "v2 fs read should return the file body")
|
||||
check(result.contentType.includes("text/plain"), "v2 fs read should return the file content type")
|
||||
}),
|
||||
"status",
|
||||
),
|
||||
http.protected.get("/api/fs/list", "v2.fs.list").json(200, locationData(array)),
|
||||
http.protected
|
||||
.get("/api/fs/find", "v2.fs.find")
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ describe("PublicApi OpenAPI v2 errors", () => {
|
|||
test("documents references separately from filesystem routes", () => {
|
||||
const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec
|
||||
|
||||
for (const path of ["/api/fs/read", "/api/fs/list"]) {
|
||||
for (const path of ["/api/fs/read/*", "/api/fs/list"]) {
|
||||
expect(spec.paths[path]?.get?.parameters, path).not.toContainEqual(expect.objectContaining({ name: "reference" }))
|
||||
}
|
||||
expect(spec.paths["/api/reference"]?.get).toBeDefined()
|
||||
|
|
|
|||
|
|
@ -389,12 +389,9 @@ describe("HttpApi SDK", () => {
|
|||
workspaceID,
|
||||
onRequest: (value) => (request = value),
|
||||
})
|
||||
const file = yield* call(() => sdk.v2.fs.read({ path: "hello.txt" }))
|
||||
const found = yield* call(() => sdk.v2.fs.find({ query: "hello", type: "file" }))
|
||||
const url = new URL(request!.url)
|
||||
|
||||
expect(file.response.status).toBe(200)
|
||||
expect(file.data).toMatchObject({ data: { content: "hello" } })
|
||||
expect(found.response.status).toBe(200)
|
||||
expect(found.data).toMatchObject({ data: [{ path: "hello.txt", type: "file" }] })
|
||||
expect(url.searchParams.get("directory")).toBe(directory)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue